TF-725 Handle upload inline image to server
This commit is contained in:
@@ -53,7 +53,7 @@ class UploadAttachment extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
_updateEvent(Right(SuccessAttachmentUploadState(uploadTaskId, attachment)));
|
_updateEvent(Right(SuccessAttachmentUploadState(uploadTaskId, attachment, fileInfo)));
|
||||||
} else {
|
} else {
|
||||||
_updateEvent(Left(ErrorAttachmentUploadState(uploadTaskId)));
|
_updateEvent(Left(ErrorAttachmentUploadState(uploadTaskId)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
import 'package:model/email/attachment.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';
|
import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
|
||||||
|
|
||||||
class PendingAttachmentUploadState extends Success {
|
class PendingAttachmentUploadState extends Success {
|
||||||
@@ -29,11 +30,12 @@ class UploadingAttachmentUploadState extends Success {
|
|||||||
class SuccessAttachmentUploadState extends Success {
|
class SuccessAttachmentUploadState extends Success {
|
||||||
final UploadTaskId uploadId;
|
final UploadTaskId uploadId;
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
|
final FileInfo fileInfo;
|
||||||
|
|
||||||
SuccessAttachmentUploadState(this.uploadId, this.attachment);
|
SuccessAttachmentUploadState(this.uploadId, this.attachment, this.fileInfo);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uploadId, attachment];
|
List<Object?> get props => [uploadId, attachment, fileInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ErrorAttachmentUploadState extends Failure {
|
class ErrorAttachmentUploadState extends Failure {
|
||||||
|
|||||||
@@ -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/features/upload/presentation/model/upload_file_status.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class UploadController extends GetxController {
|
class UploadController extends GetxController {
|
||||||
|
|
||||||
final _imagePaths = Get.find<ImagePaths>();
|
final _imagePaths = Get.find<ImagePaths>();
|
||||||
final _appToast = Get.find<AppToast>();
|
final _appToast = Get.find<AppToast>();
|
||||||
|
final _uuid = Get.find<Uuid>();
|
||||||
final _mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
final _mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||||
|
|
||||||
final UploadAttachmentInteractor _uploadAttachmentInteractor;
|
final UploadAttachmentInteractor _uploadAttachmentInteractor;
|
||||||
|
|
||||||
final listUploadAttachments = <UploadFileState>[].obs;
|
final listUploadAttachments = <UploadFileState>[].obs;
|
||||||
|
final uploadInlineViewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
|
||||||
|
|
||||||
final StreamGroup<Either<Failure, Success>> _progressUploadStateStreamGroup
|
final StreamGroup<Either<Failure, Success>> _progressUploadStateStreamGroup
|
||||||
= StreamGroup<Either<Failure, Success>>.broadcast();
|
= StreamGroup<Either<Failure, Success>>.broadcast();
|
||||||
|
final StreamGroup<Either<Failure, Success>> _progressUploadInlineImageStateStreamGroup
|
||||||
|
= StreamGroup<Either<Failure, Success>>.broadcast();
|
||||||
|
|
||||||
final UploadFileStateList _uploadingStateFiles = UploadFileStateList();
|
final UploadFileStateList _uploadingStateFiles = UploadFileStateList();
|
||||||
|
final UploadFileStateList _uploadingStateInlineFiles = UploadFileStateList();
|
||||||
|
|
||||||
UploadController(this._uploadAttachmentInteractor);
|
UploadController(this._uploadAttachmentInteractor);
|
||||||
|
|
||||||
@@ -52,11 +58,14 @@ class UploadController extends GetxController {
|
|||||||
void onClose() {
|
void onClose() {
|
||||||
_uploadingStateFiles.clear();
|
_uploadingStateFiles.clear();
|
||||||
_progressUploadStateStreamGroup.close();
|
_progressUploadStateStreamGroup.close();
|
||||||
|
_uploadingStateInlineFiles.clear();
|
||||||
|
_progressUploadInlineImageStateStreamGroup.close();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _registerProgressUploadStateStream() {
|
void _registerProgressUploadStateStream() {
|
||||||
_progressUploadStateStreamGroup.stream.listen(_handleProgressUploadStateStream);
|
_progressUploadStateStreamGroup.stream.listen(_handleProgressUploadStateStream);
|
||||||
|
_progressUploadInlineImageStateStreamGroup.stream.listen(_handleProgressUploadInlineImageStateStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleProgressUploadStateStream(Either<Failure, Success> uploadState) {
|
void _handleProgressUploadStateStream(Either<Failure, Success> uploadState) {
|
||||||
@@ -103,12 +112,67 @@ class UploadController extends GetxController {
|
|||||||
);
|
);
|
||||||
|
|
||||||
_refreshListUploadAttachmentState();
|
_refreshListUploadAttachmentState();
|
||||||
_handleUploadAttachmentsSuccess(success);
|
if (success.attachment.disposition == ContentDisposition.attachment) {
|
||||||
|
_handleUploadAttachmentsSuccess(success);
|
||||||
|
} else {
|
||||||
|
_handleUploadInlineAttachmentsSuccess(success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleProgressUploadInlineImageStateStream(Either<Failure, Success> 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<Attachment> attachments) {
|
void initializeUploadAttachments(List<Attachment> attachments) {
|
||||||
final listUploadFilesState = attachments
|
final listUploadFilesState = attachments
|
||||||
.map((attachment) => UploadFileState(
|
.map((attachment) => UploadFileState(
|
||||||
@@ -170,8 +234,9 @@ class UploadController extends GetxController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return attachmentsUploaded
|
return attachmentsUploaded
|
||||||
.map((attachment) => attachment.toEmailBodyPart(ContentDisposition.attachment.value))
|
.map((attachment) => attachment.toEmailBodyPart(
|
||||||
.toSet();
|
disposition: ContentDisposition.attachment.value))
|
||||||
|
.toSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleUploadAttachmentsFailure(ErrorAttachmentUploadState failure) {
|
void _handleUploadAttachmentsFailure(ErrorAttachmentUploadState failure) {
|
||||||
@@ -185,6 +250,7 @@ class UploadController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleUploadAttachmentsSuccess(SuccessAttachmentUploadState success) {
|
void _handleUploadAttachmentsSuccess(SuccessAttachmentUploadState success) {
|
||||||
|
log('UploadController::_handleUploadAttachmentsSuccess(): $success');
|
||||||
if (currentContext != null && currentOverlayContext != null && _uploadingStateFiles.allSuccess) {
|
if (currentContext != null && currentOverlayContext != null && _uploadingStateFiles.allSuccess) {
|
||||||
_appToast.showToastWithIcon(currentOverlayContext!,
|
_appToast.showToastWithIcon(currentOverlayContext!,
|
||||||
message: AppLocalizations.of(currentContext!).attachments_uploaded_successfully,
|
message: AppLocalizations.of(currentContext!).attachments_uploaded_successfully,
|
||||||
@@ -218,4 +284,58 @@ class UploadController extends GetxController {
|
|||||||
return listUploadAttachments
|
return listUploadAttachments
|
||||||
.every((uploadFile) => uploadFile.uploadStatus.completed);
|
.every((uploadFile) => uploadFile.uploadStatus.completed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> 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<String, Attachment> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user