TF-761 Implement reduce image size when add inline image

This commit is contained in:
dab246
2022-07-28 14:36:37 +07:00
committed by Dat H. Pham
parent 8e22bec3f1
commit e050042e2c
12 changed files with 129 additions and 110 deletions
@@ -256,16 +256,14 @@ class ComposerController extends BaseController {
ImageSource.local, ImageSource.local,
fileInfo: success.fileInfo, fileInfo: success.fileInfo,
cid: success.cid, cid: success.cid,
base64: success.imageAsBase64), base64Uri: success.base64Uri));
maxWithEditor: maxWithEditor);
} else { } else {
richTextMobileTabletController.insertImage( richTextMobileTabletController.insertImage(
InlineImage( InlineImage(
ImageSource.local, ImageSource.local,
fileInfo: success.fileInfo, fileInfo: success.fileInfo,
cid: success.cid, cid: success.cid,
base64: success.imageAsBase64), base64Uri: success.base64Uri));
maxWithEditor: maxWithEditor);
} }
maxWithEditor = null; maxWithEditor = null;
} }
@@ -337,7 +335,8 @@ class ComposerController extends BaseController {
void _initAttachments(ComposerArguments arguments) { void _initAttachments(ComposerArguments arguments) {
if (arguments.attachments?.isNotEmpty == true) { if (arguments.attachments?.isNotEmpty == true) {
initialAttachments = arguments.attachments!; initialAttachments = arguments.attachments!;
uploadController.initializeUploadAttachments(arguments.attachments!); uploadController.initializeUploadAttachments(
arguments.attachments!.listAttachmentsDisplayedOutSide);
} }
if (BuildUtils.isWeb) { if (BuildUtils.isWeb) {
expandModeAttachments.value = ExpandMode.EXPAND; expandModeAttachments.value = ExpandMode.EXPAND;
@@ -538,19 +537,22 @@ class ComposerController extends BaseController {
final generatePartId = PartId(_uuid.v1()); final generatePartId = PartId(_uuid.v1());
final generateBlobId = Id(_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 = <EmailBodyPart>{}; final attachments = <EmailBodyPart>{};
attachments.addAll(uploadController.generateAttachments() ?? []); 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; final userAgent = await userAgentPlatform;
log('ComposerController::_generateEmail(): userAgent: $userAgent'); log('ComposerController::_generateEmail(): userAgent: $userAgent');
@@ -915,7 +917,8 @@ class ComposerController extends BaseController {
void _getEmailContentSuccess(GetEmailContentSuccess success) { void _getEmailContentSuccess(GetEmailContentSuccess success) {
if (success.attachments.isNotEmpty) { if (success.attachments.isNotEmpty) {
initialAttachments = success.attachments; initialAttachments = success.attachments;
uploadController.initializeUploadAttachments(success.attachments); uploadController.initializeUploadAttachments(
success.attachments.listAttachmentsDisplayedOutSide);
} }
emailContentsViewState.value = Right(success); emailContentsViewState.value = Right(success);
_emailContents = success.emailContents; _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(); final inlineImage = await _selectFromFile();
if(inlineImage != null) { log('ComposerController::insertImage(): $inlineImage');
this.maxWithEditor = maxWithEditor; if (inlineImage != null) {
if(kIsWeb) { if (BuildUtils.isWeb) {
_insertImageOnWeb(inlineImage); _insertImageOnWeb(inlineImage);
} else { } else {
_insertImageOnMobileAndTablet(inlineImage); _insertImageOnMobileAndTablet(inlineImage);
@@ -1148,15 +1156,17 @@ class ComposerController extends BaseController {
Future<InlineImage?> _selectFromFile() async { Future<InlineImage?> _selectFromFile() async {
final filePickerResult = await FilePicker.platform.pickFiles( final filePickerResult = await FilePicker.platform.pickFiles(
type: FileType.image, type: FileType.image,
withReadStream: true); withData: !BuildUtils.isWeb,
withReadStream: BuildUtils.isWeb);
final platformFile = filePickerResult?.files.single; final platformFile = filePickerResult?.files.single;
if (platformFile != null) { if (platformFile != null) {
final fileSelected = FileInfo( final fileSelected = FileInfo(
platformFile.name, platformFile.name,
BuildUtils.isWeb ? '' : platformFile.path ?? '', BuildUtils.isWeb ? '' : platformFile.path ?? '',
platformFile.size, platformFile.size,
bytes: platformFile.bytes,
readStream: platformFile.readStream); readStream: platformFile.readStream);
return InlineImage(ImageSource.local, fileInfo: fileSelected); return InlineImage(ImageSource.local, fileInfo: fileSelected);
} }
return null; return null;
@@ -1212,7 +1222,8 @@ class ComposerController extends BaseController {
consumeState(_downloadImageAsBase64Interactor.execute( consumeState(_downloadImageAsBase64Interactor.execute(
imageUrl, imageUrl,
uploadState.attachment.cid!, uploadState.attachment.cid!,
uploadState.fileInfo)); uploadState.fileInfo,
maxWidth: maxWithEditor));
} }
} }
@@ -11,21 +11,21 @@ import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:model/model.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/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.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/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/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/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/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/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/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/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/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/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/features/email/domain/state/get_email_content_state.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, RichTextButtonMixin { class ComposerView extends GetWidget<ComposerController>
with AppLoaderMixin, RichTextButtonMixin, ComposerLoadingMixin {
final responsiveUtils = Get.find<ResponsiveUtils>(); final responsiveUtils = Get.find<ResponsiveUtils>();
final imagePaths = Get.find<ImagePaths>(); final imagePaths = Get.find<ImagePaths>();
@@ -390,9 +390,7 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
color: AppColor.colorTextButton, color: AppColor.colorTextButton,
fit: BoxFit.fill), fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).insertImage, tooltip: AppLocalizations.of(context).insertImage,
onTap: () => controller.insertImage( onTap: () => controller.insertImage(context, constraints.maxWidth))
context,
maxWithEditor: constraints.maxWidth - 120))
]) ])
) )
); );
@@ -417,7 +415,7 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
const Divider(color: AppColor.colorDividerComposer, height: 1), const Divider(color: AppColor.colorDividerComposer, height: 1),
_buildAttachmentsWidget(context), _buildAttachmentsWidget(context),
_buildToolbarMobileWidget(context), _buildToolbarMobileWidget(context),
_buildInlineLoadingView(), buildInlineLoadingView(controller),
_buildComposerEditor(context), _buildComposerEditor(context),
]), ]),
) )
@@ -462,7 +460,7 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
child: Column(children: [ child: Column(children: [
_buildToolbarRichTextWidget(context), _buildToolbarRichTextWidget(context),
_buildAttachmentsWidget(context), _buildAttachmentsWidget(context),
_buildInlineLoadingView(), buildInlineLoadingView(controller),
_buildComposerEditor(context), _buildComposerEditor(context),
]) ])
) )
@@ -493,21 +491,6 @@ class ComposerView extends GetWidget<ComposerController> 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) { Widget _buildToolbarRichTextWidget(BuildContext context) {
return Obx(() { return Obx(() {
final richTextMobileTabletController = controller.richTextMobileTabletController; final richTextMobileTabletController = controller.richTextMobileTabletController;
@@ -788,7 +771,6 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
], ],
), ),
); );
}, });
);
} }
} }
@@ -11,9 +11,9 @@ import 'package:model/model.dart';
import 'package:pointer_interceptor/pointer_interceptor.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/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu_overlay_widget.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/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/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/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/dropdown_menu_font_status.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/font_name_type.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/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/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/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/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/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/features/email/domain/state/get_email_content_state.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ComposerView extends GetWidget<ComposerController> class ComposerView extends GetWidget<ComposerController>
with AppLoaderMixin, RichTextButtonMixin { with AppLoaderMixin, RichTextButtonMixin, ComposerLoadingMixin {
final responsiveUtils = Get.find<ResponsiveUtils>(); final responsiveUtils = Get.find<ResponsiveUtils>();
final imagePaths = Get.find<ImagePaths>(); final imagePaths = Get.find<ImagePaths>();
@@ -74,7 +73,7 @@ class ComposerView extends GetWidget<ComposerController>
children: [ children: [
_buildAttachmentsWidget(context), _buildAttachmentsWidget(context),
_buildToolbarRichTextWidget(context), _buildToolbarRichTextWidget(context),
_buildInlineLoadingView(), buildInlineLoadingView(controller),
_buildEditorForm(context) _buildEditorForm(context)
] ]
)), )),
@@ -308,7 +307,7 @@ class ComposerView extends GetWidget<ComposerController>
children: [ children: [
_buildAttachmentsWidget(context), _buildAttachmentsWidget(context),
_buildToolbarRichTextWidget(context), _buildToolbarRichTextWidget(context),
_buildInlineLoadingView(), buildInlineLoadingView(controller),
_buildEditorForm(context) _buildEditorForm(context)
] ]
))), ))),
@@ -525,9 +524,7 @@ class ComposerView extends GetWidget<ComposerController>
color: AppColor.colorTextButton.withOpacity(opacity), color: AppColor.colorTextButton.withOpacity(opacity),
fit: BoxFit.fill), fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).insertImage, tooltip: AppLocalizations.of(context).insertImage,
onTap: () => controller.insertImage( onTap: () => controller.insertImage(context, constraints.maxWidth)),
context,
maxWithEditor: constraints.maxWidth - 120)),
); );
}), }),
const SizedBox(width: 4), const SizedBox(width: 4),
@@ -955,20 +952,4 @@ class ComposerView extends GetWidget<ComposerController>
); );
}); });
} }
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();
}));
}
} }
@@ -19,7 +19,7 @@ class RichTextMobileTabletController extends BaseRichTextController {
final selectedTextColor = Colors.black.obs; final selectedTextColor = Colors.black.obs;
final selectedTextBackgroundColor = Colors.white.obs; final selectedTextBackgroundColor = Colors.white.obs;
final selectedFontName = SafeFont.sansSerif.obs; final selectedFontName = SafeFont.sansSerif.obs;
final menuHeaderStyleStatus = DropdownMenuFontStatus.closed.obs; final menuHeaderStyleStatus = DropdownMenuFontStatus.closed.obs;
bool get isMenuHeaderStyleOpen => menuHeaderStyleStatus.value == DropdownMenuFontStatus.open; bool get isMenuHeaderStyleOpen => menuHeaderStyleStatus.value == DropdownMenuFontStatus.open;
@@ -106,7 +106,7 @@ class RichTextMobileTabletController extends BaseRichTextController {
Future<Tuple2<String, List<Attachment>>> refactorContentHasInlineImage( Future<Tuple2<String, List<Attachment>>> refactorContentHasInlineImage(
String emailContent, String emailContent,
Map<String, Attachment> mapInlineAttachments Map<String, Attachment> mapInlineAttachments
) async { ) async {
final document = parse(emailContent); final document = parse(emailContent);
final listImgTag = document.querySelectorAll('img[src^="data:image/"]'); final listImgTag = document.querySelectorAll('img[src^="data:image/"]');
final listInlineAttachment = await Future.wait(listImgTag.map((imgTag) async { final listInlineAttachment = await Future.wait(listImgTag.map((imgTag) async {
@@ -145,9 +145,7 @@ class RichTextMobileTabletController extends BaseRichTextController {
if (image.source == ImageSource.network) { if (image.source == ImageSource.network) {
htmlEditorApi?.insertImageLink(image.link!); htmlEditorApi?.insertImageLink(image.link!);
} else { } else {
final htmlContent = await image.generateImgTagHtml(maxWithEditor: maxWithEditor); htmlEditorApi?.insertHtml(image.base64Uri ?? '');
log('RichTextMobileTabletController::insertImage(): $htmlContent');
htmlEditorApi?.insertHtml(htmlContent);
} }
} }
@@ -156,4 +154,4 @@ class RichTextMobileTabletController extends BaseRichTextController {
htmlEditorApi?.formatHeader(styleSelected.styleValue); htmlEditorApi?.formatHeader(styleSelected.styleValue);
} }
} }
@@ -155,14 +155,12 @@ class RichTextWebController extends BaseRichTextController {
bool isTextStyleTypeSelected(RichTextStyleType richTextStyleType) => bool isTextStyleTypeSelected(RichTextStyleType richTextStyleType) =>
listTextStyleApply.contains(richTextStyleType); listTextStyleApply.contains(richTextStyleType);
void insertImage(InlineImage image, {double? maxWithEditor}) async { void insertImage(InlineImage image) async {
log('RichTextWebController::insertImage(): $image | maxWithEditor: $maxWithEditor'); log('RichTextWebController::insertImage(): $image');
if (image.source == ImageSource.network) { if (image.source == ImageSource.network) {
editorController.insertNetworkImage(image.link!); editorController.insertNetworkImage(image.link!);
} else { } else {
final htmlContent = await image.generateImgTagHtml(maxWithEditor: maxWithEditor); editorController.insertHtml(image.base64Uri ?? '');
log('RichTextWebController::insertImage(): $htmlContent');
editorController.insertHtml(htmlContent);
} }
} }
@@ -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();
});
}));
}
}
@@ -1,5 +1,4 @@
import 'package:core/presentation/extensions/html_extension.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/image_source.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 String? link;
final FileInfo? fileInfo; final FileInfo? fileInfo;
final String? cid; final String? cid;
final String? base64; final String? base64Uri;
InlineImage( InlineImage(
this.source, this.source,
@@ -17,21 +16,10 @@ class InlineImage with EquatableMixin {
this.link, this.link,
this.fileInfo, this.fileInfo,
this.cid, this.cid,
this.base64, this.base64Uri,
} }
); );
Future<String> generateImgTagHtml({double? maxWithEditor}) async {
if (source == ImageSource.local && base64 != null) {
return base64!.generateImageBase64(
cid!,
fileInfo!.fileExtension,
fileInfo!.fileName,
maxWithEditor: maxWithEditor);
}
return '';
}
@override @override
List<Object?> get props => [source, link, fileInfo, cid]; List<Object?> get props => [source, link, fileInfo, cid, base64Uri];
} }
@@ -71,7 +71,7 @@ class FileUploader {
final resultJson = await argsUpload.dioClient.post( final resultJson = await argsUpload.dioClient.post(
Uri.decodeFull(uploadUri.toString()), Uri.decodeFull(uploadUri.toString()),
options: Options(headers: headerParam), options: Options(headers: headerParam),
data: fileInfo.readStream, data: fileInfo.readStream ?? File(fileInfo.filePath).openRead(),
cancelToken: cancelToken, cancelToken: cancelToken,
onSendProgress: (progress, total) { onSendProgress: (progress, total) {
log('FileUploader::_handleUploadAttachmentAction():onSendProgress: [${argsUpload.uploadId.id}] = $progress'); log('FileUploader::_handleUploadAttachmentAction():onSendProgress: [${argsUpload.uploadId.id}] = $progress');
@@ -112,11 +112,7 @@ class UploadController extends GetxController {
); );
_refreshListUploadAttachmentState(); _refreshListUploadAttachmentState();
if (success.attachment.disposition == ContentDisposition.attachment) { _handleUploadAttachmentsSuccess(success);
_handleUploadAttachmentsSuccess(success);
} else {
_handleUploadInlineAttachmentsSuccess(success);
}
} }
} }
); );
@@ -261,7 +257,9 @@ class UploadController extends GetxController {
bool hasEnoughMaxAttachmentSize({List<FileInfo>? listFiles}) { bool hasEnoughMaxAttachmentSize({List<FileInfo>? listFiles}) {
final currentTotalAttachmentsSize = attachmentsUploaded.totalSize(); final currentTotalAttachmentsSize = attachmentsUploaded.totalSize();
final totalInlineAttachmentsSize = inlineAttachmentsUploaded.totalSize();
log('ComposerController::_validateAttachmentsSize(): $currentTotalAttachmentsSize'); log('ComposerController::_validateAttachmentsSize(): $currentTotalAttachmentsSize');
log('ComposerController::_validateAttachmentsSize(): totalInlineAttachmentsSize: $totalInlineAttachmentsSize');
num uploadedTotalSize = 0; num uploadedTotalSize = 0;
if (listFiles != null && listFiles.isNotEmpty) { if (listFiles != null && listFiles.isNotEmpty) {
final uploadedListSize = listFiles.map((file) => file.fileSize).toList(); final uploadedListSize = listFiles.map((file) => file.fileSize).toList();
@@ -269,7 +267,9 @@ class UploadController extends GetxController {
log('ComposerController::_validateAttachmentsSize(): uploadedTotalSize: $uploadedTotalSize'); log('ComposerController::_validateAttachmentsSize(): uploadedTotalSize: $uploadedTotalSize');
} }
final totalSizeReadyToUpload = currentTotalAttachmentsSize + uploadedTotalSize; final totalSizeReadyToUpload = currentTotalAttachmentsSize +
totalInlineAttachmentsSize +
uploadedTotalSize;
log('ComposerController::_validateAttachmentsSize(): totalSizeReadyToUpload: $totalSizeReadyToUpload'); log('ComposerController::_validateAttachmentsSize(): totalSizeReadyToUpload: $totalSizeReadyToUpload');
final maxSizeAttachmentsPerEmail = _mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value; final maxSizeAttachmentsPerEmail = _mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value;
@@ -318,6 +318,18 @@ class UploadController extends GetxController {
uploadInlineViewState.value = Right(UIState.idle); uploadInlineViewState.value = Right(UIState.idle);
} }
List<Attachment> 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<String, Attachment> get mapInlineAttachments { Map<String, Attachment> get mapInlineAttachments {
final inlineAttachments = _uploadingStateInlineFiles.uploadingStateFiles final inlineAttachments = _uploadingStateInlineFiles.uploadingStateFiles
.whereNotNull() .whereNotNull()
@@ -58,5 +58,6 @@ class CoreBindings extends Bindings {
void _bindingUtils() { void _bindingUtils() {
Get.put(const Uuid()); Get.put(const Uuid());
Get.put(CompressFileUtils());
} }
} }
@@ -69,7 +69,7 @@ class NetworkBindings extends Bindings {
void _bindingApi() { void _bindingApi() {
Get.put(JmapHttpClient.HttpClient(Get.find<Dio>())); Get.put(JmapHttpClient.HttpClient(Get.find<Dio>()));
Get.put(DownloadClient(Get.find<DioClient>())); Get.put(DownloadClient(Get.find<DioClient>(), Get.find<CompressFileUtils>()));
Get.put(DownloadManager(Get.find<DownloadClient>())); Get.put(DownloadManager(Get.find<DownloadClient>()));
Get.put(MailboxAPI(Get.find<JmapHttpClient.HttpClient>())); Get.put(MailboxAPI(Get.find<JmapHttpClient.HttpClient>()));
Get.put(SessionAPI(Get.find<JmapHttpClient.HttpClient>())); Get.put(SessionAPI(Get.find<JmapHttpClient.HttpClient>()));
+5 -2
View File
@@ -1,4 +1,6 @@
import 'dart:typed_data';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
@@ -8,8 +10,9 @@ class FileInfo with EquatableMixin {
final String filePath; final String filePath;
final int fileSize; final int fileSize;
final Stream<List<int>>? readStream; final Stream<List<int>>? 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() { factory FileInfo.empty() {
return FileInfo('', '', 0); return FileInfo('', '', 0);
@@ -20,5 +23,5 @@ class FileInfo with EquatableMixin {
String get mimeType => lookupMimeType(kIsWeb ? fileName : filePath) ?? 'application/json; charset=UTF-8'; String get mimeType => lookupMimeType(kIsWeb ? fileName : filePath) ?? 'application/json; charset=UTF-8';
@override @override
List<Object?> get props => [fileName, filePath, fileSize, readStream]; List<Object?> get props => [fileName, filePath, fileSize, readStream, bytes];
} }