Skip to content

Commit

Permalink
fixup! TF-2901 Implement caching composer on log out
Browse files Browse the repository at this point in the history
  • Loading branch information
tddang-linagora committed Jun 21, 2024
1 parent 1b78d0f commit 437444f
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 136 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';

class RestoringEmailInlineImages extends LoadingState {}

class RestoreEmailInlineImagesSuccess extends UIState {
final String emailContent;

RestoreEmailInlineImagesSuccess(this.emailContent);

@override
List<Object?> get props => [emailContent];
}

class RestoreEmailInlineImagesFailure extends FeatureFailure {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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/composer/domain/state/restore_email_inline_images_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/repository/composer_cache_repository.dart';

class RestoreEmailInlineImagesInteractor {
RestoreEmailInlineImagesInteractor(this._composerCacheRepository);

final ComposerCacheRepository _composerCacheRepository;

Stream<Either<Failure, Success>> execute({
required String htmlContent,
required TransformConfiguration transformConfiguration,
required Map<String, String> mapUrlDownloadCID
}) async* {
try {
yield Right(RestoringEmailInlineImages());

final emailContent = await _composerCacheRepository.restoreEmailInlineImages(
htmlContent,
transformConfiguration,
mapUrlDownloadCID);
yield Right(RestoreEmailInlineImagesSuccess(emailContent));
} catch (_) {
yield Left(RestoreEmailInlineImagesFailure());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ class SaveComposerCacheOnWebInteractor {
) async {
try {
final emailCreated = await _composerRepository.generateEmail(createEmailRequest);
_composerCacheRepository.saveComposerCacheOnWeb(
await _composerCacheRepository.saveComposerCacheOnWeb(
emailCreated,
accountId: accountId,
userName: userName);
userName: userName,
identity: createEmailRequest.identity);
return Right(SaveComposerCacheSuccess());
} catch (exception) {
return Left(SaveComposerCacheFailure(exception));
Expand Down
3 changes: 3 additions & 0 deletions lib/features/composer/presentation/composer_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:tmail_ui_user/features/composer/domain/repository/contact_reposi
import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/restore_email_inline_images_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
Expand Down Expand Up @@ -208,6 +209,8 @@ class ComposerBindings extends BaseBindings {
Get.find<MailboxRepository>(),
Get.find<ComposerRepository>(),
));
Get.lazyPut(() => RestoreEmailInlineImagesInteractor(
Get.find<ComposerCacheRepository>()));

IdentityInteractorsBindings().dependencies();
}
Expand Down
95 changes: 63 additions & 32 deletions lib/features/composer/presentation/composer_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:math';

import 'package:collection/collection.dart';
import 'package:core/core.dart';
import 'package:core/presentation/utils/html_transformer/dom/image_transformers.dart';
import 'package:dartz/dartz.dart';
import 'package:desktop_drop/desktop_drop.dart';
import 'package:dio/dio.dart';
Expand All @@ -15,6 +16,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
Expand All @@ -36,6 +38,7 @@ import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_b
import 'package:tmail_ui_user/features/composer/domain/state/generate_email_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/get_device_contact_suggestions_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/restore_email_inline_images_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart';
Expand All @@ -45,6 +48,7 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_a
import 'package:tmail_ui_user/features/composer/domain/usecases/get_all_autocomplete_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/get_device_contact_suggestions_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/restore_email_inline_images_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart';
Expand Down Expand Up @@ -132,6 +136,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
GetAllAutoCompleteInteractor? _getAllAutoCompleteInteractor;
GetAutoCompleteInteractor? _getAutoCompleteInteractor;
GetDeviceContactSuggestionsInteractor? _getDeviceContactSuggestionsInteractor;
RestoreEmailInlineImagesInteractor? _restoreEmailInlineImagesInteractor;

List<EmailAddress> listToEmailAddress = <EmailAddress>[];
List<EmailAddress> listCcEmailAddress = <EmailAddress>[];
Expand Down Expand Up @@ -287,7 +292,8 @@ class ComposerController extends BaseController with DragDropFileMixin implement
super.handleSuccessViewState(success);
if (success is GetEmailContentLoading ||
success is TransformHtmlEmailContentLoading ||
success is TransformHtmlEmailContentSuccess) {
success is TransformHtmlEmailContentSuccess ||
success is RestoringEmailInlineImages) {
emailContentsViewState.value = Right(success);
} else if (success is LocalFilePickerSuccess) {
_handlePickFileSuccess(success);
Expand All @@ -309,6 +315,11 @@ class ComposerController extends BaseController with DragDropFileMixin implement
maxWithEditor = null;
} else if (success is GetAlwaysReadReceiptSettingSuccess) {
hasRequestReadReceipt.value = success.alwaysReadReceiptEnabled;
} else if (success is RestoreEmailInlineImagesSuccess) {
richTextWebController?.editorController.setText(success.emailContent);
consumeState(Stream.value(Right(GetEmailContentSuccess(
htmlEmailContent: success.emailContent,
attachments: []))));
}
}

Expand All @@ -320,7 +331,8 @@ class ComposerController extends BaseController with DragDropFileMixin implement
} else if (failure is LocalImagePickerFailure) {
_handlePickImageFailure(failure);
} else if (failure is GetEmailContentFailure ||
failure is TransformHtmlEmailContentFailure) {
failure is TransformHtmlEmailContentFailure ||
failure is RestoreEmailInlineImagesFailure) {
emailContentsViewState.value = Left(failure);
} else if (failure is GetAllIdentitiesFailure) {
if (identitySelected.value == null) {
Expand Down Expand Up @@ -354,13 +366,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
_subscriptionOnBeforeUnload = html.window.onBeforeUnload.listen((event) async {
await _removeComposerCacheOnWebInteractor.execute();

final createEmailRequest = await _generateCreateEmailRequest();
if (createEmailRequest == null) return;

await _saveComposerCacheOnWebInteractor.execute(
createEmailRequest,
mailboxDashBoardController.accountId.value!,
mailboxDashBoardController.sessionCurrent!.username);
await _saveComposerCacheOnWebAction();
});

_subscriptionOnDragEnter = html.window.onDragEnter.listen((event) {
Expand All @@ -380,6 +386,16 @@ class ComposerController extends BaseController with DragDropFileMixin implement
});
}

Future<void> _saveComposerCacheOnWebAction() async {
final createEmailRequest = await _generateCreateEmailRequest();
if (createEmailRequest == null) return;

await _saveComposerCacheOnWebInteractor.execute(
createEmailRequest,
mailboxDashBoardController.accountId.value!,
mailboxDashBoardController.sessionCurrent!.username);
}

Future<CreateEmailRequest?> _generateCreateEmailRequest() async {
if (composerArguments.value == null ||
mailboxDashBoardController.sessionCurrent == null ||
Expand Down Expand Up @@ -500,7 +516,7 @@ class ComposerController extends BaseController with DragDropFileMixin implement
if (arguments is ComposerArguments) {
composerArguments.value = arguments;

_initIdentities(arguments.identities);
_initIdentities(arguments);

injectAutoCompleteBindings(
mailboxDashBoardController.sessionCurrent,
Expand Down Expand Up @@ -582,6 +598,8 @@ class ComposerController extends BaseController with DragDropFileMixin implement
_transformHtmlEmailContent(arguments.emailContents);
break;
case EmailActionType.reopenComposerBrowser:
if (!PlatformInfo.isWeb) return;

_initEmailAddress(
presentationEmail: arguments.presentationEmail!,
actionType: EmailActionType.reopenComposerBrowser
Expand All @@ -591,7 +609,17 @@ class ComposerController extends BaseController with DragDropFileMixin implement
actionType: EmailActionType.reopenComposerBrowser
);
_initAttachments(arguments.attachments ?? []);
_getEmailContentFromSessionStorageBrowser(arguments.emailContents!);

final accountId = mailboxDashBoardController.accountId.value;
final downloadUrl = mailboxDashBoardController.sessionCurrent
?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl);
if (accountId == null || downloadUrl == null) return;
_getEmailContentFromSessionStorageBrowser(
htmlContent: arguments.emailContents ?? '',
inlineImages: arguments.inlineImages ?? [],
accountId: accountId,
downloadUrl: downloadUrl
);
break;
case EmailActionType.composeFromUnsubscribeMailtoLink:
if (arguments.subject != null) {
Expand Down Expand Up @@ -629,10 +657,12 @@ class ComposerController extends BaseController with DragDropFileMixin implement
}
}

void _initIdentities(List<Identity>? identities) {
if (identities?.isNotEmpty == true) {
listFromIdentities.value = identities!;
identitySelected.value = identities.first;
void _initIdentities(ComposerArguments composerArguments) {
listFromIdentities.value = composerArguments.identities ?? [];
if (composerArguments.selectedIdentity != null) {
identitySelected.value = composerArguments.selectedIdentity;
} else if (composerArguments.identities?.isNotEmpty == true) {
identitySelected.value = listFromIdentities.first;
}
}

Expand Down Expand Up @@ -1245,13 +1275,20 @@ class ComposerController extends BaseController with DragDropFileMixin implement
));
}

void _getEmailContentFromSessionStorageBrowser(String content) {
consumeState(Stream.value(
Right(GetEmailContentSuccess(
htmlEmailContent: content,
attachments: [],
))
));
void _getEmailContentFromSessionStorageBrowser({
required String htmlContent,
required List<Attachment> inlineImages,
required AccountId accountId,
required String downloadUrl
}) {
_restoreEmailInlineImagesInteractor = getBinding<RestoreEmailInlineImagesInteractor>();
if (_restoreEmailInlineImagesInteractor == null) return;
consumeState(_restoreEmailInlineImagesInteractor!.execute(
htmlContent: htmlContent,
transformConfiguration: TransformConfiguration.fromDomTransformers([const ImageTransformer()]),
mapUrlDownloadCID: inlineImages.toMapCidImageDownloadUrl(
accountId: accountId,
downloadUrl: downloadUrl)));
}

void _getEmailContentFromContentShared(String content) {
Expand Down Expand Up @@ -2188,15 +2225,9 @@ class ComposerController extends BaseController with DragDropFileMixin implement
@override
Future<void> onBeforeUnload() async {
if (mailboxDashBoardController.accountId.value != null &&
mailboxDashBoardController.sessionCurrent?.username != null
) {
final createEmailRequest = await _generateCreateEmailRequest();
if (createEmailRequest == null) return;

await _saveComposerCacheOnWebInteractor.execute(
createEmailRequest,
mailboxDashBoardController.accountId.value!,
mailboxDashBoardController.sessionCurrent!.username);
}
mailboxDashBoardController.sessionCurrent?.username != null
) {
await _saveComposerCacheOnWebAction();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen

extension ComposerArgumentsExtension on ComposerArguments {

ComposerArguments withIdentity({List<Identity>? identities}) {
ComposerArguments withIdentity({List<Identity>? identities, Identity? selectedIdentity}) {
return ComposerArguments(
emailActionType: emailActionType,
presentationEmail: presentationEmail,
Expand All @@ -19,6 +19,8 @@ extension ComposerArgumentsExtension on ComposerArguments {
references: references,
previousEmailId: previousEmailId,
identities: identities,
selectedIdentity: selectedIdentity,
inlineImages: inlineImages,
);
}
}
22 changes: 13 additions & 9 deletions lib/features/email/presentation/model/composer_arguments.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:jmap_dart_client/jmap/mail/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/features/sending_queue/presentation/model/sending_email_action_type.dart';
Expand All @@ -24,6 +26,8 @@ class ComposerArguments extends RouterArguments {
final MessageIdsHeaderValue? references;
final EmailId? previousEmailId;
final List<Identity>? identities;
final Identity? selectedIdentity;
final List<Attachment>? inlineImages;

ComposerArguments({
this.emailActionType = EmailActionType.compose,
Expand All @@ -40,6 +44,8 @@ class ComposerArguments extends RouterArguments {
this.references,
this.previousEmailId,
this.identities,
this.selectedIdentity,
this.inlineImages,
});

factory ComposerArguments.fromSendingEmail(SendingEmail sendingEmail) =>
Expand Down Expand Up @@ -83,15 +89,13 @@ class ComposerArguments extends RouterArguments {
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,
presentationEmail: composerCache.email?.toPresentationEmail(),
emailContents: composerCache.email?.emailContentList.asHtmlString,
attachments: composerCache.email?.allAttachments
.where((attachment) => attachment.disposition == ContentDisposition.attachment)
.toList(),
selectedIdentity: composerCache.identity,
inlineImages: composerCache.email?.attachmentsWithCid,
);

factory ComposerArguments.replyEmail({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/data/model/composer_cache.dart';

abstract class SessionStorageComposerDatasource {
Future<void> saveComposerCacheOnWeb(Email email, {required AccountId accountId, required UserName userName});
Future<void> saveComposerCacheOnWeb(
Email email,
{
required AccountId accountId,
required UserName userName,
Identity? identity
}
);

Future<ComposerCache> getComposerCacheOnWeb(AccountId accountId, UserName userName);
Future<ComposerCache> getComposerCacheOnWeb(
AccountId accountId,
UserName userName);

Future<void> removeComposerCacheOnWeb();

Future<String> restoreEmailInlineImages(
String htmlContent,
TransformConfiguration transformConfiguration,
Map<String, String> mapUrlDownloadCID);
}
Loading

0 comments on commit 437444f

Please sign in to comment.