diff --git a/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart b/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart index 054246ff6..72b63ecec 100644 --- a/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart +++ b/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart @@ -22,7 +22,6 @@ class ConfirmDialogBuilder { TextStyle? _styleTitle; TextStyle? _styleContent; double? _radiusButton; - double? heightButton; EdgeInsetsGeometry? _paddingTitle; EdgeInsets? _paddingContent; EdgeInsets? _paddingButton; @@ -46,7 +45,6 @@ class ConfirmDialogBuilder { { this.showAsBottomSheet = false, this.listTextSpan, - this.heightButton, this.maxWith = double.infinity, } ); @@ -240,7 +238,6 @@ class ConfirmDialogBuilder { name: _cancelText, bgColor: _colorCancelButton, radius: _radiusButton, - height: heightButton, textStyle: _styleTextCancelButton, action: _onCancelButtonAction)), if (_confirmText.isNotEmpty && _cancelText.isNotEmpty) const SizedBox(width: 16), @@ -249,7 +246,6 @@ class ConfirmDialogBuilder { name: _confirmText, bgColor: _colorConfirmButton, radius: _radiusButton, - height: heightButton, textStyle: _styleTextConfirmButton, action: _onConfirmButtonAction)) ] @@ -264,12 +260,10 @@ class ConfirmDialogBuilder { TextStyle? textStyle, Color? bgColor, double? radius, - double? height, Function? action }) { return SizedBox( width: double.infinity, - height: height ?? 48, child: ElevatedButton( onPressed: () => action?.call(), style: ButtonStyle( @@ -281,8 +275,7 @@ class ConfirmDialogBuilder { borderRadius: BorderRadius.circular(radius ?? 8), side: BorderSide(width: 0, color: bgColor ?? AppColor.colorTextButton), )), - padding: MaterialStateProperty.resolveWith( - (Set states) => const EdgeInsets.symmetric(horizontal: 16)), + padding: MaterialStateProperty.resolveWith((Set states) => const EdgeInsets.all(8)), elevation: MaterialStateProperty.resolveWith((Set states) => 0)), child: Text(name ?? '', textAlign: TextAlign.center, diff --git a/lib/features/base/mixin/message_dialog_action_mixin.dart b/lib/features/base/mixin/message_dialog_action_mixin.dart index bb4f09841..0e542d15f 100644 --- a/lib/features/base/mixin/message_dialog_action_mixin.dart +++ b/lib/features/base/mixin/message_dialog_action_mixin.dart @@ -38,7 +38,7 @@ mixin MessageDialogActionMixin { if (alignCenter) { return await Get.dialog( PointerInterceptor( - child: (ConfirmDialogBuilder(imagePaths, listTextSpan: listTextSpan, heightButton: 44) + child: (ConfirmDialogBuilder(imagePaths, listTextSpan: listTextSpan) ..key(const Key('confirm_dialog_action')) ..title(title ?? '') ..content(message) diff --git a/lib/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart b/lib/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart new file mode 100644 index 000000000..cbb6c924d --- /dev/null +++ b/lib/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart @@ -0,0 +1,27 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart'; +import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart'; +import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart'; + +class SaveComposerCacheOnWebInteractor { + final ComposerCacheRepository _composerCacheRepository; + final ComposerRepository _composerRepository; + + SaveComposerCacheOnWebInteractor( + this._composerCacheRepository, + this._composerRepository, + ); + + Future> execute(CreateEmailRequest createEmailRequest) async { + try { + final emailCreated = await _composerRepository.generateEmail(createEmailRequest); + _composerCacheRepository.saveComposerCacheOnWeb(emailCreated); + return Right(SaveComposerCacheSuccess()); + } catch (exception) { + return Left(SaveComposerCacheFailure(exception)); + } + } +} diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index 2c56aff05..65d5f5b90 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -13,6 +13,7 @@ import 'package:tmail_ui_user/features/composer/domain/repository/contact_reposi import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart'; @@ -43,7 +44,6 @@ import 'package:tmail_ui_user/features/mailbox/data/repository/mailbox_repositor import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_composer_cache_on_web_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/profiles/identities/identity_interactors_bindings.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_manager.dart'; @@ -191,7 +191,10 @@ class ComposerBindings extends BaseBindings { Get.lazyPut(() => UploadAttachmentInteractor(Get.find())); Get.lazyPut(() => GetEmailContentInteractor(Get.find())); Get.lazyPut(() => RemoveComposerCacheOnWebInteractor(Get.find())); - Get.lazyPut(() => SaveComposerCacheOnWebInteractor(Get.find())); + Get.lazyPut(() => SaveComposerCacheOnWebInteractor( + Get.find(), + Get.find(), + )); Get.lazyPut(() => DownloadImageAsBase64Interactor(Get.find())); Get.lazyPut(() => TransformHtmlEmailContentInteractor(Get.find())); Get.lazyPut(() => GetAlwaysReadReceiptSettingInteractor(Get.find())); diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index d2eb6ef26..4ca93a9e9 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -16,15 +16,9 @@ import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:html_editor_enhanced/html_editor.dart' as web_html_editor; -import 'package:http_parser/http_parser.dart'; -import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email_body_value.dart'; -import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart'; -import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -49,6 +43,7 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_a import 'package:tmail_ui_user/features/composer/domain/usecases/get_all_autocomplete_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/get_device_contact_suggestions_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; @@ -72,7 +67,6 @@ import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_i import 'package:tmail_ui_user/features/email/domain/usecases/transform_html_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart'; @@ -343,14 +337,43 @@ class ComposerController extends BaseController with DragDropFileMixin { } void _listenBrowserTabRefresh() { - _subscriptionOnBeforeUnload = html.window.onBeforeUnload.listen((event) async { - _removeComposerCacheOnWebInteractor.execute(); - if (mailboxDashBoardController.sessionCurrent != null) { - final draftEmail = await _generateEmail( - currentContext!, - mailboxDashBoardController.sessionCurrent!.username); - _saveComposerCacheOnWebInteractor.execute(draftEmail); + _subscriptionOnBeforeUnload = html.window.onBeforeUnload.listen((event) async { + await _removeComposerCacheOnWebInteractor.execute(); + + if (composerArguments.value == null || + mailboxDashBoardController.sessionCurrent == null || + mailboxDashBoardController.accountId.value == null + ) { + log('ComposerController::_listenBrowserTabRefresh: SESSION or ACCOUNT_ID or ARGUMENTS is NULL'); + return; } + + final emailContent = await _getContentInEditor(); + + await _saveComposerCacheOnWebInteractor.execute(CreateEmailRequest( + session: mailboxDashBoardController.sessionCurrent!, + accountId: mailboxDashBoardController.accountId.value!, + emailActionType: composerArguments.value!.emailActionType, + subject: subjectEmail.value ?? '', + emailContent: emailContent, + fromSender: composerArguments.value!.presentationEmail?.from ?? {}, + toRecipients: listToEmailAddress.toSet(), + ccRecipients: listCcEmailAddress.toSet(), + bccRecipients: listBccEmailAddress.toSet(), + isRequestReadReceipt: hasRequestReadReceipt.value, + identity: identitySelected.value, + attachments: uploadController.attachmentsUploaded, + inlineAttachments: uploadController.mapInlineAttachments, + outboxMailboxId: mailboxDashBoardController.outboxMailbox?.mailboxId, + sentMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleSent], + draftsMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleDrafts], + draftsEmailId: _getDraftEmailId(), + answerForwardEmailId: composerArguments.value!.presentationEmail?.id, + unsubscribeEmailId: composerArguments.value!.previousEmailId, + messageId: composerArguments.value!.messageId, + references: composerArguments.value!.references, + emailSendingQueue: composerArguments.value!.sendingEmail + )); }); _subscriptionOnDragEnter = html.window.onDragEnter.listen((event) { @@ -666,128 +689,6 @@ class ComposerController extends BaseController with DragDropFileMixin { } } - Future _generateEmail( - BuildContext context, - UserName userName, - { - bool asDrafts = false, - MailboxId? draftMailboxId, - MailboxId? outboxMailboxId, - ComposerArguments? arguments, - } - ) async { - Set listFromEmailAddress = {EmailAddress(null, userName.value)}; - if (identitySelected.value?.email?.isNotEmpty == true) { - listFromEmailAddress = { - EmailAddress( - identitySelected.value?.name, - identitySelected.value?.email - ) - }; - } - Set listReplyToEmailAddress = {EmailAddress(null, userName.value)}; - if (identitySelected.value?.replyTo?.isNotEmpty == true) { - listReplyToEmailAddress = identitySelected.value!.replyTo!; - } - - final attachments = {}; - attachments.addAll(uploadController.generateAttachments() ?? []); - - var emailBodyText = await _getEmailBodyText(context, asDrafts: asDrafts); - if (uploadController.mapInlineAttachments.isNotEmpty) { - final mapContents = await _getMapContent(emailBodyText); - emailBodyText = mapContents.value1; - final listInlineAttachment = mapContents.value2; - final listInlineEmailBodyPart = listInlineAttachment - .map((attachment) => attachment.toEmailBodyPart(charset: 'base64')) - .toSet(); - attachments.addAll(listInlineEmailBodyPart); - } - - final userAgent = await applicationManager.getUserAgent(); - log('ComposerController::_generateEmail(): userAgent: $userAgent'); - - Map mailboxIds = {}; - if (asDrafts && draftMailboxId != null) { - mailboxIds[draftMailboxId] = true; - } - if (outboxMailboxId != null) { - mailboxIds[outboxMailboxId] = true; - } - - Map? mapKeywords = {}; - if (asDrafts) { - mapKeywords[KeyWordIdentifier.emailDraft] = true; - mapKeywords[KeyWordIdentifier.emailSeen] = true; - } - - final inReplyTo = _generateInReplyTo(arguments); - final references = _generateReferences(arguments); - - final generatePartId = PartId(uuid.v1()); - - return Email( - mailboxIds: mailboxIds.isNotEmpty ? mailboxIds : null, - from: listFromEmailAddress, - to: listToEmailAddress.toSet(), - cc: listCcEmailAddress.toSet(), - bcc: listBccEmailAddress.toSet(), - replyTo: listReplyToEmailAddress, - inReplyTo: inReplyTo, - references: references, - keywords: mapKeywords.isNotEmpty ? mapKeywords : null, - subject: subjectEmail.value, - htmlBody: { - EmailBodyPart( - partId: generatePartId, - type: MediaType.parse('text/html') - )}, - bodyValues: { - generatePartId: EmailBodyValue(emailBodyText, false, false) - }, - attachments: attachments.isNotEmpty ? attachments : null, - headerMdn: hasRequestReadReceipt.value ? { IndividualHeaderIdentifier.headerMdn: getEmailAddressSender() } : {}, - ); - } - - MessageIdsHeaderValue? _generateInReplyTo(ComposerArguments? arguments) { - if (arguments?.emailActionType == EmailActionType.reply || - arguments?.emailActionType == EmailActionType.replyAll) { - return arguments?.messageId; - } - return null; - } - - MessageIdsHeaderValue? _generateReferences(ComposerArguments? arguments) { - if (arguments?.emailActionType == EmailActionType.reply || - arguments?.emailActionType == EmailActionType.replyAll || - arguments?.emailActionType == EmailActionType.forward) { - Set ids = {}; - if (arguments?.messageId?.ids.isNotEmpty == true) { - ids.addAll(arguments!.messageId!.ids); - } - if (arguments?.references?.ids.isNotEmpty == true) { - ids.addAll(arguments!.references!.ids); - } - if (ids.isNotEmpty) { - return MessageIdsHeaderValue(ids); - } - } - return null; - } - - Future>> _getMapContent(String emailBodyText) async { - if (kIsWeb) { - return await richTextWebController.refactorContentHasInlineImage( - emailBodyText, - uploadController.mapInlineAttachments); - } else { - return await richTextMobileTabletController.refactorContentHasInlineImage( - emailBodyText, - uploadController.mapInlineAttachments); - } - } - void handleClickSendButton(BuildContext context) async { if (_sendButtonState == ButtonState.disabled) { log('ComposerController::handleClickSendButton: SENDING EMAIL'); @@ -1897,32 +1798,6 @@ class ComposerController extends BaseController with DragDropFileMixin { void setSubjectEmail(String subject) => subjectEmail.value = subject; - Future _getEmailBodyText(BuildContext context, {bool asDrafts = false}) async { - var contentHtml = ''; - - if (PlatformInfo.isWeb) { - if (responsiveUtils.isDesktop(context) && - screenDisplayMode.value == ScreenDisplayMode.minimize) { - contentHtml = _textEditorWeb ?? ''; - } else { - if (asDrafts) { - contentHtml = await richTextWebController.editorController.getText(); - } else { - contentHtml = await richTextWebController.editorController.getTextWithSignatureContent(); - } - } - } else { - if (asDrafts) { - contentHtml = (await htmlEditorApi?.getText()) ?? ''; - } else { - contentHtml = (await htmlEditorApi?.getTextWithSignatureContent()) ?? ''; - } - } - - final newContentHtml = contentHtml.removeEditorStartTag(); - return newContentHtml; - } - void removeDraggableEmailAddress(DraggableEmailAddress draggableEmailAddress) { log('ComposerController::removeDraggableEmailAddress: $draggableEmailAddress'); switch(draggableEmailAddress.prefix) { diff --git a/lib/features/composer/presentation/controller/base_rich_text_controller.dart b/lib/features/composer/presentation/controller/base_rich_text_controller.dart index 262dbd544..52d3f8c46 100644 --- a/lib/features/composer/presentation/controller/base_rich_text_controller.dart +++ b/lib/features/composer/presentation/controller/base_rich_text_controller.dart @@ -1,12 +1,7 @@ -import 'package:collection/collection.dart'; import 'package:core/presentation/views/dialog/color_picker_dialog_builder.dart'; -import 'package:core/utils/app_logger.dart'; -import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:html/parser.dart' show parse; -import 'package:model/email/attachment.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -37,32 +32,4 @@ abstract class BaseRichTextController extends GetxController { } ).show(); } - - Future>> refactorContentHasInlineImage( - String emailContent, - Map mapInlineAttachments - ) async { - final document = parse(emailContent); - final listImgTag = document.querySelectorAll('img[src^="data:image/"][id^="cid:"]'); - final listInlineAttachment = await Future.wait(listImgTag.map((imgTag) async { - final idImg = imgTag.attributes['id']; - final cid = idImg!.replaceFirst('cid:', '').trim(); - log('BaseRichTextController::refactorContentHasInlineImage(): $cid'); - imgTag.attributes['src'] = 'cid:$cid'; - imgTag.attributes.remove('id'); - return cid; - })).then((listCid) { - log('BaseRichTextController::refactorContentHasInlineImage(): $listCid'); - final listInlineAttachment = listCid - .whereNotNull() - .map((cid) => mapInlineAttachments[cid]) - .whereNotNull() - .toList(); - return listInlineAttachment; - }); - final newContent = document.body?.innerHtml ?? emailContent; - log('BaseRichTextController::refactorContentHasInlineImage(): $newContent'); - log('BaseRichTextController::refactorContentHasInlineImage(): listInlineAttachment: $listInlineAttachment'); - return Tuple2(newContent, listInlineAttachment); - } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart index 6674a5029..5857b4eb4 100644 --- a/lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart +++ b/lib/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart @@ -8,7 +8,7 @@ class RemoveComposerCacheOnWebInteractor { RemoveComposerCacheOnWebInteractor(this.composerCacheRepository); - Either execute() { + Future> execute() async { try { composerCacheRepository.removeComposerCacheOnWeb(); return Right(RemoveComposerCacheSuccess()); diff --git a/lib/features/mailbox_dashboard/domain/usecases/save_composer_cache_on_web_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/save_composer_cache_on_web_interactor.dart deleted file mode 100644 index e08c19eef..000000000 --- a/lib/features/mailbox_dashboard/domain/usecases/save_composer_cache_on_web_interactor.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:core/core.dart'; -import 'package:dartz/dartz.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/save_composer_cache_state.dart'; - -class SaveComposerCacheOnWebInteractor { - final ComposerCacheRepository composerCacheRepository; - - SaveComposerCacheOnWebInteractor(this.composerCacheRepository); - - Either execute(Email email) { - try { - composerCacheRepository.saveComposerCacheOnWeb(email); - return Right(SaveComposerCacheSuccess()); - } catch (exception) { - return Left(SaveComposerCacheFailure(exception)); - } - } -} 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 098226137..26ee066fa 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -69,7 +69,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_unr import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_last_time_dismissed_spam_reported_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_spam_report_state_interactor.dart'; @@ -276,7 +275,6 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find()) ); Get.lazyPut(() => GetComposerCacheOnWebInteractor(Get.find())); - Get.lazyPut(() => SaveComposerCacheOnWebInteractor(Get.find())); Get.lazyPut(() => RemoveComposerCacheOnWebInteractor(Get.find())); Get.lazyPut(() => MarkAsEmailReadInteractor( Get.find(),