diff --git a/lib/features/composer/data/repository/composer_repository_impl.dart b/lib/features/composer/data/repository/composer_repository_impl.dart index 904fd52c0..196e4de47 100644 --- a/lib/features/composer/data/repository/composer_repository_impl.dart +++ b/lib/features/composer/data/repository/composer_repository_impl.dart @@ -16,7 +16,7 @@ class ComposerRepositoryImpl extends ComposerRepository { this._composerDataSource); @override - UploadAttachment uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}) { + Future uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}) { return _attachmentUploadDataSource.uploadAttachment(fileInfo, uploadUri, cancelToken: cancelToken); } diff --git a/lib/features/composer/domain/repository/composer_repository.dart b/lib/features/composer/domain/repository/composer_repository.dart index a3eb8cf3f..33c9cf4fd 100644 --- a/lib/features/composer/domain/repository/composer_repository.dart +++ b/lib/features/composer/domain/repository/composer_repository.dart @@ -1,9 +1,9 @@ import 'package:dio/dio.dart'; -import 'package:model/model.dart'; +import 'package:model/upload/file_info.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_attachment.dart'; abstract class ComposerRepository { - UploadAttachment uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}); + Future uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}); Future downloadImageAsBase64(String url, String cid, FileInfo fileInfo, {double? maxWidth, bool? compress}); } \ No newline at end of file diff --git a/lib/features/composer/domain/state/upload_attachment_state.dart b/lib/features/composer/domain/state/upload_attachment_state.dart new file mode 100644 index 000000000..87c169d05 --- /dev/null +++ b/lib/features/composer/domain/state/upload_attachment_state.dart @@ -0,0 +1,25 @@ + +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:tmail_ui_user/features/upload/domain/model/upload_attachment.dart'; + +class UploadAttachmentSuccess extends UIState { + + final UploadAttachment uploadAttachment; + final bool isInline; + + UploadAttachmentSuccess(this.uploadAttachment, {this.isInline = false}); + + @override + List get props => [uploadAttachment, isInline]; +} + +class UploadAttachmentFailure extends FeatureFailure { + final dynamic exception; + final bool isInline; + + UploadAttachmentFailure(this.exception, {this.isInline = false}); + + @override + List get props => [exception, isInline]; +} \ No newline at end of file diff --git a/lib/features/composer/domain/usecases/upload_attachment_interactor.dart b/lib/features/composer/domain/usecases/upload_attachment_interactor.dart index ccb925399..52e3a45d5 100644 --- a/lib/features/composer/domain/usecases/upload_attachment_interactor.dart +++ b/lib/features/composer/domain/usecases/upload_attachment_interactor.dart @@ -1,14 +1,31 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart'; import 'package:dio/dio.dart'; -import 'package:model/model.dart'; +import 'package:model/upload/file_info.dart'; import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart'; -import 'package:tmail_ui_user/features/upload/domain/model/upload_attachment.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_state.dart'; class UploadAttachmentInteractor { final ComposerRepository _composerRepository; UploadAttachmentInteractor(this._composerRepository); - UploadAttachment execute(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}) { - return _composerRepository.uploadAttachment(fileInfo, uploadUri, cancelToken: cancelToken); + Stream> execute( + FileInfo fileInfo, + Uri uploadUri, { + CancelToken? cancelToken, + bool isInline = false + }) async* { + try { + final uploadAttachment = await _composerRepository.uploadAttachment( + fileInfo, + uploadUri, + cancelToken: cancelToken + ); + yield Right(UploadAttachmentSuccess(uploadAttachment, isInline: isInline)); + } catch (e) { + yield Left(UploadAttachmentFailure(e, isInline: isInline)); + } } } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index 3a5c21923..e6640c54a 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -51,6 +51,7 @@ 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 { @@ -67,7 +68,11 @@ class ComposerBindings extends BaseBindings { @override void bindingsDataSourceImpl() { - Get.lazyPut(() => AttachmentUploadDataSourceImpl(Get.find())); + Get.lazyPut(() => AttachmentUploadDataSourceImpl( + Get.find(), + Get.find(), + Get.find() + )); Get.lazyPut(() => ComposerDataSourceImpl(Get.find(), Get.find())); Get.lazyPut(() => ContactDataSourceImpl(Get.find())); Get.lazyPut(() => MailboxDataSourceImpl( diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 91e70ac87..3282f0969 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -1445,7 +1445,7 @@ class ComposerController extends BaseController { final accountId = mailboxDashBoardController.accountId.value; if (session != null && accountId != null) { final uploadUri = session.getUploadUri(accountId); - uploadController.uploadInlineImage(pickedFile, uploadUri); + uploadController.uploadFileAction(pickedFile, uploadUri, isInline: true); } } else { if (currentContext != null) { diff --git a/lib/features/upload/data/datasource/attachment_upload_datasource.dart b/lib/features/upload/data/datasource/attachment_upload_datasource.dart index 0a0659028..1c8e14536 100644 --- a/lib/features/upload/data/datasource/attachment_upload_datasource.dart +++ b/lib/features/upload/data/datasource/attachment_upload_datasource.dart @@ -4,5 +4,5 @@ import 'package:model/upload/file_info.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_attachment.dart'; abstract class AttachmentUploadDataSource { - UploadAttachment uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}); + Future uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}); } \ No newline at end of file diff --git a/lib/features/upload/data/datasource_impl/attachment_upload_datasource_impl.dart b/lib/features/upload/data/datasource_impl/attachment_upload_datasource_impl.dart index 8130d6d1f..c6f3e4054 100644 --- a/lib/features/upload/data/datasource_impl/attachment_upload_datasource_impl.dart +++ b/lib/features/upload/data/datasource_impl/attachment_upload_datasource_impl.dart @@ -5,29 +5,29 @@ import 'package:tmail_ui_user/features/upload/data/datasource/attachment_upload_ import 'package:tmail_ui_user/features/upload/data/network/file_uploader.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_attachment.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart'; +import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; import 'package:uuid/uuid.dart'; class AttachmentUploadDataSourceImpl extends AttachmentUploadDataSource { final FileUploader _fileUploader; + final Uuid _uuid; + final ExceptionThrower _exceptionThrower; - AttachmentUploadDataSourceImpl(this._fileUploader); + AttachmentUploadDataSourceImpl(this._fileUploader, this._uuid, this._exceptionThrower); @override - UploadAttachment uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}) { - final attachmentUploadId = _generateAttachmentUploadId(); - final uploadAttachment = UploadAttachment( - attachmentUploadId, - fileInfo, - uploadUri, - _fileUploader, - cancelToken: cancelToken) - ..upload(); - - return uploadAttachment; - } - - UploadTaskId _generateAttachmentUploadId() { - return UploadTaskId(const Uuid().v4()); + Future uploadAttachment(FileInfo fileInfo, Uri uploadUri, {CancelToken? cancelToken}) { + return Future.sync(() { + return UploadAttachment( + UploadTaskId(_uuid.v4()), + fileInfo, + uploadUri, + _fileUploader, + cancelToken: cancelToken + )..upload(); + }).catchError((error) { + _exceptionThrower.throwException(error); + }); } } \ No newline at end of file diff --git a/lib/features/upload/data/network/file_uploader.dart b/lib/features/upload/data/network/file_uploader.dart index 149f6cff1..1b074b67b 100644 --- a/lib/features/upload/data/network/file_uploader.dart +++ b/lib/features/upload/data/network/file_uploader.dart @@ -3,13 +3,18 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:core/core.dart'; +import 'package:core/data/network/dio_client.dart'; +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/build_utils.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.dart'; import 'package:model/email/attachment.dart'; import 'package:model/upload/file_info.dart'; import 'package:model/upload/upload_response.dart'; import 'package:tmail_ui_user/features/upload/data/model/upload_file_arguments.dart'; +import 'package:tmail_ui_user/features/upload/domain/exceptions/upload_exception.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart'; import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; import 'package:worker_manager/worker_manager.dart' as worker; @@ -36,21 +41,24 @@ class FileUploader { uploadUri, cancelToken: cancelToken); } else { - final attachmentUploaded = await _isolateExecutor.execute( - arg1: UploadFileArguments( - _dioClient, - uploadId, - fileInfo, - uploadUri, - cancelToken: cancelToken), - fun1: _handleUploadAttachmentAction, - notification: (value) { - if (value is Success) { - log('FileUploader::uploadAttachment(): onUpdateProgress: $value'); - onSendController.add(Right(value)); - } - }); - return attachmentUploaded; + return await _isolateExecutor.execute( + arg1: UploadFileArguments( + _dioClient, + uploadId, + fileInfo, + uploadUri, + cancelToken: cancelToken + ), + fun1: _handleUploadAttachmentAction, + notification: (value) { + if (value is Success) { + log('FileUploader::uploadAttachment(): onUpdateProgress: $value'); + onSendController.add(Right(value)); + } + } + ) + .then((value) => value) + .catchError((error) => throw error); } } @@ -58,80 +66,107 @@ class FileUploader { UploadFileArguments argsUpload, worker.TypeSendPort sendPort ) async { - try { - final dioClient = argsUpload.dioClient; - final fileInfo = argsUpload.fileInfo; - final uploadUri = argsUpload.uploadUri; - final cancelToken = argsUpload.cancelToken; + final dioClient = argsUpload.dioClient; + final fileInfo = argsUpload.fileInfo; + final uploadUri = argsUpload.uploadUri; + final cancelToken = argsUpload.cancelToken; - final headerParam = dioClient.getHeaders(); - headerParam[HttpHeaders.contentTypeHeader] = fileInfo.mimeType; - headerParam[HttpHeaders.contentLengthHeader] = fileInfo.fileSize; - - final resultJson = await argsUpload.dioClient.post( - Uri.decodeFull(uploadUri.toString()), - options: Options(headers: headerParam), - data: fileInfo.readStream ?? File(fileInfo.filePath).openRead(), - cancelToken: cancelToken, - onSendProgress: (progress, total) { - log('FileUploader::_handleUploadAttachmentAction():onSendProgress: [${argsUpload.uploadId.id}] = $progress'); - sendPort.send(UploadingAttachmentUploadState( - argsUpload.uploadId, - progress, - fileInfo.fileSize)); - }); - - if (cancelToken?.isCancelled == true) { - log('FileUploader::_handleUploadAttachmentAction(): cancelToken'); - return null; + final resultJson = await _invokeRequestToServer( + dioClient, + uploadUri, + fileInfo, + cancelToken: cancelToken, + onSendProgress: (count, total) { + log('FileUploader::_handleUploadAttachmentAction():onSendProgress: [${argsUpload.uploadId.id}] = $count'); + sendPort.send( + UploadingAttachmentUploadState( + argsUpload.uploadId, + count, + fileInfo.fileSize + ) + ); } - - final decodeJson = resultJson is Map ? resultJson : jsonDecode(resultJson); - final uploadResponse = UploadResponse.fromJson(decodeJson); - log('FileUploader::_handleUploadAttachmentAction(): ${uploadResponse.toString()}'); - return uploadResponse.toAttachment(fileInfo.fileName); - } catch (e) { - log('FileUploader::_handleUploadAttachmentAction(): ERROR: $e'); + ); + log('FileUploader::_handleUploadAttachmentAction():resultJson: $resultJson'); + if (cancelToken?.isCancelled == true) { + log('FileUploader::_handleUploadAttachmentAction(): upload is cancelled'); return null; } + + return _parsingResponse(resultJson: resultJson, fileName: fileInfo.fileName); } Future _handleUploadAttachmentActionOnWeb( - UploadTaskId uploadId, - StreamController> onSendController, - FileInfo fileInfo, - Uri uploadUri, - {CancelToken? cancelToken} + UploadTaskId uploadId, + StreamController> onSendController, + FileInfo fileInfo, + Uri uploadUri, + {CancelToken? cancelToken} ) async { - try { - final headerParam = _dioClient.getHeaders(); - headerParam[HttpHeaders.contentTypeHeader] = fileInfo.mimeType; - headerParam[HttpHeaders.contentLengthHeader] = fileInfo.fileSize; - - final resultJson = await _dioClient.post( - Uri.decodeFull(uploadUri.toString()), - options: Options(headers: headerParam), - data: fileInfo.readStream, - cancelToken: cancelToken, - onSendProgress: (progress, total) { - log('FileUploader::_handleUploadAttachmentActionOnWeb():onSendProgress: [$uploadId] = $progress'); - onSendController.add(Right(UploadingAttachmentUploadState( - uploadId, progress, fileInfo.fileSize))); - } - ); - - if (cancelToken?.isCancelled == true) { - log('FileUploader::_handleUploadAttachmentAction(): cancelToken'); - return null; + final resultJson = await _invokeRequestToServer( + _dioClient, + uploadUri, + fileInfo, + cancelToken: cancelToken, + onSendProgress: (count, total) { + log('FileUploader::_handleUploadAttachmentActionOnWeb():onSendProgress: [${uploadId.id}] = $count'); + onSendController.add( + Right(UploadingAttachmentUploadState( + uploadId, + count, + fileInfo.fileSize + )) + ); } + ); + log('FileUploader::_handleUploadAttachmentActionOnWeb():resultJson: $resultJson'); + + if (cancelToken?.isCancelled == true) { + log('FileUploader::_handleUploadAttachmentActionOnWeb(): upload is cancelled'); + return null; + } + + return _parsingResponse(resultJson: resultJson, fileName: fileInfo.fileName); + } + + static Future _invokeRequestToServer( + DioClient dioClient, + Uri uploadUri, + FileInfo fileInfo, { + CancelToken? cancelToken, + ProgressCallback? onSendProgress + }) { + final headerParam = dioClient.getHeaders(); + headerParam[HttpHeaders.contentTypeHeader] = fileInfo.mimeType; + headerParam[HttpHeaders.contentLengthHeader] = fileInfo.fileSize; + + final data = fileInfo.readStream ?? File(fileInfo.filePath).openRead(); + + if (cancelToken?.isCancelled == true) { + log('FileUploader::_invokeRequestToServer(): upload is cancelled'); + return Future.value(); + } + + return dioClient.post( + Uri.decodeFull(uploadUri.toString()), + options: Options(headers: headerParam), + data: data, + cancelToken: cancelToken, + onSendProgress: onSendProgress + ); + } + + static Attachment? _parsingResponse({dynamic resultJson, required String fileName}) { + log('FileUploader::_parsingResponse():resultJson: $resultJson'); + if (resultJson != null) { final decodeJson = resultJson is Map ? resultJson : jsonDecode(resultJson); final uploadResponse = UploadResponse.fromJson(decodeJson); - log('FileUploader::_handleUploadAttachmentActionOnWeb(): ${uploadResponse.toString()}'); - return uploadResponse.toAttachment(fileInfo.fileName); - } catch (e) { - log('FileUploader::_handleUploadAttachmentActionOnWeb(): $e'); - return null; + log('FileUploader::_parsingResponse():uploadResponse: ${uploadResponse.toString()}'); + return uploadResponse.toAttachment(fileName); + } else { + logError('FileUploader::_parsingResponse(): DataResponseIsNullException'); + throw DataResponseIsNullException(); } } } \ No newline at end of file diff --git a/lib/features/upload/domain/exceptions/upload_exception.dart b/lib/features/upload/domain/exceptions/upload_exception.dart new file mode 100644 index 000000000..a56e36d56 --- /dev/null +++ b/lib/features/upload/domain/exceptions/upload_exception.dart @@ -0,0 +1 @@ +class DataResponseIsNullException implements Exception {} \ No newline at end of file diff --git a/lib/features/upload/domain/model/upload_attachment.dart b/lib/features/upload/domain/model/upload_attachment.dart index bfbb97fa8..2dd3e248e 100644 --- a/lib/features/upload/domain/model/upload_attachment.dart +++ b/lib/features/upload/domain/model/upload_attachment.dart @@ -12,7 +12,7 @@ import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart'; import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; import 'package:dio/dio.dart'; -class UploadAttachment extends Equatable { +class UploadAttachment with EquatableMixin { final UploadTaskId uploadTaskId; final FileInfo fileInfo; @@ -35,31 +35,44 @@ class UploadAttachment extends Equatable { _progressStateController.add(flowUploadState); } - Future upload() async { - log('UploadFile::upload(): $uploadTaskId'); - _updateEvent(Right(PendingAttachmentUploadState(uploadTaskId, 0, fileInfo.fileSize))); + void upload() async { + try { + log('UploadFile::upload(): $uploadTaskId'); + _updateEvent(Right(PendingAttachmentUploadState(uploadTaskId, 0, fileInfo.fileSize))); - final attachment = await fileUploader.uploadAttachment( + final attachment = await fileUploader.uploadAttachment( uploadTaskId, _progressStateController, fileInfo, uploadUri, - cancelToken: cancelToken); + cancelToken: cancelToken + ); - if (cancelToken?.isCancelled == true) { - _updateEvent(Left(CancelAttachmentUploadState(uploadTaskId))); - await _progressStateController.close(); - return; - } + if (cancelToken?.isCancelled == true) { + _updateEvent(Left(CancelAttachmentUploadState(uploadTaskId))); + await _progressStateController.close(); + return; + } - if (attachment != null) { - _updateEvent(Right(SuccessAttachmentUploadState(uploadTaskId, attachment, fileInfo))); - } else { + if (attachment != null) { + _updateEvent(Right(SuccessAttachmentUploadState(uploadTaskId, attachment, fileInfo))); + } else { + _updateEvent(Left(ErrorAttachmentUploadState(uploadTaskId))); + } + } catch (e) { + logError('UploadAttachment::upload():ERROR: $e'); _updateEvent(Left(ErrorAttachmentUploadState(uploadTaskId))); + } finally { + await _progressStateController.close(); } - await _progressStateController.close(); } @override - List get props => [uploadTaskId, fileInfo, uploadUri]; + List get props => [ + uploadTaskId, + fileInfo, + uploadUri, + fileUploader, + cancelToken + ]; } \ No newline at end of file diff --git a/lib/features/upload/presentation/controller/upload_controller.dart b/lib/features/upload/presentation/controller/upload_controller.dart index c5e8c85f7..5940507c9 100644 --- a/lib/features/upload/presentation/controller/upload_controller.dart +++ b/lib/features/upload/presentation/controller/upload_controller.dart @@ -15,10 +15,13 @@ import 'package:model/email/attachment.dart'; import 'package:model/extensions/attachment_extension.dart'; import 'package:model/extensions/list_attachment_extension.dart'; import 'package:model/upload/file_info.dart'; +import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_state.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart'; import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; +import 'package:tmail_ui_user/features/upload/presentation/extensions/upload_attachment_extension.dart'; import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart'; import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state_list.dart'; import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart'; @@ -26,7 +29,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:uuid/uuid.dart'; -class UploadController extends GetxController { +class UploadController extends BaseController { final _imagePaths = Get.find(); final _appToast = Get.find(); @@ -125,6 +128,14 @@ class UploadController extends GetxController { if (failure is ErrorAttachmentUploadState) { uploadInlineViewState.value = Left(failure); _deleteInlineFileUploaded(failure.uploadId); + if (currentContext != null && currentOverlayContext != null) { + _appToast.showToastWithIcon(currentOverlayContext!, + message: AppLocalizations.of(currentContext!).thisImageCannotBeAdded, + textColor: AppColor.toastErrorBackgroundColor, + iconColor: AppColor.toastErrorBackgroundColor, + icon: _imagePaths.icInsertImage + ); + } } }, (success) { @@ -185,28 +196,21 @@ class UploadController extends GetxController { _refreshListUploadAttachmentState(); } - Future justUploadAttachmentsAction(List uploadFiles, Uri uploadUri) async { + Future justUploadAttachmentsAction(List uploadFiles, Uri uploadUri) { return Future.forEach(uploadFiles, (uploadFile) async { - await _uploadFile(uploadFile, uploadUri); + await uploadFileAction(uploadFile, uploadUri); }); } - Future _uploadFile(FileInfo uploadFile, Uri uploadUri) async { - log('UploadAttachmentManager::_uploadFile(): ${uploadFile.fileName}'); - - final cancelToken = CancelToken(); - final uploadAttachment = _uploadAttachmentInteractor.execute( - uploadFile, uploadUri, - cancelToken: cancelToken); - - _uploadingStateFiles.add(UploadFileState( - uploadAttachment.uploadTaskId, - file: uploadFile, - cancelToken: cancelToken)); - - await _progressUploadStateStreamGroup.add(uploadAttachment.progressState); - - _refreshListUploadAttachmentState(); + Future uploadFileAction(FileInfo uploadFile, Uri uploadUri, {bool isInline = false}) { + log('UploadController::_uploadFile():fileName: ${uploadFile.fileName}'); + consumeState(_uploadAttachmentInteractor.execute( + uploadFile, + uploadUri, + cancelToken: CancelToken(), + isInline: isInline + )); + return Future.value(); } void _refreshListUploadAttachmentState() { @@ -258,19 +262,19 @@ class UploadController extends GetxController { bool hasEnoughMaxAttachmentSize({List? listFiles}) { final currentTotalAttachmentsSize = attachmentsUploaded.totalSize(); final totalInlineAttachmentsSize = inlineAttachmentsUploaded.totalSize(); - log('ComposerController::_validateAttachmentsSize(): $currentTotalAttachmentsSize'); - log('ComposerController::_validateAttachmentsSize(): totalInlineAttachmentsSize: $totalInlineAttachmentsSize'); + log('UploadController::_validateAttachmentsSize(): $currentTotalAttachmentsSize'); + log('UploadController::_validateAttachmentsSize(): totalInlineAttachmentsSize: $totalInlineAttachmentsSize'); num uploadedTotalSize = 0; if (listFiles != null && listFiles.isNotEmpty) { final uploadedListSize = listFiles.map((file) => file.fileSize).toList(); uploadedTotalSize = uploadedListSize.reduce((sum, size) => sum + size); - log('ComposerController::_validateAttachmentsSize(): uploadedTotalSize: $uploadedTotalSize'); + log('UploadController::_validateAttachmentsSize(): uploadedTotalSize: $uploadedTotalSize'); } final totalSizeReadyToUpload = currentTotalAttachmentsSize + totalInlineAttachmentsSize + uploadedTotalSize; - log('ComposerController::_validateAttachmentsSize(): totalSizeReadyToUpload: $totalSizeReadyToUpload'); + log('UploadController::_validateAttachmentsSize(): totalSizeReadyToUpload: $totalSizeReadyToUpload'); final maxSizeAttachmentsPerEmail = _mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value; if (maxSizeAttachmentsPerEmail != null) { @@ -285,23 +289,6 @@ class UploadController extends GetxController { .every((uploadFile) => uploadFile.uploadStatus.completed); } - Future uploadInlineImage(FileInfo uploadFile, Uri uploadUri) async { - log('UploadAttachmentManager::uploadInlineImage(): ${uploadFile.fileName}'); - - final cancelToken = CancelToken(); - final uploadAttachment = _uploadAttachmentInteractor.execute( - uploadFile, - uploadUri, - cancelToken: cancelToken); - - _uploadingStateInlineFiles.add(UploadFileState( - uploadAttachment.uploadTaskId, - file: uploadFile, - cancelToken: cancelToken)); - - await _progressUploadInlineImageStateStreamGroup.add(uploadAttachment.progressState); - } - void _deleteInlineFileUploaded(UploadTaskId uploadId) { _uploadingStateInlineFiles.deleteElementByUploadTaskId(uploadId); } @@ -350,4 +337,48 @@ class UploadController extends GetxController { return mapInlineAttachments; } + + @override + void onDone() { + viewState.value.fold(_handleFailureViewState, _handleSuccessViewState); + } + + void _handleFailureViewState(Failure failure) async { + logError('UploadController::_handleFailureViewState():failure: $failure'); + if (failure is UploadAttachmentFailure) { + if (failure.isInline) { + if (currentContext != null && currentOverlayContext != null) { + _appToast.showToastWithIcon(currentOverlayContext!, + message: AppLocalizations.of(currentContext!).thisImageCannotBeAdded, + textColor: AppColor.toastErrorBackgroundColor, + iconColor: AppColor.toastErrorBackgroundColor, + icon: _imagePaths.icInsertImage + ); + } + } else { + if (currentContext != null && currentOverlayContext != null) { + _appToast.showToastWithIcon(currentOverlayContext!, + message: AppLocalizations.of(currentContext!).can_not_upload_this_file_as_attachments, + textColor: AppColor.toastErrorBackgroundColor, + iconColor: AppColor.toastErrorBackgroundColor, + icon: _imagePaths.icAttachment + ); + } + } + } + } + + void _handleSuccessViewState(Success success) async { + log('UploadController::_handleSuccessViewState():success: $success'); + if (success is UploadAttachmentSuccess) { + if (success.isInline) { + _uploadingStateInlineFiles.add(success.uploadAttachment.toUploadFileState()); + await _progressUploadInlineImageStateStreamGroup.add(success.uploadAttachment.progressState); + } else { + _uploadingStateFiles.add(success.uploadAttachment.toUploadFileState()); + await _progressUploadStateStreamGroup.add(success.uploadAttachment.progressState); + _refreshListUploadAttachmentState(); + } + } + } } \ No newline at end of file diff --git a/lib/features/upload/presentation/extensions/upload_attachment_extension.dart b/lib/features/upload/presentation/extensions/upload_attachment_extension.dart new file mode 100644 index 000000000..b03f846b9 --- /dev/null +++ b/lib/features/upload/presentation/extensions/upload_attachment_extension.dart @@ -0,0 +1,14 @@ + +import 'package:tmail_ui_user/features/upload/domain/model/upload_attachment.dart'; +import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart'; + +extension UploadAttachmentExtension on UploadAttachment { + + UploadFileState toUploadFileState() { + return UploadFileState( + uploadTaskId, + file: fileInfo, + cancelToken: cancelToken + ); + } +} \ No newline at end of file diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 0853723a9..1d5490a56 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-02-03T11:24:09.273116", + "@@last_modified": "2023-02-03T16:28:53.514637", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2679,5 +2679,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "thisImageCannotBeAdded": "This image cannot be added.", + "@thisImageCannotBeAdded": { + "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 3d91407be..94eafd9e0 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2754,7 +2754,7 @@ class AppLocalizations { name: 'saveEmailAsDraftFailureWithSetErrorTypeOverQuota', ); } - + String get mailBoxes { return Intl.message( 'Mailboxes', @@ -2772,4 +2772,11 @@ class AppLocalizations { 'Hide mailbox', name: 'hideMailBoxes'); } + + String get thisImageCannotBeAdded { + return Intl.message( + 'This image cannot be added.', + name: 'thisImageCannotBeAdded' + ); + } } \ No newline at end of file diff --git a/lib/main/routes/route_utils.dart b/lib/main/routes/route_utils.dart index a086f0380..31afd4a7a 100644 --- a/lib/main/routes/route_utils.dart +++ b/lib/main/routes/route_utils.dart @@ -1,8 +1,8 @@ -import 'package:core/core.dart'; import 'package:core/data/model/query/query_parameter.dart'; import 'package:core/data/network/config/service_path.dart'; import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/build_utils.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';