TF-1809: Handle sync data from cache and network when get email contents

(cherry picked from commit 896059cd5b29c62c2cf34621fe35d7b23a54acf4)
This commit is contained in:
HuyNguyen
2023-05-18 11:56:24 +07:00
committed by Dat Vu
parent b17e4e4728
commit 48f5a8b51f
19 changed files with 205 additions and 135 deletions
+10
View File
@@ -55,6 +55,16 @@ class FileUtils {
return await file.writeAsString(content, mode: FileMode.append); return await file.writeAsString(content, mode: FileMode.append);
} }
Future<void> deleteFile(String filePath) async {
final file = File(filePath);
if (await file.exists()) {
await file.delete();
log("FileUtils()::deleteFile: $file");
} else {
log("FileUtils()::deleteFile: File does not exist");
}
}
Future<String> getContentFromFile({ Future<String> getContentFromFile({
required String nameFile, required String nameFile,
String? folderPath, String? folderPath,
@@ -20,7 +20,8 @@ class CachingConstants {
static const String fcmCacheBoxName = 'fcm_cache_box'; static const String fcmCacheBoxName = 'fcm_cache_box';
static const String detailedEmailCacheBoxName = 'detailed_email_cache_box'; static const String detailedEmailCacheBoxName = 'detailed_email_cache_box';
static const String emailContentFolderName = 'email_content'; static const String newEmailContentFolderName = 'new_email';
static const String openedEmailContentFolderNamee = 'opened_email';
static const String openedEmailCacheBoxName = 'opened_email_cache_box'; static const String openedEmailCacheBoxName = 'opened_email_cache_box';
static const int maxNumberNewEmailsForOffline = 10; static const int maxNumberNewEmailsForOffline = 10;
@@ -140,7 +140,7 @@ class ComposerController extends BaseController {
List<Attachment> initialAttachments = <Attachment>[]; List<Attachment> initialAttachments = <Attachment>[];
String? _textEditorWeb; String? _textEditorWeb;
String? _initTextEditor; String? _initTextEditor;
List<EmailContent>? _emailContents; String? _emailContents;
double? maxWithEditor; double? maxWithEditor;
late Worker uploadInlineImageWorker; late Worker uploadInlineImageWorker;
@@ -281,6 +281,8 @@ class ComposerController extends BaseController {
_pickFileSuccess(success); _pickFileSuccess(success);
} else if (success is GetEmailContentSuccess) { } else if (success is GetEmailContentSuccess) {
_getEmailContentSuccess(success); _getEmailContentSuccess(success);
} else if (success is GetEmailContentFromCacheSuccess) {
_getEmailContentOffLineSuccess(success);
} else if (success is GetAllIdentitiesSuccess) { } else if (success is GetAllIdentitiesSuccess) {
_handleGetAllIdentitiesSuccess(success); _handleGetAllIdentitiesSuccess(success);
} else if (success is DownloadImageAsBase64Success) { } else if (success is DownloadImageAsBase64Success) {
@@ -595,7 +597,7 @@ class ComposerController extends BaseController {
log('ComposerController::getEmailContentQuotedAsHtml(): headerEmailQuoted: $headerEmailQuoted'); log('ComposerController::getEmailContentQuotedAsHtml(): headerEmailQuoted: $headerEmailQuoted');
final headerEmailQuotedAsHtml = headerEmailQuoted != null ? headerEmailQuoted.addBlockTag('cite') : ''; final headerEmailQuotedAsHtml = headerEmailQuoted != null ? headerEmailQuoted.addBlockTag('cite') : '';
final trustAsHtml = arguments.emailContents?.asHtmlString ?? ''; final trustAsHtml = arguments.emailContents ?? '';
final emailQuotedHtml = '${HtmlExtension.editorStartTags}$headerEmailQuotedAsHtml${trustAsHtml.addBlockQuoteTag()}'; final emailQuotedHtml = '${HtmlExtension.editorStartTags}$headerEmailQuotedAsHtml${trustAsHtml.addBlockQuoteTag()}';
return emailQuotedHtml; return emailQuotedHtml;
@@ -1108,8 +1110,7 @@ class ComposerController extends BaseController {
} }
if(arguments.emailContents != null && arguments.emailContents!.isNotEmpty) { if(arguments.emailContents != null && arguments.emailContents!.isNotEmpty) {
_emailContents = arguments.emailContents; emailContentsViewState.value = Right(GetEmailContentFromCacheSuccess(arguments.emailContents!, []));
emailContentsViewState.value = Right(GetEmailContentSuccess(_emailContents!, [], [], null));
} else { } else {
final session = mailboxDashBoardController.sessionCurrent; final session = mailboxDashBoardController.sessionCurrent;
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl); final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors.jmapUrl);
@@ -1128,6 +1129,16 @@ class ComposerController extends BaseController {
} }
} }
void _getEmailContentOffLineSuccess(GetEmailContentFromCacheSuccess success) {
if (success.attachments.isNotEmpty) {
initialAttachments = success.attachments;
uploadController.initializeUploadAttachments(
success.attachments.listAttachmentsDisplayedOutSide);
}
emailContentsViewState.value = Right(success);
_emailContents = success.emailContentString;
}
void _getEmailContentSuccess(GetEmailContentSuccess success) { void _getEmailContentSuccess(GetEmailContentSuccess success) {
if (success.attachments.isNotEmpty) { if (success.attachments.isNotEmpty) {
initialAttachments = success.attachments; initialAttachments = success.attachments;
@@ -1135,10 +1146,10 @@ class ComposerController extends BaseController {
success.attachments.listAttachmentsDisplayedOutSide); success.attachments.listAttachmentsDisplayedOutSide);
} }
emailContentsViewState.value = Right(success); emailContentsViewState.value = Right(success);
_emailContents = success.emailContents; _emailContents = success.emailContents.asHtmlString;
} }
String? getEmailContentDraftsAsHtml() => _emailContents?.asHtmlString; String? getEmailContentDraftsAsHtml() => _emailContents;
String getEmailAddressSender() { String getEmailAddressSender() {
final arguments = composerArguments.value; final arguments = composerArguments.value;
@@ -124,7 +124,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource {
final fileSaved = await _fileUtils.saveToFile( final fileSaved = await _fileUtils.saveToFile(
nameFile: detailedEmail.emailId.asString, nameFile: detailedEmail.emailId.asString,
content: detailedEmail.htmlEmailContent ?? '', content: detailedEmail.htmlEmailContent ?? '',
folderPath: detailedEmail.folderPath folderPath: detailedEmail.newEmailFolderPath
); );
log('EmailHiveCacheDataSourceImpl::storeDetailedEmailToCache():fileSavedPath: ${fileSaved.path}'); log('EmailHiveCacheDataSourceImpl::storeDetailedEmailToCache():fileSavedPath: ${fileSaved.path}');
final detailedEmailSaved = detailedEmail.fromEmailContentPath(fileSaved.path); final detailedEmailSaved = detailedEmail.fromEmailContentPath(fileSaved.path);
@@ -163,7 +163,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource {
final task = HiveTask( final task = HiveTask(
runnable: () async { runnable: () async {
final detailedEmailExisted = await _openedEmailCacheManager.isOpenedDetailEmailCached(accountId, session.username, detailedEmail); final detailedEmailExisted = await _openedEmailCacheManager.isOpenedDetailEmailCached(accountId, session.username, detailedEmail.emailId);
log('EmailHiveCacheDataSourceImpl::storeOpenedEmail():detailedEmailExisted: $detailedEmailExisted'); log('EmailHiveCacheDataSourceImpl::storeOpenedEmail():detailedEmailExisted: $detailedEmailExisted');
if (detailedEmailExisted) { if (detailedEmailExisted) {
@@ -173,7 +173,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource {
final fileSaved = await _fileUtils.saveToFile( final fileSaved = await _fileUtils.saveToFile(
nameFile: detailedEmail.emailId.asString, nameFile: detailedEmail.emailId.asString,
content: detailedEmail.htmlEmailContent ?? '', content: detailedEmail.htmlEmailContent ?? '',
folderPath: detailedEmail.folderPath folderPath: detailedEmail.openedEmailFolderPath
); );
log('EmailHiveCacheDataSourceImpl::storeOpenedEmail():fileSavedPath: ${fileSaved.path}'); log('EmailHiveCacheDataSourceImpl::storeOpenedEmail():fileSavedPath: ${fileSaved.path}');
@@ -196,7 +196,7 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource {
final emailContent = await _fileUtils.getContentFromFile( final emailContent = await _fileUtils.getContentFromFile(
nameFile: emailId.asString, nameFile: emailId.asString,
folderPath: CachingConstants.emailContentFolderName folderPath: CachingConstants.openedEmailContentFolderNamee
); );
return detailedEmailHiveCache?.toDetailedEmailWithContent(emailContent); return detailedEmailHiveCache?.toDetailedEmailWithContent(emailContent);
@@ -205,7 +205,7 @@ class EmailRepositoryImpl extends EmailRepository {
} }
@override @override
Future<DetailedEmail> getOpenedEmail(Session session, AccountId accountId, EmailId emailId) { Future<DetailedEmail?> getOpenedEmail(Session session, AccountId accountId, EmailId emailId) {
throw UnimplementedError(); return emailDataSource[DataSourceType.hiveCache]!.getOpenedEmail(session, accountId, emailId);
} }
} }
@@ -8,13 +8,13 @@ import 'package:tmail_ui_user/features/offline_mode/model/attachment_hive_cache.
extension AttachmentExtension on AttachmentHiveCache { extension AttachmentExtension on AttachmentHiveCache {
Attachment toAttachment() { Attachment toAttachment() {
return Attachment( return Attachment(
partId: PartId(partId!), partId: partId != null ? PartId(partId!) : null,
blobId: Id(blobId!), blobId: blobId != null ? Id(blobId!) : null,
size: UnsignedInt(size!), size: size != null ? UnsignedInt(size!) : null,
name: name, name: name,
type: MediaType.parse(type!), type: type != null ? MediaType.parse(type!) : null,
cid: cid, cid: cid,
disposition: disposition?.toContentDisposition(), disposition: disposition?.toContentDisposition(),
); );
} }
} }
@@ -17,7 +17,9 @@ extension DetailedEmailExtension on DetailedEmail {
); );
} }
String get folderPath => CachingConstants.emailContentFolderName; String get newEmailFolderPath => CachingConstants.newEmailContentFolderName;
String get openedEmailFolderPath => CachingConstants.openedEmailContentFolderNamee;
DetailedEmail fromEmailContentPath(String path) { DetailedEmail fromEmailContentPath(String path) {
return DetailedEmail( return DetailedEmail(
@@ -96,5 +96,5 @@ abstract class EmailRepository {
Future<void> storeOpenedEmail(Session session, AccountId accountId, DetailedEmail detailedEmail); Future<void> storeOpenedEmail(Session session, AccountId accountId, DetailedEmail detailedEmail);
Future<DetailedEmail> getOpenedEmail(Session session, AccountId accountId, EmailId emailId); Future<DetailedEmail?> getOpenedEmail(Session session, AccountId accountId, EmailId emailId);
} }
@@ -26,6 +26,22 @@ class GetEmailContentSuccess extends UIState {
]; ];
} }
class GetEmailContentFromCacheSuccess extends UIState {
final String emailContentString;
final List<Attachment> attachments;
GetEmailContentFromCacheSuccess(
this.emailContentString,
this.attachments,
);
@override
List<Object?> get props => [
emailContentString,
attachments,
];
}
class GetEmailContentFailure extends FeatureFailure { class GetEmailContentFailure extends FeatureFailure {
final dynamic exception; final dynamic exception;
@@ -1,22 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart';
class GetOpenedEmailLoading extends UIState {}
class GetOpenedEmailSuccess extends UIState {
final DetailedEmail detailedEmail;
GetOpenedEmailSuccess(this.detailedEmail);
@override
List<Object?> get props => [detailedEmail];
}
class GetOpenedEmailFailure extends FeatureFailure {
GetOpenedEmailFailure(dynamic exception) : super(exception: exception);
@override
List<Object?> get props => [exception];
}
@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
@@ -28,37 +30,85 @@ class GetEmailContentInteractor {
) async* { ) async* {
try { try {
yield Right<Failure, Success>(GetEmailContentLoading()); yield Right<Failure, Success>(GetEmailContentLoading());
final email = await emailRepository.getEmailContent(session, accountId, emailId);
if (email.emailContentList.isNotEmpty) { if (!BuildUtils.isWeb) {
final newEmailContents = await emailRepository.transformEmailContent( yield* _tryToGetOpenedEmailCache(session, accountId, emailId, baseDownloadUrl, composeEmail: composeEmail, draftsEmail: draftsEmail);
email.emailContentList,
email.allAttachments.listAttachmentsDisplayedInContent,
baseDownloadUrl,
accountId,
draftsEmail: draftsEmail
);
final newEmailContentsDisplayed = BuildUtils.isWeb && !composeEmail
? await emailRepository.addTooltipWhenHoverOnLink(newEmailContents)
: newEmailContents;
yield Right<Failure, Success>(GetEmailContentSuccess(
newEmailContents,
newEmailContentsDisplayed,
email.allAttachments,
email
));
} else if (email.allAttachments.isNotEmpty) {
yield Right<Failure, Success>(GetEmailContentSuccess([], [], email.allAttachments, email));
} else if (email.headers?.isNotEmpty == true) {
yield Right<Failure, Success>(GetEmailContentSuccess([], [], [], email));
} else { } else {
yield Left(GetEmailContentFailure(null)); yield* _getContentEmailFromServer(session, accountId, emailId, baseDownloadUrl, composeEmail: composeEmail, draftsEmail: draftsEmail);
} }
} catch (e) { } catch (e) {
log('GetEmailContentInteractor::execute(): exception = $e'); log('GetEmailContentInteractor::execute(): exception = $e');
yield Left(GetEmailContentFailure(e)); yield Left(GetEmailContentFailure(e));
} }
} }
Stream<Either<Failure, Success>> _getContentEmailFromServer(
Session session,
AccountId accountId,
EmailId emailId,
String? baseDownloadUrl,
{
bool composeEmail = false,
bool draftsEmail = false
}
) async* {
final email = await emailRepository.getEmailContent(session, accountId, emailId);
if (email.emailContentList.isNotEmpty) {
final newEmailContents = await emailRepository.transformEmailContent(
email.emailContentList,
email.allAttachments.listAttachmentsDisplayedInContent,
baseDownloadUrl,
accountId,
draftsEmail: draftsEmail
);
final newEmailContentsDisplayed = BuildUtils.isWeb && !composeEmail
? await emailRepository.addTooltipWhenHoverOnLink(newEmailContents)
: newEmailContents;
yield Right<Failure, Success>(GetEmailContentSuccess(
newEmailContents,
newEmailContentsDisplayed,
email.allAttachments,
email
));
} else if (email.allAttachments.isNotEmpty) {
yield Right<Failure, Success>(GetEmailContentSuccess([], [], email.allAttachments, email));
} else if (email.headers?.isNotEmpty == true) {
yield Right<Failure, Success>(GetEmailContentSuccess([], [], [], email));
} else {
yield Left(GetEmailContentFailure(null));
}
}
Stream<Either<Failure, Success>> _tryToGetOpenedEmailCache(
Session session,
AccountId accountId,
EmailId emailId,
String? baseDownloadUrl,
{
bool composeEmail = false,
bool draftsEmail = false
}
) async* {
log('GetEmailContentInteractor::_getOpenedEmailCache():');
try {
final detailedEmail = await emailRepository.getOpenedEmail(session, accountId, emailId);
if (detailedEmail != null) {
yield Right<Failure, Success>(GetEmailContentFromCacheSuccess(
detailedEmail.htmlEmailContent ?? "",
detailedEmail.attachments ?? [],
));
} else {
yield* _getContentEmailFromServer(session, accountId, emailId, baseDownloadUrl, composeEmail: composeEmail, draftsEmail: draftsEmail);
}
} catch (e) {
if (e is PathNotFoundException) {
yield* _getContentEmailFromServer(session, accountId, emailId, baseDownloadUrl, composeEmail: composeEmail, draftsEmail: draftsEmail);
} else {
yield Left<Failure, Success>(GetEmailContentFailure(e));
}
}
}
} }
@@ -1,25 +0,0 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_opened_email_from_cache_state.dart';
class GetOpenedEmailFromCacheInteractor {
final EmailRepository _emailRepository;
GetOpenedEmailFromCacheInteractor(this._emailRepository);
Stream<Either<Failure, Success>> execute(Session session, AccountId accountId, EmailId emailId) async* {
try {
yield Right<Failure, Success>(GetOpenedEmailLoading());
final detailedEmail = await _emailRepository.getOpenedEmail(session, accountId, emailId);
yield Right<Failure, Success>(GetOpenedEmailSuccess(detailedEmail));
} catch (e) {
yield Left<Failure, Success>(GetOpenedEmailFailure(e));
}
}
}
@@ -100,11 +100,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
final emailAddressExpandMode = ExpandMode.COLLAPSE.obs; final emailAddressExpandMode = ExpandMode.COLLAPSE.obs;
final attachmentsExpandMode = ExpandMode.COLLAPSE.obs; final attachmentsExpandMode = ExpandMode.COLLAPSE.obs;
final emailContents = <EmailContent>[].obs; final emailContents = RxnString();
final attachments = <Attachment>[].obs; final attachments = <Attachment>[].obs;
EmailId? _currentEmailId; EmailId? _currentEmailId;
Identity? _identitySelected; Identity? _identitySelected;
List<EmailContent>? initialEmailContents; String? initialEmailContents;
final ScrollController scrollControllerAttachment = ScrollController(); final ScrollController scrollControllerAttachment = ScrollController();
@@ -150,6 +150,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
super.handleSuccessViewState(success); super.handleSuccessViewState(success);
if (success is GetEmailContentSuccess) { if (success is GetEmailContentSuccess) {
_getEmailContentSuccess(success); _getEmailContentSuccess(success);
} else if (success is GetEmailContentFromCacheSuccess) {
_getEmailContentOffLineSuccess(success);
} else if (success is MarkAsEmailReadSuccess) { } else if (success is MarkAsEmailReadSuccess) {
_markAsEmailReadSuccess(success); _markAsEmailReadSuccess(success);
} else if (success is ExportAttachmentSuccess) { } else if (success is ExportAttachmentSuccess) {
@@ -356,6 +358,12 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
} }
} }
void _getEmailContentOffLineSuccess(GetEmailContentFromCacheSuccess success) {
emailContents.value = success.emailContentString;
attachments.value = success.attachments;
initialEmailContents = success.emailContentString;
}
void _getEmailContentSuccess(GetEmailContentSuccess success) { void _getEmailContentSuccess(GetEmailContentSuccess success) {
if(emailSupervisorController.presentationEmailsLoaded.length > ThreadConstants.defaultLimit.value.toInt()) { if(emailSupervisorController.presentationEmailsLoaded.length > ThreadConstants.defaultLimit.value.toInt()) {
emailSupervisorController.popFirstEmailQueue(); emailSupervisorController.popFirstEmailQueue();
@@ -370,8 +378,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
)); ));
if (success.emailCurrent?.id == currentEmail?.id) { if (success.emailCurrent?.id == currentEmail?.id) {
emailContents.value = success.emailContentsDisplayed; emailContents.value = success.emailContentsDisplayed.asHtmlString;
initialEmailContents = success.emailContents; initialEmailContents = success.emailContents.asHtmlString;
attachments.value = success.attachments; attachments.value = success.attachments;
if (!BuildUtils.isWeb) { if (!BuildUtils.isWeb) {
@@ -379,7 +387,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
emailId: currentEmail!.id!, emailId: currentEmail!.id!,
attachments: attachments, attachments: attachments,
headers: currentEmail?.emailHeader, headers: currentEmail?.emailHeader,
htmlEmailContent: emailContents.asHtmlString htmlEmailContent: emailContents.value
); );
_storeOpenedEmailToCache( _storeOpenedEmailToCache(
@@ -414,8 +422,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void _resetToOriginalValue() { void _resetToOriginalValue() {
attachmentsExpandMode.value = ExpandMode.COLLAPSE; attachmentsExpandMode.value = ExpandMode.COLLAPSE;
emailAddressExpandMode.value = ExpandMode.COLLAPSE; emailAddressExpandMode.value = ExpandMode.COLLAPSE;
emailContents.clear(); emailContents.value = null;
initialEmailContents?.clear(); initialEmailContents = null;
attachments.clear(); attachments.clear();
} }
@@ -1133,7 +1141,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
presentationEmail: mailboxDashBoardController.selectedEmail.value!, presentationEmail: mailboxDashBoardController.selectedEmail.value!,
emailContents: initialEmailContents, emailContents: initialEmailContents,
attachments: emailActionType == EmailActionType.forward ? attachments : null, attachments: emailActionType == EmailActionType.forward ? attachments : null,
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role); mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role
);
mailboxDashBoardController.goToComposer(arguments); mailboxDashBoardController.goToComposer(arguments);
} }
@@ -18,7 +18,6 @@ import 'package:model/email/attachment.dart';
import 'package:model/email/email_action_type.dart'; import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart'; import 'package:model/email/presentation_email.dart';
import 'package:model/extensions/list_attachment_extension.dart'; import 'package:model/extensions/list_attachment_extension.dart';
import 'package:model/extensions/list_email_content_extension.dart';
import 'package:model/extensions/presentation_email_extension.dart'; import 'package:model/extensions/presentation_email_extension.dart';
import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/base/widget/custom_scroll_behavior.dart'; import 'package:tmail_ui_user/features/base/widget/custom_scroll_behavior.dart';
@@ -441,20 +440,20 @@ class EmailView extends GetWidget<SingleEmailController> {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return Obx(() { return Obx(() {
if (controller.emailContents.isNotEmpty) { if (controller.emailContents.value != null) {
final allEmailContents = controller.emailContents.asHtmlString; final allEmailContents = controller.emailContents.value;
if (BuildUtils.isWeb) { if (BuildUtils.isWeb) {
return HtmlContentViewerOnWeb( return HtmlContentViewerOnWeb(
widthContent: constraints.maxWidth, widthContent: constraints.maxWidth,
heightContent: responsiveUtils.getSizeScreenHeight(context), heightContent: responsiveUtils.getSizeScreenHeight(context),
contentHtml: allEmailContents, contentHtml: allEmailContents ?? "",
controller: HtmlViewerControllerForWeb(), controller: HtmlViewerControllerForWeb(),
mailtoDelegate: (uri) => controller.openMailToLink(uri)); mailtoDelegate: (uri) => controller.openMailToLink(uri));
} else { } else {
return HtmlContentViewer( return HtmlContentViewer(
heightContent: responsiveUtils.getSizeScreenHeight(context), heightContent: responsiveUtils.getSizeScreenHeight(context),
contentHtml: allEmailContents, contentHtml: allEmailContents ?? "",
mailtoDelegate: (uri) async => controller.openMailToLink(uri), mailtoDelegate: (uri) async => controller.openMailToLink(uri),
onScrollHorizontalEnd: controller.toggleScrollPhysicsPagerView, onScrollHorizontalEnd: controller.toggleScrollPhysicsPagerView,
onWebViewLoaded: (isScrollPageViewActivated) { onWebViewLoaded: (isScrollPageViewActivated) {
@@ -7,7 +7,7 @@ import 'package:tmail_ui_user/main/routes/router_arguments.dart';
class ComposerArguments extends RouterArguments { class ComposerArguments extends RouterArguments {
final EmailActionType emailActionType; final EmailActionType emailActionType;
final PresentationEmail? presentationEmail; final PresentationEmail? presentationEmail;
final List<EmailContent>? emailContents; final String? emailContents;
final List<SharedMediaFile>? listSharedMediaFile; final List<SharedMediaFile>? listSharedMediaFile;
final EmailAddress? emailAddress; final EmailAddress? emailAddress;
final List<Attachment>? attachments; final List<Attachment>? attachments;
@@ -240,7 +240,7 @@ class MailboxDashBoardController extends ReloadableController {
cc: success.composerCache.cc, cc: success.composerCache.cc,
bcc: success.composerCache.bcc, bcc: success.composerCache.bcc,
), ),
emailContents: success.composerCache.emailContentList, emailContents: success.composerCache.emailContentList.asHtmlString,
); );
openComposerOverlay(composerArguments); openComposerOverlay(composerArguments);
} }
@@ -350,7 +350,7 @@ class MailboxDashBoardController extends ReloadableController {
_emailReceiveManager.clearPendingEmailContent(); _emailReceiveManager.clearPendingEmailContent();
final arguments = ComposerArguments( final arguments = ComposerArguments(
emailActionType: EmailActionType.edit, emailActionType: EmailActionType.edit,
emailContents: [emailContent], emailContents: [emailContent].asHtmlString,
mailboxRole: selectedMailbox.value?.role); mailboxRole: selectedMailbox.value?.role);
goToComposer(arguments); goToComposer(arguments);
} }
@@ -1,5 +1,6 @@
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:core/utils/file_utils.dart';
import 'package:jmap_dart_client/jmap/account_id.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/core/user_name.dart';
import 'package:model/extensions/account_id_extensions.dart'; import 'package:model/extensions/account_id_extensions.dart';
@@ -12,8 +13,9 @@ import 'package:tmail_ui_user/features/offline_mode/model/detailed_email_hive_ca
class DetailedEmailCacheManager { class DetailedEmailCacheManager {
final DetailedEmailHiveCacheClient _cacheClient; final DetailedEmailHiveCacheClient _cacheClient;
final FileUtils _fileUtils;
DetailedEmailCacheManager(this._cacheClient); DetailedEmailCacheManager(this._cacheClient, this._fileUtils);
Future<DetailedEmailHiveCache> handleStoreDetailedEmail( Future<DetailedEmailHiveCache> handleStoreDetailedEmail(
AccountId accountId, AccountId accountId,
@@ -23,9 +25,14 @@ class DetailedEmailCacheManager {
final listDetailedEmails = await getAllDetailedEmails(accountId, userName); final listDetailedEmails = await getAllDetailedEmails(accountId, userName);
if (listDetailedEmails.length >= CachingConstants.maxNumberNewEmailsForOffline) { if (listDetailedEmails.length >= CachingConstants.maxNumberNewEmailsForOffline) {
final latestEmail = listDetailedEmails.last; final lastElementsListEmail = listDetailedEmails.sublist(CachingConstants.maxNumberNewEmailsForOffline, listDetailedEmails.length);
log('DetailedEmailCacheManager::handleStoreDetailedEmail():latestEmail: $latestEmail'); for (var email in lastElementsListEmail) {
await removeDetailedEmail(accountId, userName, latestEmail.emailId); log('DetailedEmailCacheManager::handleStoreDetailedEmail():latestEmail: $email');
if (email.emailContentPath != null) {
await _deleteFileExisted(email.emailContentPath!);
}
await removeDetailedEmail(accountId, userName, email.emailId);
}
} }
await insertDetailedEmail(accountId, userName, detailedEmailCache); await insertDetailedEmail(accountId, userName, detailedEmailCache);
@@ -58,4 +65,8 @@ class DetailedEmailCacheManager {
log('DetailedEmailCacheManager::getAllDetailedEmails():SIZE: ${detailedEmailCacheList.length}'); log('DetailedEmailCacheManager::getAllDetailedEmails():SIZE: ${detailedEmailCacheList.length}');
return detailedEmailCacheList; return detailedEmailCacheList;
} }
Future<void> _deleteFileExisted(String pathFile) async {
await _fileUtils.deleteFile(pathFile);
}
} }
@@ -21,9 +21,9 @@ class OpenedEmailCacheManager {
OpenedEmailCacheManager(this._cacheClient, this._fileUtils); OpenedEmailCacheManager(this._cacheClient, this._fileUtils);
Future<void> insertDetailedEmail( Future<void> insertDetailedEmail(
AccountId accountId, AccountId accountId,
UserName userName, UserName userName,
DetailedEmailHiveCache detailedEmailCache DetailedEmailHiveCache detailedEmailCache
) { ) {
final keyCache = TupleKey(detailedEmailCache.emailId, accountId.asString, userName.value).encodeKey; final keyCache = TupleKey(detailedEmailCache.emailId, accountId.asString, userName.value).encodeKey;
log('OpenedEmailCacheManager::insertDetailedEmail(): $keyCache'); log('OpenedEmailCacheManager::insertDetailedEmail(): $keyCache');
@@ -31,9 +31,9 @@ class OpenedEmailCacheManager {
} }
Future<void> removeDetailedEmail( Future<void> removeDetailedEmail(
AccountId accountId, AccountId accountId,
UserName userName, UserName userName,
String emailId String emailId
) { ) {
final keyCache = TupleKey(emailId, accountId.asString, userName.value).encodeKey; final keyCache = TupleKey(emailId, accountId.asString, userName.value).encodeKey;
log('OpenedEmailCacheManager::removeDetailedEmail(): $keyCache'); log('OpenedEmailCacheManager::removeDetailedEmail(): $keyCache');
@@ -48,35 +48,40 @@ class OpenedEmailCacheManager {
} }
Future<void> storeOpenedEmail( Future<void> storeOpenedEmail(
AccountId accountId, AccountId accountId,
UserName userName, UserName userName,
DetailedEmail detailedEmail DetailedEmail detailedEmail
) async { ) async {
final listDetailedEmails = await getAllDetailedEmails(accountId, userName); final listDetailedEmails = await getAllDetailedEmails(accountId, userName);
if (listDetailedEmails.length >= CachingConstants.maxNumberOpenedEmailsForOffline) { if (listDetailedEmails.length >= CachingConstants.maxNumberOpenedEmailsForOffline) {
final latestEmail = listDetailedEmails.last; final lastElementsListEmail = listDetailedEmails.sublist(CachingConstants.maxNumberOpenedEmailsForOffline, listDetailedEmails.length);
log('OpenedEmailCacheManager::handleStoreDetailedEmail():latestEmail: $latestEmail'); for (var email in lastElementsListEmail) {
await removeDetailedEmail(accountId, userName, latestEmail.emailId); log('OpenedEmailCacheManager::handleStoreDetailedEmail():latestEmail: $email');
if (email.emailContentPath != null) {
await _deleteFileExisted(email.emailContentPath!);
}
await removeDetailedEmail(accountId, userName, email.emailId);
}
} }
await insertDetailedEmail(accountId, userName, detailedEmail.toHiveCache()); await insertDetailedEmail(accountId, userName, detailedEmail.toHiveCache());
} }
Future<bool> isOpenedDetailEmailCached( Future<bool> isOpenedDetailEmailCached(
AccountId accountId, AccountId accountId,
UserName userName, UserName userName,
DetailedEmail detailedEmail EmailId emailId
) async { ) async {
final emailContentPathExists = await _isFileExisted(detailedEmail); final emailContentPathExists = await _isFileExisted(emailId);
final detailedEmailCacheExists = await getDetailEmailExistedInCache(accountId, userName, detailedEmail.emailId); final detailedEmailCacheExists = await getDetailEmailExistedInCache(accountId, userName, emailId);
return emailContentPathExists == true && detailedEmailCacheExists != null; return emailContentPathExists == true && detailedEmailCacheExists != null;
} }
Future<bool?> _isFileExisted(DetailedEmail detailedEmail) async { Future<bool?> _isFileExisted(EmailId emailId) async {
final fileSaved = await _fileUtils.isFileExisted( final fileSaved = await _fileUtils.isFileExisted(
nameFile: detailedEmail.emailId.asString, nameFile: emailId.asString,
folderPath: detailedEmail.folderPath, folderPath: CachingConstants.openedEmailContentFolderNamee,
); );
log('OpenedEmailCacheManager::_getDetailedEmailCache():_getEmailContentPath: $fileSaved'); log('OpenedEmailCacheManager::_getDetailedEmailCache():_getEmailContentPath: $fileSaved');
return fileSaved; return fileSaved;
@@ -93,4 +98,7 @@ class OpenedEmailCacheManager {
return detailedEmailCache; return detailedEmailCache;
} }
Future<void> _deleteFileExisted(String pathFile) async {
await _fileUtils.deleteFile(pathFile);
}
} }
+1 -1
View File
@@ -73,7 +73,7 @@ class LocalBindings extends Bindings {
Get.put(FCMCacheManager(Get.find<FcmCacheClient>(),Get.find<FCMSubscriptionCacheClient>())); Get.put(FCMCacheManager(Get.find<FcmCacheClient>(),Get.find<FCMSubscriptionCacheClient>()));
Get.put(HiveCacheVersionClient(Get.find<SharedPreferences>(), Get.find<CacheExceptionThrower>())); Get.put(HiveCacheVersionClient(Get.find<SharedPreferences>(), Get.find<CacheExceptionThrower>()));
Get.put(DetailedEmailHiveCacheClient()); Get.put(DetailedEmailHiveCacheClient());
Get.put(DetailedEmailCacheManager(Get.find<DetailedEmailHiveCacheClient>())); Get.put(DetailedEmailCacheManager(Get.find<DetailedEmailHiveCacheClient>(), Get.find<FileUtils>()));
Get.put(OpenedEmailHiveCacheClient()); Get.put(OpenedEmailHiveCacheClient());
Get.put(OpenedEmailCacheManager(Get.find<OpenedEmailHiveCacheClient>(), Get.find<FileUtils>())); Get.put(OpenedEmailCacheManager(Get.find<OpenedEmailHiveCacheClient>(), Get.find<FileUtils>()));
Get.put(CachingManager( Get.put(CachingManager(