From e050042e2c765f211592d84212c25421636202c3 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 28 Jul 2022 14:36:37 +0700 Subject: [PATCH] TF-761 Implement reduce image size when add inline image --- .../presentation/composer_controller.dart | 61 +++++++++++-------- .../composer/presentation/composer_view.dart | 32 +++------- .../presentation/composer_view_web.dart | 29 ++------- .../rich_text_mobile_tablet_controller.dart | 10 ++- .../controller/rich_text_web_controller.dart | 8 +-- .../mixin/composer_loading_mixin.dart | 45 ++++++++++++++ .../presentation/model/inline_image.dart | 18 +----- .../upload/data/network/file_uploader.dart | 2 +- .../controller/upload_controller.dart | 24 ++++++-- lib/main/bindings/core/core_bindings.dart | 1 + .../bindings/network/network_bindings.dart | 2 +- model/lib/upload/file_info.dart | 7 ++- 12 files changed, 129 insertions(+), 110 deletions(-) create mode 100644 lib/features/composer/presentation/mixin/composer_loading_mixin.dart diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index e044a96c5..97833f600 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -256,16 +256,14 @@ class ComposerController extends BaseController { ImageSource.local, fileInfo: success.fileInfo, cid: success.cid, - base64: success.imageAsBase64), - maxWithEditor: maxWithEditor); + base64Uri: success.base64Uri)); } else { richTextMobileTabletController.insertImage( InlineImage( ImageSource.local, fileInfo: success.fileInfo, cid: success.cid, - base64: success.imageAsBase64), - maxWithEditor: maxWithEditor); + base64Uri: success.base64Uri)); } maxWithEditor = null; } @@ -337,7 +335,8 @@ class ComposerController extends BaseController { void _initAttachments(ComposerArguments arguments) { if (arguments.attachments?.isNotEmpty == true) { initialAttachments = arguments.attachments!; - uploadController.initializeUploadAttachments(arguments.attachments!); + uploadController.initializeUploadAttachments( + arguments.attachments!.listAttachmentsDisplayedOutSide); } if (BuildUtils.isWeb) { expandModeAttachments.value = ExpandMode.EXPAND; @@ -538,19 +537,22 @@ class ComposerController extends BaseController { final generatePartId = PartId(_uuid.v1()); final generateBlobId = Id(_uuid.v1()); - var emailBodyText = await _getEmailBodyText(context); - final mapContents = await _getMapContent(emailBodyText); - log('ComposerController::_generateEmail(): mapContents: $mapContents'); - emailBodyText = mapContents.value1; - final listInlineAttachment = mapContents.value2; - final listInlineEmailBodyPart = listInlineAttachment - .map((attachment) => attachment.toEmailBodyPart(charset: 'base64')) - .toSet(); - final attachments = {}; attachments.addAll(uploadController.generateAttachments() ?? []); - attachments.addAll(listInlineEmailBodyPart); - log('ComposerController::_generateEmail(): listInlineEmailBodyPart: $listInlineEmailBodyPart'); + + var emailBodyText = await _getEmailBodyText(context); + + if (uploadController.mapInlineAttachments.isNotEmpty) { + final mapContents = await _getMapContent(emailBodyText); + log('ComposerController::_generateEmail(): mapContents: $mapContents'); + emailBodyText = mapContents.value1; + final listInlineAttachment = mapContents.value2; + final listInlineEmailBodyPart = listInlineAttachment + .map((attachment) => attachment.toEmailBodyPart(charset: 'base64')) + .toSet(); + attachments.addAll(listInlineEmailBodyPart); + log('ComposerController::_generateEmail(): listInlineEmailBodyPart: $listInlineEmailBodyPart'); + } final userAgent = await userAgentPlatform; log('ComposerController::_generateEmail(): userAgent: $userAgent'); @@ -915,7 +917,8 @@ class ComposerController extends BaseController { void _getEmailContentSuccess(GetEmailContentSuccess success) { if (success.attachments.isNotEmpty) { initialAttachments = success.attachments; - uploadController.initializeUploadAttachments(success.attachments); + uploadController.initializeUploadAttachments( + success.attachments.listAttachmentsDisplayedOutSide); } emailContentsViewState.value = Right(success); _emailContents = success.emailContents; @@ -1133,11 +1136,16 @@ class ComposerController extends BaseController { } } - void insertImage(BuildContext context, {double? maxWithEditor}) async { + void insertImage(BuildContext context, double maxWith) async { + if (_responsiveUtils.isMobile(context)) { + maxWithEditor = maxWith - 40; + } else { + maxWithEditor = maxWith - 120; + } final inlineImage = await _selectFromFile(); - if(inlineImage != null) { - this.maxWithEditor = maxWithEditor; - if(kIsWeb) { + log('ComposerController::insertImage(): $inlineImage'); + if (inlineImage != null) { + if (BuildUtils.isWeb) { _insertImageOnWeb(inlineImage); } else { _insertImageOnMobileAndTablet(inlineImage); @@ -1148,15 +1156,17 @@ class ComposerController extends BaseController { Future _selectFromFile() async { final filePickerResult = await FilePicker.platform.pickFiles( type: FileType.image, - withReadStream: true); + withData: !BuildUtils.isWeb, + withReadStream: BuildUtils.isWeb); final platformFile = filePickerResult?.files.single; if (platformFile != null) { - final fileSelected = FileInfo( + final fileSelected = FileInfo( platformFile.name, BuildUtils.isWeb ? '' : platformFile.path ?? '', platformFile.size, + bytes: platformFile.bytes, readStream: platformFile.readStream); - return InlineImage(ImageSource.local, fileInfo: fileSelected); + return InlineImage(ImageSource.local, fileInfo: fileSelected); } return null; @@ -1212,7 +1222,8 @@ class ComposerController extends BaseController { consumeState(_downloadImageAsBase64Interactor.execute( imageUrl, uploadState.attachment.cid!, - uploadState.fileInfo)); + uploadState.fileInfo, + maxWidth: maxWithEditor)); } } diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index 5f5324e22..7b4c67d42 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -11,21 +11,21 @@ import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; -import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_base64_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/composer/presentation/mixin/composer_loading_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/mixin/rich_text_button_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/header_style_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/drop_down_menu_header_style_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart'; -import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; import 'package:tmail_ui_user/features/upload/presentation/extensions/list_upload_file_state_extension.dart'; import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -class ComposerView extends GetWidget with AppLoaderMixin, RichTextButtonMixin { +class ComposerView extends GetWidget + with AppLoaderMixin, RichTextButtonMixin, ComposerLoadingMixin { final responsiveUtils = Get.find(); final imagePaths = Get.find(); @@ -390,9 +390,7 @@ class ComposerView extends GetWidget with AppLoaderMixin, Ri color: AppColor.colorTextButton, fit: BoxFit.fill), tooltip: AppLocalizations.of(context).insertImage, - onTap: () => controller.insertImage( - context, - maxWithEditor: constraints.maxWidth - 120)) + onTap: () => controller.insertImage(context, constraints.maxWidth)) ]) ) ); @@ -417,7 +415,7 @@ class ComposerView extends GetWidget with AppLoaderMixin, Ri const Divider(color: AppColor.colorDividerComposer, height: 1), _buildAttachmentsWidget(context), _buildToolbarMobileWidget(context), - _buildInlineLoadingView(), + buildInlineLoadingView(controller), _buildComposerEditor(context), ]), ) @@ -462,7 +460,7 @@ class ComposerView extends GetWidget with AppLoaderMixin, Ri child: Column(children: [ _buildToolbarRichTextWidget(context), _buildAttachmentsWidget(context), - _buildInlineLoadingView(), + buildInlineLoadingView(controller), _buildComposerEditor(context), ]) ) @@ -493,21 +491,6 @@ class ComposerView extends GetWidget with AppLoaderMixin, Ri }); } - Widget _buildInlineLoadingView() { - return Obx(() => controller.uploadController.uploadInlineViewState.value.fold( - (failure) => const SizedBox.shrink(), - (success) { - if (success is UploadingAttachmentUploadState || success is DownloadingImageAsBase64) { - return Padding( - padding: const EdgeInsets.all(5), - child: loadingWidgetWithSizeColor( - size: 30, - color: AppColor.primaryColor)); - } - return const SizedBox.shrink(); - })); - } - Widget _buildToolbarRichTextWidget(BuildContext context) { return Obx(() { final richTextMobileTabletController = controller.richTextMobileTabletController; @@ -788,7 +771,6 @@ class ComposerView extends GetWidget with AppLoaderMixin, Ri ], ), ); - }, - ); + }); } } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 8315d492d..b9341cd12 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -11,9 +11,9 @@ import 'package:model/model.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.dart'; -import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_base64_state.dart'; import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/composer/presentation/mixin/composer_loading_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/mixin/rich_text_button_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/dropdown_menu_font_status.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.dart'; @@ -25,14 +25,13 @@ import 'package:tmail_ui_user/features/composer/presentation/model/screen_displa import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/drop_down_menu_header_style_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart'; -import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; import 'package:tmail_ui_user/features/upload/presentation/extensions/list_upload_file_state_extension.dart'; import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class ComposerView extends GetWidget - with AppLoaderMixin, RichTextButtonMixin { + with AppLoaderMixin, RichTextButtonMixin, ComposerLoadingMixin { final responsiveUtils = Get.find(); final imagePaths = Get.find(); @@ -74,7 +73,7 @@ class ComposerView extends GetWidget children: [ _buildAttachmentsWidget(context), _buildToolbarRichTextWidget(context), - _buildInlineLoadingView(), + buildInlineLoadingView(controller), _buildEditorForm(context) ] )), @@ -308,7 +307,7 @@ class ComposerView extends GetWidget children: [ _buildAttachmentsWidget(context), _buildToolbarRichTextWidget(context), - _buildInlineLoadingView(), + buildInlineLoadingView(controller), _buildEditorForm(context) ] ))), @@ -525,9 +524,7 @@ class ComposerView extends GetWidget color: AppColor.colorTextButton.withOpacity(opacity), fit: BoxFit.fill), tooltip: AppLocalizations.of(context).insertImage, - onTap: () => controller.insertImage( - context, - maxWithEditor: constraints.maxWidth - 120)), + onTap: () => controller.insertImage(context, constraints.maxWidth)), ); }), const SizedBox(width: 4), @@ -955,20 +952,4 @@ class ComposerView extends GetWidget ); }); } - - Widget _buildInlineLoadingView() { - return Obx(() => controller.uploadController.uploadInlineViewState.value.fold( - (failure) => const SizedBox.shrink(), - (success) { - if (success is UploadingAttachmentUploadState || - success is DownloadingImageAsBase64) { - return Padding( - padding: const EdgeInsets.all(5), - child: loadingWidgetWithSizeColor( - size: 30, - color: AppColor.primaryColor)); - } - return const SizedBox.shrink(); - })); - } } \ No newline at end of file diff --git a/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart b/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart index d11b3964f..0c5e3fc5b 100644 --- a/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart +++ b/lib/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart @@ -19,7 +19,7 @@ class RichTextMobileTabletController extends BaseRichTextController { final selectedTextColor = Colors.black.obs; final selectedTextBackgroundColor = Colors.white.obs; final selectedFontName = SafeFont.sansSerif.obs; - + final menuHeaderStyleStatus = DropdownMenuFontStatus.closed.obs; bool get isMenuHeaderStyleOpen => menuHeaderStyleStatus.value == DropdownMenuFontStatus.open; @@ -106,7 +106,7 @@ class RichTextMobileTabletController extends BaseRichTextController { Future>> refactorContentHasInlineImage( String emailContent, Map mapInlineAttachments - ) async { + ) async { final document = parse(emailContent); final listImgTag = document.querySelectorAll('img[src^="data:image/"]'); final listInlineAttachment = await Future.wait(listImgTag.map((imgTag) async { @@ -145,9 +145,7 @@ class RichTextMobileTabletController extends BaseRichTextController { if (image.source == ImageSource.network) { htmlEditorApi?.insertImageLink(image.link!); } else { - final htmlContent = await image.generateImgTagHtml(maxWithEditor: maxWithEditor); - log('RichTextMobileTabletController::insertImage(): $htmlContent'); - htmlEditorApi?.insertHtml(htmlContent); + htmlEditorApi?.insertHtml(image.base64Uri ?? ''); } } @@ -156,4 +154,4 @@ class RichTextMobileTabletController extends BaseRichTextController { htmlEditorApi?.formatHeader(styleSelected.styleValue); } -} +} \ No newline at end of file diff --git a/lib/features/composer/presentation/controller/rich_text_web_controller.dart b/lib/features/composer/presentation/controller/rich_text_web_controller.dart index de577f087..daa64f315 100644 --- a/lib/features/composer/presentation/controller/rich_text_web_controller.dart +++ b/lib/features/composer/presentation/controller/rich_text_web_controller.dart @@ -155,14 +155,12 @@ class RichTextWebController extends BaseRichTextController { bool isTextStyleTypeSelected(RichTextStyleType richTextStyleType) => listTextStyleApply.contains(richTextStyleType); - void insertImage(InlineImage image, {double? maxWithEditor}) async { - log('RichTextWebController::insertImage(): $image | maxWithEditor: $maxWithEditor'); + void insertImage(InlineImage image) async { + log('RichTextWebController::insertImage(): $image'); if (image.source == ImageSource.network) { editorController.insertNetworkImage(image.link!); } else { - final htmlContent = await image.generateImgTagHtml(maxWithEditor: maxWithEditor); - log('RichTextWebController::insertImage(): $htmlContent'); - editorController.insertHtml(htmlContent); + editorController.insertHtml(image.base64Uri ?? ''); } } diff --git a/lib/features/composer/presentation/mixin/composer_loading_mixin.dart b/lib/features/composer/presentation/mixin/composer_loading_mixin.dart new file mode 100644 index 000000000..01091239f --- /dev/null +++ b/lib/features/composer/presentation/mixin/composer_loading_mixin.dart @@ -0,0 +1,45 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_base64_state.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; + +mixin ComposerLoadingMixin { + + Widget _loadingWidgetWithSizeColor({double? size, Color? color}) { + return Center(child: Container( + margin: const EdgeInsets.all(10), + width: size ?? 24, + height: size ?? 24, + child: CircularProgressIndicator(color: color ?? AppColor.primaryColor))); + } + + Widget buildInlineLoadingView(ComposerController controller) { + return Obx(() => controller.uploadController.uploadInlineViewState.value.fold( + (failure) { + return controller.viewState.value.fold( + (failure) => const SizedBox.shrink(), + (success) { + if (success is DownloadingImageAsBase64) { + return _loadingWidgetWithSizeColor(); + } + return const SizedBox.shrink(); + }); + }, + (success) { + if (success is UploadingAttachmentUploadState) { + return _loadingWidgetWithSizeColor(); + } + return controller.viewState.value.fold( + (failure) => const SizedBox.shrink(), + (success) { + if (success is DownloadingImageAsBase64) { + return _loadingWidgetWithSizeColor(); + } + return const SizedBox.shrink(); + }); + })); + } +} \ No newline at end of file diff --git a/lib/features/composer/presentation/model/inline_image.dart b/lib/features/composer/presentation/model/inline_image.dart index 1650dd184..2dc8e33f0 100644 --- a/lib/features/composer/presentation/model/inline_image.dart +++ b/lib/features/composer/presentation/model/inline_image.dart @@ -1,5 +1,4 @@ -import 'package:core/presentation/extensions/html_extension.dart'; import 'package:equatable/equatable.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/image_source.dart'; @@ -9,7 +8,7 @@ class InlineImage with EquatableMixin { final String? link; final FileInfo? fileInfo; final String? cid; - final String? base64; + final String? base64Uri; InlineImage( this.source, @@ -17,21 +16,10 @@ class InlineImage with EquatableMixin { this.link, this.fileInfo, this.cid, - this.base64, + this.base64Uri, } ); - Future generateImgTagHtml({double? maxWithEditor}) async { - if (source == ImageSource.local && base64 != null) { - return base64!.generateImageBase64( - cid!, - fileInfo!.fileExtension, - fileInfo!.fileName, - maxWithEditor: maxWithEditor); - } - return ''; - } - @override - List get props => [source, link, fileInfo, cid]; + List get props => [source, link, fileInfo, cid, base64Uri]; } \ 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 5006631a6..149f6cff1 100644 --- a/lib/features/upload/data/network/file_uploader.dart +++ b/lib/features/upload/data/network/file_uploader.dart @@ -71,7 +71,7 @@ class FileUploader { final resultJson = await argsUpload.dioClient.post( Uri.decodeFull(uploadUri.toString()), options: Options(headers: headerParam), - data: fileInfo.readStream, + data: fileInfo.readStream ?? File(fileInfo.filePath).openRead(), cancelToken: cancelToken, onSendProgress: (progress, total) { log('FileUploader::_handleUploadAttachmentAction():onSendProgress: [${argsUpload.uploadId.id}] = $progress'); diff --git a/lib/features/upload/presentation/controller/upload_controller.dart b/lib/features/upload/presentation/controller/upload_controller.dart index b8c4921af..c5e8c85f7 100644 --- a/lib/features/upload/presentation/controller/upload_controller.dart +++ b/lib/features/upload/presentation/controller/upload_controller.dart @@ -112,11 +112,7 @@ class UploadController extends GetxController { ); _refreshListUploadAttachmentState(); - if (success.attachment.disposition == ContentDisposition.attachment) { - _handleUploadAttachmentsSuccess(success); - } else { - _handleUploadInlineAttachmentsSuccess(success); - } + _handleUploadAttachmentsSuccess(success); } } ); @@ -261,7 +257,9 @@ 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'); num uploadedTotalSize = 0; if (listFiles != null && listFiles.isNotEmpty) { final uploadedListSize = listFiles.map((file) => file.fileSize).toList(); @@ -269,7 +267,9 @@ class UploadController extends GetxController { log('ComposerController::_validateAttachmentsSize(): uploadedTotalSize: $uploadedTotalSize'); } - final totalSizeReadyToUpload = currentTotalAttachmentsSize + uploadedTotalSize; + final totalSizeReadyToUpload = currentTotalAttachmentsSize + + totalInlineAttachmentsSize + + uploadedTotalSize; log('ComposerController::_validateAttachmentsSize(): totalSizeReadyToUpload: $totalSizeReadyToUpload'); final maxSizeAttachmentsPerEmail = _mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value; @@ -318,6 +318,18 @@ class UploadController extends GetxController { uploadInlineViewState.value = Right(UIState.idle); } + List get inlineAttachmentsUploaded { + if (_uploadingStateInlineFiles.uploadingStateFiles.isEmpty) { + return List.empty(); + } + return _uploadingStateInlineFiles.uploadingStateFiles + .whereNotNull() + .map((fileState) => fileState.attachment) + .whereNotNull() + .where((attachment) => attachment.cid != null) + .toList(); + } + Map get mapInlineAttachments { final inlineAttachments = _uploadingStateInlineFiles.uploadingStateFiles .whereNotNull() diff --git a/lib/main/bindings/core/core_bindings.dart b/lib/main/bindings/core/core_bindings.dart index 9262a9850..72741eabf 100644 --- a/lib/main/bindings/core/core_bindings.dart +++ b/lib/main/bindings/core/core_bindings.dart @@ -58,5 +58,6 @@ class CoreBindings extends Bindings { void _bindingUtils() { Get.put(const Uuid()); + Get.put(CompressFileUtils()); } } \ No newline at end of file diff --git a/lib/main/bindings/network/network_bindings.dart b/lib/main/bindings/network/network_bindings.dart index 19d03497d..6ecc50da1 100644 --- a/lib/main/bindings/network/network_bindings.dart +++ b/lib/main/bindings/network/network_bindings.dart @@ -69,7 +69,7 @@ class NetworkBindings extends Bindings { void _bindingApi() { Get.put(JmapHttpClient.HttpClient(Get.find())); - Get.put(DownloadClient(Get.find())); + Get.put(DownloadClient(Get.find(), Get.find())); Get.put(DownloadManager(Get.find())); Get.put(MailboxAPI(Get.find())); Get.put(SessionAPI(Get.find())); diff --git a/model/lib/upload/file_info.dart b/model/lib/upload/file_info.dart index 89183c30b..7612093cf 100644 --- a/model/lib/upload/file_info.dart +++ b/model/lib/upload/file_info.dart @@ -1,4 +1,6 @@ +import 'dart:typed_data'; + import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; import 'package:mime/mime.dart'; @@ -8,8 +10,9 @@ class FileInfo with EquatableMixin { final String filePath; final int fileSize; final Stream>? readStream; + final Uint8List? bytes; - FileInfo(this.fileName, this.filePath, this.fileSize, {this.readStream}); + FileInfo(this.fileName, this.filePath, this.fileSize, {this.readStream, this.bytes}); factory FileInfo.empty() { return FileInfo('', '', 0); @@ -20,5 +23,5 @@ class FileInfo with EquatableMixin { String get mimeType => lookupMimeType(kIsWeb ? fileName : filePath) ?? 'application/json; charset=UTF-8'; @override - List get props => [fileName, filePath, fileSize, readStream]; + List get props => [fileName, filePath, fileSize, readStream, bytes]; } \ No newline at end of file