From eb51e9b3b1417593e27c80a8dfdd8beec2fac6bf Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 19 Dec 2024 00:50:13 +0700 Subject: [PATCH] TF-3334 Remove `Email/get` of mark as read & mark as star action --- .../data/datasource/email_datasource.dart | 13 +- .../email_datasource_impl.dart | 24 ++- .../email_hive_cache_datasource_impl.dart | 9 +- .../email/data/network/email_api.dart | 107 +++++----- .../repository/email_repository_impl.dart | 26 ++- .../email/domain/model/event_action.dart | 26 +++ .../domain/repository/email_repository.dart | 13 +- .../state/mark_as_email_read_state.dart | 6 +- .../state/mark_as_email_star_state.dart | 7 +- .../store_event_attendance_status_state.dart | 4 - .../mark_as_email_read_interactor.dart | 39 ++-- .../mark_as_star_email_interactor.dart | 30 +-- ...re_event_attendance_status_interactor.dart | 3 +- .../controller/single_email_controller.dart | 198 +++++++++--------- .../data/datasource/mailbox_datasource.dart | 2 +- .../mailbox_cache_datasource_impl.dart | 2 +- .../mailbox_datasource_impl.dart | 2 +- .../data/network/mailbox_isolate_worker.dart | 36 ++-- .../repository/mailbox_repository_impl.dart | 2 +- .../domain/repository/mailbox_repository.dart | 2 +- .../mailbox_dashboard_controller.dart | 137 ++++++------ ...ark_as_multiple_email_read_interactor.dart | 21 +- ...ark_as_star_multiple_email_interactor.dart | 19 +- .../mixin/email_action_controller.dart | 12 +- .../presentation_email_extension.dart | 7 +- ...ent_attendance_status_interactor_test.dart | 1 - .../controller/thread_controller_test.dart | 16 +- 27 files changed, 419 insertions(+), 345 deletions(-) diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index 2cfa7a9b4..4248f413e 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -43,7 +43,12 @@ abstract class EmailDataSource { } ); - Future> markAsRead(Session session, AccountId accountId, List emails, ReadActions readActions); + Future> markAsRead( + Session session, + AccountId accountId, + List emailIds, + ReadActions readActions, + ); Future> downloadAttachments( List attachments, @@ -72,10 +77,10 @@ abstract class EmailDataSource { Future> moveToMailbox(Session session, AccountId accountId, MoveToMailboxRequest moveRequest); - Future> markAsStar( + Future> markAsStar( Session session, AccountId accountId, - List emails, + List emailIds, MarkStarAction markStarAction ); @@ -144,7 +149,7 @@ abstract class EmailDataSource { Future getRestoredDeletedMessage(EmailRecoveryActionId emailRecoveryActionId); - Future storeEventAttendanceStatus( + Future storeEventAttendanceStatus( Session session, AccountId accountId, EmailId emailId, diff --git a/lib/features/email/data/datasource_impl/email_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_datasource_impl.dart index c64e3ea66..c1b150c67 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -75,14 +75,14 @@ class EmailDataSourceImpl extends EmailDataSource { } @override - Future> markAsRead( + Future> markAsRead( Session session, AccountId accountId, - List emails, - ReadActions readActions + List emailIds, + ReadActions readActions, ) { return Future.sync(() async { - return await emailAPI.markAsRead(session, accountId, emails, readActions); + return await emailAPI.markAsRead(session, accountId, emailIds, readActions); }).catchError(_exceptionThrower.throwException); } @@ -119,9 +119,19 @@ class EmailDataSourceImpl extends EmailDataSource { } @override - Future> markAsStar(Session session, AccountId accountId, List emails, MarkStarAction markStarAction) { + Future> markAsStar( + Session session, + AccountId accountId, + List emailIds, + MarkStarAction markStarAction, + ) { return Future.sync(() async { - return await emailAPI.markAsStar(session, accountId, emails, markStarAction); + return await emailAPI.markAsStar( + session, + accountId, + emailIds, + markStarAction, + ); }).catchError(_exceptionThrower.throwException); } @@ -318,7 +328,7 @@ class EmailDataSourceImpl extends EmailDataSource { } @override - Future storeEventAttendanceStatus( + Future storeEventAttendanceStatus( Session session, AccountId accountId, EmailId emailId, diff --git a/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart index e866992c1..accf354e5 100644 --- a/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart @@ -120,12 +120,17 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { } @override - Future> markAsRead(Session session, AccountId accountId, List emails, ReadActions readActions) { + Future> markAsRead( + Session session, + AccountId accountId, + List emailIds, + ReadActions readActions, + ) { throw UnimplementedError(); } @override - Future> markAsStar(Session session, AccountId accountId, List emails, MarkStarAction markStarAction) { + Future> markAsStar(Session session, AccountId accountId, List emailIds, MarkStarAction markStarAction) { throw UnimplementedError(); } diff --git a/lib/features/email/data/network/email_api.dart b/lib/features/email/data/network/email_api.dart index 4ff128005..f93ff0246 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -44,13 +44,11 @@ import 'package:model/account/authentication_type.dart'; import 'package:model/download/download_task_id.dart'; import 'package:model/email/attachment.dart'; import 'package:model/email/email_action_type.dart'; -import 'package:model/email/email_property.dart'; import 'package:model/email/mark_star_action.dart'; import 'package:model/email/read_actions.dart'; import 'package:model/extensions/email_extension.dart'; import 'package:model/extensions/email_id_extensions.dart'; import 'package:model/extensions/keyword_identifier_extension.dart'; -import 'package:model/extensions/list_email_extension.dart'; import 'package:model/extensions/list_email_id_extension.dart'; import 'package:model/extensions/mailbox_id_extension.dart'; import 'package:model/extensions/session_extension.dart'; @@ -239,24 +237,18 @@ class EmailAPI with HandleSetErrorMixin { } } - Future> markAsRead( + Future> markAsRead( Session session, AccountId accountId, - List emails, - ReadActions readActions + List emailIds, + ReadActions readActions, ) async { final setEmailMethod = SetEmailMethod(accountId) - ..addUpdates(emails.listEmailIds.generateMapUpdateObjectMarkAsRead(readActions)); - - final getEmailMethod = GetEmailMethod(accountId) - ..addIds(emails.listEmailIds.toIds().toSet()) - ..addProperties(Properties({EmailProperty.keywords})); + ..addUpdates(emailIds.generateMapUpdateObjectMarkAsRead(readActions)); final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); - requestBuilder.invocation(setEmailMethod); - - final getEmailInvocation = requestBuilder.invocation(getEmailMethod); + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); final capabilities = setEmailMethod.requiredCapabilities .toCapabilitiesSupportTeamMailboxes(session, accountId); @@ -266,15 +258,22 @@ class EmailAPI with HandleSetErrorMixin { .build() .execute(); - final getEmailResponse = response.parse( - getEmailInvocation.methodCallId, - GetEmailResponse.deserialize); + final setEmailResponse = response.parse( + setEmailInvocation.methodCallId, + SetEmailResponse.deserialize, + ); - return Future.sync(() async { - return getEmailResponse!.list; - }).catchError((error) { - throw error; - }); + final emailIdUpdated = setEmailResponse?.updated + ?.keys + .map((id) => EmailId(id)) + .toList() ?? []; + final mapErrors = handleSetResponse([setEmailResponse]); + + if (emailIdUpdated.isNotEmpty) { + return emailIdUpdated; + } else { + throw SetMethodException(mapErrors); + } } Future> downloadAttachments( @@ -449,24 +448,18 @@ class EmailAPI with HandleSetErrorMixin { return listEmailIdRequest.where((emailId) => listUpdated.expand((e) => e).toList().contains(emailId.id)).toList(); } - Future> markAsStar( + Future> markAsStar( Session session, AccountId accountId, - List emails, + List emailIds, MarkStarAction markStarAction ) async { final setEmailMethod = SetEmailMethod(accountId) - ..addUpdates(emails.listEmailIds.generateMapUpdateObjectMarkAsStar(markStarAction)); - - final getEmailMethod = GetEmailMethod(accountId) - ..addIds(emails.listEmailIds.toIds().toSet()) - ..addProperties(Properties({EmailProperty.keywords})); + ..addUpdates(emailIds.generateMapUpdateObjectMarkAsStar(markStarAction)); final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); - requestBuilder.invocation(setEmailMethod); - - final getEmailInvocation = requestBuilder.invocation(getEmailMethod); + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); final capabilities = setEmailMethod.requiredCapabilities .toCapabilitiesSupportTeamMailboxes(session, accountId); @@ -476,15 +469,22 @@ class EmailAPI with HandleSetErrorMixin { .build() .execute(); - final getEmailResponse = response.parse( - getEmailInvocation.methodCallId, - GetEmailResponse.deserialize); + final setEmailResponse = response.parse( + setEmailInvocation.methodCallId, + SetEmailResponse.deserialize, + ); - return Future.sync(() async { - return getEmailResponse!.list; - }).catchError((error) { - throw error; - }); + final emailIdUpdated = setEmailResponse?.updated + ?.keys + .map((id) => EmailId(id)) + .toList() ?? []; + final mapErrors = handleSetResponse([setEmailResponse]); + + if (emailIdUpdated.isNotEmpty) { + return emailIdUpdated; + } else { + throw SetMethodException(mapErrors); + } } Future saveEmailAsDrafts( @@ -756,7 +756,7 @@ class EmailAPI with HandleSetErrorMixin { } } - Future storeEventAttendanceStatus( + Future storeEventAttendanceStatus( Session session, AccountId accountId, EmailId emailId, @@ -765,15 +765,9 @@ class EmailAPI with HandleSetErrorMixin { final setEmailMethod = SetEmailMethod(accountId) ..addUpdates(emailId.generateMapUpdateObjectEventAttendanceStatus(eventActionType)); - final getEmailMethod = GetEmailMethod(accountId) - ..addIds({emailId.id}) - ..addProperties(Properties({EmailProperty.keywords})); - final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); - requestBuilder.invocation(setEmailMethod); - - final getEmailInvocation = requestBuilder.invocation(getEmailMethod); + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); final capabilities = setEmailMethod.requiredCapabilities .toCapabilitiesSupportTeamMailboxes(session, accountId); @@ -783,16 +777,19 @@ class EmailAPI with HandleSetErrorMixin { .build() .execute(); - final getEmailResponse = response.parse( - getEmailInvocation.methodCallId, - GetEmailResponse.deserialize); + final setEmailResponse = response.parse( + setEmailInvocation.methodCallId, + SetEmailResponse.deserialize, + ); - final listEmails = getEmailResponse?.list ?? []; + final emailIdUpdated = setEmailResponse?.updated + ?.keys + .map((id) => EmailId(id)) + .toList() ?? []; + final mapErrors = handleSetResponse([setEmailResponse]); - if (listEmails.isNotEmpty) { - return listEmails.first; - } else { - throw NotFoundEmailException(); + if (emailIdUpdated.isEmpty) { + throw SetMethodException(mapErrors); } } } \ No newline at end of file diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index 57860f7ef..cbc7f5201 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -83,13 +83,18 @@ class EmailRepositoryImpl extends EmailRepository { } @override - Future> markAsRead( + Future> markAsRead( Session session, AccountId accountId, - List emails, - ReadActions readActions + List emailIds, + ReadActions readActions, ) { - return emailDataSource[DataSourceType.network]!.markAsRead(session, accountId, emails, readActions); + return emailDataSource[DataSourceType.network]!.markAsRead( + session, + accountId, + emailIds, + readActions, + ); } @override @@ -124,13 +129,18 @@ class EmailRepositoryImpl extends EmailRepository { } @override - Future> markAsStar( + Future> markAsStar( Session session, AccountId accountId, - List emails, + List emailIds, MarkStarAction markStarAction ) { - return emailDataSource[DataSourceType.network]!.markAsStar(session, accountId, emails, markStarAction); + return emailDataSource[DataSourceType.network]!.markAsStar( + session, + accountId, + emailIds, + markStarAction, + ); } @override @@ -303,7 +313,7 @@ class EmailRepositoryImpl extends EmailRepository { } @override - Future storeEventAttendanceStatus( + Future storeEventAttendanceStatus( Session session, AccountId accountId, EmailId emailId, diff --git a/lib/features/email/domain/model/event_action.dart b/lib/features/email/domain/model/event_action.dart index a14a5ebdb..098ba6b33 100644 --- a/lib/features/email/domain/model/event_action.dart +++ b/lib/features/email/domain/model/event_action.dart @@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/cupertino.dart'; import 'package:jmap_dart_client/jmap/core/patch_object.dart'; +import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:model/extensions/keyword_identifier_extension.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -61,6 +62,31 @@ enum EventActionType { return ''; } } + + Map getMapKeywords() { + switch(this) { + case EventActionType.yes: + return { + KeyWordIdentifierExtension.acceptedEventAttendance: true, + KeyWordIdentifierExtension.tentativelyAcceptedEventAttendance: false, + KeyWordIdentifierExtension.rejectedEventAttendance: false, + }; + case EventActionType.maybe: + return { + KeyWordIdentifierExtension.acceptedEventAttendance: false, + KeyWordIdentifierExtension.tentativelyAcceptedEventAttendance: true, + KeyWordIdentifierExtension.rejectedEventAttendance: false, + }; + case EventActionType.no: + return { + KeyWordIdentifierExtension.acceptedEventAttendance: false, + KeyWordIdentifierExtension.tentativelyAcceptedEventAttendance: false, + KeyWordIdentifierExtension.rejectedEventAttendance: true, + }; + case EventActionType.mailToAttendees: + return {}; + } + } } class EventAction with EquatableMixin { diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 88ae516c2..5e62b863e 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -45,7 +45,12 @@ abstract class EmailRepository { } ); - Future> markAsRead(Session session, AccountId accountId, List emails, ReadActions readActions); + Future> markAsRead( + Session session, + AccountId accountId, + List emailIds, + ReadActions readActions, + ); Future> downloadAttachments( List attachments, @@ -74,10 +79,10 @@ abstract class EmailRepository { Future> moveToMailbox(Session session, AccountId accountId, MoveToMailboxRequest moveRequest); - Future> markAsStar( + Future> markAsStar( Session session, AccountId accountId, - List emails, + List emailIds, MarkStarAction markStarAction ); @@ -147,7 +152,7 @@ abstract class EmailRepository { Future printEmail(EmailPrint emailPrint); - Future storeEventAttendanceStatus( + Future storeEventAttendanceStatus( Session session, AccountId accountId, EmailId emailId, diff --git a/lib/features/email/domain/state/mark_as_email_read_state.dart b/lib/features/email/domain/state/mark_as_email_read_state.dart index 28e48586c..2e7ddbd68 100644 --- a/lib/features/email/domain/state/mark_as_email_read_state.dart +++ b/lib/features/email/domain/state/mark_as_email_read_state.dart @@ -7,12 +7,12 @@ import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart'; class MarkAsEmailReadSuccess extends UIActionState { - final Email updatedEmail; + final EmailId emailId; final ReadActions readActions; final MarkReadAction markReadAction; MarkAsEmailReadSuccess( - this.updatedEmail, + this.emailId, this.readActions, this.markReadAction, { @@ -22,7 +22,7 @@ class MarkAsEmailReadSuccess extends UIActionState { ) : super(currentEmailState, currentMailboxState); @override - List get props => [updatedEmail, readActions, markReadAction, ...super.props]; + List get props => [emailId, readActions, markReadAction, ...super.props]; } class MarkAsEmailReadFailure extends FeatureFailure { diff --git a/lib/features/email/domain/state/mark_as_email_star_state.dart b/lib/features/email/domain/state/mark_as_email_star_state.dart index dbe215734..c9d639e72 100644 --- a/lib/features/email/domain/state/mark_as_email_star_state.dart +++ b/lib/features/email/domain/state/mark_as_email_star_state.dart @@ -1,15 +1,12 @@ import 'package:core/presentation/state/failure.dart'; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; -import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:model/model.dart'; +import 'package:model/email/mark_star_action.dart'; import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; class MarkAsStarEmailSuccess extends UIActionState { - final Email updatedEmail; final MarkStarAction markStarAction; MarkAsStarEmailSuccess( - this.updatedEmail, this.markStarAction, { jmap.State? currentEmailState, @@ -18,7 +15,7 @@ class MarkAsStarEmailSuccess extends UIActionState { ) : super(currentEmailState, currentMailboxState); @override - List get props => [updatedEmail, markStarAction, ...super.props]; + List get props => [markStarAction, ...super.props]; } class MarkAsStarEmailFailure extends FeatureFailure { diff --git a/lib/features/email/domain/state/store_event_attendance_status_state.dart b/lib/features/email/domain/state/store_event_attendance_status_state.dart index 942e6accb..1325cf81b 100644 --- a/lib/features/email/domain/state/store_event_attendance_status_state.dart +++ b/lib/features/email/domain/state/store_event_attendance_status_state.dart @@ -1,7 +1,6 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; -import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; @@ -10,11 +9,9 @@ class StoreEventAttendanceStatusLoading extends LoadingState {} class StoreEventAttendanceStatusSuccess extends UIActionState { final EventActionType eventActionType; - final Email updatedEmail; StoreEventAttendanceStatusSuccess( this.eventActionType, - this.updatedEmail, { jmap.State? currentEmailState, jmap.State? currentMailboxState, @@ -24,7 +21,6 @@ class StoreEventAttendanceStatusSuccess extends UIActionState { @override List get props => [ eventActionType, - updatedEmail, ...super.props]; } diff --git a/lib/features/email/domain/usecases/mark_as_email_read_interactor.dart b/lib/features/email/domain/usecases/mark_as_email_read_interactor.dart index 435f6064c..7fe15acbb 100644 --- a/lib/features/email/domain/usecases/mark_as_email_read_interactor.dart +++ b/lib/features/email/domain/usecases/mark_as_email_read_interactor.dart @@ -1,9 +1,10 @@ -import 'package:core/core.dart'; +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:model/model.dart'; +import 'package:model/email/read_actions.dart'; import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart'; @@ -15,7 +16,13 @@ class MarkAsEmailReadInteractor { MarkAsEmailReadInteractor(this._emailRepository, this._mailboxRepository); - Stream> execute(Session session, AccountId accountId, Email email, ReadActions readAction, MarkReadAction markReadAction) async* { + Stream> execute( + Session session, + AccountId accountId, + EmailId emailId, + ReadActions readAction, + MarkReadAction markReadAction, + ) async* { try { final listState = await Future.wait([ _mailboxRepository.getMailboxState( session,accountId), @@ -25,18 +32,20 @@ class MarkAsEmailReadInteractor { final currentMailboxState = listState.first; final currentEmailState = listState.last; - final result = await _emailRepository.markAsRead(session, accountId, [email], readAction); - if (result.isNotEmpty) { - final updatedEmail = email.updatedEmail(newKeywords: result.first.keywords); - yield Right(MarkAsEmailReadSuccess( - updatedEmail, - readAction, - markReadAction, - currentEmailState: currentEmailState, - currentMailboxState: currentMailboxState)); - } else { - yield Left(MarkAsEmailReadFailure(readAction)); - } + final result = await _emailRepository.markAsRead( + session, + accountId, + [emailId], + readAction, + ); + + yield Right(MarkAsEmailReadSuccess( + result.first, + readAction, + markReadAction, + currentEmailState: currentEmailState, + currentMailboxState: currentMailboxState, + )); } catch (e) { yield Left(MarkAsEmailReadFailure(readAction, exception: e)); } diff --git a/lib/features/email/domain/usecases/mark_as_star_email_interactor.dart b/lib/features/email/domain/usecases/mark_as_star_email_interactor.dart index df89ea182..6ca420eb7 100644 --- a/lib/features/email/domain/usecases/mark_as_star_email_interactor.dart +++ b/lib/features/email/domain/usecases/mark_as_star_email_interactor.dart @@ -1,4 +1,5 @@ -import 'package:core/core.dart'; +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'; @@ -12,19 +13,24 @@ class MarkAsStarEmailInteractor { MarkAsStarEmailInteractor(this.emailRepository); - Stream> execute(Session session, AccountId accountId, Email email, MarkStarAction markStarAction) async* { + Stream> execute( + Session session, + AccountId accountId, + EmailId emailId, + MarkStarAction markStarAction, + ) async* { try { final currentEmailState = await emailRepository.getEmailState(session, accountId); - final result = await emailRepository.markAsStar(session, accountId, [email], markStarAction); - if (result.isNotEmpty) { - final updatedEmail = email.updatedEmail(newKeywords: result.first.keywords); - yield Right(MarkAsStarEmailSuccess( - updatedEmail, - markStarAction, - currentEmailState: currentEmailState)); - } else { - yield Left(MarkAsStarEmailFailure(markStarAction)); - } + await emailRepository.markAsStar( + session, + accountId, + [emailId], + markStarAction, + ); + yield Right(MarkAsStarEmailSuccess( + markStarAction, + currentEmailState: currentEmailState, + )); } catch (e) { yield Left(MarkAsStarEmailFailure(markStarAction, exception: e)); } diff --git a/lib/features/email/domain/usecases/store_event_attendance_status_interactor.dart b/lib/features/email/domain/usecases/store_event_attendance_status_interactor.dart index d2abe8422..d524691aa 100644 --- a/lib/features/email/domain/usecases/store_event_attendance_status_interactor.dart +++ b/lib/features/email/domain/usecases/store_event_attendance_status_interactor.dart @@ -24,7 +24,7 @@ class StoreEventAttendanceStatusInteractor { final currentEmailState = await _emailRepository.getEmailState(session, accountId); - final updatedEmail = await _emailRepository.storeEventAttendanceStatus( + await _emailRepository.storeEventAttendanceStatus( session, accountId, emailId, @@ -32,7 +32,6 @@ class StoreEventAttendanceStatusInteractor { yield Right(StoreEventAttendanceStatusSuccess( eventActionType, - updatedEmail, currentEmailState: currentEmailState)); } catch (e) { yield Left(StoreEventAttendanceStatusFailure(exception: e)); diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 45449b497..8988f2df7 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -23,6 +23,7 @@ import 'package:jmap_dart_client/jmap/mail/calendar/properties/attendee/calendar import 'package:jmap_dart_client/jmap/mail/calendar/properties/calendar_organizer.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/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mdn/disposition.dart'; import 'package:jmap_dart_client/jmap/mdn/mdn.dart'; import 'package:model/email/eml_attachment.dart'; @@ -62,6 +63,7 @@ import 'package:tmail_ui_user/features/email/domain/state/send_receipt_to_sender import 'package:tmail_ui_user/features/email/domain/state/store_event_attendance_status_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_accept_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/maybe_calendar_event_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/calendar_event_reject_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart'; @@ -69,7 +71,6 @@ import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; -import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/parse_calendar_event_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart'; @@ -169,6 +170,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin { CalendarEvent? get calendarEvent => blobCalendarEvent.value?.calendarEventList.firstOrNull; Id? get _displayingEventBlobId => blobCalendarEvent.value?.blobId; + AccountId? get accountId => mailboxDashBoardController.accountId.value; + + Session? get session => mailboxDashBoardController.sessionCurrent; + SingleEmailController( this._getEmailContentInteractor, this._markAsEmailReadInteractor, @@ -206,7 +211,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } else if (success is GetEmailContentFromCacheSuccess) { _getEmailContentOfflineSuccess(success); } else if (success is MarkAsEmailReadSuccess) { - _markAsEmailReadSuccess(success); + _handleMarkAsEmailReadCompleted(success.readActions); } else if (success is ExportAttachmentSuccess) { _exportAttachmentSuccessAction(success); } else if (success is MoveToMailboxSuccess) { @@ -244,7 +249,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void handleFailureViewState(Failure failure) { super.handleFailureViewState(failure); if (failure is MarkAsEmailReadFailure) { - _markAsEmailReadFailure(failure); + _handleMarkAsEmailReadCompleted(failure.readActions); } else if (failure is DownloadAttachmentsFailure) { _downloadAttachmentsFailure(failure); } else if (failure is ExportAttachmentFailure) { @@ -267,7 +272,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ever(mailboxDashBoardController.accountId, (accountId) { if (accountId is AccountId) { _injectAndGetInteractorBindings( - mailboxDashBoardController.sessionCurrent, + session, accountId ); } @@ -421,10 +426,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _getAllIdentities() { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; if (accountId != null && session != null) { - consumeState(_getAllIdentitiesInteractor.execute(session, accountId)); + consumeState(_getAllIdentitiesInteractor.execute(session!, accountId!)); } } @@ -477,17 +480,15 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ) ))); } else { - final session = mailboxDashBoardController.sessionCurrent; - final accountId = mailboxDashBoardController.accountId.value; if (session != null && accountId != null) { - final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl) ?? ''; + final baseDownloadUrl = session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); TransformConfiguration transformConfiguration = PlatformInfo.isWeb ? TransformConfiguration.forPreviewEmailOnWeb() : TransformConfiguration.forPreviewEmail(); consumeState(_getEmailContentInteractor.execute( - session, - accountId, + session!, + accountId!, emailId, baseDownloadUrl, transformConfiguration @@ -585,8 +586,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ); _storeOpenedEmailAction( - mailboxDashBoardController.sessionCurrent, - mailboxDashBoardController.accountId.value, + session, + accountId, detailedEmail ); } @@ -647,27 +648,24 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } } - void markAsEmailRead(PresentationEmail presentationEmail, ReadActions readActions, MarkReadAction markReadAction) async { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; + void markAsEmailRead( + PresentationEmail presentationEmail, + ReadActions readActions, + MarkReadAction markReadAction, + ) { if (accountId != null && session != null) { - consumeState(_markAsEmailReadInteractor.execute(session, accountId, presentationEmail.toEmail(), readActions, markReadAction)); + consumeState(_markAsEmailReadInteractor.execute( + session!, + accountId!, + presentationEmail.id!, + readActions, + markReadAction, + )); } } - void _markAsEmailReadSuccess(Success success) { - log('SingleEmailController::_markAsEmailReadSuccess(): $success'); - mailboxDashBoardController.dispatchState(Right(success)); - - if (success is MarkAsEmailReadSuccess - && success.readActions == ReadActions.markAsUnread) { - closeEmailView(context: currentContext); - } - } - - void _markAsEmailReadFailure(Failure failure) { - if (failure is MarkAsEmailReadFailure - && failure.readActions == ReadActions.markAsUnread) { + void _handleMarkAsEmailReadCompleted(ReadActions readActions) { + if (readActions == ReadActions.markAsUnread) { closeEmailView(context: currentContext); } } @@ -711,11 +709,16 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } } - void _downloadAttachmentsAction(List attachments) async { - final accountId = mailboxDashBoardController.accountId.value; - if (accountId != null && mailboxDashBoardController.sessionCurrent != null) { - final baseDownloadUrl = mailboxDashBoardController.sessionCurrent!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); - consumeState(_downloadAttachmentsInteractor.execute(attachments, accountId, baseDownloadUrl)); + void _downloadAttachmentsAction(List attachments) { + if (accountId != null && session != null) { + final baseDownloadUrl = session!.getDownloadUrl( + jmapUrl: dynamicUrlInterceptors.jmapUrl, + ); + consumeState(_downloadAttachmentsInteractor.execute( + attachments, + accountId!, + baseDownloadUrl, + )); } } @@ -760,11 +763,17 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } } - void _exportAttachmentAction(Attachment attachment, CancelToken cancelToken) async { - final accountId = mailboxDashBoardController.accountId.value; - if (accountId != null && mailboxDashBoardController.sessionCurrent != null) { - final baseDownloadUrl = mailboxDashBoardController.sessionCurrent!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); - consumeState(_exportAttachmentInteractor.execute(attachment, accountId, baseDownloadUrl, cancelToken)); + void _exportAttachmentAction(Attachment attachment, CancelToken cancelToken) { + if (accountId != null && session != null) { + final baseDownloadUrl = session!.getDownloadUrl( + jmapUrl: dynamicUrlInterceptors.jmapUrl, + ); + consumeState(_exportAttachmentInteractor.execute( + attachment, + accountId!, + baseDownloadUrl, + cancelToken, + )); } } @@ -807,15 +816,15 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void downloadAttachmentForWeb(Attachment attachment) { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; if (accountId != null && session != null) { - final baseDownloadUrl = session.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); + final baseDownloadUrl = session!.getDownloadUrl( + jmapUrl: dynamicUrlInterceptors.jmapUrl, + ); final generateTaskId = DownloadTaskId(uuid.v4()); consumeState(_downloadAttachmentForWebInteractor.execute( generateTaskId, attachment, - accountId, + accountId!, baseDownloadUrl, _downloadProgressStateController)); } else { @@ -876,12 +885,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void moveToMailbox(BuildContext context, PresentationEmail email) async { final currentMailbox = getMailboxContain(email); - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; if (currentMailbox != null && accountId != null) { final arguments = DestinationPickerArguments( - accountId, + accountId!, MailboxActions.moveEmail, session, mailboxIdSelected: currentMailbox.mailboxId @@ -893,13 +900,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin { if (destinationMailbox != null && destinationMailbox is PresentationMailbox && - mailboxDashBoardController.sessionCurrent != null && + session != null && context.mounted ) { _dispatchMoveToAction( context, - accountId, - mailboxDashBoardController.sessionCurrent!, + accountId!, + session!, email, currentMailbox, destinationMailbox); @@ -978,24 +985,20 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _revertedToOriginalMailbox(MoveToMailboxRequest newMoveRequest) { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; if (accountId != null && session != null) { - _moveToMailbox(currentContext!, session, accountId, newMoveRequest); + _moveToMailbox(currentContext!, session!, accountId!, newMoveRequest); } } - void moveToTrash(BuildContext context, PresentationEmail email) async { - final session = mailboxDashBoardController.sessionCurrent; - final accountId = mailboxDashBoardController.accountId.value; + void moveToTrash(BuildContext context, PresentationEmail email) { final trashMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleTrash); final currentMailbox = getMailboxContain(email); if (session != null && accountId != null && currentMailbox != null && trashMailboxId != null) { _moveToTrashAction( context, - session, - accountId, + session!, + accountId!, MoveToMailboxRequest( {currentMailbox.id: [email.id!]}, trashMailboxId, @@ -1015,17 +1018,15 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mailboxDashBoardController.moveToMailbox(session, accountId, moveRequest); } - void moveToSpam(BuildContext context, PresentationEmail email) async { - final session = mailboxDashBoardController.sessionCurrent; - final accountId = mailboxDashBoardController.accountId.value; + void moveToSpam(BuildContext context, PresentationEmail email) { final spamMailboxId = mailboxDashBoardController.spamMailboxId; final currentMailbox = getMailboxContain(email); if (session != null && accountId != null && currentMailbox != null && spamMailboxId != null) { _moveToSpamAction( context, - session, - accountId, + session!, + accountId!, MoveToMailboxRequest( {currentMailbox.id: [email.id!]}, spamMailboxId, @@ -1035,17 +1036,15 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } } - void unSpam(BuildContext context, PresentationEmail email) async { - final session = mailboxDashBoardController.sessionCurrent; - final accountId = mailboxDashBoardController.accountId.value; + void unSpam(BuildContext context, PresentationEmail email) { final spamMailboxId = mailboxDashBoardController.spamMailboxId; final inboxMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleInbox); if (session != null && accountId != null && spamMailboxId != null && inboxMailboxId != null) { _moveToSpamAction( context, - session, - accountId, + session!, + accountId!, MoveToMailboxRequest( {spamMailboxId: [email.id!]}, inboxMailboxId, @@ -1065,18 +1064,25 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mailboxDashBoardController.moveToMailbox(session, accountId, moveRequest); } - void markAsStarEmail(PresentationEmail presentationEmail, MarkStarAction markStarAction) async { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; + void markAsStarEmail( + PresentationEmail presentationEmail, + MarkStarAction markStarAction, + ) { if (accountId != null && session != null) { - consumeState(_markAsStarEmailInteractor.execute(session, accountId, presentationEmail.toEmail(), markStarAction)); + consumeState(_markAsStarEmailInteractor.execute( + session!, + accountId!, + presentationEmail.id!, + markStarAction, + )); } } void _markAsEmailStarSuccess(MarkAsStarEmailSuccess success) { - final selectedEmail = mailboxDashBoardController.selectedEmail.value; - mailboxDashBoardController.setSelectedEmail(selectedEmail?.updateKeywords(success.updatedEmail.keywords)); - mailboxDashBoardController.dispatchState(Right(success)); + final newEmail = currentEmail?.updateKeywords({ + KeyWordIdentifier.emailFlagged: true, + }); + mailboxDashBoardController.setSelectedEmail(newEmail); } void handleEmailAction(BuildContext context, PresentationEmail presentationEmail, EmailActionType actionType) { @@ -1210,8 +1216,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _handleSendReceiptToSenderAction(BuildContext context) { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; if (accountId == null || session == null) { return; } @@ -1237,7 +1241,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { return; } - final receiverEmailAddress = _getReceiverEmailAddress(currentEmail!) ?? session.username.value; + final receiverEmailAddress = _getReceiverEmailAddress(currentEmail!) ?? session!.username.value; log('SingleEmailController::_handleSendReceiptToSenderAction():receiverEmailAddress: $receiverEmailAddress'); final mdnToSender = _generateMDN(context, currentEmail!, receiverEmailAddress); final sendReceiptRequest = SendReceiptToSenderRequest( @@ -1246,7 +1250,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { sendId: Id(uuid.v1())); log('SingleEmailController::_handleSendReceiptToSenderAction(): sendReceiptRequest: $sendReceiptRequest'); - consumeState(_sendReceiptToSenderInteractor!.execute(accountId, sendReceiptRequest)); + consumeState(_sendReceiptToSenderInteractor!.execute(accountId!, sendReceiptRequest)); } String? _getReceiverEmailAddress(PresentationEmail presentationEmail) { @@ -1395,12 +1399,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void quickCreatingRule(BuildContext context, EmailAddress emailAddress) async { popBack(); - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; if (accountId != null && session != null) { final arguments = RulesFilterCreatorArguments( - accountId, - session, + accountId!, + session!, emailAddress: emailAddress); final newRuleFilterRequest = PlatformInfo.isWeb @@ -1408,7 +1410,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { : await push(AppRoutes.rulesFilterCreator, arguments: arguments); if (newRuleFilterRequest is CreateNewEmailRuleFilterRequest) { - _createNewRuleFilterAction(accountId, newRuleFilterRequest); + _createNewRuleFilterAction(accountId!, newRuleFilterRequest); } } } @@ -1460,11 +1462,9 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } bool get _isCalendarEventSupported { - final accountId = mailboxDashBoardController.accountId.value; - final session = mailboxDashBoardController.sessionCurrent; return session != null && accountId != null && - CapabilityIdentifier.jamesCalendarEvent.isSupported(session, accountId); + CapabilityIdentifier.jamesCalendarEvent.isSupported(session!, accountId!); } @visibleForTesting @@ -1690,21 +1690,21 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void _acceptCalendarEventAction(EmailId emailId) { if (_acceptCalendarEventInteractor == null || _displayingEventBlobId == null - || mailboxDashBoardController.accountId.value == null - || mailboxDashBoardController.sessionCurrent == null - || mailboxDashBoardController.sessionCurrent - !.validateCalendarEventCapability(mailboxDashBoardController.accountId.value!) - .isAvailable == false + || accountId == null + || session == null + || session!.validateCalendarEventCapability(accountId!).isAvailable == false ) { consumeState(Stream.value(Left(CalendarEventAcceptFailure()))); } else { consumeState(_acceptCalendarEventInteractor!.execute( - mailboxDashBoardController.accountId.value!, + accountId!, {_displayingEventBlobId!}, emailId, - mailboxDashBoardController.sessionCurrent!.getLanguageForCalendarEvent( + session!.getLanguageForCalendarEvent( LocalizationService.getLocaleFromLanguage(), - mailboxDashBoardController.accountId.value!))); + accountId!, + ), + )); } } @@ -1768,10 +1768,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _showToastMessageEventAttendanceSuccess(StoreEventAttendanceStatusSuccess success) { - final selectedEmail = mailboxDashBoardController.selectedEmail.value; - final newEmail = selectedEmail?.updateKeywords(success.updatedEmail.keywords); + final newEmail = currentEmail?.updateKeywords( + success.eventActionType.getMapKeywords(), + ); mailboxDashBoardController.setSelectedEmail(newEmail); - mailboxDashBoardController.dispatchState(Right(success)); if (currentOverlayContext == null || currentContext == null) { return; diff --git a/lib/features/mailbox/data/datasource/mailbox_datasource.dart b/lib/features/mailbox/data/datasource/mailbox_datasource.dart index 4b9f30c7e..dc5238178 100644 --- a/lib/features/mailbox/data/datasource/mailbox_datasource.dart +++ b/lib/features/mailbox/data/datasource/mailbox_datasource.dart @@ -38,7 +38,7 @@ abstract class MailboxDataSource { Future moveMailbox(Session session, AccountId accountId, MoveMailboxRequest request); - Future> markAsMailboxRead( + Future> markAsMailboxRead( Session session, AccountId accountId, MailboxId mailboxId, diff --git a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart index b52e767b2..e0c604a39 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart @@ -78,7 +78,7 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource { } @override - Future> markAsMailboxRead( + Future> markAsMailboxRead( Session session, AccountId accountId, MailboxId mailboxId, diff --git a/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart b/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart index 062e7effa..fdcd4e7f5 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart @@ -87,7 +87,7 @@ class MailboxDataSourceImpl extends MailboxDataSource { } @override - Future> markAsMailboxRead( + Future> markAsMailboxRead( Session session, AccountId accountId, MailboxId mailboxId, diff --git a/lib/features/mailbox/data/network/mailbox_isolate_worker.dart b/lib/features/mailbox/data/network/mailbox_isolate_worker.dart index 58a3306f1..33b0146eb 100644 --- a/lib/features/mailbox/data/network/mailbox_isolate_worker.dart +++ b/lib/features/mailbox/data/network/mailbox_isolate_worker.dart @@ -19,6 +19,7 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_property.dart'; import 'package:model/email/read_actions.dart'; +import 'package:model/extensions/list_email_extension.dart'; import 'package:tmail_ui_user/features/base/isolate/background_isolate_binary_messenger/background_isolate_binary_messenger.dart'; import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; @@ -37,7 +38,7 @@ class MailboxIsolateWorker { MailboxIsolateWorker(this._threadApi, this._emailApi, this._isolateExecutor); - Future> markAsMailboxRead( + Future> markAsMailboxRead( Session session, AccountId accountId, MailboxId mailboxId, @@ -80,7 +81,7 @@ class MailboxIsolateWorker { } } - static Future> _handleMarkAsMailboxReadAction( + static Future> _handleMarkAsMailboxReadAction( MailboxMarkAsReadArguments args, TypeSendPort sendPort ) async { @@ -88,7 +89,7 @@ class MailboxIsolateWorker { BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken); await HiveCacheConfig.instance.setUp(); - List emailListCompleted = List.empty(growable: true); + List emailIdsCompleted = List.empty(growable: true); try { bool mailboxHasEmails = true; UTCDate? lastReceivedDate; @@ -134,29 +135,29 @@ class MailboxIsolateWorker { final result = await args.emailAPI.markAsRead( args.session, args.accountId, - listEmailUnread, + listEmailUnread.listEmailIds, ReadActions.markAsRead); log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): MARK_READ: ${result.length}'); - emailListCompleted.addAll(result); - sendPort.send(emailListCompleted); + emailIdsCompleted.addAll(result); + sendPort.send(emailIdsCompleted); } } } catch (e) { log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): ERROR: $e'); } - log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): TOTAL_READ: ${emailListCompleted.length}'); - return emailListCompleted; + log('MailboxIsolateWorker::_handleMarkAsMailboxRead(): TOTAL_READ: ${emailIdsCompleted.length}'); + return emailIdsCompleted; } - Future> _handleMarkAsMailboxReadActionOnWeb( + Future> _handleMarkAsMailboxReadActionOnWeb( Session session, AccountId accountId, MailboxId mailboxId, int totalEmailUnread, StreamController> onProgressController ) async { - List emailListCompleted = List.empty(growable: true); + List emailIdsCompleted = List.empty(growable: true); try { bool mailboxHasEmails = true; UTCDate? lastReceivedDate; @@ -199,20 +200,25 @@ class MailboxIsolateWorker { lastEmailId = listEmailUnread.last.id; lastReceivedDate = listEmailUnread.last.receivedAt; - final result = await _emailApi.markAsRead(session, accountId, listEmailUnread, ReadActions.markAsRead); + final result = await _emailApi.markAsRead( + session, + accountId, + listEmailUnread.listEmailIds, + ReadActions.markAsRead, + ); log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnWeb(): MARK_READ: ${result.length}'); - emailListCompleted.addAll(result); + emailIdsCompleted.addAll(result); onProgressController.add(Right(UpdatingMarkAsMailboxReadState( mailboxId: mailboxId, totalUnread: totalEmailUnread, - countRead: emailListCompleted.length))); + countRead: emailIdsCompleted.length))); } } } catch (e) { log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnWeb(): ERROR: $e'); } - log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnWeb(): TOTAL_READ: ${emailListCompleted.length}'); - return emailListCompleted; + log('MailboxIsolateWorker::_handleMarkAsMailboxReadActionOnWeb(): TOTAL_READ: ${emailIdsCompleted.length}'); + return emailIdsCompleted; } } diff --git a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart index a0fde06d7..bfc6fcc06 100644 --- a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart +++ b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart @@ -216,7 +216,7 @@ class MailboxRepositoryImpl extends MailboxRepository { } @override - Future> markAsMailboxRead( + Future> markAsMailboxRead( Session session, AccountId accountId, MailboxId mailboxId, diff --git a/lib/features/mailbox/domain/repository/mailbox_repository.dart b/lib/features/mailbox/domain/repository/mailbox_repository.dart index a3f40851e..57b8b17de 100644 --- a/lib/features/mailbox/domain/repository/mailbox_repository.dart +++ b/lib/features/mailbox/domain/repository/mailbox_repository.dart @@ -31,7 +31,7 @@ abstract class MailboxRepository { Future renameMailbox(Session session, AccountId accountId, RenameMailboxRequest request); - Future> markAsMailboxRead( + Future> markAsMailboxRead( Session session, AccountId accountId, MailboxId mailboxId, diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 1387e4fc4..d477d0a09 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -362,12 +362,20 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo } } else if (success is UpdateVacationSuccess) { _handleUpdateVacationSuccess(success); - } else if (success is MarkAsMultipleEmailReadAllSuccess || - success is MarkAsMultipleEmailReadHasSomeEmailFailure) { - _markAsReadSelectedMultipleEmailSuccess(success); - } else if (success is MarkAsStarMultipleEmailAllSuccess || - success is MarkAsStarMultipleEmailHasSomeEmailFailure) { - _markAsStarMultipleEmailSuccess(success); + } else if (success is MarkAsMultipleEmailReadAllSuccess) { + _markAsReadSelectedMultipleEmailSuccess(success.readActions); + } else if (success is MarkAsMultipleEmailReadHasSomeEmailFailure) { + _markAsReadSelectedMultipleEmailSuccess(success.readActions); + } else if (success is MarkAsStarMultipleEmailAllSuccess) { + _markAsStarMultipleEmailSuccess( + success.markStarAction, + success.countMarkStarSuccess, + ); + } else if (success is MarkAsStarMultipleEmailHasSomeEmailFailure) { + _markAsStarMultipleEmailSuccess( + success.markStarAction, + success.countMarkStarSuccess, + ); } else if (success is MoveMultipleEmailToMailboxAllSuccess || success is MoveMultipleEmailToMailboxHasSomeEmailFailure) { _moveSelectedMultipleEmailToMailboxSuccess(success); @@ -867,14 +875,19 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo } } - void markAsEmailRead(PresentationEmail presentationEmail, ReadActions readActions, MarkReadAction markReadAction) async { + void markAsEmailRead( + EmailId emailId, + ReadActions readActions, + MarkReadAction markReadAction, + ) { if (accountId.value != null && sessionCurrent != null) { consumeState(_markAsEmailReadInteractor.execute( sessionCurrent!, accountId.value!, - presentationEmail.toEmail(), + emailId, readActions, - markReadAction)); + markReadAction, + )); } } @@ -883,35 +896,34 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo consumeState(_markAsStarEmailInteractor.execute( sessionCurrent!, accountId.value!, - presentationEmail.toEmail(), + presentationEmail.id!, action)); } } void markAsReadSelectedMultipleEmail(List listPresentationEmail, ReadActions readActions) { - final listEmail = listPresentationEmail - .map((presentationEmail) => presentationEmail.toEmail()) - .toList(); - log('MailboxDashBoardController::markAsReadSelectedMultipleEmail(): listEmail: ${listEmail.length}'); + final listEmailNeedMarkAsRead = listPresentationEmail + .where((email) { + if (readActions == ReadActions.markAsUnread) { + return email.hasRead; + } else { + return !email.hasRead; + } + }) + .toList(); + if (accountId.value != null && sessionCurrent != null) { consumeState(_markAsMultipleEmailReadInteractor.execute( sessionCurrent!, accountId.value!, - listEmail, - readActions)); + listEmailNeedMarkAsRead.listEmailIds, + readActions, + )); } } - void _markAsReadSelectedMultipleEmailSuccess(Success success) { - ReadActions? readActions; - - if (success is MarkAsMultipleEmailReadAllSuccess) { - readActions = success.readActions; - } else if (success is MarkAsMultipleEmailReadHasSomeEmailFailure) { - readActions = success.readActions; - } - - if (readActions != null && currentContext != null && currentOverlayContext != null) { + void _markAsReadSelectedMultipleEmailSuccess(ReadActions readActions) { + if (currentContext != null && currentOverlayContext != null) { final message = readActions == ReadActions.markAsUnread ? AppLocalizations.of(currentContext!).marked_message_toast(AppLocalizations.of(currentContext!).unread) : AppLocalizations.of(currentContext!).marked_message_toast(AppLocalizations.of(currentContext!).read); @@ -926,30 +938,24 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo } } - void _markAsReadEmailSuccess(Success success) { - ReadActions? readActions; - MarkReadAction? markReadAction; - PresentationEmail? presentationEmail; - - if (success is MarkAsEmailReadSuccess) { - readActions = success.readActions; - markReadAction = success.markReadAction; - presentationEmail = success.updatedEmail.toPresentationEmail(); - } - - if (readActions != null && currentContext != null && currentOverlayContext != null && markReadAction == MarkReadAction.swipeOnThread) { - final message = readActions == ReadActions.markAsUnread + void _markAsReadEmailSuccess(MarkAsEmailReadSuccess success) { + if (currentContext != null && + currentOverlayContext != null && + success.markReadAction == MarkReadAction.swipeOnThread) { + final message = success.readActions == ReadActions.markAsUnread ? AppLocalizations.of(currentContext!).markedSingleMessageToast(AppLocalizations.of(currentContext!).unread.toLowerCase()) : AppLocalizations.of(currentContext!).markedSingleMessageToast(AppLocalizations.of(currentContext!).read.toLowerCase()); - final undoAction = readActions == ReadActions.markAsUnread ? ReadActions.markAsRead : ReadActions.markAsUnread; + final undoAction = success.readActions == ReadActions.markAsUnread + ? ReadActions.markAsRead + : ReadActions.markAsUnread; appToast.showToastMessage( currentOverlayContext!, message, actionName: AppLocalizations.of(currentContext!).undo, onActionClick: () { - markAsEmailRead(presentationEmail!, undoAction, MarkReadAction.undo); + markAsEmailRead(success.emailId, undoAction, MarkReadAction.undo); }, leadingSVGIcon: imagePaths.icToastSuccessMessage, backgroundColor: AppColor.toastSuccessBackgroundColor, @@ -960,43 +966,42 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo } void markAsStarSelectedMultipleEmail(List listPresentationEmail, MarkStarAction markStarAction) { - final listEmail = listPresentationEmail - .map((presentationEmail) => presentationEmail.toEmail()) - .toList(); if (accountId.value != null && sessionCurrent != null) { + final listEmailIds = listPresentationEmail + .where((email) { + if (markStarAction == MarkStarAction.unMarkStar) { + return email.hasStarred; + } else { + return !email.hasStarred; + } + }) + .toList() + .listEmailIds; + consumeState(_markAsStarMultipleEmailInteractor.execute( sessionCurrent!, accountId.value!, - listEmail, + listEmailIds, markStarAction)); } } - void _markAsStarMultipleEmailSuccess(Success success) { - MarkStarAction? markStarAction; - int countMarkStarSuccess = 0; - - if (success is MarkAsStarMultipleEmailAllSuccess) { - markStarAction = success.markStarAction; - countMarkStarSuccess = success.countMarkStarSuccess; - } else if (success is MarkAsStarMultipleEmailHasSomeEmailFailure) { - markStarAction = success.markStarAction; - countMarkStarSuccess = success.countMarkStarSuccess; - } - - if (markStarAction != null) { + void _markAsStarMultipleEmailSuccess( + MarkStarAction markStarAction, + int countMarkStarSuccess, + ) { + if (currentOverlayContext != null && currentContext != null) { final message = markStarAction == MarkStarAction.unMarkStar ? AppLocalizations.of(currentContext!).marked_unstar_multiple_item(countMarkStarSuccess) : AppLocalizations.of(currentContext!).marked_star_multiple_item(countMarkStarSuccess); - if (currentOverlayContext != null && currentContext != null) { - appToast.showToastMessage( - currentOverlayContext!, - message, - leadingSVGIcon: markStarAction == MarkStarAction.unMarkStar - ? imagePaths.icUnStar - : imagePaths.icStar); - } + appToast.showToastMessage( + currentOverlayContext!, + message, + leadingSVGIcon: markStarAction == MarkStarAction.unMarkStar + ? imagePaths.icUnStar + : imagePaths.icStar, + ); } } diff --git a/lib/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart b/lib/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart index e99da0356..68cae7562 100644 --- a/lib/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart +++ b/lib/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart @@ -17,7 +17,7 @@ class MarkAsMultipleEmailReadInteractor { Stream> execute( Session session, AccountId accountId, - List emails, + List emailIds, ReadActions readAction ) async* { try { @@ -31,25 +31,24 @@ class MarkAsMultipleEmailReadInteractor { final currentMailboxState = listState.first; final currentEmailState = listState.last; - final listEmailNeedMarkAsRead = emails - .where((email) => readAction == ReadActions.markAsUnread ? email.hasRead : !email.hasRead) - .toList(); + final result = await _emailRepository.markAsRead( + session, + accountId, + emailIds, + readAction, + ); - final result = await _emailRepository.markAsRead(session, accountId, listEmailNeedMarkAsRead, readAction); - - if (listEmailNeedMarkAsRead.length == result.length) { - final countMarkAsReadSuccess = emails.length; + if (emailIds.length == result.length) { yield Right(MarkAsMultipleEmailReadAllSuccess( - countMarkAsReadSuccess, + result.length, readAction, currentEmailState: currentEmailState, currentMailboxState: currentMailboxState)); } else if (result.isEmpty) { yield Left(MarkAsMultipleEmailReadAllFailure(readAction)); } else { - final countMarkAsReadSuccess = emails.length - (listEmailNeedMarkAsRead.length - result.length); yield Right(MarkAsMultipleEmailReadHasSomeEmailFailure( - countMarkAsReadSuccess, + result.length, readAction, currentEmailState: currentEmailState, currentMailboxState: currentMailboxState)); diff --git a/lib/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart b/lib/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart index 27062847b..840056fc4 100644 --- a/lib/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart +++ b/lib/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart @@ -1,4 +1,5 @@ -import 'package:core/core.dart'; +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'; @@ -15,7 +16,7 @@ class MarkAsStarMultipleEmailInteractor { Stream> execute( Session session, AccountId accountId, - List emails, + List emailIds, MarkStarAction markStarAction ) async* { try { @@ -23,24 +24,18 @@ class MarkAsStarMultipleEmailInteractor { final currentEmailState = await _emailRepository.getEmailState(session, accountId); - final listEmailNeedMarkStar = emails - .where((email) => markStarAction == MarkStarAction.unMarkStar ? email.hasStarred : !email.hasStarred) - .toList(); + final result = await _emailRepository.markAsStar(session, accountId, emailIds, markStarAction); - final result = await _emailRepository.markAsStar(session, accountId, listEmailNeedMarkStar, markStarAction); - - if (listEmailNeedMarkStar.length == result.length) { - final countMarkStarSuccess = emails.length; + if (emailIds.length == result.length) { yield Right(MarkAsStarMultipleEmailAllSuccess( - countMarkStarSuccess, + emailIds.length, markStarAction, currentEmailState: currentEmailState)); } else if (result.isEmpty) { yield Left(MarkAsStarMultipleEmailAllFailure(markStarAction)); } else { - final countMarkStarSuccess = emails.length - (listEmailNeedMarkStar.length - result.length); yield Right(MarkAsStarMultipleEmailHasSomeEmailFailure( - countMarkStarSuccess, + result.length, markStarAction, currentEmailState: currentEmailState)); } diff --git a/lib/features/thread/presentation/mixin/email_action_controller.dart b/lib/features/thread/presentation/mixin/email_action_controller.dart index d6899667b..baefee994 100644 --- a/lib/features/thread/presentation/mixin/email_action_controller.dart +++ b/lib/features/thread/presentation/mixin/email_action_controller.dart @@ -224,8 +224,16 @@ mixin EmailActionController { mailboxDashBoardController.deleteEmailPermanently(email); } - void markAsEmailRead(PresentationEmail presentationEmail, ReadActions readActions, MarkReadAction markReadAction) async { - mailboxDashBoardController.markAsEmailRead(presentationEmail, readActions, markReadAction); + void markAsEmailRead( + PresentationEmail presentationEmail, + ReadActions readActions, + MarkReadAction markReadAction, + ) { + mailboxDashBoardController.markAsEmailRead( + presentationEmail.id!, + readActions, + markReadAction, + ); } void markAsStarEmail(PresentationEmail presentationEmail, MarkStarAction action) { diff --git a/model/lib/extensions/presentation_email_extension.dart b/model/lib/extensions/presentation_email_extension.dart index 0a0fa4026..7b1c5c46e 100644 --- a/model/lib/extensions/presentation_email_extension.dart +++ b/model/lib/extensions/presentation_email_extension.dart @@ -217,11 +217,14 @@ extension PresentationEmailExtension on PresentationEmail { ..searchSnippetPreview = searchSnippetPreview; } - PresentationEmail updateKeywords(Map? newKeywords) { + PresentationEmail updateKeywords(Map newKeywords) { + final combinedMap = {...(keywords ?? {}), ...newKeywords}; + combinedMap.removeWhere((key, value) => !value); + log('PresentationEmailExtension::updateKeywords:combinedMap = $combinedMap'); return PresentationEmail( id: this.id, blobId: blobId, - keywords: newKeywords, + keywords: combinedMap, size: size, receivedAt: receivedAt, hasAttachment: hasAttachment, diff --git a/test/features/email/domain/usecases/store_event_attendance_status_interactor_test.dart b/test/features/email/domain/usecases/store_event_attendance_status_interactor_test.dart index e30b9a7f9..3deda8c8c 100644 --- a/test/features/email/domain/usecases/store_event_attendance_status_interactor_test.dart +++ b/test/features/email/domain/usecases/store_event_attendance_status_interactor_test.dart @@ -60,7 +60,6 @@ void main() { Right(StoreEventAttendanceStatusLoading()), Right(StoreEventAttendanceStatusSuccess( eventActionType, - updatedEmail, currentEmailState: currentEmailState)), ]), ); diff --git a/test/features/thread/presentation/controller/thread_controller_test.dart b/test/features/thread/presentation/controller/thread_controller_test.dart index 094c73e95..7f8ad860d 100644 --- a/test/features/thread/presentation/controller/thread_controller_test.dart +++ b/test/features/thread/presentation/controller/thread_controller_test.dart @@ -4,22 +4,22 @@ import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/utils/application_manager.dart'; -import 'package:dartz/dartz.dart'; +import 'package:dartz/dartz.dart' hide State; import 'package:flutter_test/flutter_test.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:model/email/mark_star_action.dart'; import 'package:model/email/presentation_email.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/select_mode.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; -import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart'; +import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; @@ -266,10 +266,6 @@ void main() { 'AND `mailboxDashBoardController.emailsInCurrentMailbox` should not be cleared', () async { // Arrange - final updatedEmail = Email( - id: EmailId(Id('email1')), - keywords: {KeyWordIdentifier.emailFlagged: true} - ); final emailList = [ PresentationEmail( id: EmailId(Id('email1')), @@ -308,10 +304,8 @@ void main() { // Act threadController.onInit(); - final markAsStarEmailSuccess = MarkAsStarEmailSuccess( - updatedEmail, - MarkStarAction.markStar); - mockMailboxDashBoardController.viewState.value = Right(markAsStarEmailSuccess); + mockMailboxDashBoardController.emailUIAction.value = + RefreshChangeEmailAction(State('new-state')); await untilCalled(mockSearchEmailInteractor.execute( any,