diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 568b0bb9b..455159a5a 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -134,6 +134,7 @@ class MailboxController extends BaseMailboxController WebSocketQueueHandler? _webSocketQueueHandler; final _openMailboxEventController = StreamController(); + StreamSubscription? _openMailboxEventStreamSubscription; final mailboxListScrollController = ScrollController(); PresentationMailbox? get selectedMailbox => mailboxDashBoardController.selectedMailbox.value; @@ -177,10 +178,13 @@ class MailboxController extends BaseMailboxController @override void onReady() { - _openMailboxEventController.stream.debounceTime(const Duration(milliseconds: 500)).listen((event) { - if (!event.buildContext.mounted) return; - _handleOpenMailbox(event.buildContext, event.presentationMailbox); - }); + _openMailboxEventStreamSubscription = _openMailboxEventController + .stream + .debounceTime(const Duration(milliseconds: 500)) + .listen((event) { + if (!event.buildContext.mounted) return; + _handleOpenMailbox(event.buildContext, event.presentationMailbox); + }); _initCollapseMailboxCategories(); mailboxListScrollController.addListener(_mailboxListScrollControllerListener); super.onReady(); @@ -188,6 +192,8 @@ class MailboxController extends BaseMailboxController @override void onClose() { + _openMailboxEventStreamSubscription?.cancel(); + _openMailboxEventStreamSubscription = null; _openMailboxEventController.close(); mailboxListScrollController.dispose(); _webSocketQueueHandler?.dispose(); diff --git a/lib/features/thread/data/repository/thread_repository_impl.dart b/lib/features/thread/data/repository/thread_repository_impl.dart index d142a798f..f85eec412 100644 --- a/lib/features/thread/data/repository/thread_repository_impl.dart +++ b/lib/features/thread/data/repository/thread_repository_impl.dart @@ -314,12 +314,14 @@ class ThreadRepositoryImpl extends ThreadRepository { @override Stream loadMoreEmails(GetEmailRequest emailRequest) async* { final response = await _getAllEmailsWithoutLastEmailId(emailRequest); - await _updateEmailCache( - emailRequest.accountId, - emailRequest.session.username, - newCreated: response.emailList, - newDestroyed: response.notFoundEmailIds, - ); + if (emailRequest.useCache) { + await _updateEmailCache( + emailRequest.accountId, + emailRequest.session.username, + newCreated: response.emailList, + newDestroyed: response.notFoundEmailIds, + ); + } yield response; } @@ -498,4 +500,27 @@ class ThreadRepositoryImpl extends ThreadRepository { accountId, session, ); + + @override + Stream loadAllEmailInFolderWithoutCache({ + required Session session, + required AccountId accountId, + UnsignedInt? limit, + int? position, + Set? sort, + EmailFilter? emailFilter, + Properties? propertiesCreated, + }) async* { + final networkDataSource = mapDataSource[DataSourceType.network]!; + final emailResponse = await networkDataSource.getAllEmail( + session, + accountId, + limit: limit, + position: position, + sort: sort, + filter: emailFilter?.filter, + properties: propertiesCreated, + ); + yield emailResponse; + } } \ No newline at end of file diff --git a/lib/features/thread/domain/model/get_email_request.dart b/lib/features/thread/domain/model/get_email_request.dart index 429fa7b18..29e26bbd0 100644 --- a/lib/features/thread/domain/model/get_email_request.dart +++ b/lib/features/thread/domain/model/get_email_request.dart @@ -18,6 +18,7 @@ class GetEmailRequest with EquatableMixin { final FilterMessageOption? filterOption; final Properties? properties; final EmailId? lastEmailId; + final bool useCache; GetEmailRequest( this.session, @@ -30,6 +31,7 @@ class GetEmailRequest with EquatableMixin { this.filterOption, this.properties, this.lastEmailId, + this.useCache = true, } ); @@ -43,6 +45,7 @@ class GetEmailRequest with EquatableMixin { filter, properties, lastEmailId, - filterOption + filterOption, + useCache, ]; } \ No newline at end of file diff --git a/lib/features/thread/domain/repository/thread_repository.dart b/lib/features/thread/domain/repository/thread_repository.dart index 4303abd02..686b46c0a 100644 --- a/lib/features/thread/domain/repository/thread_repository.dart +++ b/lib/features/thread/domain/repository/thread_repository.dart @@ -24,6 +24,7 @@ abstract class ThreadRepository { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, EmailFilter? emailFilter, Properties? propertiesCreated, @@ -32,6 +33,16 @@ abstract class ThreadRepository { } ); + Stream loadAllEmailInFolderWithoutCache({ + required Session session, + required AccountId accountId, + UnsignedInt? limit, + int? position, + Set? sort, + EmailFilter? emailFilter, + Properties? propertiesCreated, + }); + Stream refreshChanges( Session session, AccountId accountId, diff --git a/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart b/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart index 0eccaae50..d052fe04a 100644 --- a/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart +++ b/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart @@ -27,13 +27,14 @@ class GetEmailsInMailboxInteractor { Properties? propertiesCreated, Properties? propertiesUpdated, bool getLatestChanges = true, + bool useCache = true, } ) async* { try { yield Right(GetAllEmailLoading()); - yield* threadRepository - .getAllEmail( + if (useCache) { + yield* threadRepository.getAllEmail( session, accountId, limit: limit, @@ -41,11 +42,24 @@ class GetEmailsInMailboxInteractor { emailFilter: emailFilter, propertiesCreated: propertiesCreated, propertiesUpdated: propertiesUpdated, - getLatestChanges: getLatestChanges) - .map((emailResponse) => _toGetEmailState( + getLatestChanges: getLatestChanges, + ).map((emailResponse) => _toGetEmailState( emailResponse: emailResponse, - currentMailboxId: emailFilter?.mailboxId + currentMailboxId: emailFilter?.mailboxId, )); + } else { + yield* threadRepository.loadAllEmailInFolderWithoutCache( + session: session, + accountId: accountId, + limit: limit, + sort: sort, + emailFilter: emailFilter, + propertiesCreated: propertiesCreated, + ).map((emailResponse) => _toGetEmailState( + emailResponse: emailResponse, + currentMailboxId: emailFilter?.mailboxId, + )); + } } catch (e) { yield Left(GetAllEmailFailure(e)); } diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 5f5581f89..24ecd0c0e 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -9,6 +9,7 @@ import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/filter/filter.dart' show Filter; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; @@ -165,7 +166,6 @@ class ThreadController extends BaseController with EmailActionController { @override void handleSuccessViewState(Success success) { - super.handleSuccessViewState(success); if (success is GetAllEmailSuccess) { _getAllEmailSuccess(success); } else if (success is LoadMoreEmailsSuccess) { @@ -192,12 +192,13 @@ class ThreadController extends BaseController with EmailActionController { _openEmailWithoutMailboxFromLocationBar(success.email); } } + } else { + super.handleSuccessViewState(success); } } @override void handleFailureViewState(Failure failure) { - super.handleFailureViewState(failure); if (failure is SearchEmailFailure) { mailboxDashBoardController.updateRefreshAllEmailState(Left(RefreshAllEmailFailure())); canSearchMore = false; @@ -215,6 +216,8 @@ class ThreadController extends BaseController with EmailActionController { } else if (failure is GetAllEmailFailure || failure is CleanAndGetAllEmailFailure) { mailboxDashBoardController.updateRefreshAllEmailState(Left(RefreshAllEmailFailure())); canLoadMore = true; + } else { + super.handleFailureViewState(failure); } } @@ -503,7 +506,8 @@ class ThreadController extends BaseController with EmailActionController { void _getAllEmailSuccess(GetAllEmailSuccess success) { mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess())); - if (success.currentMailboxId != selectedMailboxId) { + if (success.currentMailboxId != selectedMailboxId && + selectedMailboxId?.isNotFavoriteMailboxId == true) { log('ThreadController::_getAllEmailSuccess: GetAllForMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}'); return; } @@ -543,7 +547,8 @@ class ThreadController extends BaseController with EmailActionController { } void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) { - if (success.currentMailboxId != selectedMailboxId) { + if (success.currentMailboxId != selectedMailboxId && + selectedMailboxId?.isNotFavoriteMailboxId == true) { log('ThreadController::_refreshChangesAllEmailSuccess: RefreshedMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}'); return; } @@ -579,23 +584,49 @@ class ThreadController extends BaseController with EmailActionController { _accountId!, limit: ThreadConstants.defaultLimit, sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), - emailFilter: EmailFilter( - filter: getFilterCondition(mailboxIdSelected: selectedMailboxId), - filterOption: mailboxDashBoardController.filterMessageOption.value, - mailboxId: selectedMailboxId - ), + emailFilter: _getEmailFilterForLoadMailbox(), propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), propertiesUpdated: EmailUtils.getPropertiesForEmailChangeMethod( _session!, _accountId!, ), getLatestChanges: getLatestChanges, + useCache: selectedMailboxId?.isNotFavoriteMailboxId == true, )); } else { consumeState(Stream.value(Left(GetAllEmailFailure(NotFoundSessionException())))); } } + EmailFilter _getEmailFilterForLoadMailbox({PresentationEmail? oldestEmail}) { + if (selectedMailboxId?.isNotFavoriteMailboxId != true) { + return EmailFilter( + filter: _getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), + filterOption: mailboxDashBoardController.filterMessageOption.value, + ); + } else { + return EmailFilter( + filter: _getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), + filterOption: mailboxDashBoardController.filterMessageOption.value, + mailboxId: selectedMailboxId, + ); + } + } + + Filter _getFilterConditionForLoadMailbox({PresentationEmail? oldestEmail}) { + if (selectedMailboxId?.isNotFavoriteMailboxId != true) { + return EmailFilterCondition( + hasKeyword: KeyWordIdentifier.emailFlagged.value, + before: oldestEmail?.receivedAt, + ); + } else { + return getFilterCondition( + mailboxIdSelected: selectedMailboxId, + oldestEmail: oldestEmail, + ); + } + } + EmailFilterCondition getFilterCondition({PresentationEmail? oldestEmail, MailboxId? mailboxIdSelected}) { switch(mailboxDashBoardController.filterMessageOption.value) { case FilterMessageOption.all: @@ -741,11 +772,7 @@ class ThreadController extends BaseController with EmailActionController { _session!, _accountId!, ), - emailFilter: EmailFilter( - filter: getFilterCondition(mailboxIdSelected: selectedMailboxId), - filterOption: mailboxDashBoardController.filterMessageOption.value, - mailboxId: selectedMailboxId, - ), + emailFilter: _getEmailFilterForLoadMailbox(), ).last; refreshState.fold( @@ -788,16 +815,17 @@ class ThreadController extends BaseController with EmailActionController { limit: ThreadConstants.defaultLimit, sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), filterOption: mailboxDashBoardController.filterMessageOption.value, - filter: getFilterCondition(oldestEmail: oldestEmail, mailboxIdSelected: selectedMailboxId), + filter: _getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), - lastEmailId: oldestEmail?.id + lastEmailId: oldestEmail?.id, + useCache: selectedMailboxId?.isNotFavoriteMailboxId == true, ) )); } } bool _validatePresentationEmail(PresentationEmail email) { - return _belongToCurrentMailboxId(email) + return (_belongToCurrentMailboxId(email) || selectedMailboxId?.isNotFavoriteMailboxId != true) && _notDuplicatedInCurrentList(email); } diff --git a/model/lib/extensions/mailbox_id_extension.dart b/model/lib/extensions/mailbox_id_extension.dart index 0b701caf5..d9924a98e 100644 --- a/model/lib/extensions/mailbox_id_extension.dart +++ b/model/lib/extensions/mailbox_id_extension.dart @@ -3,6 +3,7 @@ import 'package:jmap_dart_client/jmap/core/reference_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/extensions/keyword_identifier_extension.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; extension MailboxIdExtension on MailboxId { String generatePath() { @@ -31,4 +32,7 @@ extension MailboxIdExtension on MailboxId { } String get asString => id.value; + + bool get isNotFavoriteMailboxId => + this != PresentationMailbox.favoriteFolder.id; } \ No newline at end of file