diff --git a/lib/features/composer/domain/exceptions/send_email_exception.dart b/lib/features/composer/domain/exceptions/send_email_exception.dart deleted file mode 100644 index 417539ee0..000000000 --- a/lib/features/composer/domain/exceptions/send_email_exception.dart +++ /dev/null @@ -1,4 +0,0 @@ - -class NotFoundOutboxMailboxException implements Exception { - NotFoundOutboxMailboxException(); -} \ No newline at end of file diff --git a/lib/features/composer/domain/exceptions/set_email_method_exception.dart b/lib/features/composer/domain/exceptions/set_email_method_exception.dart new file mode 100644 index 000000000..4886b79fb --- /dev/null +++ b/lib/features/composer/domain/exceptions/set_email_method_exception.dart @@ -0,0 +1,10 @@ + +import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; + +class SetEmailMethodException implements Exception { + + final Map mapErrors; + + SetEmailMethodException(this.mapErrors); +} \ No newline at end of file diff --git a/lib/features/composer/domain/state/send_email_state.dart b/lib/features/composer/domain/state/send_email_state.dart index 56f0772b9..5c866fe43 100644 --- a/lib/features/composer/domain/state/send_email_state.dart +++ b/lib/features/composer/domain/state/send_email_state.dart @@ -26,5 +26,5 @@ class SendEmailFailure extends FeatureFailure { SendEmailFailure(this.exception); @override - List get props => [exception]; + List get props => [exception]; } \ No newline at end of file diff --git a/lib/features/composer/domain/usecases/send_email_interactor.dart b/lib/features/composer/domain/usecases/send_email_interactor.dart index bdfb81a0b..7eb7f4591 100644 --- a/lib/features/composer/domain/usecases/send_email_interactor.dart +++ b/lib/features/composer/domain/usecases/send_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:tmail_ui_user/features/composer/domain/model/email_request.dart'; @@ -6,14 +7,12 @@ import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.da import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; -import 'package:uuid/uuid.dart'; class SendEmailInteractor { final EmailRepository _emailRepository; final MailboxRepository _mailboxRepository; - final Uuid _uuid; - SendEmailInteractor(this._emailRepository, this._mailboxRepository, this._uuid); + SendEmailInteractor(this._emailRepository, this._mailboxRepository); Stream> execute( AccountId accountId, @@ -31,13 +30,21 @@ class SendEmailInteractor { final currentMailboxState = listState.first; final currentEmailState = listState.last; - final result = await _emailRepository.sendEmail(accountId, emailRequest, mailboxRequest: mailboxRequest); + final result = await _emailRepository.sendEmail( + accountId, + emailRequest, + mailboxRequest: mailboxRequest + ); + if (result) { - yield Right(SendEmailSuccess( + yield Right( + SendEmailSuccess( currentEmailState: currentEmailState, - currentMailboxState: currentMailboxState)); + currentMailboxState: currentMailboxState + ) + ); } else { - yield Left(SendEmailFailure(result)); + yield Left(SendEmailFailure(null)); } } catch (e) { yield Left(SendEmailFailure(e)); diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index cc1355502..3a5c21923 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -51,7 +51,6 @@ import 'package:tmail_ui_user/features/upload/presentation/controller/upload_con import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart'; import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; -import 'package:uuid/uuid.dart'; import 'package:worker_manager/worker_manager.dart'; class ComposerBindings extends BaseBindings { @@ -132,9 +131,9 @@ class ComposerBindings extends BaseBindings { Get.lazyPut(() => LocalFilePickerInteractor()); Get.lazyPut(() => UploadAttachmentInteractor(Get.find())); Get.lazyPut(() => SendEmailInteractor( - Get.find(), - Get.find(), - Get.find())); + Get.find(), + Get.find() + )); Get.lazyPut(() => SaveEmailAsDraftsInteractor( Get.find(), Get.find())); diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index 9b0c35e60..12d3196a8 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -5,7 +5,6 @@ import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.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:tmail_ui_user/features/composer/domain/model/email_request.dart'; diff --git a/lib/features/email/data/network/email_api.dart b/lib/features/email/data/network/email_api.dart index 272e14a79..a331b7a36 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -11,6 +11,8 @@ import 'package:jmap_dart_client/http/http_client.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/capability/core_capability.dart'; +import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/patch_object.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/reference_id.dart'; @@ -27,6 +29,7 @@ import 'package:jmap_dart_client/jmap/mail/email/submission/email_submission.dar import 'package:jmap_dart_client/jmap/mail/email/submission/email_submission_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/submission/envelope.dart'; import 'package:jmap_dart_client/jmap/mail/email/submission/set/set_email_submission_method.dart'; +import 'package:jmap_dart_client/jmap/mail/email/submission/set/set_email_submission_response.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/set/set_mailbox_method.dart'; import 'package:model/account/account_request.dart'; @@ -43,6 +46,8 @@ import 'package:model/extensions/mailbox_id_extension.dart'; import 'package:model/extensions/session_extension.dart'; import 'package:model/oidc/token.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart'; +import 'package:tmail_ui_user/features/composer/domain/exceptions/set_email_method_exception.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart'; import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart'; @@ -50,7 +55,7 @@ import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_ex import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/main/error/capability_validator.dart'; -class EmailAPI { +class EmailAPI with HandleSetErrorMixin { final HttpClient _httpClient; final DownloadManager _downloadManager; @@ -93,9 +98,9 @@ class EmailAPI { } Future sendEmail( - AccountId accountId, - EmailRequest emailRequest, - {CreateNewMailboxRequest? mailboxRequest} + AccountId accountId, + EmailRequest emailRequest, + {CreateNewMailboxRequest? mailboxRequest} ) async { final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); @@ -158,21 +163,55 @@ class EmailAPI { setEmailInvocation.methodCallId, SetEmailResponse.deserialize); - final setEmailSubmissionResponse = response.parse( + final setEmailSubmissionResponse = response.parse( setEmailSubmissionInvocation.methodCallId, - SetEmailResponse.deserialize, + SetEmailSubmissionResponse.deserialize, methodName: setEmailInvocation.methodName); final emailCreated = setEmailResponse?.created?[emailNeedsToBeCreated.id.id]; - if (emailCreated != null) { - return setEmailSubmissionResponse?.notUpdated == null && - setEmailSubmissionResponse?.notCreated == null && - setEmailSubmissionResponse?.notDestroyed == null; + final listEntriesErrors = _handleSetEmailResponse( + response: setEmailResponse, + submissionResponse: setEmailSubmissionResponse + ); + final mapErrors = Map.fromEntries(listEntriesErrors); + + if (emailCreated != null && mapErrors.isEmpty) { + return true; } else { - return false; + throw SetEmailMethodException(mapErrors); } } + List> _handleSetEmailResponse({ + SetEmailResponse? response, + SetEmailSubmissionResponse? submissionResponse + }) { + final List> remainedErrors = []; + if (response != null) { + handleSetErrors( + notDestroyedError: response.notDestroyed, + notUpdatedError: response.notUpdated, + notCreatedError: response.notCreated, + unCatchErrorHandler: (setErrorEntry) { + remainedErrors.add(setErrorEntry); + return false; + } + ); + } + if (submissionResponse != null) { + handleSetErrors( + notDestroyedError: submissionResponse.notDestroyed, + notUpdatedError: submissionResponse.notUpdated, + notCreatedError: submissionResponse.notCreated, + unCatchErrorHandler: (setErrorEntry) { + remainedErrors.add(setErrorEntry); + return false; + } + ); + } + return remainedErrors; + } + Future> markAsRead(AccountId accountId, List emails, ReadActions readActions) async { final emailIds = emails.map((email) => email.id).toList(); diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index e897b55b4..5f69eb66a 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -6,7 +6,6 @@ import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.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/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/model.dart'; diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 5a876d0f9..4ddca04c7 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -5,7 +5,6 @@ import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.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:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:model/model.dart'; 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 0200b9604..4e211cc0a 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -11,6 +11,7 @@ import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/capability/mail_capability.dart'; +import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; @@ -22,6 +23,7 @@ import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:rxdart/transformers.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart'; import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart'; +import 'package:tmail_ui_user/features/composer/domain/exceptions/set_email_method_exception.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; @@ -274,14 +276,7 @@ class MailboxDashBoardController extends ReloadableController { viewState.value.fold( (failure) { if (failure is SendEmailFailure) { - if (currentOverlayContext != null && currentContext != null) { - _appToast.showToastWithIcon( - currentOverlayContext!, - textColor: AppColor.toastErrorBackgroundColor, - message: AppLocalizations.of(currentContext!).message_has_been_sent_failure, - icon: _imagePaths.icSendToast); - } - clearState(); + _handleSendEmailFailure(failure); } else if (failure is SaveEmailAsDraftsFailure || failure is RemoveEmailDraftsFailure || failure is UpdateEmailDraftsFailure) { @@ -1547,6 +1542,51 @@ class MailboxDashBoardController extends ReloadableController { } bool get isDraggingMailbox => _isDraggingMailbox.value; + + void _handleSendEmailFailure(SendEmailFailure failure) { + logError('MailboxDashBoardController::_handleSendEmailFailure():failure: $failure'); + if (currentContext == null) { + clearState(); + return; + } + final exception = failure.exception; + logError('MailboxDashBoardController::_handleSendEmailFailure():exception: $exception'); + if (exception is SetEmailMethodException) { + final listErrors = exception.mapErrors.values.toList(); + final toastSuccess = _handleSetErrors(listErrors); + if (!toastSuccess) { + _showToastSendMessageFailure(AppLocalizations.of(currentContext!).message_has_been_sent_failure); + } + } else { + _showToastSendMessageFailure(AppLocalizations.of(currentContext!).message_has_been_sent_failure); + } + + clearState(); + } + + bool _handleSetErrors(List listErrors) { + for (var error in listErrors) { + if (error.type == SetError.tooLarge) { + _showToastSendMessageFailure(AppLocalizations.of(currentContext!).sendMessageFailureWithSetErrorTypeTooLarge); + return true; + } else if (error.type == SetError.overQuota) { + _showToastSendMessageFailure(AppLocalizations.of(currentContext!).sendMessageFailureWithSetErrorTypeOverQuota); + return true; + } + } + return false; + } + + void _showToastSendMessageFailure(String message) { + if (currentOverlayContext != null) { + _appToast.showToastWithIcon( + currentOverlayContext!, + textColor: AppColor.toastErrorBackgroundColor, + message: message, + icon: _imagePaths.icSendToast + ); + } + } @override void onClose() { diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 2b73fcf56..62ca75ecb 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-01-27T17:10:17.205660", + "@@last_modified": "2023-02-02T19:29:42.134695", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2649,5 +2649,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "sendMessageFailureWithSetErrorTypeTooLarge": "Failure to send your message, because it is too large.", + "@sendMessageFailureWithSetErrorTypeTooLarge": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "sendMessageFailureWithSetErrorTypeOverQuota": "Failure to send your message, because it is over quota.", + "@sendMessageFailureWithSetErrorTypeOverQuota": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 2d13cc3e9..e4d942ebb 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2719,4 +2719,18 @@ class AppLocalizations { 'Let\'s reduce some filters and try again', name: 'reduceSomeFiltersAndTryAgain'); } + + String get sendMessageFailureWithSetErrorTypeTooLarge { + return Intl.message( + 'Failure to send your message, because it is too large.', + name: 'sendMessageFailureWithSetErrorTypeTooLarge', + ); + } + + String get sendMessageFailureWithSetErrorTypeOverQuota { + return Intl.message( + 'Failure to send your message, because it is over quota.', + name: 'sendMessageFailureWithSetErrorTypeOverQuota', + ); + } } \ No newline at end of file