diff --git a/core/lib/presentation/utils/html_transformer/base/text_transformer.dart b/core/lib/presentation/utils/html_transformer/base/text_transformer.dart
index af064550d..e7100b8b1 100644
--- a/core/lib/presentation/utils/html_transformer/base/text_transformer.dart
+++ b/core/lib/presentation/utils/html_transformer/base/text_transformer.dart
@@ -1,7 +1,9 @@
+import 'dart:convert';
+
/// Transforms plain text messages.
abstract class TextTransformer {
const TextTransformer();
- String process(String text);
+ String process(String text, HtmlEscape htmlEscape);
}
\ No newline at end of file
diff --git a/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart
index e5e1874be..6d2a7aeef 100644
--- a/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart
+++ b/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart
@@ -12,7 +12,9 @@ import 'package:html/dom.dart';
class ImageTransformer extends DomTransformer {
- const ImageTransformer();
+ final bool useLoadingAttribute;
+
+ const ImageTransformer({this.useLoadingAttribute = false});
@override
Future process({
@@ -40,14 +42,19 @@ class ImageTransformer extends DomTransformer {
);
imageElement.attributes['src'] = imageBase64 ?? src;
} else if (src.startsWith('https://') || src.startsWith('http://')) {
- final classAttribute = imageElement.attributes['class'];
- if (classAttribute != null) {
- imageElement.attributes['class'] = '$classAttribute lazy-loading';
+ if (useLoadingAttribute) {
+ imageElement.attributes['loading'] = 'lazy';
} else {
- imageElement.attributes['class'] = 'lazy-loading';
+ final classAttribute = imageElement.attributes['class'];
+ if (classAttribute != null) {
+ imageElement.attributes['class'] = '$classAttribute lazy-loading';
+ } else {
+ imageElement.attributes['class'] = 'lazy-loading';
+ }
+ imageElement.attributes['data-src'] = src;
+ imageElement.attributes.remove('src');
+ imageElement.attributes.remove('loading');
}
- imageElement.attributes['data-src'] = src;
- imageElement.attributes.remove('src');
}
}));
}
diff --git a/core/lib/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart
new file mode 100644
index 000000000..54a7b0708
--- /dev/null
+++ b/core/lib/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart
@@ -0,0 +1,35 @@
+
+import 'package:core/data/network/dio_client.dart';
+import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
+import 'package:core/presentation/utils/html_transformer/html_template.dart';
+import 'package:core/utils/app_logger.dart';
+import 'package:html/dom.dart';
+
+class RemoveTooltipLinkTransformer extends DomTransformer {
+
+ const RemoveTooltipLinkTransformer();
+
+ @override
+ Future process({
+ required Document document,
+ Map? mapUrlDownloadCID,
+ DioClient? dioClient
+ }) async {
+ final linkElements = document.querySelectorAll('a.$nameClassToolTip');
+ await Future.wait(linkElements.map((linkElement) async {
+ final classAttribute = linkElement.attributes['class'];
+ if (classAttribute != null) {
+ final newClassAttribute = classAttribute.replaceFirst(nameClassToolTip, '');
+ linkElement.attributes['class'] = newClassAttribute;
+ }
+ final listSpanTag = linkElement.querySelectorAll('span.tooltiptext');
+ log('RemoveTooltipLinkTransformer::process:listSpanTag: ${listSpanTag.length}');
+ if (listSpanTag.isNotEmpty) {
+ for (var element in listSpanTag) {
+ element.remove();
+ }
+ }
+ }));
+ }
+
+}
\ No newline at end of file
diff --git a/core/lib/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart b/core/lib/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart
new file mode 100644
index 000000000..32f8d4c74
--- /dev/null
+++ b/core/lib/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart
@@ -0,0 +1,32 @@
+
+
+import 'package:core/data/network/dio_client.dart';
+import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
+import 'package:html/dom.dart';
+
+class ReplaceLazyLoadImageTransformer extends DomTransformer {
+
+ const ReplaceLazyLoadImageTransformer();
+
+ @override
+ Future process({
+ required Document document,
+ Map? mapUrlDownloadCID,
+ DioClient? dioClient
+ }) async {
+ final imageElements = document.querySelectorAll('img.lazy-loading');
+ await Future.wait(imageElements.map((imageElement) async {
+ final classAttribute = imageElement.attributes['class'];
+ if (classAttribute != null) {
+ final newClassAttribute = classAttribute.replaceFirst('lazy-loading', '');
+ imageElement.attributes['class'] = newClassAttribute;
+ }
+ final dataSrc = imageElement.attributes['data-src'];
+ if (dataSrc != null) {
+ imageElement.attributes['src'] = dataSrc;
+ imageElement.attributes.remove('data-src');
+ }
+ imageElement.attributes['loading'] = 'lazy';
+ }));
+ }
+}
\ No newline at end of file
diff --git a/core/lib/presentation/utils/html_transformer/html_transform.dart b/core/lib/presentation/utils/html_transformer/html_transform.dart
index b0ed967b5..1d523af59 100644
--- a/core/lib/presentation/utils/html_transformer/html_transform.dart
+++ b/core/lib/presentation/utils/html_transformer/html_transform.dart
@@ -1,23 +1,26 @@
+import 'dart:convert';
+
import 'package:core/core.dart';
import 'package:core/presentation/utils/html_transformer/message_content_transformer.dart';
class HtmlTransform {
final DioClient _dioClient;
+ final HtmlEscape _htmlEscape;
- HtmlTransform(this._dioClient);
+ HtmlTransform(this._dioClient, this._htmlEscape);
/// Transforms this message to HTML code.
Future transformToHtml({
- required String contentHtml,
- Map? mapUrlDownloadCID,
+ required String htmlContent,
+ Map? mapCidImageDownloadUrl,
TransformConfiguration? transformConfiguration,
}) async {
transformConfiguration ??= TransformConfiguration.create();
- final transformer = MessageContentTransformer(transformConfiguration, _dioClient);
+ final transformer = MessageContentTransformer(transformConfiguration, _dioClient, _htmlEscape);
final document = await transformer.toDocument(
- message: contentHtml,
- mapUrlDownloadCID: mapUrlDownloadCID
+ message: htmlContent,
+ mapUrlDownloadCID: mapCidImageDownloadUrl
);
return document.outerHtml;
}
@@ -28,7 +31,7 @@ class HtmlTransform {
TransformConfiguration? transformConfiguration
}) {
transformConfiguration ??= TransformConfiguration.create();
- final transformer = MessageContentTransformer(transformConfiguration, _dioClient);
+ final transformer = MessageContentTransformer(transformConfiguration, _dioClient, _htmlEscape);
final message = transformer.toMessage(content);
return message;
}
diff --git a/core/lib/presentation/utils/html_transformer/message_content_transformer.dart b/core/lib/presentation/utils/html_transformer/message_content_transformer.dart
index ac31e27f8..f4e5a1624 100644
--- a/core/lib/presentation/utils/html_transformer/message_content_transformer.dart
+++ b/core/lib/presentation/utils/html_transformer/message_content_transformer.dart
@@ -1,3 +1,5 @@
+import 'dart:convert';
+
import 'package:core/data/network/dio_client.dart';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:html/dom.dart';
@@ -5,23 +7,28 @@ import 'package:html/parser.dart' show parse;
/// Transforms messages
class MessageContentTransformer {
- /// The configuration used for the transformation
- final TransformConfiguration configuration;
- final DioClient dioClient;
+ /// The _configuration used for the transformation
+ final TransformConfiguration _configuration;
+ final DioClient _dioClient;
+ final HtmlEscape _htmlEscape;
- MessageContentTransformer(this.configuration, this.dioClient);
+ MessageContentTransformer(
+ this._configuration,
+ this._dioClient,
+ this._htmlEscape
+ );
Future _transformDocument({
required Document document,
Map? mapUrlDownloadCID
}) async {
await Future.wait([
- if (configuration.domTransformers.isNotEmpty)
- ...configuration.domTransformers.map((domTransformer) async =>
+ if (_configuration.domTransformers.isNotEmpty)
+ ..._configuration.domTransformers.map((domTransformer) async =>
domTransformer.process(
document: document,
mapUrlDownloadCID: mapUrlDownloadCID,
- dioClient: dioClient
+ dioClient: _dioClient
)
)
]);
@@ -40,9 +47,9 @@ class MessageContentTransformer {
}
String _transformMessage(String message) {
- if (configuration.textTransformers.isNotEmpty) {
- for (var transformer in configuration.textTransformers) {
- message = transformer.process(message);
+ if (_configuration.textTransformers.isNotEmpty) {
+ for (var transformer in _configuration.textTransformers) {
+ message = transformer.process(message, _htmlEscape);
}
}
return message;
diff --git a/core/lib/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart b/core/lib/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart
index e1bcbb30c..0bab1f355 100644
--- a/core/lib/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart
+++ b/core/lib/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart
@@ -6,10 +6,8 @@ import 'package:core/presentation/utils/html_transformer/base/text_transformer.d
class SanitizeAutolinkHtmlTransformers extends TextTransformer {
- final HtmlEscape htmlEscape;
-
- SanitizeAutolinkHtmlTransformers(this.htmlEscape);
+ const SanitizeAutolinkHtmlTransformers();
@override
- String process(String text) => SanitizeAutolinkFilter(htmlEscape).process(text);
+ String process(String text, HtmlEscape htmlEscape) => SanitizeAutolinkFilter(htmlEscape).process(text);
}
\ No newline at end of file
diff --git a/core/lib/presentation/utils/html_transformer/transform_configuration.dart b/core/lib/presentation/utils/html_transformer/transform_configuration.dart
index e9c15b7ef..af4af62ad 100644
--- a/core/lib/presentation/utils/html_transformer/transform_configuration.dart
+++ b/core/lib/presentation/utils/html_transformer/transform_configuration.dart
@@ -1,12 +1,16 @@
+import 'package:core/core.dart';
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
import 'package:core/presentation/utils/html_transformer/base/text_transformer.dart';
import 'package:core/presentation/utils/html_transformer/dom/add_target_blank_in_tag_a_transformers.dart';
import 'package:core/presentation/utils/html_transformer/dom/blockcode_transformers.dart';
import 'package:core/presentation/utils/html_transformer/dom/blockquoted_transformers.dart';
import 'package:core/presentation/utils/html_transformer/dom/image_transformers.dart';
+import 'package:core/presentation/utils/html_transformer/dom/remove_tooltip_link_transformers.dart';
+import 'package:core/presentation/utils/html_transformer/dom/replace_lazy_load_image_transformer.dart';
import 'package:core/presentation/utils/html_transformer/dom/script_transformers.dart';
import 'package:core/presentation/utils/html_transformer/dom/sigature_transformers.dart';
+import 'package:core/presentation/utils/html_transformer/text/sanitize_autolink_html_transformers.dart';
/// Contains the configuration for all transformations.
class TransformConfiguration {
@@ -25,6 +29,45 @@ class TransformConfiguration {
this.textTransformers
);
+ factory TransformConfiguration.forReplyForwardEmail() => TransformConfiguration.create(
+ customDomTransformers: [
+ const ReplaceLazyLoadImageTransformer(),
+ if (PlatformInfo.isWeb)
+ const RemoveTooltipLinkTransformer(),
+ ]
+ );
+
+ factory TransformConfiguration.forDraftsEmail() => TransformConfiguration.create(
+ customDomTransformers: [
+ const RemoveScriptTransformer(),
+ const BlockQuotedTransformer(),
+ const BlockCodeTransformer(),
+ const AddTargetBlankInTagATransformer(),
+ const ImageTransformer(useLoadingAttribute: true),
+ ]
+ );
+
+ factory TransformConfiguration.forComposeEmailPlatformWeb() => TransformConfiguration.create(
+ customDomTransformers: [
+ const RemoveScriptTransformer(),
+ const BlockQuotedTransformer(),
+ const BlockCodeTransformer(),
+ const AddTargetBlankInTagATransformer(),
+ const ImageTransformer(useLoadingAttribute: true)
+ ]
+ );
+
+ factory TransformConfiguration.forPreviewEmailPlatformWeb() => TransformConfiguration.create(
+ customDomTransformers: [
+ const RemoveScriptTransformer(),
+ const BlockQuotedTransformer(),
+ const BlockCodeTransformer(),
+ const AddTargetBlankInTagATransformer(),
+ const ImageTransformer(),
+ const AddTooltipLinkTransformer(),
+ ]
+ );
+
/// Provides easy access to a standard configuration that does not block external images.
static const TransformConfiguration standardConfiguration = TransformConfiguration(
standardDomTransformers,
@@ -61,13 +104,7 @@ class TransformConfiguration {
ImageTransformer(),
];
- static const List domTransformersForDraftEmail = [
- RemoveScriptTransformer(),
- BlockQuotedTransformer(),
- BlockCodeTransformer(),
- AddTargetBlankInTagATransformer(),
- ImageTransformer(),
+ static const List standardTextTransformers = [
+ SanitizeAutolinkHtmlTransformers()
];
-
- static const List standardTextTransformers = [];
}
\ No newline at end of file
diff --git a/lib/features/base/reloadable/reloadable_controller.dart b/lib/features/base/reloadable/reloadable_controller.dart
index e72d65fd7..c5d962a69 100644
--- a/lib/features/base/reloadable/reloadable_controller.dart
+++ b/lib/features/base/reloadable/reloadable_controller.dart
@@ -24,7 +24,7 @@ import 'package:tmail_ui_user/features/session/domain/usecases/get_session_inter
import 'package:tmail_ui_user/main/error/capability_validator.dart';
abstract class ReloadableController extends BaseController {
- final DynamicUrlInterceptors _dynamicUrlInterceptors = Get.find();
+ final DynamicUrlInterceptors dynamicUrlInterceptors = Get.find();
final GetSessionInteractor _getSessionInteractor = Get.find();
final GetAuthenticatedAccountInteractor _getAuthenticatedAccountInteractor;
final UpdateAuthenticationAccountInteractor _updateAuthenticationAccountInteractor;
@@ -72,8 +72,8 @@ abstract class ReloadableController extends BaseController {
}
void _setUpInterceptors(GetCredentialViewState credentialViewState) {
- _dynamicUrlInterceptors.setJmapUrl(credentialViewState.baseUrl.origin);
- _dynamicUrlInterceptors.changeBaseUrl(credentialViewState.baseUrl.origin);
+ dynamicUrlInterceptors.setJmapUrl(credentialViewState.baseUrl.origin);
+ dynamicUrlInterceptors.changeBaseUrl(credentialViewState.baseUrl.origin);
authorizationInterceptors.setBasicAuthorization(
credentialViewState.userName.value,
credentialViewState.password.value,
@@ -100,10 +100,10 @@ abstract class ReloadableController extends BaseController {
void _handleGetSessionSuccess(GetSessionSuccess success) {
final session = success.session;
final personalAccount = session.personalAccount;
- final apiUrl = session.getQualifiedApiUrl(baseUrl: _dynamicUrlInterceptors.jmapUrl);
+ final apiUrl = session.getQualifiedApiUrl(baseUrl: dynamicUrlInterceptors.jmapUrl);
log('ReloadableController::_handleGetSessionSuccess():apiUrl: $apiUrl');
if (apiUrl.isNotEmpty) {
- _dynamicUrlInterceptors.changeBaseUrl(apiUrl);
+ dynamicUrlInterceptors.changeBaseUrl(apiUrl);
updateAuthenticationAccount(session, personalAccount.accountId, session.username);
handleReloaded(session);
} else {
@@ -120,8 +120,8 @@ abstract class ReloadableController extends BaseController {
}
void _setUpInterceptorsOidc(GetStoredTokenOidcSuccess tokenOidcSuccess) {
- _dynamicUrlInterceptors.setJmapUrl(tokenOidcSuccess.baseUrl.toString());
- _dynamicUrlInterceptors.changeBaseUrl(tokenOidcSuccess.baseUrl.toString());
+ dynamicUrlInterceptors.setJmapUrl(tokenOidcSuccess.baseUrl.toString());
+ dynamicUrlInterceptors.changeBaseUrl(tokenOidcSuccess.baseUrl.toString());
authorizationInterceptors.setTokenAndAuthorityOidc(
newToken: tokenOidcSuccess.tokenOidc.toToken(),
newConfig: tokenOidcSuccess.oidcConfiguration);
@@ -140,7 +140,7 @@ abstract class ReloadableController extends BaseController {
}
void updateAuthenticationAccount(Session session, AccountId accountId, UserName userName) {
- final apiUrl = session.getQualifiedApiUrl(baseUrl: _dynamicUrlInterceptors.jmapUrl);
+ final apiUrl = session.getQualifiedApiUrl(baseUrl: dynamicUrlInterceptors.jmapUrl);
log('ReloadableController::updateAuthenticationAccount():apiUrl: $apiUrl');
if (apiUrl.isNotEmpty) {
consumeState(_updateAuthenticationAccountInteractor.execute(accountId, apiUrl, userName));
diff --git a/lib/features/base/widget/cupertino_loading_widget.dart b/lib/features/base/widget/cupertino_loading_widget.dart
index 69db2e76d..52a4c4a2b 100644
--- a/lib/features/base/widget/cupertino_loading_widget.dart
+++ b/lib/features/base/widget/cupertino_loading_widget.dart
@@ -4,17 +4,35 @@ import 'package:tmail_ui_user/features/base/styles/cupertino_loading_widget_styl
class CupertinoLoadingWidget extends StatelessWidget {
final double? size;
+ final EdgeInsetsGeometry? padding;
- const CupertinoLoadingWidget({super.key, this.size});
+ const CupertinoLoadingWidget({super.key, this.size, this.padding});
@override
Widget build(BuildContext context) {
- return Center(
- child: SizedBox(
- width: size ?? CupertinoLoadingWidgetStyles.size,
- height: size ?? CupertinoLoadingWidgetStyles.size,
- child: const CupertinoActivityIndicator(color: CupertinoLoadingWidgetStyles.progressColor)
- )
- );
+ if (padding != null) {
+ return Padding(
+ padding: padding!,
+ child: Center(
+ child: SizedBox(
+ width: size ?? CupertinoLoadingWidgetStyles.size,
+ height: size ?? CupertinoLoadingWidgetStyles.size,
+ child: const CupertinoActivityIndicator(
+ color: CupertinoLoadingWidgetStyles.progressColor
+ )
+ )
+ ),
+ );
+ } else {
+ return Center(
+ child: SizedBox(
+ width: size ?? CupertinoLoadingWidgetStyles.size,
+ height: size ?? CupertinoLoadingWidgetStyles.size,
+ child: const CupertinoActivityIndicator(
+ color: CupertinoLoadingWidgetStyles.progressColor
+ )
+ )
+ );
+ }
}
}
\ No newline at end of file
diff --git a/lib/features/composer/presentation/base_composer_view.dart b/lib/features/composer/presentation/base_composer_view.dart
index 3648241fe..25d25148a 100644
--- a/lib/features/composer/presentation/base_composer_view.dart
+++ b/lib/features/composer/presentation/base_composer_view.dart
@@ -5,6 +5,7 @@ import 'package:core/presentation/utils/app_toast.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/utils/style_utils.dart';
import 'package:core/presentation/views/button/icon_button_web.dart';
+import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/presentation/views/list/sliver_grid_delegate_fixed_height.dart';
import 'package:core/presentation/views/text/text_field_builder.dart';
import 'package:core/presentation/views/text/text_overflow_builder.dart';
@@ -321,22 +322,17 @@ abstract class BaseComposerView extends GetWidget
)
),
const Spacer(),
- Material(
- type: MaterialType.circle,
- color: Colors.transparent,
- child: TextButton(
- onPressed: controller.toggleDisplayAttachments,
- child: Text(
- expandModeAttachment == ExpandMode.EXPAND
- ? AppLocalizations.of(context).hide
- : '${AppLocalizations.of(context).showAll} (${uploadFilesState.length})',
- style: const TextStyle(
- fontWeight: FontWeight.w500,
- fontSize: 12,
- color: AppColor.colorTextButton
- )
- )
- )
+ TMailButtonWidget.fromText(
+ text: expandModeAttachment == ExpandMode.EXPAND
+ ? AppLocalizations.of(context).hide
+ : '${AppLocalizations.of(context).showAll} (${uploadFilesState.length})',
+ onTapActionCallback: controller.toggleDisplayAttachments,
+ textStyle: const TextStyle(
+ fontWeight: FontWeight.w500,
+ fontSize: 12,
+ color: AppColor.colorTextButton
+ ),
+ backgroundColor: Colors.transparent,
)
],
);
diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart
index 0210639ac..254b3b229 100644
--- a/lib/features/composer/presentation/composer_bindings.dart
+++ b/lib/features/composer/presentation/composer_bindings.dart
@@ -29,6 +29,7 @@ import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
+import 'package:tmail_ui_user/features/email/domain/usecases/transform_html_email_content_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart';
@@ -163,6 +164,7 @@ class ComposerBindings extends BaseBindings {
Get.lazyPut(() => RemoveComposerCacheOnWebInteractor(Get.find()));
Get.lazyPut(() => SaveComposerCacheOnWebInteractor(Get.find()));
Get.lazyPut(() => DownloadImageAsBase64Interactor(Get.find()));
+ Get.lazyPut(() => TransformHtmlEmailContentInteractor(Get.find()));
IdentityInteractorsBindings().dependencies();
}
@@ -184,6 +186,7 @@ class ComposerBindings extends BaseBindings {
Get.find(),
Get.find(),
Get.find(),
+ Get.find(),
));
}
diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart
index d0345c0f1..2a4816f33 100644
--- a/lib/features/composer/presentation/composer_controller.dart
+++ b/lib/features/composer/presentation/composer_controller.dart
@@ -48,8 +48,11 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/email_ac
import 'package:tmail_ui_user/features/composer/presentation/model/image_source.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
+import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
+import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_content_state.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
+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/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart';
@@ -60,6 +63,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_id
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/identity_extension.dart';
import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/extensions/sending_email_extension.dart';
+import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_action_type.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_arguments.dart';
import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
@@ -95,7 +99,7 @@ class ComposerController extends BaseController {
final bccAddressExpandMode = ExpandMode.EXPAND.obs;
final identitySelected = Rxn();
final listIdentities = [].obs;
- final emailContentsViewState = Rx>(Right(UIState.idle));
+ final emailContentsViewState = Rxn>();
final hasRequestReadReceipt = false.obs;
final LocalFilePickerInteractor _localFilePickerInteractor;
@@ -109,6 +113,7 @@ class ComposerController extends BaseController {
final SaveComposerCacheOnWebInteractor _saveComposerCacheOnWebInteractor;
final RichTextWebController richTextWebController;
final DownloadImageAsBase64Interactor _downloadImageAsBase64Interactor;
+ final TransformHtmlEmailContentInteractor _transformHtmlEmailContentInteractor;
GetAutoCompleteWithDeviceContactInteractor? _getAutoCompleteWithDeviceContactInteractor;
GetAutoCompleteInteractor? _getAutoCompleteInteractor;
@@ -145,7 +150,6 @@ class ComposerController extends BaseController {
List initialAttachments = [];
String? _textEditorWeb;
String? _initTextEditor;
- String? _emailContents;
double? maxWithEditor;
late Worker uploadInlineImageWorker;
@@ -201,6 +205,7 @@ class ComposerController extends BaseController {
this._saveComposerCacheOnWebInteractor,
this.richTextWebController,
this._downloadImageAsBase64Interactor,
+ this._transformHtmlEmailContentInteractor,
);
@override
@@ -264,7 +269,9 @@ class ComposerController extends BaseController {
@override
void handleSuccessViewState(Success success) {
super.handleSuccessViewState(success);
- if (success is GetEmailContentLoading) {
+ if (success is GetEmailContentLoading ||
+ success is TransformHtmlEmailContentLoading ||
+ success is TransformHtmlEmailContentSuccess) {
emailContentsViewState.value = Right(success);
} else if (success is LocalFilePickerSuccess) {
_pickFileSuccess(success);
@@ -299,7 +306,8 @@ class ComposerController extends BaseController {
super.handleFailureViewState(failure);
if (failure is LocalFilePickerFailure || failure is LocalFilePickerCancel) {
_pickFileFailure(failure);
- } else if (failure is GetEmailContentFailure) {
+ } else if (failure is GetEmailContentFailure ||
+ failure is TransformHtmlEmailContentFailure) {
emailContentsViewState.value = Left(failure);
}
}
@@ -387,39 +395,105 @@ class ComposerController extends BaseController {
: Get.arguments;
if (arguments is ComposerArguments) {
composerArguments.value = arguments;
+
injectAutoCompleteBindings(
- mailboxDashBoardController.sessionCurrent,
- mailboxDashBoardController.accountId.value);
+ mailboxDashBoardController.sessionCurrent,
+ mailboxDashBoardController.accountId.value
+ );
- if (arguments.emailActionType == EmailActionType.edit) {
- _getEmailContentAction(arguments);
+ switch(arguments.emailActionType) {
+ case EmailActionType.editDraft:
+ _initEmailAddress(
+ presentationEmail: arguments.presentationEmail!,
+ actionType: EmailActionType.editDraft
+ );
+ _initSubjectEmail(
+ presentationEmail: arguments.presentationEmail!,
+ actionType: EmailActionType.editDraft
+ );
+ _getEmailContentFromEmailId(
+ emailId: arguments.presentationEmail!.id!,
+ isDraftEmail: arguments.presentationEmail!.isDraft
+ );
+ break;
+ case EmailActionType.editSendingEmail:
+ _initEmailAddress(
+ presentationEmail: arguments.sendingEmail!.presentationEmail,
+ actionType: EmailActionType.editSendingEmail
+ );
+ _initSubjectEmail(
+ presentationEmail: arguments.sendingEmail!.presentationEmail,
+ actionType: EmailActionType.editSendingEmail
+ );
+ _getEmailContentFromSendingEmail(arguments.sendingEmail!);
+ break;
+ case EmailActionType.composeFromContentShared:
+ _getEmailContentFromContentShared(arguments.emailContents!);
+ break;
+ case EmailActionType.composeFromFileShared:
+ _addAttachmentFromFileShare(arguments.listSharedMediaFile!);
+ break;
+ case EmailActionType.composeFromEmailAddress:
+ listToEmailAddress.add(arguments.emailAddress!);
+ isInitialRecipient.value = true;
+ toAddressExpandMode.value = ExpandMode.COLLAPSE;
+ _updateStatusEmailSendButton();
+ break;
+ case EmailActionType.reply:
+ case EmailActionType.replyAll:
+ _initEmailAddress(
+ presentationEmail: arguments.presentationEmail!,
+ actionType: arguments.emailActionType,
+ mailboxRole: arguments.presentationEmail!.mailboxContain?.role ?? mailboxDashBoardController.selectedMailbox.value?.role
+ );
+ _initSubjectEmail(
+ presentationEmail: arguments.presentationEmail!,
+ actionType: arguments.emailActionType
+ );
+ _transformHtmlEmailContent(arguments.emailContents);
+ break;
+ case EmailActionType.forward:
+ _initSubjectEmail(
+ presentationEmail: arguments.presentationEmail!,
+ actionType: arguments.emailActionType
+ );
+ _initAttachments(arguments.attachments ?? []);
+ _transformHtmlEmailContent(arguments.emailContents);
+ break;
+ case EmailActionType.reopenComposerBrowser:
+ _initEmailAddress(
+ presentationEmail: arguments.presentationEmail!,
+ actionType: EmailActionType.reopenComposerBrowser
+ );
+ _initSubjectEmail(
+ presentationEmail: arguments.presentationEmail!,
+ actionType: EmailActionType.reopenComposerBrowser
+ );
+ _initAttachments(arguments.attachments ?? []);
+ _getEmailContentFromSessionStorageBrowser(arguments.emailContents!);
+ break;
+ default:
+ break;
}
-
- _initEmailAddress(arguments);
- _initSubjectEmail(arguments);
- _initAttachments(arguments);
}
_autoFocusFieldWhenLauncher();
}
- void _initSubjectEmail(ComposerArguments arguments) {
- if (currentContext != null) {
- final subjectEmail = arguments.presentationEmail?.getEmailTitle().trim() ?? '';
- final newSubject = arguments.emailActionType.getSubjectComposer(currentContext!, subjectEmail);
- setSubjectEmail(newSubject);
- subjectEmailInputController.text = newSubject;
- }
+ void _initSubjectEmail({
+ required PresentationEmail presentationEmail,
+ required EmailActionType actionType
+ }) {
+ final subjectEmail = presentationEmail.getEmailTitle().trim();
+ final newSubject = actionType.getSubjectComposer(currentContext, subjectEmail);
+ setSubjectEmail(newSubject);
+ subjectEmailInputController.text = newSubject;
}
- void _initAttachments(ComposerArguments arguments) {
- if (arguments.attachments?.isNotEmpty == true) {
- initialAttachments = arguments.attachments!;
- uploadController.initializeUploadAttachments(
- arguments.attachments!.listAttachmentsDisplayedOutSide);
- }
- if (PlatformInfo.isWeb) {
- expandModeAttachments.value = ExpandMode.EXPAND;
+ void _initAttachments(List attachments) {
+ if (attachments.isNotEmpty) {
+ initialAttachments = attachments;
+ uploadController.initializeUploadAttachments(attachments.listAttachmentsDisplayedOutSide);
}
}
@@ -438,7 +512,6 @@ class ComposerController extends BaseController {
.toList();
if (listIdentities.isNotEmpty) {
- _initTextEditor = null;
await selectIdentity(listIdentities.first);
}
}
@@ -446,113 +519,49 @@ class ComposerController extends BaseController {
_autoFocusFieldWhenLauncher();
}
- String? _getHeaderEmailQuoted(BuildContext context, ComposerArguments arguments) {
- final presentationEmail = arguments.presentationEmail;
- if (presentationEmail != null) {
- final locale = Localizations.localeOf(context).toLanguageTag();
- log('ComposerController::_getHeaderEmailQuoted(): emailActionType: ${arguments.emailActionType}');
- switch(arguments.emailActionType) {
- case EmailActionType.reply:
- case EmailActionType.replyAll:
- final receivedAt = presentationEmail.receivedAt;
- final emailAddress = presentationEmail.from.listEmailAddressToString(isFullEmailAddress: true);
- return AppLocalizations.of(context).header_email_quoted(
- receivedAt.formatDateToLocal(pattern: 'MMM d, y h:mm a', locale: locale),
- emailAddress);
- case EmailActionType.forward:
- var headerQuoted = '------- ${AppLocalizations.of(context).forwarded_message} -------'.addNewLineTag();
-
- final subject = presentationEmail.subject ?? '';
- final receivedAt = presentationEmail.receivedAt;
- final fromEmailAddress = presentationEmail.from.listEmailAddressToString(isFullEmailAddress: true);
- final toEmailAddress = presentationEmail.to.listEmailAddressToString(isFullEmailAddress: true);
- final ccEmailAddress = presentationEmail.cc.listEmailAddressToString(isFullEmailAddress: true);
- final bccEmailAddress = presentationEmail.bcc.listEmailAddressToString(isFullEmailAddress: true);
-
- if (subject.isNotEmpty) {
- headerQuoted = headerQuoted
- .append('${AppLocalizations.of(context).subject_email}: ')
- .append(subject)
- .addNewLineTag();
- }
- if (receivedAt != null) {
- headerQuoted = headerQuoted
- .append('${AppLocalizations.of(context).date}: ')
- .append(receivedAt.formatDateToLocal(pattern: 'MMM d, y h:mm a', locale: locale))
- .addNewLineTag();
- }
- if (fromEmailAddress.isNotEmpty) {
- headerQuoted = headerQuoted
- .append('${AppLocalizations.of(context).from_email_address_prefix}: ')
- .append(fromEmailAddress)
- .addNewLineTag();
- }
- if (toEmailAddress.isNotEmpty) {
- headerQuoted = headerQuoted
- .append('${AppLocalizations.of(context).to_email_address_prefix}: ')
- .append(toEmailAddress)
- .addNewLineTag();
- }
- if (ccEmailAddress.isNotEmpty) {
- headerQuoted = headerQuoted
- .append('${AppLocalizations.of(context).cc_email_address_prefix}: ')
- .append(ccEmailAddress)
- .addNewLineTag();
- }
- if (bccEmailAddress.isNotEmpty) {
- headerQuoted = headerQuoted
- .append('${AppLocalizations.of(context).bcc_email_address_prefix}: ')
- .append(bccEmailAddress)
- .addNewLineTag();
- }
-
- return headerQuoted;
- default:
- return null;
- }
- }
- return null;
- }
-
- void _initEmailAddress(ComposerArguments arguments) {
+ void _initEmailAddress({
+ required PresentationEmail presentationEmail,
+ required EmailActionType actionType,
+ Role? mailboxRole,
+ }) {
+ final recipients = presentationEmail.generateRecipientsEmailAddressForComposer(
+ emailActionType: actionType,
+ mailboxRole: mailboxRole
+ );
+ log('ComposerController::_initEmailAddress:recipients: $recipients');
final userProfile = mailboxDashBoardController.userProfile.value;
- if (arguments.presentationEmail != null && userProfile != null) {
- final userEmailAddress = EmailAddress(null, userProfile.email);
- final recipients = arguments.presentationEmail!.generateRecipientsEmailAddressForComposer(
- arguments.emailActionType,
- arguments.mailboxRole);
-
- final isSender = arguments.presentationEmail!.from.asList().every((element) => element.email == userEmailAddress.email);
-
+ if (userProfile != null) {
+ final isSender = presentationEmail.from.asList().every((element) => element.email == userProfile.email);
if (isSender) {
- listToEmailAddress = List.from(recipients.value1);
- listCcEmailAddress = List.from(recipients.value2);
- listBccEmailAddress = List.from(recipients.value3);
+ listToEmailAddress = List.from(recipients.value1.toSet());
+ listCcEmailAddress = List.from(recipients.value2.toSet());
+ listBccEmailAddress = List.from(recipients.value3.toSet());
} else {
- listToEmailAddress = List.from(recipients.value1.toSet().filterEmailAddress(userEmailAddress));
- listCcEmailAddress = List.from(recipients.value2.toSet().filterEmailAddress(userEmailAddress));
- listBccEmailAddress = List.from(recipients.value3.toSet().filterEmailAddress(userEmailAddress));
+ listToEmailAddress = List.from(recipients.value1.toSet().filterEmailAddress(userProfile.email));
+ listCcEmailAddress = List.from(recipients.value2.toSet().filterEmailAddress(userProfile.email));
+ listBccEmailAddress = List.from(recipients.value3.toSet().filterEmailAddress(userProfile.email));
}
+ } else {
+ listToEmailAddress = List.from(recipients.value1.toSet());
+ listCcEmailAddress = List.from(recipients.value2.toSet());
+ listBccEmailAddress = List.from(recipients.value3.toSet());
+ }
- if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty) {
- isInitialRecipient.value = true;
- toAddressExpandMode.value = ExpandMode.COLLAPSE;
- }
-
- if (listCcEmailAddress.isNotEmpty) {
- listEmailAddressType.add(PrefixEmailAddress.cc);
- ccAddressExpandMode.value = ExpandMode.COLLAPSE;
- }
-
- if (listBccEmailAddress.isNotEmpty) {
- listEmailAddressType.add(PrefixEmailAddress.bcc);
- bccAddressExpandMode.value = ExpandMode.COLLAPSE;
- }
- } else if (arguments.emailAddress != null) {
- listToEmailAddress.add(arguments.emailAddress!);
+ if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty) {
isInitialRecipient.value = true;
toAddressExpandMode.value = ExpandMode.COLLAPSE;
}
+
+ if (listCcEmailAddress.isNotEmpty) {
+ listEmailAddressType.add(PrefixEmailAddress.cc);
+ ccAddressExpandMode.value = ExpandMode.COLLAPSE;
+ }
+
+ if (listBccEmailAddress.isNotEmpty) {
+ listEmailAddressType.add(PrefixEmailAddress.bcc);
+ bccAddressExpandMode.value = ExpandMode.COLLAPSE;
+ }
+
_updateStatusEmailSendButton();
}
@@ -586,13 +595,21 @@ class ComposerController extends BaseController {
}
}
- String getEmailContentQuotedAsHtml(BuildContext context, ComposerArguments arguments) {
- final headerEmailQuoted = _getHeaderEmailQuoted(context, arguments);
+ String getEmailContentQuotedAsHtml({
+ required BuildContext context,
+ required String emailContent,
+ required EmailActionType emailActionType,
+ required PresentationEmail presentationEmail,
+ }) {
+ final headerEmailQuoted = emailActionType.getHeaderEmailQuoted(
+ context: context,
+ presentationEmail: presentationEmail
+ );
log('ComposerController::getEmailContentQuotedAsHtml(): headerEmailQuoted: $headerEmailQuoted');
- final headerEmailQuotedAsHtml = headerEmailQuoted != null ? headerEmailQuoted.addBlockTag('cite') : '';
-
- final trustAsHtml = arguments.emailContents ?? '';
- final emailQuotedHtml = '${HtmlExtension.editorStartTags}$headerEmailQuotedAsHtml${trustAsHtml.addBlockQuoteTag()}';
+ final headerEmailQuotedAsHtml = headerEmailQuoted != null
+ ? headerEmailQuoted.addCiteTag()
+ : '';
+ final emailQuotedHtml = '${HtmlExtension.editorStartTags}$headerEmailQuotedAsHtml${emailContent.addBlockQuoteTag()}';
return emailQuotedHtml;
}
@@ -789,13 +806,13 @@ class ComposerController extends BaseController {
if (arguments != null && accountId != null && userProfile != null && session != null) {
final createdEmail = await _generateEmail(context, userProfile, outboxMailboxId: outboxMailboxId);
- final emailRequest = arguments.sendingEmail != null
+ final emailRequest = arguments.emailActionType == EmailActionType.editSendingEmail
? arguments.sendingEmail!.toEmailRequest(newEmail: createdEmail)
: EmailRequest(
email: createdEmail,
sentMailboxId: sentMailboxId,
identityId: identitySelected.value?.id,
- emailIdDestroyed: arguments.emailActionType == EmailActionType.edit
+ emailIdDestroyed: arguments.emailActionType == EmailActionType.editDraft
? arguments.presentationEmail?.id
: null,
emailIdAnsweredOrForwarded: arguments.presentationEmail?.id,
@@ -952,36 +969,40 @@ class ComposerController extends BaseController {
uploadController.deleteFileUploaded(uploadId);
}
- Future _isEmailChanged(
- BuildContext context,
- ComposerArguments arguments,
- ) async {
+ Future _isEmailChanged({
+ required BuildContext context,
+ required EmailActionType emailActionType,
+ PresentationEmail? presentationEmail,
+ Role? mailboxRole,
+ }) async {
final newEmailBody = await _getEmailBodyText(context, changedEmail: true);
log('ComposerController::_isEmailChanged(): newEmailBody: $newEmailBody');
- var oldEmailBody = _initTextEditor ?? '';
+ final oldEmailBody = _initTextEditor ?? '';
log('ComposerController::_isEmailChanged(): oldEmailBody: $oldEmailBody');
final isEmailBodyChanged = !oldEmailBody.trim().isSame(newEmailBody.trim());
log('ComposerController::_isEmailChanged(): isEmailBodyChanged: $isEmailBodyChanged');
-
final newEmailSubject = subjectEmail.value ?? '';
- final titleEmail = arguments.presentationEmail?.getEmailTitle().trim() ?? '';
- final oldEmailSubject = arguments.emailActionType == EmailActionType.edit ? titleEmail : '';
+ final oldEmailSubject = emailActionType == EmailActionType.editDraft
+ ? presentationEmail?.getEmailTitle().trim() ?? ''
+ : '';
final isEmailSubjectChanged = !oldEmailSubject.trim().isSame(newEmailSubject.trim());
- final recipients = arguments.presentationEmail
- ?.generateRecipientsEmailAddressForComposer(arguments.emailActionType, arguments.mailboxRole)
- ?? const Tuple3([], [], []);
+ final recipients = presentationEmail
+ ?.generateRecipientsEmailAddressForComposer(
+ emailActionType: emailActionType,
+ mailboxRole: mailboxRole
+ ) ?? const Tuple3([], [], []);
final newToEmailAddress = listToEmailAddress;
- final oldToEmailAddress = arguments.emailActionType == EmailActionType.edit ? recipients.value1 : [];
+ final oldToEmailAddress = emailActionType == EmailActionType.editDraft ? recipients.value1 : [];
final isToEmailAddressChanged = !oldToEmailAddress.isSame(newToEmailAddress);
final newCcEmailAddress = listCcEmailAddress;
- final oldCcEmailAddress = arguments.emailActionType == EmailActionType.edit ? recipients.value2 : [];
+ final oldCcEmailAddress = emailActionType == EmailActionType.editDraft ? recipients.value2 : [];
final isCcEmailAddressChanged = !oldCcEmailAddress.isSame(newCcEmailAddress);
final newBccEmailAddress = listBccEmailAddress;
- final oldBccEmailAddress = arguments.emailActionType == EmailActionType.edit ? recipients.value3 : [];
+ final oldBccEmailAddress = emailActionType == EmailActionType.editDraft ? recipients.value3 : [];
final isBccEmailAddressChanged = !oldBccEmailAddress.isSame(newBccEmailAddress);
final isAttachmentsChanged = !initialAttachments.isSame(uploadController.attachmentsUploaded.toList());
@@ -999,36 +1020,60 @@ class ComposerController extends BaseController {
clearFocusEditor(context);
final arguments = composerArguments.value;
- final draftMailboxId = mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleDrafts];
final userProfile = mailboxDashBoardController.userProfile.value;
final accountId = mailboxDashBoardController.accountId.value;
final session = mailboxDashBoardController.sessionCurrent;
- if (arguments != null && userProfile != null && accountId != null && session != null) {
- final isChanged = await _isEmailChanged(context, arguments);
- if (isChanged && context.mounted) {
- final newEmail = await _generateEmail(
- context,
- userProfile,
- asDrafts: true,
- draftMailboxId: draftMailboxId);
- final oldEmail = arguments.presentationEmail;
-
- if (arguments.emailActionType == EmailActionType.edit && oldEmail != null && oldEmail.id != null) {
- mailboxDashBoardController.consumeState(
- _updateEmailDraftsInteractor.execute(
- session,
- accountId,
- newEmail,
- oldEmail.id!
- )
- );
- } else {
- mailboxDashBoardController.consumeState(_saveEmailAsDraftsInteractor.execute(session, accountId, newEmail));
- }
-
- uploadController.clearInlineFileUploaded();
+ if (arguments == null ||
+ userProfile == null ||
+ session == null ||
+ accountId == null
+ ) {
+ if (PlatformInfo.isWeb) {
+ mailboxDashBoardController.closeComposerOverlay();
+ } else {
+ if (canPop) popBack();
}
+ return;
+ }
+
+ final isChanged = await _isEmailChanged(
+ context: context,
+ emailActionType: arguments.emailActionType,
+ presentationEmail: arguments.presentationEmail,
+ mailboxRole: arguments.mailboxRole
+ );
+
+ if (isChanged && context.mounted) {
+ final draftMailboxId = mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleDrafts];
+
+ final newEmail = await _generateEmail(
+ context,
+ userProfile,
+ asDrafts: true,
+ draftMailboxId: draftMailboxId
+ );
+
+ if (arguments.emailActionType == EmailActionType.editDraft) {
+ mailboxDashBoardController.consumeState(
+ _updateEmailDraftsInteractor.execute(
+ session,
+ accountId,
+ newEmail,
+ arguments.presentationEmail!.id!
+ )
+ );
+ } else {
+ mailboxDashBoardController.consumeState(
+ _saveEmailAsDraftsInteractor.execute(
+ session,
+ accountId,
+ newEmail
+ )
+ );
+ }
+
+ uploadController.clearInlineFileUploaded();
}
if (PlatformInfo.isWeb) {
@@ -1087,90 +1132,109 @@ class ComposerController extends BaseController {
return listFileInfo;
}
- void _getEmailContentAction(ComposerArguments arguments) async {
-
- final listSharedMediaFile = arguments.listSharedMediaFile;
- if (listSharedMediaFile != null && listSharedMediaFile.isNotEmpty) {
- final listImageSharedMediaFile = listSharedMediaFile.where((element) => element.type == SharedMediaType.IMAGE);
- final listFileAttachmentSharedMediaFile = listSharedMediaFile.where((element) => element.type != SharedMediaType.IMAGE);
- if (listImageSharedMediaFile.isNotEmpty) {
- final listInlineImage = covertListSharedMediaFileToInlineImage(arguments.listSharedMediaFile!);
- for (var e in listInlineImage) {
- _uploadInlineAttachmentsAction(e.fileInfo!);
- }
+ void _addAttachmentFromFileShare(List listSharedMediaFile) {
+ final listImageSharedMediaFile = listSharedMediaFile.where((element) => element.type == SharedMediaType.IMAGE);
+ final listFileAttachmentSharedMediaFile = listSharedMediaFile.where((element) => element.type != SharedMediaType.IMAGE);
+ if (listImageSharedMediaFile.isNotEmpty) {
+ final listInlineImage = covertListSharedMediaFileToInlineImage(listSharedMediaFile);
+ for (var e in listInlineImage) {
+ _uploadInlineAttachmentsAction(e.fileInfo!);
}
- if (listFileAttachmentSharedMediaFile.isNotEmpty) {
- final listFile = covertListSharedMediaFileToFileInfo(arguments.listSharedMediaFile!);
- if (uploadController.hasEnoughMaxAttachmentSize(listFiles: listFile)) {
- _uploadAttachmentsAction(listFile);
- } else {
- if (currentContext != null) {
- showConfirmDialogAction(
- currentContext!,
- AppLocalizations.of(currentContext!).message_dialog_upload_attachments_exceeds_maximum_size(
- filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)),
- AppLocalizations.of(currentContext!).got_it,
- onConfirmAction: () => {},
- title: AppLocalizations.of(currentContext!).maximum_files_size,
- hasCancelButton: false,
- );
- }
+ }
+ if (listFileAttachmentSharedMediaFile.isNotEmpty) {
+ final listFile = covertListSharedMediaFileToFileInfo(listSharedMediaFile);
+ if (uploadController.hasEnoughMaxAttachmentSize(listFiles: listFile)) {
+ _uploadAttachmentsAction(listFile);
+ } else {
+ if (currentContext != null) {
+ showConfirmDialogAction(
+ currentContext!,
+ AppLocalizations.of(currentContext!).message_dialog_upload_attachments_exceeds_maximum_size(
+ filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)),
+ AppLocalizations.of(currentContext!).got_it,
+ title: AppLocalizations.of(currentContext!).maximum_files_size,
+ hasCancelButton: false,
+ );
}
}
}
+ }
- if (arguments.emailContents != null && arguments.emailContents!.isNotEmpty && arguments.sendingEmail != null) {
- _emailContents = arguments.emailContents;
- emailContentsViewState.value = Right(
- GetEmailContentSuccess(
- emailContent: _emailContents!,
- emailContentDisplayed: '',
- attachments: [],
- emailCurrent: arguments.presentationEmail?.toEmail()
- )
- );
- } else {
- final session = mailboxDashBoardController.sessionCurrent;
- final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
- final accountId = mailboxDashBoardController.sessionCurrent?.accounts.keys.first;
- final emailId = arguments.presentationEmail?.id;
- if (session != null && emailId != null && baseDownloadUrl != null && accountId != null) {
- consumeState(_getEmailContentInteractor.execute(
- session,
- accountId,
- emailId,
- baseDownloadUrl,
- composeEmail: true,
- draftsEmail: arguments.presentationEmail?.isDraft ?? false
- ));
+ void _getEmailContentFromSendingEmail(SendingEmail sendingEmail) {
+ consumeState(Stream.value(
+ Right(GetEmailContentSuccess(
+ htmlEmailContent: sendingEmail.presentationEmail.emailContentList.asHtmlString,
+ attachments: sendingEmail.email.allAttachments,
+ emailCurrent: sendingEmail.email
+ ))
+ ));
+ }
+
+ void _getEmailContentFromSessionStorageBrowser(String content) {
+ consumeState(Stream.value(
+ Right(GetEmailContentSuccess(
+ htmlEmailContent: content,
+ attachments: [],
+ ))
+ ));
+ }
+
+ void _getEmailContentFromContentShared(String content) {
+ consumeState(Stream.value(
+ Right(GetEmailContentSuccess(
+ htmlEmailContent: content,
+ attachments: [],
+ ))
+ ));
+ }
+
+ void _getEmailContentFromEmailId({required EmailId emailId, bool isDraftEmail = false}) {
+ final session = mailboxDashBoardController.sessionCurrent;
+ final accountId = mailboxDashBoardController.accountId.value;
+ if (session != null && accountId != null) {
+ TransformConfiguration transformConfiguration = TransformConfiguration.standardConfiguration;
+ if (isDraftEmail) {
+ transformConfiguration = TransformConfiguration.forDraftsEmail();
+ } else if (PlatformInfo.isWeb) {
+ transformConfiguration = TransformConfiguration.forComposeEmailPlatformWeb();
}
+
+ consumeState(_getEmailContentInteractor.execute(
+ session,
+ accountId,
+ emailId,
+ mailboxDashBoardController.baseDownloadUrl,
+ transformConfiguration
+ ));
}
}
void _getEmailContentOffLineSuccess(GetEmailContentFromCacheSuccess success) {
- if (success.attachments.isNotEmpty) {
- initialAttachments = success.attachments;
- uploadController.initializeUploadAttachments(
- success.attachments.listAttachmentsDisplayedOutSide);
- }
+ _initAttachments(success.attachments);
emailContentsViewState.value = Right(success);
- _emailContents = success.emailContent;
}
void _getEmailContentSuccess(GetEmailContentSuccess success) {
- if (success.attachments.isNotEmpty) {
- initialAttachments = success.attachments;
- uploadController.initializeUploadAttachments(
- success.attachments.listAttachmentsDisplayedOutSide);
- }
+ _initAttachments(success.attachments);
emailContentsViewState.value = Right(success);
- _emailContents = success.emailContent;
+ }
+
+ void _transformHtmlEmailContent(String? emailContent) {
+ emailContentsViewState(Right(TransformHtmlEmailContentLoading()));
+ if (emailContent?.isEmpty == true) {
+ consumeState(Stream.value(Left(TransformHtmlEmailContentFailure(EmptyEmailContentException()))));
+ } else {
+ consumeState(_transformHtmlEmailContentInteractor.execute(
+ emailContent!,
+ TransformConfiguration.forReplyForwardEmail()
+ ));
+ }
}
String getEmailAddressSender() {
final arguments = composerArguments.value;
if (arguments != null) {
- if (arguments.emailActionType == EmailActionType.edit) {
+ if (arguments.emailActionType == EmailActionType.editDraft) {
return arguments.presentationEmail?.from?.first.emailAddress ?? '';
} else {
return mailboxDashBoardController.userProfile.value?.email ?? '';
diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart
index ec2c3c8f1..3413fde7c 100644
--- a/lib/features/composer/presentation/composer_view.dart
+++ b/lib/features/composer/presentation/composer_view.dart
@@ -15,9 +15,11 @@ import 'package:get/get.dart';
import 'package:model/email/email_action_type.dart';
import 'package:rich_text_composer/rich_text_composer.dart';
import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart';
+import 'package:tmail_ui_user/features/base/widget/cupertino_loading_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/base_composer_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
+import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_content_state.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
@@ -276,38 +278,96 @@ class ComposerView extends BaseComposerView {
switch(argsComposer.emailActionType) {
case EmailActionType.compose:
case EmailActionType.composeFromEmailAddress:
- return _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags);
- case EmailActionType.edit:
- return controller.emailContentsViewState.value.fold(
- (failure) => _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags),
+ case EmailActionType.composeFromFileShared:
+ return _buildHtmlEditor(
+ context,
+ initialContent: HtmlExtension.editorStartTags
+ );
+ case EmailActionType.editDraft:
+ case EmailActionType.editSendingEmail:
+ case EmailActionType.composeFromContentShared:
+ case EmailActionType.reopenComposerBrowser:
+ final emailContentsViewState = controller.emailContentsViewState.value;
+ if (emailContentsViewState == null) {
+ return const SizedBox.shrink();
+ }
+ return emailContentsViewState.fold(
+ (failure) => _buildHtmlEditor(
+ context,
+ initialContent: HtmlExtension.editorStartTags
+ ),
(success) {
if (success is GetEmailContentLoading) {
- return Padding(
- padding: const EdgeInsets.all(16.0),
- child: loadingWidget,
- );
+ return const CupertinoLoadingWidget(padding: EdgeInsets.all(16.0));
} else if (success is GetEmailContentSuccess) {
- var contentHtml = success.emailContent;
+ var contentHtml = success.htmlEmailContent;
if (contentHtml.isEmpty == true) {
contentHtml = HtmlExtension.editorStartTags;
}
- return _buildHtmlEditor(context, initialContent: contentHtml);
+ return _buildHtmlEditor(
+ context,
+ initialContent: contentHtml
+ );
} else {
- return _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags);
+ return _buildHtmlEditor(
+ context,
+ initialContent: HtmlExtension.editorStartTags
+ );
}
});
case EmailActionType.reply:
case EmailActionType.replyAll:
case EmailActionType.forward:
- var contentHtml = controller.getEmailContentQuotedAsHtml(
- context,
- argsComposer);
- if (contentHtml.isEmpty == true) {
- contentHtml = HtmlExtension.editorStartTags;
+ final emailContentsViewState = controller.emailContentsViewState.value;
+ if (emailContentsViewState == null) {
+ return const SizedBox.shrink();
}
- return _buildHtmlEditor(context, initialContent: contentHtml);
+ return emailContentsViewState.fold(
+ (failure) {
+ final emailContentQuoted = controller.getEmailContentQuotedAsHtml(
+ context: context,
+ emailContent: '',
+ emailActionType: argsComposer.emailActionType,
+ presentationEmail: argsComposer.presentationEmail!
+ );
+ return _buildHtmlEditor(
+ context,
+ initialContent: emailContentQuoted
+ );
+ },
+ (success) {
+ if (success is TransformHtmlEmailContentLoading) {
+ return const CupertinoLoadingWidget(padding: EdgeInsets.all(16.0));
+ } else if (success is TransformHtmlEmailContentSuccess) {
+ final emailContentQuoted = controller.getEmailContentQuotedAsHtml(
+ context: context,
+ emailContent: success.htmlContent,
+ emailActionType: argsComposer.emailActionType,
+ presentationEmail: argsComposer.presentationEmail!
+ );
+ return _buildHtmlEditor(
+ context,
+ initialContent: emailContentQuoted
+ );
+ } else {
+ final emailContentQuoted = controller.getEmailContentQuotedAsHtml(
+ context: context,
+ emailContent: '',
+ emailActionType: argsComposer.emailActionType,
+ presentationEmail: argsComposer.presentationEmail!
+ );
+ return _buildHtmlEditor(
+ context,
+ initialContent: emailContentQuoted
+ );
+ }
+ }
+ );
default:
- return _buildHtmlEditor(context, initialContent: HtmlExtension.editorStartTags);
+ return _buildHtmlEditor(
+ context,
+ initialContent: HtmlExtension.editorStartTags
+ );
}
});
}
diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart
index b77e8d002..a252fb9c8 100644
--- a/lib/features/composer/presentation/composer_view_web.dart
+++ b/lib/features/composer/presentation/composer_view_web.dart
@@ -10,12 +10,14 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/email/email_action_type.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
+import 'package:tmail_ui_user/features/base/widget/cupertino_loading_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/base_composer_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/email_editor_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/toolbar_rich_text_builder.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
+import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_content_state.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
@@ -385,46 +387,96 @@ class ComposerView extends BaseComposerView {
switch(argsComposer.emailActionType) {
case EmailActionType.compose:
case EmailActionType.composeFromEmailAddress:
+ case EmailActionType.composeFromFileShared:
return _buildHtmlEditor(
- context,
- currentTextEditor ?? HtmlExtension.editorStartTags);
- case EmailActionType.edit:
- return controller.emailContentsViewState.value.fold(
+ context,
+ currentTextEditor ?? HtmlExtension.editorStartTags
+ );
+ case EmailActionType.editDraft:
+ case EmailActionType.editSendingEmail:
+ case EmailActionType.composeFromContentShared:
+ case EmailActionType.reopenComposerBrowser:
+ final emailContentsViewState = controller.emailContentsViewState.value;
+ if (emailContentsViewState == null) {
+ return const SizedBox.shrink();
+ }
+ return emailContentsViewState.fold(
(failure) => _buildHtmlEditor(
- context,
- currentTextEditor ?? HtmlExtension.editorStartTags),
+ context,
+ currentTextEditor ?? HtmlExtension.editorStartTags
+ ),
(success) {
if (success is GetEmailContentLoading) {
- return Padding(
- padding: const EdgeInsets.all(16.0),
- child: loadingWidget,
- );
+ return const CupertinoLoadingWidget(padding: EdgeInsets.all(16.0));
} else if (success is GetEmailContentSuccess) {
- var contentHtml = success.emailContent;
+ var contentHtml = success.htmlEmailContent;
if (contentHtml.isEmpty == true) {
contentHtml = HtmlExtension.editorStartTags;
}
- return _buildHtmlEditor(context, currentTextEditor ?? contentHtml);
+ return _buildHtmlEditor(
+ context,
+ currentTextEditor ?? contentHtml
+ );
} else {
return _buildHtmlEditor(
context,
- currentTextEditor ?? HtmlExtension.editorStartTags);
+ currentTextEditor ?? HtmlExtension.editorStartTags
+ );
}
});
case EmailActionType.reply:
case EmailActionType.replyAll:
case EmailActionType.forward:
- var contentHtml = controller.getEmailContentQuotedAsHtml(
- context,
- argsComposer);
- if (contentHtml.isEmpty == true) {
- contentHtml = HtmlExtension.editorStartTags;
+ final emailContentsViewState = controller.emailContentsViewState.value;
+ if (emailContentsViewState == null) {
+ return const SizedBox.shrink();
}
- return _buildHtmlEditor(context, currentTextEditor ?? contentHtml);
+ return emailContentsViewState.fold(
+ (failure) {
+ final emailContentQuoted = controller.getEmailContentQuotedAsHtml(
+ context: context,
+ emailContent: '',
+ emailActionType: argsComposer.emailActionType,
+ presentationEmail: argsComposer.presentationEmail!
+ );
+ return _buildHtmlEditor(
+ context,
+ currentTextEditor ?? emailContentQuoted
+ );
+ },
+ (success) {
+ if (success is TransformHtmlEmailContentLoading) {
+ return const CupertinoLoadingWidget(padding: EdgeInsets.all(16.0));
+ } else if (success is TransformHtmlEmailContentSuccess) {
+ final emailContentQuoted = controller.getEmailContentQuotedAsHtml(
+ context: context,
+ emailContent: success.htmlContent,
+ emailActionType: argsComposer.emailActionType,
+ presentationEmail: argsComposer.presentationEmail!
+ );
+ return _buildHtmlEditor(
+ context,
+ currentTextEditor ?? emailContentQuoted
+ );
+ } else {
+ final emailContentQuoted = controller.getEmailContentQuotedAsHtml(
+ context: context,
+ emailContent: '',
+ emailActionType: argsComposer.emailActionType,
+ presentationEmail: argsComposer.presentationEmail!
+ );
+ return _buildHtmlEditor(
+ context,
+ currentTextEditor ?? emailContentQuoted
+ );
+ }
+ }
+ );
default:
return _buildHtmlEditor(
- context,
- currentTextEditor ?? HtmlExtension.editorStartTags);
+ context,
+ currentTextEditor ?? HtmlExtension.editorStartTags
+ );
}
});
}
diff --git a/lib/features/composer/presentation/extensions/email_action_type_extension.dart b/lib/features/composer/presentation/extensions/email_action_type_extension.dart
index 362507bb3..8a7f35dc8 100644
--- a/lib/features/composer/presentation/extensions/email_action_type_extension.dart
+++ b/lib/features/composer/presentation/extensions/email_action_type_extension.dart
@@ -1,25 +1,35 @@
+import 'package:core/presentation/extensions/html_extension.dart';
import 'package:flutter/cupertino.dart';
import 'package:model/email/email_action_type.dart';
+import 'package:model/email/presentation_email.dart';
+import 'package:model/extensions/list_email_address_extension.dart';
+import 'package:model/extensions/utc_date_extension.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension EmailActionTypeExtension on EmailActionType {
- String getSubjectComposer(BuildContext context, String subject) {
+ String getSubjectComposer(BuildContext? context, String subject) {
switch(this) {
case EmailActionType.reply:
case EmailActionType.replyAll:
if (subject.toLowerCase().startsWith('re:')) {
return subject;
} else {
- return '${AppLocalizations.of(context).prefix_reply_email} $subject';
+ return context != null
+ ? '${AppLocalizations.of(context).prefix_reply_email} $subject'
+ : subject;
}
case EmailActionType.forward:
if (subject.toLowerCase().startsWith('fwd:')) {
return subject;
} else {
- return '${AppLocalizations.of(context).prefix_forward_email} $subject';
+ return context != null
+ ? '${AppLocalizations.of(context).prefix_forward_email} $subject'
+ : subject;
}
- case EmailActionType.edit:
+ case EmailActionType.editDraft:
+ case EmailActionType.editSendingEmail:
+ case EmailActionType.reopenComposerBrowser:
return subject;
default:
return '';
@@ -40,4 +50,71 @@ extension EmailActionTypeExtension on EmailActionType {
return '';
}
}
+
+ String? getHeaderEmailQuoted({
+ required BuildContext context,
+ required PresentationEmail presentationEmail
+ }) {
+ final locale = Localizations.localeOf(context).toLanguageTag();
+ switch(this) {
+ case EmailActionType.reply:
+ case EmailActionType.replyAll:
+ final receivedAt = presentationEmail.receivedAt;
+ final emailAddress = presentationEmail.from.listEmailAddressToString(isFullEmailAddress: true);
+ return AppLocalizations.of(context).header_email_quoted(
+ receivedAt.formatDateToLocal(pattern: 'MMM d, y h:mm a', locale: locale),
+ emailAddress
+ );
+ case EmailActionType.forward:
+ var headerQuoted = '------- ${AppLocalizations.of(context).forwarded_message} -------'.addNewLineTag();
+
+ final subject = presentationEmail.subject ?? '';
+ final receivedAt = presentationEmail.receivedAt;
+ final fromEmailAddress = presentationEmail.from.listEmailAddressToString(isFullEmailAddress: true);
+ final toEmailAddress = presentationEmail.to.listEmailAddressToString(isFullEmailAddress: true);
+ final ccEmailAddress = presentationEmail.cc.listEmailAddressToString(isFullEmailAddress: true);
+ final bccEmailAddress = presentationEmail.bcc.listEmailAddressToString(isFullEmailAddress: true);
+
+ if (subject.isNotEmpty) {
+ headerQuoted = headerQuoted
+ .append('${AppLocalizations.of(context).subject_email}: ')
+ .append(subject)
+ .addNewLineTag();
+ }
+ if (receivedAt != null) {
+ headerQuoted = headerQuoted
+ .append('${AppLocalizations.of(context).date}: ')
+ .append(receivedAt.formatDateToLocal(pattern: 'MMM d, y h:mm a', locale: locale))
+ .addNewLineTag();
+ }
+ if (fromEmailAddress.isNotEmpty) {
+ headerQuoted = headerQuoted
+ .append('${AppLocalizations.of(context).from_email_address_prefix}: ')
+ .append(fromEmailAddress)
+ .addNewLineTag();
+ }
+ if (toEmailAddress.isNotEmpty) {
+ headerQuoted = headerQuoted
+ .append('${AppLocalizations.of(context).to_email_address_prefix}: ')
+ .append(toEmailAddress)
+ .addNewLineTag();
+ }
+ if (ccEmailAddress.isNotEmpty) {
+ headerQuoted = headerQuoted
+ .append('${AppLocalizations.of(context).cc_email_address_prefix}: ')
+ .append(ccEmailAddress)
+ .addNewLineTag();
+ }
+ if (bccEmailAddress.isNotEmpty) {
+ headerQuoted = headerQuoted
+ .append('${AppLocalizations.of(context).bcc_email_address_prefix}: ')
+ .append(bccEmailAddress)
+ .addNewLineTag();
+ }
+
+ return headerQuoted;
+ default:
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/lib/features/composer/presentation/styles/composer_style.dart b/lib/features/composer/presentation/styles/composer_style.dart
index 32a034428..61948eda5 100644
--- a/lib/features/composer/presentation/styles/composer_style.dart
+++ b/lib/features/composer/presentation/styles/composer_style.dart
@@ -99,7 +99,7 @@ class ComposerStyle {
if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeMobile(context)) {
return const EdgeInsetsDirectional.symmetric(horizontal: 16);
} else {
- return const EdgeInsetsDirectional.only(start: 88, end: 48);
+ return const EdgeInsetsDirectional.only(start: 88, end: 48, top: 8);
}
}
diff --git a/lib/features/email/data/datasource/html_datasource.dart b/lib/features/email/data/datasource/html_datasource.dart
index 8cce703fb..36f7d8975 100644
--- a/lib/features/email/data/datasource/html_datasource.dart
+++ b/lib/features/email/data/datasource/html_datasource.dart
@@ -1,12 +1,16 @@
+import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:model/model.dart';
abstract class HtmlDataSource {
Future transformEmailContent(
EmailContent emailContent,
- Map mapUrlDownloadCID,
- {bool draftsEmail = false}
+ Map mapCidImageDownloadUrl,
+ TransformConfiguration transformConfiguration
);
- Future addTooltipWhenHoverOnLink(EmailContent emailContent);
+ Future transformHtmlEmailContent(
+ String htmlContent,
+ TransformConfiguration configuration
+ );
}
\ No newline at end of file
diff --git a/lib/features/email/data/datasource_impl/html_datasource_impl.dart b/lib/features/email/data/datasource_impl/html_datasource_impl.dart
index c6f65a32d..7ce83177e 100644
--- a/lib/features/email/data/datasource_impl/html_datasource_impl.dart
+++ b/lib/features/email/data/datasource_impl/html_datasource_impl.dart
@@ -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 transformEmailContent(
EmailContent emailContent,
- Map? mapUrlDownloadCID,
- {bool draftsEmail = false}
+ Map mapCidImageDownloadUrl,
+ TransformConfiguration transformConfiguration
) {
return Future.sync(() async {
return await _htmlAnalyzer.transformEmailContent(
emailContent,
- mapUrlDownloadCID,
- draftsEmail: draftsEmail
+ mapCidImageDownloadUrl,
+ transformConfiguration
);
}).catchError(_exceptionThrower.throwException);
}
@override
- Future addTooltipWhenHoverOnLink(EmailContent emailContent) {
+ Future transformHtmlEmailContent(String htmlContent, TransformConfiguration configuration) {
return Future.sync(() async {
- return await _htmlAnalyzer.addTooltipWhenHoverOnLink(emailContent);
+ return await _htmlAnalyzer.transformHtmlEmailContent(
+ htmlContent,
+ configuration
+ );
}).catchError(_exceptionThrower.throwException);
}
}
\ No newline at end of file
diff --git a/lib/features/email/data/local/html_analyzer.dart b/lib/features/email/data/local/html_analyzer.dart
index ebdee846f..d6c5a2610 100644
--- a/lib/features/email/data/local/html_analyzer.dart
+++ b/lib/features/email/data/local/html_analyzer.dart
@@ -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 transformEmailContent(
EmailContent emailContent,
- Map? mapUrlDownloadCID,
- {bool draftsEmail = false}
+ Map 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 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> 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 transformHtmlEmailContent(
+ String htmlContent,
+ TransformConfiguration configuration
+ ) async {
+ final htmlContentTransformed = await _htmlTransform.transformToHtml(
+ htmlContent: htmlContent,
+ transformConfiguration: configuration
+ );
+ return htmlContentTransformed;
+ }
}
\ No newline at end of file
diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart
index 36d2217a0..554b7e486 100644
--- a/lib/features/email/data/repository/email_repository_impl.dart
+++ b/lib/features/email/data/repository/email_repository_impl.dart
@@ -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> transformEmailContent(
- List emailContents,
- List attachmentInlines,
- String? baseUrlDownload,
- AccountId accountId,
- {bool draftsEmail = false}
- ) async {
- final mapUrlDownloadCID = {
- for (var attachment in attachmentInlines)
- attachment.cid! : attachment.getDownloadUrl(baseUrlDownload!, accountId)
- };
+ List emailContents,
+ Map 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> addTooltipWhenHoverOnLink(List emailContents) {
- return Future.wait(emailContents
- .map((emailContent) => _htmlDataSource.addTooltipWhenHoverOnLink(emailContent))
- .toList());
- }
-
@override
Future getEmailState(Session session, AccountId accountId) {
return _stateDataSource.getState(accountId, session.username, StateType.email);
@@ -219,4 +207,9 @@ class EmailRepositoryImpl extends EmailRepository {
Future getStoredNewEmail(Session session, AccountId accountId, EmailId emailId) {
return emailDataSource[DataSourceType.hiveCache]!.getStoredNewEmail(session, accountId, emailId);
}
+
+ @override
+ Future transformHtmlEmailContent(String htmlContent, TransformConfiguration configuration) {
+ return _htmlDataSource.transformHtmlEmailContent(htmlContent, configuration);
+ }
}
\ No newline at end of file
diff --git a/lib/features/email/domain/exceptions/email_exceptions.dart b/lib/features/email/domain/exceptions/email_exceptions.dart
index 054268e88..a59cbe218 100644
--- a/lib/features/email/domain/exceptions/email_exceptions.dart
+++ b/lib/features/email/domain/exceptions/email_exceptions.dart
@@ -3,4 +3,6 @@ class CannotDeleteOldEmailException implements Exception {}
class NotFoundEmailException implements Exception {}
-class NotFoundEmailContentException implements Exception {}
\ No newline at end of file
+class NotFoundEmailContentException implements Exception {}
+
+class EmptyEmailContentException implements Exception {}
\ No newline at end of file
diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart
index 4db11ed56..88f22aea4 100644
--- a/lib/features/email/domain/repository/email_repository.dart
+++ b/lib/features/email/domain/repository/email_repository.dart
@@ -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> transformEmailContent(
List emailContents,
- List attachmentInlines,
- String? baseUrlDownload,
- AccountId accountId,
- {bool draftsEmail = false}
+ Map mapCidImageDownloadUrl,
+ TransformConfiguration transformConfiguration
);
- Future> addTooltipWhenHoverOnLink(List emailContents);
-
Future saveEmailAsDrafts(Session session, AccountId accountId, Email email);
Future removeEmailDrafts(Session session, AccountId accountId, EmailId emailId);
@@ -102,4 +99,9 @@ abstract class EmailRepository {
Future getStoredOpenedEmail(Session session, AccountId accountId, EmailId emailId);
Future getStoredNewEmail(Session session, AccountId accountId, EmailId emailId);
+
+ Future transformHtmlEmailContent(
+ String htmlContent,
+ TransformConfiguration configuration
+ );
}
\ No newline at end of file
diff --git a/lib/features/email/domain/state/get_email_content_state.dart b/lib/features/email/domain/state/get_email_content_state.dart
index 8581209dc..9742216d9 100644
--- a/lib/features/email/domain/state/get_email_content_state.dart
+++ b/lib/features/email/domain/state/get_email_content_state.dart
@@ -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 attachments;
final Email? emailCurrent;
GetEmailContentSuccess({
- required this.emailContent,
- required this.emailContentDisplayed,
- required this.attachments,
- required this.emailCurrent
- });
-
- @override
- List