TF-1961 Transform html email content in composer

(cherry picked from commit f5470c130744242195b265a0ea4aad044ad8e740)
This commit is contained in:
dab246
2023-08-18 19:42:04 +07:00
committed by Dat Vu
parent e06d35f1e1
commit 8eed49fd73
45 changed files with 1139 additions and 644 deletions
@@ -1,12 +1,16 @@
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:model/model.dart';
abstract class HtmlDataSource {
Future<EmailContent> transformEmailContent(
EmailContent emailContent,
Map<String, String> mapUrlDownloadCID,
{bool draftsEmail = false}
Map<String, String> mapCidImageDownloadUrl,
TransformConfiguration transformConfiguration
);
Future<EmailContent> addTooltipWhenHoverOnLink(EmailContent emailContent);
Future<String> transformHtmlEmailContent(
String htmlContent,
TransformConfiguration configuration
);
}
@@ -1,3 +1,4 @@
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:model/email/email_content.dart';
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
@@ -13,22 +14,25 @@ class HtmlDataSourceImpl extends HtmlDataSource {
@override
Future<EmailContent> transformEmailContent(
EmailContent emailContent,
Map<String, String>? mapUrlDownloadCID,
{bool draftsEmail = false}
Map<String, String> mapCidImageDownloadUrl,
TransformConfiguration transformConfiguration
) {
return Future.sync(() async {
return await _htmlAnalyzer.transformEmailContent(
emailContent,
mapUrlDownloadCID,
draftsEmail: draftsEmail
mapCidImageDownloadUrl,
transformConfiguration
);
}).catchError(_exceptionThrower.throwException);
}
@override
Future<EmailContent> addTooltipWhenHoverOnLink(EmailContent emailContent) {
Future<String> transformHtmlEmailContent(String htmlContent, TransformConfiguration configuration) {
return Future.sync(() async {
return await _htmlAnalyzer.addTooltipWhenHoverOnLink(emailContent);
return await _htmlAnalyzer.transformHtmlEmailContent(
htmlContent,
configuration
);
}).catchError(_exceptionThrower.throwException);
}
}
@@ -1,11 +1,5 @@
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:core/data/network/dio_client.dart';
import 'package:core/presentation/utils/html_transformer/dom/add_tooltip_link_transformers.dart';
import 'package:core/presentation/utils/html_transformer/html_transform.dart';
import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:html/parser.dart';
import 'package:model/email/email_content.dart';
@@ -14,32 +8,27 @@ import 'package:model/email/email_content_type.dart';
class HtmlAnalyzer {
final HtmlTransform _htmlTransform;
final HtmlEscape _htmlEscape;
HtmlAnalyzer(this._htmlTransform, this._htmlEscape);
HtmlAnalyzer(this._htmlTransform);
Future<EmailContent> transformEmailContent(
EmailContent emailContent,
Map<String, String>? mapUrlDownloadCID,
{bool draftsEmail = false}
Map<String, String> mapCidImageDownloadUrl,
TransformConfiguration transformConfiguration
) async {
switch(emailContent.type) {
case EmailContentType.textHtml:
final htmlContent = await _htmlTransform.transformToHtml(
contentHtml: emailContent.content,
mapUrlDownloadCID: mapUrlDownloadCID,
transformConfiguration: draftsEmail
? TransformConfiguration.create(customDomTransformers: TransformConfiguration.domTransformersForDraftEmail)
: null
htmlContent: emailContent.content,
mapCidImageDownloadUrl: mapCidImageDownloadUrl,
transformConfiguration: transformConfiguration
);
return EmailContent(emailContent.type, htmlContent);
case EmailContentType.textPlain:
final message = _htmlTransform.transformToTextPlain(
content: emailContent.content,
transformConfiguration: TransformConfiguration.create(
customTextTransformers: [SanitizeAutolinkHtmlTransformers(_htmlEscape)]
)
transformConfiguration: transformConfiguration
);
return EmailContent(emailContent.type, message);
default:
@@ -47,21 +36,6 @@ class HtmlAnalyzer {
}
}
Future<EmailContent> addTooltipWhenHoverOnLink(EmailContent emailContent) async {
switch(emailContent.type) {
case EmailContentType.textHtml:
final htmlContent = await _htmlTransform.transformToHtml(
contentHtml: emailContent.content,
transformConfiguration: TransformConfiguration.create(
customDomTransformers: [const AddTooltipLinkTransformer()]
)
);
return EmailContent(emailContent.type, htmlContent);
default:
return emailContent;
}
}
Future<List<String>> getListLinkCalendarEvent(String emailContents) async {
final document = parse(emailContents);
final linkElements = document.querySelectorAll('a.part-button');
@@ -71,4 +45,15 @@ class HtmlAnalyzer {
.toList();
return listLink;
}
Future<String> transformHtmlEmailContent(
String htmlContent,
TransformConfiguration configuration
) async {
final htmlContentTransformed = await _htmlTransform.transformToHtml(
htmlContent: htmlContent,
transformConfiguration: configuration
);
return htmlContentTransformed;
}
}
@@ -6,6 +6,7 @@ import 'package:core/data/model/source_type/data_source_type.dart';
import 'package:core/data/network/download/downloaded_response.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
@@ -109,22 +110,16 @@ class EmailRepositoryImpl extends EmailRepository {
@override
Future<List<EmailContent>> transformEmailContent(
List<EmailContent> emailContents,
List<Attachment> attachmentInlines,
String? baseUrlDownload,
AccountId accountId,
{bool draftsEmail = false}
) async {
final mapUrlDownloadCID = {
for (var attachment in attachmentInlines)
attachment.cid! : attachment.getDownloadUrl(baseUrlDownload!, accountId)
};
List<EmailContent> emailContents,
Map<String, String> mapCidImageDownloadUrl,
TransformConfiguration transformConfiguration
) async {
return await Future.wait(emailContents
.map((emailContent) async {
return await _htmlDataSource.transformEmailContent(
emailContent,
mapUrlDownloadCID,
draftsEmail: draftsEmail
mapCidImageDownloadUrl,
transformConfiguration,
);
})
.toList());
@@ -173,13 +168,6 @@ class EmailRepositoryImpl extends EmailRepository {
return emailDataSource[DataSourceType.network]!.deleteEmailPermanently(session, accountId, emailId);
}
@override
Future<List<EmailContent>> addTooltipWhenHoverOnLink(List<EmailContent> emailContents) {
return Future.wait(emailContents
.map((emailContent) => _htmlDataSource.addTooltipWhenHoverOnLink(emailContent))
.toList());
}
@override
Future<jmap.State?> getEmailState(Session session, AccountId accountId) {
return _stateDataSource.getState(accountId, session.username, StateType.email);
@@ -219,4 +207,9 @@ class EmailRepositoryImpl extends EmailRepository {
Future<DetailedEmail> getStoredNewEmail(Session session, AccountId accountId, EmailId emailId) {
return emailDataSource[DataSourceType.hiveCache]!.getStoredNewEmail(session, accountId, emailId);
}
@override
Future<String> transformHtmlEmailContent(String htmlContent, TransformConfiguration configuration) {
return _htmlDataSource.transformHtmlEmailContent(htmlContent, configuration);
}
}
@@ -3,4 +3,6 @@ class CannotDeleteOldEmailException implements Exception {}
class NotFoundEmailException implements Exception {}
class NotFoundEmailContentException implements Exception {}
class NotFoundEmailContentException implements Exception {}
class EmptyEmailContentException implements Exception {}
@@ -4,6 +4,7 @@ import 'dart:typed_data';
import 'package:core/data/network/download/downloaded_response.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
@@ -69,14 +70,10 @@ abstract class EmailRepository {
Future<List<EmailContent>> transformEmailContent(
List<EmailContent> emailContents,
List<Attachment> attachmentInlines,
String? baseUrlDownload,
AccountId accountId,
{bool draftsEmail = false}
Map<String, String> mapCidImageDownloadUrl,
TransformConfiguration transformConfiguration
);
Future<List<EmailContent>> addTooltipWhenHoverOnLink(List<EmailContent> emailContents);
Future<Email> saveEmailAsDrafts(Session session, AccountId accountId, Email email);
Future<bool> removeEmailDrafts(Session session, AccountId accountId, EmailId emailId);
@@ -102,4 +99,9 @@ abstract class EmailRepository {
Future<DetailedEmail> getStoredOpenedEmail(Session session, AccountId accountId, EmailId emailId);
Future<DetailedEmail> getStoredNewEmail(Session session, AccountId accountId, EmailId emailId);
Future<String> transformHtmlEmailContent(
String htmlContent,
TransformConfiguration configuration
);
}
@@ -6,41 +6,38 @@ import 'package:model/email/attachment.dart';
class GetEmailContentLoading extends LoadingState {}
class GetEmailContentSuccess extends UIState {
final String emailContent;
final String emailContentDisplayed;
final String htmlEmailContent;
final List<Attachment> attachments;
final Email? emailCurrent;
GetEmailContentSuccess({
required this.emailContent,
required this.emailContentDisplayed,
required this.attachments,
required this.emailCurrent
});
@override
List<Object?> get props => [
emailContent,
emailContentDisplayed,
attachments,
emailCurrent
];
}
class GetEmailContentFromCacheSuccess extends UIState {
final String emailContent;
final List<Attachment> attachments;
final Email? emailCurrent;
GetEmailContentFromCacheSuccess({
required this.emailContent,
required this.htmlEmailContent,
required this.attachments,
this.emailCurrent
});
@override
List<Object?> get props => [
emailContent,
htmlEmailContent,
attachments,
emailCurrent
];
}
class GetEmailContentFromCacheSuccess extends UIState {
final String htmlEmailContent;
final List<Attachment> attachments;
final Email? emailCurrent;
GetEmailContentFromCacheSuccess({
required this.htmlEmailContent,
required this.attachments,
this.emailCurrent
});
@override
List<Object?> get props => [
htmlEmailContent,
attachments,
emailCurrent,
];
@@ -0,0 +1,18 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class TransformHtmlEmailContentLoading extends LoadingState {}
class TransformHtmlEmailContentSuccess extends UIState {
final String htmlContent;
TransformHtmlEmailContentSuccess(this.htmlContent);
@override
List<Object?> get props => [htmlContent];
}
class TransformHtmlEmailContentFailure extends FeatureFailure {
TransformHtmlEmailContentFailure(dynamic exception) : super(exception: exception);
}
@@ -1,6 +1,7 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:core/utils/app_logger.dart';
import 'package:core/utils/platform_info.dart';
import 'package:dartz/dartz.dart';
@@ -20,19 +21,16 @@ class GetEmailContentInteractor {
Session session,
AccountId accountId,
EmailId emailId,
String? baseDownloadUrl,
{
bool composeEmail = false,
bool draftsEmail = false
}
String baseDownloadUrl,
TransformConfiguration transformConfiguration,
) async* {
try {
yield Right<Failure, Success>(GetEmailContentLoading());
if (PlatformInfo.isMobile) {
yield* _getStoredOpenedEmail(session, accountId, emailId, baseDownloadUrl, composeEmail: composeEmail, draftsEmail: draftsEmail);
yield* _getStoredOpenedEmail(session, accountId, emailId, baseDownloadUrl, transformConfiguration);
} else {
yield* _getContentEmailFromServer(session, accountId, emailId, baseDownloadUrl, composeEmail: composeEmail, draftsEmail: draftsEmail);
yield* _getContentEmailFromServer(session, accountId, emailId, baseDownloadUrl, transformConfiguration);
}
} catch (e) {
log('GetEmailContentInteractor::execute(): exception = $e');
@@ -44,38 +42,31 @@ class GetEmailContentInteractor {
Session session,
AccountId accountId,
EmailId emailId,
String? baseDownloadUrl,
{
bool composeEmail = false,
bool draftsEmail = false
}
String baseDownloadUrl,
TransformConfiguration transformConfiguration,
) async* {
try {
final email = await emailRepository.getEmailContent(session, accountId, emailId);
if (email.emailContentList.isNotEmpty) {
final mapCidImageDownloadUrl = email.attachmentsWithCid.toMapCidImageDownloadUrl(
accountId: accountId,
downloadUrl: baseDownloadUrl
);
final newEmailContents = await emailRepository.transformEmailContent(
email.emailContentList,
email.allAttachments.listAttachmentsDisplayedInContent,
baseDownloadUrl,
accountId,
draftsEmail: draftsEmail
mapCidImageDownloadUrl,
transformConfiguration
);
final newEmailContentsDisplayed = PlatformInfo.isWeb && !composeEmail
? await emailRepository.addTooltipWhenHoverOnLink(newEmailContents)
: newEmailContents;
yield Right<Failure, Success>(GetEmailContentSuccess(
emailContent: newEmailContents.asHtmlString,
emailContentDisplayed: newEmailContentsDisplayed.asHtmlString,
htmlEmailContent: newEmailContents.asHtmlString,
attachments: email.allAttachments,
emailCurrent: email
));
} else {
yield Right<Failure, Success>(GetEmailContentSuccess(
emailContent: '',
emailContentDisplayed: '',
htmlEmailContent: '',
attachments: email.allAttachments,
emailCurrent: email
));
@@ -90,17 +81,14 @@ class GetEmailContentInteractor {
Session session,
AccountId accountId,
EmailId emailId,
String? baseDownloadUrl,
{
bool composeEmail = false,
bool draftsEmail = false
}
String baseDownloadUrl,
TransformConfiguration transformConfiguration,
) async* {
try {
log('GetEmailContentInteractor::_getStoredOpenedEmail(): CALLED');
final detailedEmail = await emailRepository.getStoredOpenedEmail(session, accountId, emailId);
yield Right<Failure, Success>(GetEmailContentFromCacheSuccess(
emailContent: detailedEmail.htmlEmailContent ?? "",
htmlEmailContent: detailedEmail.htmlEmailContent ?? '',
attachments: detailedEmail.attachments ?? [],
emailCurrent: Email(
id: emailId,
@@ -115,8 +103,8 @@ class GetEmailContentInteractor {
accountId,
emailId,
baseDownloadUrl,
composeEmail: composeEmail,
draftsEmail: draftsEmail);
transformConfiguration
);
}
}
@@ -124,17 +112,14 @@ class GetEmailContentInteractor {
Session session,
AccountId accountId,
EmailId emailId,
String? baseDownloadUrl,
{
bool composeEmail = false,
bool draftsEmail = false
}
String baseDownloadUrl,
TransformConfiguration transformConfiguration,
) async* {
try {
log('GetEmailContentInteractor::_getStoredNewEmail():CALLED');
final detailedEmail = await emailRepository.getStoredNewEmail(session, accountId, emailId);
yield Right<Failure, Success>(GetEmailContentFromCacheSuccess(
emailContent: detailedEmail.htmlEmailContent ?? "",
htmlEmailContent: detailedEmail.htmlEmailContent ?? '',
attachments: detailedEmail.attachments ?? [],
emailCurrent: Email(
id: emailId,
@@ -149,8 +134,8 @@ class GetEmailContentInteractor {
accountId,
emailId,
baseDownloadUrl,
composeEmail: composeEmail,
draftsEmail: draftsEmail);
transformConfiguration
);
}
}
}
@@ -1,5 +1,7 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:core/utils/platform_info.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/extensions/utc_date_extension.dart';
@@ -23,7 +25,7 @@ class GetListDetailedEmailByIdInteractor {
Session session,
AccountId accountId,
Set<EmailId> emailIds,
String? baseDownloadUrl,
String baseDownloadUrl,
{Set<Comparator>? sort}
) async* {
try {
@@ -57,17 +59,27 @@ class GetListDetailedEmailByIdInteractor {
Future<Tuple2<Email, DetailedEmail>> _parsingEmailToDetailedEmail(
AccountId accountId,
Email email,
String? baseDownloadUrl
String baseDownloadUrl
) async {
String? htmlEmailContent;
final listEmailContent = email.emailContentList;
if (listEmailContent.isNotEmpty) {
final mapCidImageDownloadUrl = email.attachmentsWithCid.toMapCidImageDownloadUrl(
accountId: accountId,
downloadUrl: baseDownloadUrl
);
TransformConfiguration transformConfiguration = TransformConfiguration.standardConfiguration;
if (email.isDraft) {
transformConfiguration = TransformConfiguration.forDraftsEmail();
} else if (PlatformInfo.isWeb) {
transformConfiguration = TransformConfiguration.forPreviewEmailPlatformWeb();
}
final newEmailContents = await _emailRepository.transformEmailContent(
listEmailContent,
email.allAttachments.listAttachmentsDisplayedInContent,
baseDownloadUrl,
accountId);
email.emailContentList,
mapCidImageDownloadUrl,
transformConfiguration
);
htmlEmailContent = newEmailContents.asHtmlString;
}
@@ -0,0 +1,26 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_content_state.dart';
class TransformHtmlEmailContentInteractor {
final EmailRepository emailRepository;
TransformHtmlEmailContentInteractor(this.emailRepository);
Stream<Either<Failure, Success>> execute(
String htmlContent,
TransformConfiguration configuration
) async* {
try {
yield Right<Failure, Success>(TransformHtmlEmailContentLoading());
final htmlContentTransformed = await emailRepository.transformHtmlEmailContent(htmlContent, configuration);
yield Right<Failure, Success>(TransformHtmlEmailContentSuccess(htmlContentTransformed));
} catch (e) {
yield Left<Failure, Success>(TransformHtmlEmailContentFailure(e));
}
}
}
@@ -360,22 +360,33 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
void _getEmailContentAction(EmailId emailId) async {
final session = mailboxDashBoardController.sessionCurrent;
final accountId = mailboxDashBoardController.accountId.value;
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
final emailLoaded = emailSupervisorController.getEmailInQueueByEmailId(emailId);
if (emailLoaded != null) {
consumeState(Stream.value(Right<Failure, Success>(
GetEmailContentSuccess(
emailContent: emailLoaded.originalContent,
emailContentDisplayed: emailLoaded.displayedContent,
htmlEmailContent: emailLoaded.htmlContent,
attachments: emailLoaded.attachments,
emailCurrent: emailLoaded.emailCurrent
)
)));
} else if (session != null && accountId != null && baseDownloadUrl != null) {
consumeState(_getEmailContentInteractor.execute(session, accountId, emailId, baseDownloadUrl));
} else {
final session = mailboxDashBoardController.sessionCurrent;
final accountId = mailboxDashBoardController.accountId.value;
if (session != null && accountId != null) {
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl) ?? '';
TransformConfiguration transformConfiguration = PlatformInfo.isWeb
? TransformConfiguration.forPreviewEmailPlatformWeb()
: TransformConfiguration.standardConfiguration;
consumeState(_getEmailContentInteractor.execute(
session,
accountId,
emailId,
baseDownloadUrl,
transformConfiguration
));
}
}
}
@@ -387,8 +398,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
emailSupervisorController.popEmailQueue(success.emailCurrent?.id);
_currentEmailLoaded = EmailLoaded(
originalContent: success.emailContent,
displayedContent: success.emailContent,
htmlContent: success.htmlEmailContent,
attachments: List.of(success.attachments),
emailCurrent: success.emailCurrent,
);
@@ -401,10 +411,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_parseCalendarEventAction(
accountId: mailboxDashBoardController.accountId.value!,
blobIds: success.attachments.calendarEventBlobIds,
emailContents: success.emailContent
emailContents: success.htmlEmailContent
);
} else {
emailContents.value = success.emailContent;
emailContents.value = success.htmlEmailContent;
}
final isShowMessageReadReceipt = success.emailCurrent?.hasReadReceipt(mailboxDashBoardController.mapMailboxById) == true;
@@ -422,8 +432,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
emailSupervisorController.popEmailQueue(success.emailCurrent?.id);
_currentEmailLoaded = EmailLoaded(
originalContent: success.emailContent,
displayedContent: success.emailContentDisplayed,
htmlContent: success.htmlEmailContent,
attachments: List.of(success.attachments),
emailCurrent: success.emailCurrent,
);
@@ -436,10 +445,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_parseCalendarEventAction(
accountId: mailboxDashBoardController.accountId.value!,
blobIds: success.attachments.calendarEventBlobIds,
emailContents: success.emailContent
emailContents: success.htmlEmailContent
);
} else {
emailContents.value = success.emailContentDisplayed;
emailContents.value = success.htmlEmailContent;
}
if (PlatformInfo.isMobile) {
@@ -449,7 +458,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
attachments: success.attachments,
headers: currentEmail?.emailHeader?.toSet(),
keywords: currentEmail?.keywords,
htmlEmailContent: success.emailContentDisplayed
htmlEmailContent: success.htmlEmailContent
);
_storeOpenedEmailAction(
@@ -978,13 +987,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void composeEmailFromEmailAddress(EmailAddress emailAddress) {
popBack();
final arguments = ComposerArguments(
emailActionType: EmailActionType.composeFromEmailAddress,
emailAddress: emailAddress,
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
mailboxDashBoardController.goToComposer(arguments);
mailboxDashBoardController.goToComposer(ComposerArguments.fromEmailAddress(emailAddress));
}
void openMailToLink(Uri? uri) {
@@ -993,12 +996,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
log('SingleEmailController::openMailToLink(): address: $address');
if (address.isNotEmpty) {
final emailAddress = EmailAddress(null, address);
final arguments = ComposerArguments(
emailActionType: EmailActionType.composeFromEmailAddress,
emailAddress: emailAddress,
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
mailboxDashBoardController.goToComposer(arguments);
mailboxDashBoardController.goToComposer(ComposerArguments.fromEmailAddress(emailAddress));
}
}
@@ -1158,19 +1156,43 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
}
void pressEmailAction(EmailActionType emailActionType) {
if (emailActionType == EmailActionType.compose) {
mailboxDashBoardController.goToComposer(ComposerArguments());
} else {
final arguments = ComposerArguments(
emailActionType: emailActionType,
presentationEmail: mailboxDashBoardController.selectedEmail.value!,
emailContents: _currentEmailLoaded?.originalContent,
attachments: emailActionType == EmailActionType.forward ? attachments : null,
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role
);
mailboxDashBoardController.goToComposer(arguments);
void pressEmailAction(
EmailActionType emailActionType,
PresentationEmail presentationEmail
) {
switch(emailActionType) {
case EmailActionType.compose:
mailboxDashBoardController.goToComposer(ComposerArguments());
break;
case EmailActionType.reply:
mailboxDashBoardController.goToComposer(
ComposerArguments.replyEmail(
presentationEmail: presentationEmail,
content: _currentEmailLoaded?.htmlContent ?? '',
mailboxRole: presentationEmail.mailboxContain?.role
)
);
break;
case EmailActionType.replyAll:
mailboxDashBoardController.goToComposer(
ComposerArguments.replyAllEmail(
presentationEmail: presentationEmail,
content: _currentEmailLoaded?.htmlContent ?? '',
mailboxRole: presentationEmail.mailboxContain?.role
)
);
break;
case EmailActionType.forward:
mailboxDashBoardController.goToComposer(
ComposerArguments.forwardEmail(
presentationEmail: presentationEmail,
content: _currentEmailLoaded?.htmlContent ?? '',
attachments: attachments
)
);
break;
default:
break;
}
}
@@ -1276,7 +1298,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void _handleParseCalendarEventFailure(ParseCalendarEventFailure failure) {
emailLoadedViewState.value = Left<Failure, Success>(failure);
emailContents.value = _currentEmailLoaded?.displayedContent;
emailContents.value = _currentEmailLoaded?.htmlContent;
}
void _enableScrollPageView() {
@@ -1289,11 +1311,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void openNewComposerAction(String mailTo) {
final emailAddress = EmailAddress(mailTo, mailTo);
final arguments = ComposerArguments(
emailActionType: EmailActionType.composeFromEmailAddress,
emailAddress: emailAddress,
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role
);
mailboxDashBoardController.goToComposer(arguments);
mailboxDashBoardController.goToComposer(ComposerArguments.fromEmailAddress(emailAddress));
}
}
@@ -2,6 +2,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
import 'package:tmail_ui_user/main/routes/router_arguments.dart';
@@ -26,6 +27,84 @@ class ComposerArguments extends RouterArguments {
this.sendingEmail
});
factory ComposerArguments.fromSendingEmail(SendingEmail sendingEmail) =>
ComposerArguments(
emailActionType: EmailActionType.editSendingEmail,
sendingEmail: sendingEmail
);
factory ComposerArguments.fromContentShared(String content) =>
ComposerArguments(
emailActionType: EmailActionType.composeFromContentShared,
emailContents: content
);
factory ComposerArguments.fromFileShared(List<SharedMediaFile> filesShared) =>
ComposerArguments(
emailActionType: EmailActionType.composeFromFileShared,
listSharedMediaFile: filesShared
);
factory ComposerArguments.fromEmailAddress(EmailAddress emailAddress) =>
ComposerArguments(
emailActionType: EmailActionType.composeFromEmailAddress,
emailAddress: emailAddress
);
factory ComposerArguments.editDraftEmail(PresentationEmail presentationEmail) =>
ComposerArguments(
emailActionType: EmailActionType.editDraft,
presentationEmail: presentationEmail
);
factory ComposerArguments.fromSessionStorageBrowser(ComposerCache composerCache) =>
ComposerArguments(
emailActionType: EmailActionType.reopenComposerBrowser,
presentationEmail: PresentationEmail(
id: composerCache.id,
subject: composerCache.subject,
from: composerCache.from,
to: composerCache.to,
cc: composerCache.cc,
bcc: composerCache.bcc,
),
emailContents: composerCache.emailContentList.asHtmlString,
);
factory ComposerArguments.replyEmail({
required PresentationEmail presentationEmail,
required String content,
Role? mailboxRole,
}) => ComposerArguments(
emailActionType: EmailActionType.reply,
presentationEmail: presentationEmail,
emailContents: content,
mailboxRole: mailboxRole
);
factory ComposerArguments.replyAllEmail({
required PresentationEmail presentationEmail,
required String content,
Role? mailboxRole,
}) => ComposerArguments(
emailActionType: EmailActionType.replyAll,
presentationEmail: presentationEmail,
emailContents: content,
mailboxRole: mailboxRole
);
factory ComposerArguments.forwardEmail({
required PresentationEmail presentationEmail,
required String content,
required List<Attachment> attachments,
}) => ComposerArguments(
emailActionType: EmailActionType.forward,
presentationEmail: presentationEmail,
emailContents: content,
attachments: attachments,
mailboxRole: presentationEmail.mailboxContain?.role
);
@override
List<Object?> get props => [
emailActionType,
@@ -3,22 +3,19 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/email/attachment.dart';
class EmailLoaded with EquatableMixin {
final String originalContent;
final String displayedContent;
final String htmlContent;
final List<Attachment> attachments;
final Email? emailCurrent;
EmailLoaded({
required this.originalContent,
required this.displayedContent,
required this.htmlContent,
required this.attachments,
this.emailCurrent,
});
@override
List<Object?> get props => [
originalContent,
displayedContent,
htmlContent,
attachments,
emailCurrent
];
@@ -9,7 +9,10 @@ import 'package:model/email/presentation_email.dart';
import 'package:model/extensions/presentation_email_extension.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnPressEmailActionClick = void Function(EmailActionType emailActionType);
typedef OnPressEmailActionClick = void Function(
EmailActionType emailActionType,
PresentationEmail presentationEmail
);
class BottomBarMailWidgetBuilder extends StatelessWidget {
@@ -60,7 +63,7 @@ class BottomBarMailWidgetBuilder extends StatelessWidget {
color: AppColor.colorTextButton
),
verticalDirection: responsiveUtils.isPortraitMobile(context),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.replyAll),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.replyAll, _presentationEmail),
),
),
Expanded(
@@ -79,7 +82,7 @@ class BottomBarMailWidgetBuilder extends StatelessWidget {
color: AppColor.colorTextButton
),
verticalDirection: responsiveUtils.isPortraitMobile(context),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.reply),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.reply, _presentationEmail),
),
),
Expanded(
@@ -98,7 +101,7 @@ class BottomBarMailWidgetBuilder extends StatelessWidget {
color: AppColor.colorTextButton
),
verticalDirection: responsiveUtils.isPortraitMobile(context),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.forward),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.forward, _presentationEmail),
),
),
Expanded(
@@ -117,7 +120,7 @@ class BottomBarMailWidgetBuilder extends StatelessWidget {
color: AppColor.colorTextButton
),
verticalDirection: responsiveUtils.isPortraitMobile(context),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.compose),
onTapActionCallback: () => onPressEmailActionClick?.call(EmailActionType.compose, _presentationEmail),
),
),
]