TF-761 Implement reduce image size when add inline image
This commit is contained in:
@@ -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();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+4
-6
@@ -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>()));
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user