TF-725 Implement UI/UX for insert image to composer on web
This commit is contained in:
@@ -31,4 +31,12 @@ mixin AppLoaderMixin {
|
||||
progressColor: AppColor.primaryColor,
|
||||
));
|
||||
}
|
||||
|
||||
Widget loadingWidgetWithSizeColor({double? size, Color? color}) {
|
||||
return Center(child: SizedBox(
|
||||
width: size ?? 24,
|
||||
height: size ?? 24,
|
||||
child: CircularProgressIndicator(
|
||||
color: color ?? AppColor.colorLoading)));
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ import 'package:core/core.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_bindings.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource/composer_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource/contact_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource_impl/composer_datasource_impl.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource_impl/contact_datasource_impl.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/repository/auto_complete_repository_impl.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/repository/composer_repository_impl.dart';
|
||||
@@ -11,6 +13,7 @@ import 'package:tmail_ui_user/features/composer/data/repository/contact_reposito
|
||||
import 'package:tmail_ui_user/features/composer/domain/repository/auto_complete_repository.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_with_device_contact_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/get_device_contact_suggestions_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/save_email_as_drafts_interactor.dart';
|
||||
@@ -74,6 +77,7 @@ class ComposerBindings extends BaseBindings {
|
||||
}
|
||||
|
||||
Get.lazyPut(() => AttachmentUploadDataSourceImpl(Get.find<FileUploader>()));
|
||||
Get.lazyPut(() => ComposerDataSourceImpl(Get.find<DownloadClient>()));
|
||||
Get.lazyPut(() => ContactDataSourceImpl());
|
||||
Get.lazyPut(() => EmailDataSourceImpl(Get.find<EmailAPI>()));
|
||||
Get.lazyPut(() => HtmlDataSourceImpl(
|
||||
@@ -88,6 +92,7 @@ class ComposerBindings extends BaseBindings {
|
||||
@override
|
||||
void bindingsDataSource() {
|
||||
Get.lazyPut<AttachmentUploadDataSource>(() => Get.find<AttachmentUploadDataSourceImpl>());
|
||||
Get.lazyPut<ComposerDataSource>(() => Get.find<ComposerDataSourceImpl>());
|
||||
Get.lazyPut<ContactDataSource>(() => Get.find<ContactDataSourceImpl>());
|
||||
Get.lazyPut<EmailDataSource>(() => Get.find<EmailDataSourceImpl>());
|
||||
Get.lazyPut<HtmlDataSource>(() => Get.find<HtmlDataSourceImpl>());
|
||||
@@ -96,7 +101,9 @@ class ComposerBindings extends BaseBindings {
|
||||
|
||||
@override
|
||||
void bindingsRepositoryImpl() {
|
||||
Get.lazyPut(() => ComposerRepositoryImpl(Get.find<AttachmentUploadDataSource>()));
|
||||
Get.lazyPut(() => ComposerRepositoryImpl(
|
||||
Get.find<AttachmentUploadDataSource>(),
|
||||
Get.find<ComposerDataSource>()));
|
||||
Get.lazyPut(() => AutoCompleteRepositoryImpl(dataSources));
|
||||
Get.lazyPut(() => ContactRepositoryImpl(Get.find<ContactDataSource>()));
|
||||
Get.lazyPut(() => EmailRepositoryImpl(
|
||||
@@ -132,6 +139,7 @@ class ComposerBindings extends BaseBindings {
|
||||
Get.lazyPut(() => GetAllIdentitiesInteractor(Get.find<ManageAccountRepository>()));
|
||||
Get.lazyPut(() => RemoveComposerCacheOnWebInteractor(Get.find<ComposerCacheRepository>()));
|
||||
Get.lazyPut(() => SaveComposerCacheOnWebInteractor(Get.find<ComposerCacheRepository>()));
|
||||
Get.lazyPut(() => DownloadImageAsBase64Interactor(Get.find<ComposerRepository>()));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -153,6 +161,7 @@ class ComposerBindings extends BaseBindings {
|
||||
Get.find<RemoveComposerCacheOnWebInteractor>(),
|
||||
Get.find<SaveComposerCacheOnWebInteractor>(),
|
||||
Get.find<RichTextWebController>(),
|
||||
Get.find<DownloadImageAsBase64Interactor>(),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@ import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_base64_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_with_device_contact_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/save_email_as_drafts_interactor.dart';
|
||||
@@ -36,7 +38,10 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/update_email_dra
|
||||
import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/image_source.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/insert_image_dialog_builder.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||
@@ -46,6 +51,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/state/local_file_picker_state.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/controller/upload_controller.dart';
|
||||
@@ -90,6 +96,7 @@ class ComposerController extends BaseController {
|
||||
final RemoveComposerCacheOnWebInteractor _removeComposerCacheOnWebInteractor;
|
||||
final SaveComposerCacheOnWebInteractor _saveComposerCacheOnWebInteractor;
|
||||
final RichTextWebController richTextWebController;
|
||||
final DownloadImageAsBase64Interactor _downloadImageAsBase64Interactor;
|
||||
|
||||
List<EmailAddress> listToEmailAddress = <EmailAddress>[];
|
||||
List<EmailAddress> listCcEmailAddress = <EmailAddress>[];
|
||||
@@ -104,6 +111,8 @@ class ComposerController extends BaseController {
|
||||
List<Attachment> initialAttachments = <Attachment>[];
|
||||
String? _textEditorWeb;
|
||||
List<EmailContent>? _emailContents;
|
||||
double? maxWithEditor;
|
||||
late Worker uploadInlineImageWorker;
|
||||
|
||||
void setTextEditorWeb(String? text) => _textEditorWeb = text;
|
||||
|
||||
@@ -159,11 +168,13 @@ class ComposerController extends BaseController {
|
||||
this._removeComposerCacheOnWebInteractor,
|
||||
this._saveComposerCacheOnWebInteractor,
|
||||
this.richTextWebController,
|
||||
this._downloadImageAsBase64Interactor,
|
||||
);
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_listenWorker();
|
||||
if (!BuildUtils.isWeb) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
await FkUserAgent.init();
|
||||
@@ -200,6 +211,7 @@ class ComposerController extends BaseController {
|
||||
toEmailAddressController.dispose();
|
||||
ccEmailAddressController.dispose();
|
||||
bccEmailAddressController.dispose();
|
||||
uploadInlineImageWorker.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -228,13 +240,22 @@ class ComposerController extends BaseController {
|
||||
_pickFileSuccess(success);
|
||||
} else if (success is GetEmailContentSuccess) {
|
||||
_getEmailContentSuccess(success);
|
||||
} if (success is GetAllIdentitiesSuccess) {
|
||||
} else if (success is GetAllIdentitiesSuccess) {
|
||||
if (success.identities?.isNotEmpty == true) {
|
||||
listIdentities.value = success.identities!
|
||||
.where((identity) => identity.mayDelete == true)
|
||||
.toList();
|
||||
selectIdentity(listIdentities.first);
|
||||
}
|
||||
} else if (success is DownloadImageAsBase64Success) {
|
||||
richTextWebController.insertImage(
|
||||
InlineImage(
|
||||
ImageSource.local,
|
||||
fileInfo: success.fileInfo,
|
||||
cid: success.cid,
|
||||
base64: success.imageAsBase64),
|
||||
maxWithEditor: maxWithEditor);
|
||||
maxWithEditor = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -251,6 +272,19 @@ class ComposerController extends BaseController {
|
||||
popBack();
|
||||
}
|
||||
|
||||
void _listenWorker() {
|
||||
uploadInlineImageWorker = ever(uploadController.uploadInlineViewState, (state) {
|
||||
log('ComposerController::_listenWorker(): $state');
|
||||
if (state is Either) {
|
||||
state.fold((failure) => null, (success) {
|
||||
if (success is SuccessAttachmentUploadState) {
|
||||
_handleUploadInlineSuccess(success);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _listenBrowserTabRefresh() {
|
||||
html.window.onBeforeUnload.listen((event) async {
|
||||
final userProfile = mailboxDashBoardController.userProfile.value;
|
||||
@@ -497,7 +531,21 @@ class ComposerController extends BaseController {
|
||||
final generateBlobId = Id(_uuid.v1());
|
||||
|
||||
var emailBodyText = await _getEmailBodyText(context);
|
||||
log('ComposerController::_generateEmail(): $emailBodyText');
|
||||
final mapContents = await richTextWebController.refactorContentHasInlineImage(
|
||||
emailBodyText,
|
||||
uploadController.mapInlineAttachments);
|
||||
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>{};
|
||||
attachments.addAll(uploadController.generateAttachments() ?? []);
|
||||
attachments.addAll(listInlineEmailBodyPart);
|
||||
log('ComposerController::_generateEmail(): listInlineEmailBodyPart: $listInlineEmailBodyPart');
|
||||
|
||||
final userAgent = await userAgentPlatform;
|
||||
log('ComposerController::_generateEmail(): userAgent: $userAgent');
|
||||
|
||||
@@ -521,7 +569,7 @@ class ComposerController extends BaseController {
|
||||
generatePartId: EmailBodyValue(emailBodyText, false, false)
|
||||
},
|
||||
headerUserAgent: {IndividualHeaderIdentifier.headerUserAgent : userAgent},
|
||||
attachments: uploadController.generateAttachments(),
|
||||
attachments: attachments.isNotEmpty ? attachments : null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -623,7 +671,7 @@ class ComposerController extends BaseController {
|
||||
final email = await _generateEmail(context, mapDefaultMailboxId, userProfile);
|
||||
final accountId = session.accounts.keys.first;
|
||||
final sentMailboxId = mapDefaultMailboxId[PresentationMailbox.roleSent];
|
||||
final submissionCreateId = Id(const Uuid().v1());
|
||||
final submissionCreateId = Id(_uuid.v1());
|
||||
|
||||
mailboxDashBoardController.consumeState(_sendEmailInteractor.execute(
|
||||
accountId,
|
||||
@@ -631,6 +679,8 @@ class ComposerController extends BaseController {
|
||||
emailIdDestroyed: arguments.emailActionType == EmailActionType.edit
|
||||
? arguments.presentationEmail?.id
|
||||
: null)));
|
||||
|
||||
uploadController.clearInlineFileUploaded();
|
||||
}
|
||||
|
||||
if (kIsWeb) {
|
||||
@@ -1055,6 +1105,65 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
void insertImage(BuildContext context, {double? maxWithEditor}) async {
|
||||
await InsertImageDialogBuilder(
|
||||
context,
|
||||
insertActionCallback: (inlineImage) {
|
||||
log('ComposerController::insertImage(): ${inlineImage.source}|$maxWithEditor');
|
||||
if (BuildUtils.isWeb) {
|
||||
this.maxWithEditor = maxWithEditor;
|
||||
_insertImageOnWeb(inlineImage);
|
||||
}
|
||||
}
|
||||
).show();
|
||||
}
|
||||
|
||||
void _insertImageOnWeb(InlineImage inlineImage) {
|
||||
if (inlineImage.source == ImageSource.local) {
|
||||
_uploadInlineAttachmentsAction(inlineImage.fileInfo!);
|
||||
} else {
|
||||
richTextWebController.insertImage(inlineImage);
|
||||
}
|
||||
}
|
||||
|
||||
void _uploadInlineAttachmentsAction(FileInfo pickedFile) async {
|
||||
if (uploadController.hasEnoughMaxAttachmentSize(listFiles: [pickedFile])) {
|
||||
final session = mailboxDashBoardController.sessionCurrent;
|
||||
final accountId = mailboxDashBoardController.accountId.value;
|
||||
if (session != null && accountId != null) {
|
||||
final uploadUri = session.getUploadUri(accountId);
|
||||
uploadController.uploadInlineImage(pickedFile, uploadUri);
|
||||
}
|
||||
} else {
|
||||
if (currentContext != null) {
|
||||
showConfirmDialogAction(
|
||||
currentContext!,
|
||||
AppLocalizations.of(currentContext!).message_dialog_upload_attachments_exceeds_maximum_size(
|
||||
filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)),
|
||||
AppLocalizations.of(currentContext!).got_it,
|
||||
() => {},
|
||||
title: AppLocalizations.of(currentContext!).maximum_files_size,
|
||||
hasCancelButton: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _handleUploadInlineSuccess(SuccessAttachmentUploadState uploadState) {
|
||||
uploadController.clearUploadInlineViewState();
|
||||
|
||||
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl();
|
||||
final accountId = mailboxDashBoardController.accountId.value;
|
||||
|
||||
if (baseDownloadUrl != null && accountId != null) {
|
||||
final imageUrl = uploadState.attachment.getDownloadUrl(baseDownloadUrl, accountId);
|
||||
log('ComposerController::_handleUploadInlineSuccess(): imageUrl: $imageUrl');
|
||||
consumeState(_downloadImageAsBase64Interactor.execute(
|
||||
imageUrl,
|
||||
uploadState.attachment.cid!,
|
||||
uploadState.fileInfo));
|
||||
}
|
||||
}
|
||||
|
||||
void closeComposer() {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
popBack();
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:enough_html_editor/enough_html_editor.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
@@ -11,7 +10,6 @@ import 'package:get/get.dart';
|
||||
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/composer/domain/state/upload_attachment_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/mixin/rich_text_button_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart';
|
||||
@@ -412,7 +410,6 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
|
||||
child: _buildAttachmentsTitle(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value)),
|
||||
_buildAttachmentsLoadingView(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
child: _buildAttachmentsList(context,
|
||||
@@ -479,7 +476,6 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
|
||||
child: _buildAttachmentsTitle(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value)),
|
||||
_buildAttachmentsLoadingView(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
child: _buildAttachmentsList(context,
|
||||
@@ -589,19 +585,6 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsLoadingView({EdgeInsets? padding, double? size}) {
|
||||
return Obx(() => controller.viewState.value.fold(
|
||||
(failure) => const SizedBox.shrink(),
|
||||
(success) => success is UploadingAttachmentState
|
||||
? Center(child: Padding(
|
||||
padding: padding ?? const EdgeInsets.all(10),
|
||||
child: SizedBox(
|
||||
width: size ?? 20,
|
||||
height: size ?? 20,
|
||||
child: const CupertinoActivityIndicator(color: AppColor.colorTextButton))))
|
||||
: const SizedBox.shrink()));
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsTitle(
|
||||
BuildContext context,
|
||||
List<UploadFileState> uploadFilesState,
|
||||
@@ -612,7 +595,6 @@ class ComposerView extends GetWidget<ComposerController> with AppLoaderMixin, Ri
|
||||
Text(
|
||||
'${AppLocalizations.of(context).attachments} (${filesize(uploadFilesState.totalSize, 0)}):',
|
||||
style: const TextStyle(fontSize: 12, color: AppColor.colorHintEmailAddressInput, fontWeight: FontWeight.normal)),
|
||||
_buildAttachmentsLoadingView(padding: const EdgeInsets.only(left: 16), size: 16),
|
||||
const Spacer(),
|
||||
Material(
|
||||
type: MaterialType.circle,
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:core/core.dart';
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -11,13 +10,14 @@ import 'package:jmap_dart_client/jmap/identities/identity.dart';
|
||||
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/composer/domain/state/upload_attachment_state.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/rich_text_button_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/rich_text_style_type.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_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/model/upload_file_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
||||
@@ -54,14 +54,19 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
: const SizedBox.shrink()),
|
||||
_buildEmailAddress(context, constraints),
|
||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 16), child: _buildSubjectEmail(context)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildSubjectEmail(context)),
|
||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 16), child: _buildListButton(context)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildListButton(context, constraints)),
|
||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Expanded(child: Column(
|
||||
children: [
|
||||
_buildAttachmentsWidget(context),
|
||||
_buildToolbarRichTextWidget(),
|
||||
_buildInlineLoadingView(),
|
||||
_buildEditorForm(context)
|
||||
]
|
||||
)),
|
||||
@@ -282,7 +287,7 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Padding(padding: const EdgeInsets.only(right: 16), child: _buildSubjectEmail(context)),
|
||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
_buildListButton(context),
|
||||
_buildListButton(context, constraints),
|
||||
]),
|
||||
))
|
||||
])),
|
||||
@@ -295,6 +300,7 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
children: [
|
||||
_buildAttachmentsWidget(context),
|
||||
_buildToolbarRichTextWidget(),
|
||||
_buildInlineLoadingView(),
|
||||
_buildEditorForm(context)
|
||||
]
|
||||
))),
|
||||
@@ -483,7 +489,7 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListButton(BuildContext context) {
|
||||
Widget _buildListButton(BuildContext context, BoxConstraints constraints) {
|
||||
return Transform(
|
||||
transform: Matrix4.translationValues(-5.0, 0.0, 0.0),
|
||||
child: Padding(
|
||||
@@ -499,6 +505,17 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).attach_file,
|
||||
onTap: () => controller.openFilePickerByType(context, FileType.any)),
|
||||
const SizedBox(width: 4),
|
||||
buildIconWeb(
|
||||
minSize: 40,
|
||||
iconPadding: EdgeInsets.zero,
|
||||
icon: SvgPicture.asset(imagePaths.icInsertImage,
|
||||
color: AppColor.colorTextButton,
|
||||
fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).insertImage,
|
||||
onTap: () => controller.insertImage(
|
||||
context,
|
||||
maxWithEditor: constraints.maxWidth - 120)),
|
||||
])
|
||||
)
|
||||
);
|
||||
@@ -604,7 +621,6 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
)
|
||||
)
|
||||
);
|
||||
// });
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsWidget(BuildContext context) {
|
||||
@@ -622,7 +638,6 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
context,
|
||||
attachments,
|
||||
controller.expandModeAttachments.value)),
|
||||
_buildAttachmentsLoadingView(),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 8,
|
||||
@@ -639,19 +654,6 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsLoadingView({EdgeInsets? padding, double? size}) {
|
||||
return Obx(() => controller.viewState.value.fold(
|
||||
(failure) => const SizedBox.shrink(),
|
||||
(success) => success is UploadingAttachmentState
|
||||
? Center(child: Padding(
|
||||
padding: padding ?? const EdgeInsets.all(10),
|
||||
child: SizedBox(
|
||||
width: size ?? 20,
|
||||
height: size ?? 20,
|
||||
child: const CupertinoActivityIndicator(color: AppColor.colorTextButton))))
|
||||
: const SizedBox.shrink()));
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsTitle(
|
||||
BuildContext context,
|
||||
List<UploadFileState> uploadFilesState,
|
||||
@@ -661,7 +663,6 @@ class ComposerView extends GetWidget<ComposerController>
|
||||
Text(
|
||||
'${AppLocalizations.of(context).attachments} (${filesize(uploadFilesState.totalSize, 0)}):',
|
||||
style: const TextStyle(fontSize: 12, color: AppColor.colorHintEmailAddressInput, fontWeight: FontWeight.normal)),
|
||||
_buildAttachmentsLoadingView(padding: const EdgeInsets.only(left: 16), size: 16),
|
||||
const Spacer(),
|
||||
Material(
|
||||
type: MaterialType.circle,
|
||||
@@ -746,4 +747,20 @@ 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();
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2022-07-11T12:17:57.489417",
|
||||
"@@last_modified": "2022-07-18T16:31:40.598846",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -1573,5 +1573,47 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"insertImage": "Insert image",
|
||||
"@insertImage": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"selectFromFile": "Select from file",
|
||||
"@selectFromFile": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"chooseImage": "Choose image",
|
||||
"@chooseImage": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"urlLink": "URL",
|
||||
"@urlLink": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"insert": "Insert",
|
||||
"@insert": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"insertImageErrorFileEmpty": "Please either choose an image or enter an image URL",
|
||||
"@insertImageErrorFileEmpty": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"insertImageErrorDuplicate": "Please input either an image or an image URL, not both",
|
||||
"@insertImageErrorDuplicate": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -1614,4 +1614,49 @@ class AppLocalizations {
|
||||
'Save & close',
|
||||
name: 'saveAndClose');
|
||||
}
|
||||
|
||||
String get insertImage {
|
||||
return Intl.message(
|
||||
'Insert image',
|
||||
name: 'insertImage');
|
||||
}
|
||||
|
||||
String get selectFromFile {
|
||||
return Intl.message(
|
||||
'Select from file',
|
||||
name: 'selectFromFile',
|
||||
);
|
||||
}
|
||||
|
||||
String get chooseImage {
|
||||
return Intl.message(
|
||||
'Choose image',
|
||||
name: 'chooseImage',
|
||||
);
|
||||
}
|
||||
|
||||
String get urlLink {
|
||||
return Intl.message(
|
||||
'URL',
|
||||
name: 'urlLink',
|
||||
);
|
||||
}
|
||||
|
||||
String get insert {
|
||||
return Intl.message(
|
||||
'Insert',
|
||||
name: 'insert');
|
||||
}
|
||||
|
||||
String get insertImageErrorFileEmpty {
|
||||
return Intl.message(
|
||||
'Please either choose an image or enter an image URL',
|
||||
name: 'insertImageErrorFileEmpty');
|
||||
}
|
||||
|
||||
String get insertImageErrorDuplicate {
|
||||
return Intl.message(
|
||||
'Please input either an image or an image URL, not both',
|
||||
name: 'insertImageErrorDuplicate');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user