From d416f858c7afc2f50a6705bf1b2477e559c8c1d7 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 20 Jul 2022 16:47:32 +0700 Subject: [PATCH] TF-725 Handle upload inline image to server --- .../domain/model/upload_attachment.dart | 2 +- .../domain/state/attachment_upload_state.dart | 6 +- .../controller/upload_controller.dart | 126 +++++++++++++++++- 3 files changed, 128 insertions(+), 6 deletions(-) diff --git a/lib/features/upload/domain/model/upload_attachment.dart b/lib/features/upload/domain/model/upload_attachment.dart index 425b512e4..bfbb97fa8 100644 --- a/lib/features/upload/domain/model/upload_attachment.dart +++ b/lib/features/upload/domain/model/upload_attachment.dart @@ -53,7 +53,7 @@ class UploadAttachment extends Equatable { } if (attachment != null) { - _updateEvent(Right(SuccessAttachmentUploadState(uploadTaskId, attachment))); + _updateEvent(Right(SuccessAttachmentUploadState(uploadTaskId, attachment, fileInfo))); } else { _updateEvent(Left(ErrorAttachmentUploadState(uploadTaskId))); } diff --git a/lib/features/upload/domain/state/attachment_upload_state.dart b/lib/features/upload/domain/state/attachment_upload_state.dart index f842b47b8..c4794f6ab 100644 --- a/lib/features/upload/domain/state/attachment_upload_state.dart +++ b/lib/features/upload/domain/state/attachment_upload_state.dart @@ -2,6 +2,7 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:model/email/attachment.dart'; +import 'package:model/upload/file_info.dart'; import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart'; class PendingAttachmentUploadState extends Success { @@ -29,11 +30,12 @@ class UploadingAttachmentUploadState extends Success { class SuccessAttachmentUploadState extends Success { final UploadTaskId uploadId; final Attachment attachment; + final FileInfo fileInfo; - SuccessAttachmentUploadState(this.uploadId, this.attachment); + SuccessAttachmentUploadState(this.uploadId, this.attachment, this.fileInfo); @override - List get props => [uploadId, attachment]; + List get props => [uploadId, attachment, fileInfo]; } class ErrorAttachmentUploadState extends Failure { diff --git a/lib/features/upload/presentation/controller/upload_controller.dart b/lib/features/upload/presentation/controller/upload_controller.dart index dcf14e231..b8c4921af 100644 --- a/lib/features/upload/presentation/controller/upload_controller.dart +++ b/lib/features/upload/presentation/controller/upload_controller.dart @@ -24,21 +24,27 @@ import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_sta import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart'; 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 { final _imagePaths = Get.find(); final _appToast = Get.find(); + final _uuid = Get.find(); final _mailboxDashBoardController = Get.find(); final UploadAttachmentInteractor _uploadAttachmentInteractor; final listUploadAttachments = [].obs; + final uploadInlineViewState = Rx>(Right(UIState.idle)); final StreamGroup> _progressUploadStateStreamGroup = StreamGroup>.broadcast(); + final StreamGroup> _progressUploadInlineImageStateStreamGroup + = StreamGroup>.broadcast(); final UploadFileStateList _uploadingStateFiles = UploadFileStateList(); + final UploadFileStateList _uploadingStateInlineFiles = UploadFileStateList(); UploadController(this._uploadAttachmentInteractor); @@ -52,11 +58,14 @@ class UploadController extends GetxController { void onClose() { _uploadingStateFiles.clear(); _progressUploadStateStreamGroup.close(); + _uploadingStateInlineFiles.clear(); + _progressUploadInlineImageStateStreamGroup.close(); super.onClose(); } void _registerProgressUploadStateStream() { _progressUploadStateStreamGroup.stream.listen(_handleProgressUploadStateStream); + _progressUploadInlineImageStateStreamGroup.stream.listen(_handleProgressUploadInlineImageStateStream); } void _handleProgressUploadStateStream(Either uploadState) { @@ -103,12 +112,67 @@ class UploadController extends GetxController { ); _refreshListUploadAttachmentState(); - _handleUploadAttachmentsSuccess(success); + if (success.attachment.disposition == ContentDisposition.attachment) { + _handleUploadAttachmentsSuccess(success); + } else { + _handleUploadInlineAttachmentsSuccess(success); + } } } ); } + void _handleProgressUploadInlineImageStateStream(Either uploadState) { + uploadState.fold( + (failure) { + log('UploadController::_handleProgressUploadInlineImageStateStream():failure: $failure'); + if (failure is ErrorAttachmentUploadState) { + uploadInlineViewState.value = Left(failure); + _deleteInlineFileUploaded(failure.uploadId); + } + }, + (success) { + if (success is UploadingAttachmentUploadState) { + log('UploadController::_handleProgressUploadInlineImageStateStream():uploading[${success.uploadId}]: ${success.progress}'); + _uploadingStateInlineFiles.updateElementByUploadTaskId( + success.uploadId, + (currentState) { + if (currentState?.uploadStatus.completed ?? false) { + return currentState; + } else { + return currentState?.copyWith( + uploadingProgress: (success.progress * 100 / success.total).floor(), + uploadStatus: UploadFileStatus.uploading); + } + } + ); + uploadInlineViewState.value = Right(success); + } else if (success is SuccessAttachmentUploadState) { + log('UploadController::_handleProgressUploadInlineImageStateStream():succeed[${success.uploadId}]'); + final inlineAttachment = success.attachment.toAttachmentWithDisposition( + disposition: ContentDisposition.inline, + cid: _uuid.v1()); + _uploadingStateInlineFiles.updateElementByUploadTaskId( + success.uploadId, + (currentState) { + final newState = currentState?.copyWith( + uploadingProgress: 100, + uploadStatus: UploadFileStatus.succeed, + attachment: inlineAttachment + ); + return newState; + }, + ); + final newUploadSuccess = SuccessAttachmentUploadState( + success.uploadId, + inlineAttachment, + success.fileInfo); + _handleUploadInlineAttachmentsSuccess(newUploadSuccess); + } + } + ); + } + void initializeUploadAttachments(List attachments) { final listUploadFilesState = attachments .map((attachment) => UploadFileState( @@ -170,8 +234,9 @@ class UploadController extends GetxController { return null; } return attachmentsUploaded - .map((attachment) => attachment.toEmailBodyPart(ContentDisposition.attachment.value)) - .toSet(); + .map((attachment) => attachment.toEmailBodyPart( + disposition: ContentDisposition.attachment.value)) + .toSet(); } void _handleUploadAttachmentsFailure(ErrorAttachmentUploadState failure) { @@ -185,6 +250,7 @@ class UploadController extends GetxController { } void _handleUploadAttachmentsSuccess(SuccessAttachmentUploadState success) { + log('UploadController::_handleUploadAttachmentsSuccess(): $success'); if (currentContext != null && currentOverlayContext != null && _uploadingStateFiles.allSuccess) { _appToast.showToastWithIcon(currentOverlayContext!, message: AppLocalizations.of(currentContext!).attachments_uploaded_successfully, @@ -218,4 +284,58 @@ class UploadController extends GetxController { return listUploadAttachments .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); + } + + void clearInlineFileUploaded() { + _uploadingStateInlineFiles.clear(); + } + + void _handleUploadInlineAttachmentsSuccess(SuccessAttachmentUploadState success) { + uploadInlineViewState.value = Right(success); + } + + void clearUploadInlineViewState() { + uploadInlineViewState.value = Right(UIState.idle); + } + + Map get mapInlineAttachments { + final inlineAttachments = _uploadingStateInlineFiles.uploadingStateFiles + .whereNotNull() + .map((fileState) => fileState.attachment) + .whereNotNull() + .where((attachment) => attachment.cid != null) + .toList(); + + log('UploadController::mapInlineAttachments(): $inlineAttachments'); + + if (inlineAttachments.isEmpty) { + return {}; + } + + final mapInlineAttachments = { + for (var item in inlineAttachments) item.cid!: item + }; + + return mapInlineAttachments; + } } \ No newline at end of file