TF-1809: Handle sync data from cache and network when get email contents
(cherry picked from commit 896059cd5b29c62c2cf34621fe35d7b23a54acf4)
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
+2
-2
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user