TF-332 Fix when nothing is change tmail still making jmap request

This commit is contained in:
dab246
2022-07-11 12:33:29 +07:00
committed by Dat H. Pham
parent bce3f0a27a
commit 7473fdffdf
5 changed files with 283 additions and 175 deletions
@@ -12,7 +12,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:html_editor_enhanced/html_editor.dart' as html_editor_browser; import 'package:html_editor_enhanced/html_editor.dart' as editor_web;
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart';
import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart';
@@ -62,7 +62,6 @@ class ComposerController extends BaseController {
final composerArguments = Rxn<ComposerArguments>(); final composerArguments = Rxn<ComposerArguments>();
final isEnableEmailSendButton = false.obs; final isEnableEmailSendButton = false.obs;
final isInitialRecipient = false.obs; final isInitialRecipient = false.obs;
final emailContents = Rxn<List<EmailContent>>();
final listEmailAddressType = <PrefixEmailAddress>[].obs; final listEmailAddressType = <PrefixEmailAddress>[].obs;
final subjectEmail = Rxn<String>(); final subjectEmail = Rxn<String>();
final screenDisplayMode = ScreenDisplayMode.normal.obs; final screenDisplayMode = ScreenDisplayMode.normal.obs;
@@ -71,6 +70,7 @@ class ComposerController extends BaseController {
final bccAddressExpandMode = ExpandMode.EXPAND.obs; final bccAddressExpandMode = ExpandMode.EXPAND.obs;
final identitySelected = Rxn<Identity>(); final identitySelected = Rxn<Identity>();
final listIdentities = <Identity>[].obs; final listIdentities = <Identity>[].obs;
final emailContentsViewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
final SendEmailInteractor _sendEmailInteractor; final SendEmailInteractor _sendEmailInteractor;
final GetAutoCompleteInteractor _getAutoCompleteInteractor; final GetAutoCompleteInteractor _getAutoCompleteInteractor;
@@ -88,8 +88,7 @@ class ComposerController extends BaseController {
List<EmailAddress> listBccEmailAddress = <EmailAddress>[]; List<EmailAddress> listBccEmailAddress = <EmailAddress>[];
ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact; ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact;
HtmlEditorApi? htmlEditorApi; HtmlEditorApi? htmlEditorApi;
final html_editor_browser.HtmlEditorController htmlControllerBrowser = final htmlControllerBrowser = editor_web.HtmlEditorController(processNewLineAsBr: true);
html_editor_browser.HtmlEditorController(processNewLineAsBr: true);
final subjectEmailInputController = TextEditingController(); final subjectEmailInputController = TextEditingController();
final toEmailAddressController = TextEditingController(); final toEmailAddressController = TextEditingController();
@@ -98,6 +97,7 @@ class ComposerController extends BaseController {
List<Attachment> initialAttachments = <Attachment>[]; List<Attachment> initialAttachments = <Attachment>[];
String? _textEditorWeb; String? _textEditorWeb;
List<EmailContent>? _emailContents;
void setTextEditorWeb(String? text) => _textEditorWeb = text; void setTextEditorWeb(String? text) => _textEditorWeb = text;
@@ -105,21 +105,34 @@ class ComposerController extends BaseController {
void setSubjectEmail(String subject) => subjectEmail.value = subject; void setSubjectEmail(String subject) => subjectEmail.value = subject;
Future<String> _getEmailBodyText({bool changedEmail = false}) async { Future<String> _getEmailBodyText(BuildContext context, {
if (kIsWeb) { bool changedEmail = false
return await htmlControllerBrowser.getText(); }) async {
} else { if (BuildUtils.isWeb) {
if (changedEmail) { var contentHtml = '';
return await htmlEditorApi?.getText() ?? ''; if (_responsiveUtils.isWebDesktop(context) &&
screenDisplayMode.value == ScreenDisplayMode.minimize) {
contentHtml = textEditorWeb ?? '';
} else { } else {
final content = await htmlEditorApi?.getText() ?? ''; contentHtml = await htmlControllerBrowser.getText();
if (_isMobileApp && identitySelected.value?.textSignature?.value.isNotEmpty == true) { }
final newContent = '$content${identitySelected.value?.textSignature?.value.toSignatureBlock()}'; log('ComposerController::_getEmailBodyText():WEB: contentHtml: $contentHtml');
log('ComposerController::_generateEmail()_MOBILE: $newContent'); final newContentHtml = contentHtml.removeEditorStartTag();
return newContent; log('ComposerController::_getEmailBodyText():WEB: newContentHtml: $newContentHtml');
} else { return newContentHtml;
return content; } else {
} final contentHtml = await htmlEditorApi?.getText() ?? '';
log('ComposerController::_getEmailBodyText():MOBILE: $contentHtml');
final newContentHtml = contentHtml.removeEditorStartTag();
if (changedEmail) {
return newContentHtml;
} else if (_isMobileApp && identitySelected.value?.textSignature?.value.isNotEmpty == true) {
final contentHtmlWithSignature =
'$newContentHtml${identitySelected.value?.textSignature?.value.toSignatureBlock()}';
log('ComposerController::_getEmailBodyText():MOBILE:SIGNATURE: $contentHtmlWithSignature');
return contentHtmlWithSignature;
} else {
return newContentHtml;
} }
} }
} }
@@ -175,12 +188,24 @@ class ComposerController extends BaseController {
super.dispose(); super.dispose();
} }
@override
void onData(Either<Failure, Success> newState) {
super.onData(newState);
newState.map((success) async {
if (success is GetEmailContentLoading) {
emailContentsViewState.value = Right(success);
}
});
}
@override @override
void onDone() { void onDone() {
viewState.value.fold( viewState.value.fold(
(failure) { (failure) {
if (failure is LocalFilePickerFailure || failure is LocalFilePickerCancel) { if (failure is LocalFilePickerFailure || failure is LocalFilePickerCancel) {
_pickFileFailure(failure); _pickFileFailure(failure);
} else if (failure is GetEmailContentFailure) {
emailContentsViewState.value = Left(failure);
} }
}, },
(success) { (success) {
@@ -218,7 +243,7 @@ class ComposerController extends BaseController {
if (arguments.emailActionType == EmailActionType.edit) { if (arguments.emailActionType == EmailActionType.edit) {
_getEmailContentAction(arguments); _getEmailContentAction(arguments);
} }
_initToEmailAddress(arguments); _initEmailAddress(arguments);
_initSubjectEmail(arguments); _initSubjectEmail(arguments);
_initAttachments(arguments); _initAttachments(arguments);
} }
@@ -338,7 +363,7 @@ class ComposerController extends BaseController {
return null; return null;
} }
void _initToEmailAddress(ComposerArguments arguments) { void _initEmailAddress(ComposerArguments arguments) {
final userProfile = mailboxDashBoardController.userProfile.value; final userProfile = mailboxDashBoardController.userProfile.value;
if (arguments.presentationEmail != null && userProfile != null) { if (arguments.presentationEmail != null && userProfile != null) {
final userEmailAddress = EmailAddress(null, userProfile.email); final userEmailAddress = EmailAddress(null, userProfile.email);
@@ -419,8 +444,12 @@ class ComposerController extends BaseController {
return emailQuotedHtml; return emailQuotedHtml;
} }
Future<Email> _generateEmail(Map<Role, MailboxId> mapDefaultMailboxId, Future<Email> _generateEmail(
UserProfile userProfile, {bool asDrafts = false}) async { BuildContext context,
Map<Role, MailboxId> mapDefaultMailboxId,
UserProfile userProfile,
{bool asDrafts = false}
) async {
final generateEmailId = EmailId(Id(_uuid.v1())); final generateEmailId = EmailId(Id(_uuid.v1()));
final outboxMailboxId = mapDefaultMailboxId[PresentationMailbox.roleOutbox]; final outboxMailboxId = mapDefaultMailboxId[PresentationMailbox.roleOutbox];
final draftMailboxId = mapDefaultMailboxId[PresentationMailbox.roleDrafts]; final draftMailboxId = mapDefaultMailboxId[PresentationMailbox.roleDrafts];
@@ -437,7 +466,7 @@ 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(); var emailBodyText = await _getEmailBodyText(context);
log('ComposerController::_generateEmail(): $emailBodyText'); log('ComposerController::_generateEmail(): $emailBodyText');
final userAgent = await userAgentPlatform; final userAgent = await userAgentPlatform;
log('ComposerController::_generateEmail(): userAgent: $userAgent'); log('ComposerController::_generateEmail(): userAgent: $userAgent');
@@ -561,7 +590,7 @@ class ComposerController extends BaseController {
if (arguments != null && session != null && mapDefaultMailboxId.isNotEmpty if (arguments != null && session != null && mapDefaultMailboxId.isNotEmpty
&& userProfile != null) { && userProfile != null) {
final email = await _generateEmail(mapDefaultMailboxId, userProfile); final email = await _generateEmail(context, mapDefaultMailboxId, userProfile);
final accountId = session.accounts.keys.first; final accountId = session.accounts.keys.first;
final sentMailboxId = mapDefaultMailboxId[PresentationMailbox.roleSent]; final sentMailboxId = mapDefaultMailboxId[PresentationMailbox.roleSent];
final submissionCreateId = Id(const Uuid().v1()); final submissionCreateId = Id(const Uuid().v1());
@@ -666,14 +695,17 @@ class ComposerController extends BaseController {
uploadController.deleteFileUploaded(uploadId); uploadController.deleteFileUploaded(uploadId);
} }
Future<bool> _isEmailChanged(BuildContext context, ComposerArguments arguments) async { Future<bool> _isEmailChanged(
final currentTextInComposer = await _getEmailBodyText(changedEmail: true); BuildContext context,
final newEmailBody = currentTextInComposer.removeEditorDefaultSpace(); ComposerArguments arguments,
) async {
final newEmailBody = await _getEmailBodyText(context, changedEmail: true);
log('ComposerController::_isEmailChanged(): newEmailBody: $newEmailBody'); log('ComposerController::_isEmailChanged(): newEmailBody: $newEmailBody');
var oldEmailBody = ''; var oldEmailBody = getContentEmail(context) ?? '';
final contentEmail = getContentEmail(context); log('ComposerController::_isEmailChanged(): getContentEmail: $oldEmailBody');
if (arguments.emailActionType != EmailActionType.compose && contentEmail != null && contentEmail.isNotEmpty) { if (arguments.emailActionType != EmailActionType.compose &&
oldEmailBody = kIsWeb ? contentEmail : '\n$contentEmail\n'; oldEmailBody.isNotEmpty) {
oldEmailBody = BuildUtils.isWeb ? oldEmailBody : '\n$oldEmailBody\n';
} }
if (BuildUtils.isWeb) { if (BuildUtils.isWeb) {
if (identitySelected.value?.htmlSignature?.value.isNotEmpty == true) { if (identitySelected.value?.htmlSignature?.value.isNotEmpty == true) {
@@ -733,7 +765,11 @@ class ComposerController extends BaseController {
final isChanged = await _isEmailChanged(context, arguments); final isChanged = await _isEmailChanged(context, arguments);
log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts isChanged: $isChanged'); log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts isChanged: $isChanged');
if (isChanged) { if (isChanged) {
final newEmail = await _generateEmail(mapDefaultMailboxId, userProfile, asDrafts: true); final newEmail = await _generateEmail(
context,
mapDefaultMailboxId,
userProfile,
asDrafts: true);
final accountId = session.accounts.keys.first; final accountId = session.accounts.keys.first;
final oldEmail = arguments.presentationEmail; final oldEmail = arguments.presentationEmail;
@@ -764,21 +800,15 @@ class ComposerController extends BaseController {
} }
void _getEmailContentSuccess(GetEmailContentSuccess success) { void _getEmailContentSuccess(GetEmailContentSuccess success) {
emailContents.value = success.emailContents;
if (success.attachments.isNotEmpty) { if (success.attachments.isNotEmpty) {
initialAttachments = success.attachments; initialAttachments = success.attachments;
uploadController.initializeUploadAttachments(success.attachments); uploadController.initializeUploadAttachments(success.attachments);
} }
emailContentsViewState.value = Right(success);
_emailContents = success.emailContents;
} }
String? getEmailContentDraftsAsHtml() { String? getEmailContentDraftsAsHtml() => _emailContents?.asHtmlString;
final listContents = emailContents.value;
if (listContents != null) {
return listContents.asHtmlString;
} else {
return null;
}
}
String getEmailAddressSender() { String getEmailAddressSender() {
final arguments = composerArguments.value; final arguments = composerArguments.value;
@@ -10,15 +10,17 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart'; 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/composer/domain/state/upload_attachment_state.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/composer_controller.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/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/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/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 {
final responsiveUtils = Get.find<ResponsiveUtils>(); final responsiveUtils = Get.find<ResponsiveUtils>();
final imagePaths = Get.find<ImagePaths>(); final imagePaths = Get.find<ImagePaths>();
@@ -490,25 +492,59 @@ class ComposerView extends GetWidget<ComposerController> {
Widget _buildComposerEditor(BuildContext context) { Widget _buildComposerEditor(BuildContext context) {
return Obx(() { return Obx(() {
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) { final argsComposer = controller.composerArguments.value;
return HtmlEditor(
key: const Key('composer_editor'), if (argsComposer == null) {
minHeight: 550, return const SizedBox.shrink();
initialContent: ''.addEditorDefaultSpace(), }
onCreated: (editorApi) => controller.htmlEditorApi = editorApi);
} else { switch(argsComposer.emailActionType) {
final message = controller.getContentEmail(context); case EmailActionType.compose:
return message != null && message.isNotEmpty case EmailActionType.composeFromEmailAddress:
? HtmlEditor( return _buildHtmlEditor(HtmlExtension.editorStartTags);
key: const Key('composer_editor'), case EmailActionType.edit:
minHeight: 550, return controller.emailContentsViewState.value.fold(
onCreated: (editorApi) => controller.htmlEditorApi = editorApi, (failure) => _buildHtmlEditor(HtmlExtension.editorStartTags),
initialContent: message) (success) {
: const SizedBox.shrink(); if (success is GetEmailContentLoading) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: loadingWidget,
);
} else if (success is GetEmailContentSuccess) {
var contentHtml = success.emailContents.asHtmlString;
if (contentHtml.isEmpty == true) {
contentHtml = HtmlExtension.editorStartTags;
}
return _buildHtmlEditor(contentHtml);
} else {
return _buildHtmlEditor(HtmlExtension.editorStartTags);
}
});
case EmailActionType.reply:
case EmailActionType.replyAll:
case EmailActionType.forward:
var contentHtml = controller.getEmailContentQuotedAsHtml(
context,
argsComposer);
if (contentHtml.isEmpty == true) {
contentHtml = HtmlExtension.editorStartTags;
}
return _buildHtmlEditor(contentHtml);
default:
return _buildHtmlEditor(HtmlExtension.editorStartTags);
} }
}); });
} }
Widget _buildHtmlEditor(String initialContent) {
return HtmlEditor(
key: const Key('composer_editor'),
minHeight: 550,
initialContent: initialContent,
onCreated: (editorApi) => controller.htmlEditorApi = editorApi);
}
Widget _buildAttachmentsLoadingView({EdgeInsets? padding, double? size}) { Widget _buildAttachmentsLoadingView({EdgeInsets? padding, double? size}) {
return Obx(() => controller.viewState.value.fold( return Obx(() => controller.viewState.value.fold(
(failure) => const SizedBox.shrink(), (failure) => const SizedBox.shrink(),
@@ -6,10 +6,11 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:html_editor_enhanced/html_editor.dart' as html_editor_browser; import 'package:html_editor_enhanced/html_editor.dart' as editor_web;
import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:model/model.dart'; 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/composer/domain/state/upload_attachment_state.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/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
@@ -17,9 +18,10 @@ import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_
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/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/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 {
final responsiveUtils = Get.find<ResponsiveUtils>(); final responsiveUtils = Get.find<ResponsiveUtils>();
final imagePaths = Get.find<ImagePaths>(); final imagePaths = Get.find<ImagePaths>();
@@ -53,7 +55,12 @@ class ComposerView extends GetWidget<ComposerController> {
const Divider(color: AppColor.colorDividerComposer, height: 1), 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)),
const Divider(color: AppColor.colorDividerComposer, height: 1), const Divider(color: AppColor.colorDividerComposer, height: 1),
Expanded(child: _buildEditorAndAttachments(context)), Expanded(child: Column(
children: [
_buildAttachmentsWidget(context),
_buildEditorForm(context)
]
)),
] ]
))) )))
) )
@@ -92,7 +99,7 @@ class ComposerView extends GetWidget<ComposerController> {
padding: const EdgeInsets.only(left: 10), padding: const EdgeInsets.only(left: 10),
child: buildIconWeb( child: buildIconWeb(
icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill), icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).close, tooltip: AppLocalizations.of(context).saveAndClose,
onTap: () => controller.saveEmailAsDrafts(context) onTap: () => controller.saveEmailAsDrafts(context)
)), )),
buildIconWeb( buildIconWeb(
@@ -147,23 +154,7 @@ class ComposerView extends GetWidget<ComposerController> {
) )
) )
)) ))
), )
tabletLarge: Scaffold(
backgroundColor: Colors.black38,
body: Align(alignment: Alignment.center, child: Card(
color: Colors.transparent,
shadowColor: Colors.transparent,
child: Container(
decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(24))),
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(24)),
child: LayoutBuilder(builder: (context, constraints) =>
PointerInterceptor(child: _buildBodyForDesktop(context, constraints)))
)
)
))
),
); );
} }
@@ -172,7 +163,7 @@ class ComposerView extends GetWidget<ComposerController> {
children: [ children: [
buildIconWeb( buildIconWeb(
icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill), icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).close, tooltip: AppLocalizations.of(context).saveAndClose,
onTap: () => controller.saveEmailAsDrafts(context)), onTap: () => controller.saveEmailAsDrafts(context)),
if (responsiveUtils.isDesktop(context)) if (responsiveUtils.isDesktop(context))
Obx(() => buildIconWeb( Obx(() => buildIconWeb(
@@ -204,7 +195,7 @@ class ComposerView extends GetWidget<ComposerController> {
children: [ children: [
buildIconWeb( buildIconWeb(
icon: SvgPicture.asset(imagePaths.icClose, width: 30, height: 30, fit: BoxFit.fill), icon: SvgPicture.asset(imagePaths.icClose, width: 30, height: 30, fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).close, tooltip: AppLocalizations.of(context).saveAndClose,
iconPadding: EdgeInsets.zero, iconPadding: EdgeInsets.zero,
onTap: () => controller.saveEmailAsDrafts(context)), onTap: () => controller.saveEmailAsDrafts(context)),
Expanded(child: _buildTitleComposer(context)), Expanded(child: _buildTitleComposer(context)),
@@ -287,8 +278,15 @@ class ComposerView extends GetWidget<ComposerController> {
])), ])),
const Divider(color: AppColor.colorDividerComposer, height: 1), const Divider(color: AppColor.colorDividerComposer, height: 1),
Expanded(child: Padding( Expanded(child: Padding(
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 60, right: responsiveUtils.isMobile(context) ? 16 : 25), padding: EdgeInsets.only(
child: _buildEditorAndAttachments(context))), left: responsiveUtils.isMobile(context) ? 16 : 60,
right: responsiveUtils.isMobile(context) ? 16 : 25),
child: Column(
children: [
_buildAttachmentsWidget(context),
_buildEditorForm(context)
]
))),
const Divider(color: AppColor.colorDividerComposer, height: 1), const Divider(color: AppColor.colorDividerComposer, height: 1),
Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)), Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)),
]); ]);
@@ -489,105 +487,137 @@ class ComposerView extends GetWidget<ComposerController> {
); );
} }
Widget _buildEditorAndAttachments(BuildContext context) { Widget _buildEditorForm(BuildContext context) {
return Obx(() { return Obx(() {
final uploadAttachments = controller.uploadController.listUploadAttachments; final argsComposer = controller.composerArguments.value;
return Column( if (argsComposer == null) {
children: [ return const SizedBox.shrink();
if (uploadAttachments.isNotEmpty) }
...[
Padding( final currentTextEditor = controller.textEditorWeb;
padding: EdgeInsets.only(
top: 4, switch(argsComposer.emailActionType) {
bottom: 4, case EmailActionType.compose:
left: responsiveUtils.isMobile(context) ? 16 : 20, case EmailActionType.composeFromEmailAddress:
right: responsiveUtils.isMobile(context) ? 16: 0), return _buildHtmlEditor(
child: _buildAttachmentsTitle(context, context,
uploadAttachments, currentTextEditor ?? HtmlExtension.editorStartTags);
controller.expandModeAttachments.value)), case EmailActionType.edit:
_buildAttachmentsLoadingView(), return controller.emailContentsViewState.value.fold(
Padding( (failure) => _buildHtmlEditor(
padding: EdgeInsets.only( context,
bottom: 8, currentTextEditor ?? HtmlExtension.editorStartTags),
left: responsiveUtils.isMobile(context) ? 16 : 10, (success) {
right: responsiveUtils.isMobile(context) ? 16 : 10), if (success is GetEmailContentLoading) {
child: _buildAttachmentsList(context, return Padding(
uploadAttachments, padding: const EdgeInsets.all(16.0),
controller.expandModeAttachments.value)) child: loadingWidget,
], );
if (controller.composerArguments.value != null) } else if (success is GetEmailContentSuccess) {
_buildComposeEditor(context) var contentHtml = success.emailContents.asHtmlString;
] if (contentHtml.isEmpty == true) {
); contentHtml = HtmlExtension.editorStartTags;
}
return _buildHtmlEditor(context, currentTextEditor ?? contentHtml);
} else {
return _buildHtmlEditor(
context,
currentTextEditor ?? HtmlExtension.editorStartTags);
}
});
case EmailActionType.reply:
case EmailActionType.replyAll:
case EmailActionType.forward:
var contentHtml = controller.getEmailContentQuotedAsHtml(
context,
argsComposer);
if (contentHtml.isEmpty == true) {
contentHtml = HtmlExtension.editorStartTags;
}
return _buildHtmlEditor(context, currentTextEditor ?? contentHtml);
default:
return _buildHtmlEditor(
context,
currentTextEditor ?? HtmlExtension.editorStartTags);
}
}); });
} }
Widget _buildComposeEditor(BuildContext context) { Widget _buildHtmlEditor(BuildContext context, String initContent) {
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) { log('ComposerView::_buildHtmlEditor(): initContent: $initContent');
final initContent = controller.textEditorWeb ?? ''.addEditorDefaultSpace();
return Expanded(child: Padding( return Expanded(
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10), child: Padding(
child: _buildEditor(context, initContent))); padding: EdgeInsets.symmetric(
} else if (controller.composerArguments.value?.emailActionType == EmailActionType.edit) { horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
final initContent = controller.textEditorWeb ?? controller.getEmailContentDraftsAsHtml(); child: editor_web.HtmlEditor(
if (initContent != null) { key: const Key('composer_editor_web'),
return Expanded(child: Padding( controller: controller.htmlControllerBrowser,
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10), htmlEditorOptions: const editor_web.HtmlEditorOptions(
child: _buildEditor(context, initContent))); hint: '',
} else { darkMode: false,
return const Padding( ),
padding: EdgeInsets.all(16), blockQuotedContent: initContent,
child: SizedBox( htmlToolbarOptions: const editor_web.HtmlToolbarOptions(
width: 30, toolbarPosition: editor_web.ToolbarPosition.custom),
height: 30, otherOptions: const editor_web.OtherOptions(height: 550),
child: CupertinoActivityIndicator(color: AppColor.colorLoading))); callbacks: editor_web.Callbacks(
} onBeforeCommand: (String? currentHtml) {
} else { log('ComposerView::_buildComposerEditor(): onBeforeCommand : $currentHtml');
final initContent = controller.textEditorWeb ?? controller.getEmailContentQuotedAsHtml(context, controller.composerArguments.value!); controller.setTextEditorWeb(currentHtml);
return Expanded(child: Padding( }, onChangeContent: (String? changed) {
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10), log('ComposerView::_buildComposerEditor(): onChangeContent : $changed');
child: _buildEditor(context, initContent))); controller.setTextEditorWeb(changed);
} }, onInit: () {
log('ComposerView::_buildComposerEditor(): onInit');
controller.setTextEditorWeb(initContent);
controller.setFullScreenEditor();
}, onFocus: () {
FocusManager.instance.primaryFocus?.unfocus();
Future.delayed(const Duration(milliseconds: 500), () {
controller.htmlControllerBrowser.setFocus();
});
}, onBlur: () {
controller.onEditorFocusChange(false);
}, onMouseDown: () {
controller.onEditorFocusChange(true);
}),
)
)
);
} }
Widget _buildEditor(BuildContext context, String initContent) { Widget _buildAttachmentsWidget(BuildContext context) {
log('ComposerView::_buildEditor(): initContent: $initContent'); return Obx(() {
final attachments = controller.uploadController.listUploadAttachments;
return html_editor_browser.HtmlEditor( if (attachments.isNotEmpty) {
key: const Key('composer_editor_web'), return Column(children: [
controller: controller.htmlControllerBrowser, Padding(
htmlEditorOptions: const html_editor_browser.HtmlEditorOptions( padding: EdgeInsets.only(
hint: '', top: 4,
darkMode: false, bottom: 4,
), left: responsiveUtils.isMobile(context) ? 16 : 20,
blockQuotedContent: initContent, right: responsiveUtils.isMobile(context) ? 16: 0),
htmlToolbarOptions: const html_editor_browser.HtmlToolbarOptions( child: _buildAttachmentsTitle(
toolbarPosition: html_editor_browser.ToolbarPosition.custom context,
), attachments,
otherOptions: const html_editor_browser.OtherOptions(height: 550), controller.expandModeAttachments.value)),
callbacks: html_editor_browser.Callbacks( _buildAttachmentsLoadingView(),
onBeforeCommand: (String? currentHtml) { Padding(
log('ComposerView::_buildComposerEditor(): onBeforeCommand : $currentHtml'); padding: EdgeInsets.only(
controller.setTextEditorWeb(currentHtml); bottom: 8,
}, onChangeContent: (String? changed) { left: responsiveUtils.isMobile(context) ? 16 : 10,
log('ComposerView::_buildComposerEditor(): onChangeContent : $changed'); right: responsiveUtils.isMobile(context) ? 16 : 10),
controller.setTextEditorWeb(changed); child: _buildAttachmentsList(
}, onInit: () { context,
log('ComposerView::_buildComposerEditor(): onInit'); attachments,
controller.setFullScreenEditor(); controller.expandModeAttachments.value))
}, onFocus: () { ]);
FocusManager.instance.primaryFocus?.unfocus(); } else {
Future.delayed(const Duration(milliseconds: 500), () { return const SizedBox.shrink();
controller.htmlControllerBrowser.setFocus(); }
}); });
}, onBlur: () {
controller.onEditorFocusChange(false);
}, onMouseDown: () {
controller.onEditorFocusChange(true);
}
),
);
} }
Widget _buildAttachmentsLoadingView({EdgeInsets? padding, double? size}) { Widget _buildAttachmentsLoadingView({EdgeInsets? padding, double? size}) {
+7 -1
View File
@@ -1,5 +1,5 @@
{ {
"@@last_modified": "2022-07-05T19:24:56.876056", "@@last_modified": "2022-07-11T12:17:57.489417",
"initializing_data": "Initializing data...", "initializing_data": "Initializing data...",
"@initializing_data": { "@initializing_data": {
"type": "text", "type": "text",
@@ -1567,5 +1567,11 @@
"type": "text", "type": "text",
"placeholders_order": [], "placeholders_order": [],
"placeholders": {} "placeholders": {}
},
"saveAndClose": "Save & close",
"@saveAndClose": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
} }
} }
@@ -1608,4 +1608,10 @@ class AppLocalizations {
name: 'messageDialogSendEmailUploadingAttachment' name: 'messageDialogSendEmailUploadingAttachment'
); );
} }
String get saveAndClose {
return Intl.message(
'Save & close',
name: 'saveAndClose');
}
} }