TF-1961 Transform html email content in composer
(cherry picked from commit f5470c130744242195b265a0ea4aad044ad8e740)
This commit is contained in:
@@ -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),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user