diff --git a/core/lib/presentation/extensions/html_extension.dart b/core/lib/presentation/extensions/html_extension.dart index 0ede25835..92f655d38 100644 --- a/core/lib/presentation/extensions/html_extension.dart +++ b/core/lib/presentation/extensions/html_extension.dart @@ -32,4 +32,17 @@ extension HtmlExtension on String { String addBlockQuoteTag() => addBlockTag( 'blockquote', attribute: 'style=\"margin-left:8px;margin-right:8px;padding-left:12px;padding-right:12px;border-left:5px solid #eee;\"'); + + String asSignatureHtml() => '--

$this'; + + String toSignatureBlock() => + '
${asSignatureHtml()}

'; + + String removeEditorDefaultSpace() { + return replaceAll('




', ''); + } + + String addEditorDefaultSpace() { + return '




'; + } } diff --git a/lib/features/composer/domain/state/save_email_as_drafts_state.dart b/lib/features/composer/domain/state/save_email_as_drafts_state.dart index e3d32db5e..c0c657d25 100644 --- a/lib/features/composer/domain/state/save_email_as_drafts_state.dart +++ b/lib/features/composer/domain/state/save_email_as_drafts_state.dart @@ -1,6 +1,14 @@ import 'package:core/core.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +class SaveEmailAsDraftsLoading extends UIState { + + SaveEmailAsDraftsLoading(); + + @override + List get props => []; +} + class SaveEmailAsDraftsSuccess extends UIState { final Email emailAsDrafts; diff --git a/lib/features/composer/domain/usecases/save_email_as_drafts_interactor.dart b/lib/features/composer/domain/usecases/save_email_as_drafts_interactor.dart index e20c53868..91e580f5f 100644 --- a/lib/features/composer/domain/usecases/save_email_as_drafts_interactor.dart +++ b/lib/features/composer/domain/usecases/save_email_as_drafts_interactor.dart @@ -12,6 +12,7 @@ class SaveEmailAsDraftsInteractor { Stream> execute(AccountId accountId, Email email) async* { try { + yield Right(SaveEmailAsDraftsLoading()); final emailAsDrafts = await emailRepository.saveEmailAsDrafts(accountId, email); if (emailAsDrafts != null) { yield Right(SaveEmailAsDraftsSuccess(emailAsDrafts)); diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 10f4b7faf..075174379 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -116,7 +116,7 @@ class ComposerController extends BaseController { } else { final content = await htmlEditorApi?.getText() ?? ''; if (_isMobileApp && identitySelected.value?.textSignature?.value.isNotEmpty == true) { - final newContent = '$content


--

${identitySelected.value?.textSignature?.value}

'; + final newContent = '$content${identitySelected.value?.textSignature?.value.toSignatureBlock()}'; log('ComposerController::_generateEmail()_MOBILE: $newContent'); return newContent; } else { @@ -143,9 +143,11 @@ class ComposerController extends BaseController { @override void onInit() { super.onInit(); - WidgetsBinding.instance?.addPostFrameCallback((timeStamp) async { - await FkUserAgent.init(); - }); + if (!BuildUtils.isWeb) { + WidgetsBinding.instance?.addPostFrameCallback((timeStamp) async { + await FkUserAgent.init(); + }); + } } @override @@ -161,11 +163,19 @@ class ComposerController extends BaseController { @override void onClose() { + if (!BuildUtils.isWeb) { + FkUserAgent.release(); + } + super.onClose(); + } + + @override + void dispose() { subjectEmailInputController.dispose(); toEmailAddressController.dispose(); ccEmailAddressController.dispose(); bccEmailAddressController.dispose(); - super.onClose(); + super.dispose(); } @override @@ -435,6 +445,7 @@ class ComposerController extends BaseController { var emailBodyText = await _getEmailBodyText(); log('ComposerController::_generateEmail(): $emailBodyText'); final userAgent = await userAgentPlatform; + log('ComposerController::_generateEmail(): userAgent: $userAgent'); return Email( generateEmailId, @@ -708,14 +719,22 @@ class ComposerController extends BaseController { } Future _isEmailChanged(BuildContext context, ComposerArguments arguments) async { - final newEmailBody = (await _getEmailBodyText(changedEmail: true)) - .replaceAll('




', ''); + final currentTextInComposer = await _getEmailBodyText(changedEmail: true); + final newEmailBody = currentTextInComposer.removeEditorDefaultSpace(); log('ComposerController::_isEmailChanged(): newEmailBody: $newEmailBody'); var oldEmailBody = ''; final contentEmail = getContentEmail(context); if (arguments.emailActionType != EmailActionType.compose && contentEmail != null && contentEmail.isNotEmpty) { oldEmailBody = kIsWeb ? contentEmail : '\n$contentEmail\n'; } + if (BuildUtils.isWeb) { + if (identitySelected.value?.htmlSignature?.value.isNotEmpty == true) { + oldEmailBody = '$oldEmailBody${identitySelected.value?.htmlSignature?.value.toSignatureBlock()}'; + } else if (identitySelected.value?.textSignature?.value.isNotEmpty == true) { + oldEmailBody = '$oldEmailBody${identitySelected.value?.textSignature?.value.toSignatureBlock()}'; + } + } + log('ComposerController::_isEmailChanged(): oldEmailBody: $oldEmailBody'); final isEmailBodyChanged = !oldEmailBody.trim().isSame(newEmailBody.trim()); log('ComposerController::_isEmailChanged(): isEmailBodyChanged: $isEmailBodyChanged'); @@ -752,7 +771,8 @@ class ComposerController extends BaseController { return false; } - void saveEmailAsDrafts(BuildContext context) async { + void saveEmailAsDrafts(BuildContext context, {bool canPop = true}) async { + log('ComposerController::saveEmailAsDrafts():'); clearFocusEditor(context); final arguments = composerArguments.value; @@ -763,8 +783,8 @@ class ComposerController extends BaseController { if (arguments != null && mapDefaultMailboxId.isNotEmpty && userProfile != null && session != null) { log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts START'); final isChanged = await _isEmailChanged(context, arguments); + log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts isChanged: $isChanged'); if (isChanged) { - log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts isChanged: $isChanged'); final newEmail = await _generateEmail(mapDefaultMailboxId, userProfile, asDrafts: true); final accountId = session.accounts.keys.first; final oldEmail = arguments.presentationEmail; @@ -778,6 +798,12 @@ class ComposerController extends BaseController { } } } + + if (BuildUtils.isWeb) { + mailboxDashBoardController.dispatchAction(CloseComposeEmailAction()); + } else { + if (canPop) popBack(); + } } void _getEmailContentAction(ComposerArguments arguments) async { @@ -819,7 +845,6 @@ class ComposerController extends BaseController { void clearFocusEditor(BuildContext context) { if (!kIsWeb) { htmlEditorApi?.unfocus(context); - htmlControllerBrowser.clearFocus(); } FocusManager.instance.primaryFocus?.unfocus(); } diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index cac5d8064..4aaea1bc5 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -39,7 +39,7 @@ class ComposerView extends GetWidget { Widget _buildComposerViewForMobile(BuildContext context) { return WillPopScope( onWillPop: () async { - controller.saveEmailAsDrafts(context); + controller.saveEmailAsDrafts(context, canPop: false); return true; }, child: GestureDetector( @@ -68,7 +68,7 @@ class ComposerView extends GetWidget { Widget _buildComposerViewForTablet(BuildContext context) { return WillPopScope( onWillPop: () async { - controller.saveEmailAsDrafts(context); + controller.saveEmailAsDrafts(context, canPop: false); return true; }, child: GestureDetector( @@ -119,12 +119,9 @@ class ComposerView extends GetWidget { icon: SvgPicture.asset(imagePaths.icClose, width: 30, height: 30, fit: BoxFit.fill), tooltip: AppLocalizations.of(context).close, iconPadding: EdgeInsets.zero, - onTap: () { - controller.saveEmailAsDrafts(context); - controller.closeComposer(); - }), + onTap: () => controller.saveEmailAsDrafts(context)), Expanded(child: _buildTitleComposer(context)), - if (responsiveUtils.isMobile(context)) + if (responsiveUtils.isScreenWithShortestSide(context)) buildIconWeb( icon: SvgPicture.asset( isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendDisable, @@ -158,10 +155,7 @@ class ComposerView extends GetWidget { width: 150, height: 44, radius: 10, - onTap: () { - controller.saveEmailAsDrafts(context); - controller.closeComposer(); - }), + onTap: () => controller.saveEmailAsDrafts(context)), const SizedBox(width: 12), buildTextButton( AppLocalizations.of(context).send, @@ -487,7 +481,7 @@ class ComposerView extends GetWidget { return HtmlEditor( key: const Key('composer_editor'), minHeight: 550, - initialContent: '




', + initialContent: ''.addEditorDefaultSpace(), onCreated: (editorApi) => controller.htmlEditorApi = editorApi); } else { final message = controller.getContentEmail(context); diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 4d2da6fbd..38dc84f36 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -91,10 +91,7 @@ class ComposerView extends GetWidget { child: buildIconWeb( icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill), tooltip: AppLocalizations.of(context).close, - onTap: () { - controller.saveEmailAsDrafts(context); - controller.closeComposerWeb(); - } + onTap: () => controller.saveEmailAsDrafts(context) )), buildIconWeb( icon: SvgPicture.asset(imagePaths.icFullScreenComposer, fit: BoxFit.fill), @@ -174,10 +171,7 @@ class ComposerView extends GetWidget { buildIconWeb( icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill), tooltip: AppLocalizations.of(context).close, - onTap: () { - controller.saveEmailAsDrafts(context); - controller.closeComposerWeb(); - }), + onTap: () => controller.saveEmailAsDrafts(context)), if (responsiveUtils.isDesktop(context)) Obx(() => buildIconWeb( icon: SvgPicture.asset( @@ -210,10 +204,7 @@ class ComposerView extends GetWidget { icon: SvgPicture.asset(imagePaths.icClose, width: 30, height: 30, fit: BoxFit.fill), tooltip: AppLocalizations.of(context).close, iconPadding: EdgeInsets.zero, - onTap: () { - controller.saveEmailAsDrafts(context); - controller.closeComposerWeb(); - }), + onTap: () => controller.saveEmailAsDrafts(context)), Expanded(child: _buildTitleComposer(context)), buildIconWeb( icon: SvgPicture.asset( @@ -248,10 +239,7 @@ class ComposerView extends GetWidget { width: 150, height: 44, radius: 10, - onTap: () { - controller.saveEmailAsDrafts(context); - controller.closeComposerWeb(); - }), + onTap: () => controller.saveEmailAsDrafts(context)), const SizedBox(width: 12), buildTextButton( AppLocalizations.of(context).send, @@ -518,7 +506,7 @@ class ComposerView extends GetWidget { Obx(() { if (controller.composerArguments.value != null) { if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) { - final initContent = controller.textEditorWeb ?? '




'; + final initContent = controller.textEditorWeb ?? ''.addEditorDefaultSpace(); return Expanded(child: Padding( padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10), child: _buildEditor(context, initContent)));