TF-475 Fix save a draft email

This commit is contained in:
dab246
2022-05-30 15:35:23 +07:00
committed by Dat H. Pham
parent 8e6f905c43
commit 38bc7d9118
6 changed files with 68 additions and 39 deletions
@@ -32,4 +32,17 @@ extension HtmlExtension on String {
String addBlockQuoteTag() => addBlockTag( String addBlockQuoteTag() => addBlockTag(
'blockquote', 'blockquote',
attribute: 'style=\"margin-left:8px;margin-right:8px;padding-left:12px;padding-right:12px;border-left:5px solid #eee;\"'); attribute: 'style=\"margin-left:8px;margin-right:8px;padding-left:12px;padding-right:12px;border-left:5px solid #eee;\"');
String asSignatureHtml() => '--<br><br>$this';
String toSignatureBlock() =>
'<br class="tmail-break-tag"><div class="tmail-signature">${asSignatureHtml()}</div><br class="tmail-break-tag">';
String removeEditorDefaultSpace() {
return replaceAll('<p><br><br><br></p>', '');
}
String addEditorDefaultSpace() {
return '<p><br><br><br></p>';
}
} }
@@ -1,6 +1,14 @@
import 'package:core/core.dart'; import 'package:core/core.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart';
class SaveEmailAsDraftsLoading extends UIState {
SaveEmailAsDraftsLoading();
@override
List<Object?> get props => [];
}
class SaveEmailAsDraftsSuccess extends UIState { class SaveEmailAsDraftsSuccess extends UIState {
final Email emailAsDrafts; final Email emailAsDrafts;
@@ -12,6 +12,7 @@ class SaveEmailAsDraftsInteractor {
Stream<Either<Failure, Success>> execute(AccountId accountId, Email email) async* { Stream<Either<Failure, Success>> execute(AccountId accountId, Email email) async* {
try { try {
yield Right<Failure, Success>(SaveEmailAsDraftsLoading());
final emailAsDrafts = await emailRepository.saveEmailAsDrafts(accountId, email); final emailAsDrafts = await emailRepository.saveEmailAsDrafts(accountId, email);
if (emailAsDrafts != null) { if (emailAsDrafts != null) {
yield Right<Failure, Success>(SaveEmailAsDraftsSuccess(emailAsDrafts)); yield Right<Failure, Success>(SaveEmailAsDraftsSuccess(emailAsDrafts));
@@ -116,7 +116,7 @@ class ComposerController extends BaseController {
} else { } else {
final content = await htmlEditorApi?.getText() ?? ''; final content = await htmlEditorApi?.getText() ?? '';
if (_isMobileApp && identitySelected.value?.textSignature?.value.isNotEmpty == true) { if (_isMobileApp && identitySelected.value?.textSignature?.value.isNotEmpty == true) {
final newContent = '$content<br><br><br>--<br><br><div>${identitySelected.value?.textSignature?.value}</div><br>'; final newContent = '$content${identitySelected.value?.textSignature?.value.toSignatureBlock()}';
log('ComposerController::_generateEmail()_MOBILE: $newContent'); log('ComposerController::_generateEmail()_MOBILE: $newContent');
return newContent; return newContent;
} else { } else {
@@ -143,9 +143,11 @@ class ComposerController extends BaseController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) async { if (!BuildUtils.isWeb) {
await FkUserAgent.init(); WidgetsBinding.instance?.addPostFrameCallback((timeStamp) async {
}); await FkUserAgent.init();
});
}
} }
@override @override
@@ -161,11 +163,19 @@ class ComposerController extends BaseController {
@override @override
void onClose() { void onClose() {
if (!BuildUtils.isWeb) {
FkUserAgent.release();
}
super.onClose();
}
@override
void dispose() {
subjectEmailInputController.dispose(); subjectEmailInputController.dispose();
toEmailAddressController.dispose(); toEmailAddressController.dispose();
ccEmailAddressController.dispose(); ccEmailAddressController.dispose();
bccEmailAddressController.dispose(); bccEmailAddressController.dispose();
super.onClose(); super.dispose();
} }
@override @override
@@ -435,6 +445,7 @@ class ComposerController extends BaseController {
var emailBodyText = await _getEmailBodyText(); var emailBodyText = await _getEmailBodyText();
log('ComposerController::_generateEmail(): $emailBodyText'); log('ComposerController::_generateEmail(): $emailBodyText');
final userAgent = await userAgentPlatform; final userAgent = await userAgentPlatform;
log('ComposerController::_generateEmail(): userAgent: $userAgent');
return Email( return Email(
generateEmailId, generateEmailId,
@@ -708,14 +719,22 @@ class ComposerController extends BaseController {
} }
Future<bool> _isEmailChanged(BuildContext context, ComposerArguments arguments) async { Future<bool> _isEmailChanged(BuildContext context, ComposerArguments arguments) async {
final newEmailBody = (await _getEmailBodyText(changedEmail: true)) final currentTextInComposer = await _getEmailBodyText(changedEmail: true);
.replaceAll('<p><br><br><br></p>', ''); final newEmailBody = currentTextInComposer.removeEditorDefaultSpace();
log('ComposerController::_isEmailChanged(): newEmailBody: $newEmailBody'); log('ComposerController::_isEmailChanged(): newEmailBody: $newEmailBody');
var oldEmailBody = ''; var oldEmailBody = '';
final contentEmail = getContentEmail(context); final contentEmail = getContentEmail(context);
if (arguments.emailActionType != EmailActionType.compose && contentEmail != null && contentEmail.isNotEmpty) { if (arguments.emailActionType != EmailActionType.compose && contentEmail != null && contentEmail.isNotEmpty) {
oldEmailBody = kIsWeb ? contentEmail : '\n$contentEmail\n'; 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'); log('ComposerController::_isEmailChanged(): oldEmailBody: $oldEmailBody');
final isEmailBodyChanged = !oldEmailBody.trim().isSame(newEmailBody.trim()); final isEmailBodyChanged = !oldEmailBody.trim().isSame(newEmailBody.trim());
log('ComposerController::_isEmailChanged(): isEmailBodyChanged: $isEmailBodyChanged'); log('ComposerController::_isEmailChanged(): isEmailBodyChanged: $isEmailBodyChanged');
@@ -752,7 +771,8 @@ class ComposerController extends BaseController {
return false; return false;
} }
void saveEmailAsDrafts(BuildContext context) async { void saveEmailAsDrafts(BuildContext context, {bool canPop = true}) async {
log('ComposerController::saveEmailAsDrafts():');
clearFocusEditor(context); clearFocusEditor(context);
final arguments = composerArguments.value; final arguments = composerArguments.value;
@@ -763,8 +783,8 @@ class ComposerController extends BaseController {
if (arguments != null && mapDefaultMailboxId.isNotEmpty && userProfile != null && session != null) { if (arguments != null && mapDefaultMailboxId.isNotEmpty && userProfile != null && session != null) {
log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts START'); log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts START');
final isChanged = await _isEmailChanged(context, arguments); final isChanged = await _isEmailChanged(context, arguments);
log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts isChanged: $isChanged');
if (isChanged) { if (isChanged) {
log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts isChanged: $isChanged');
final newEmail = await _generateEmail(mapDefaultMailboxId, userProfile, asDrafts: true); final newEmail = await _generateEmail(mapDefaultMailboxId, userProfile, asDrafts: true);
final accountId = session.accounts.keys.first; final accountId = session.accounts.keys.first;
final oldEmail = arguments.presentationEmail; 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 { void _getEmailContentAction(ComposerArguments arguments) async {
@@ -819,7 +845,6 @@ class ComposerController extends BaseController {
void clearFocusEditor(BuildContext context) { void clearFocusEditor(BuildContext context) {
if (!kIsWeb) { if (!kIsWeb) {
htmlEditorApi?.unfocus(context); htmlEditorApi?.unfocus(context);
htmlControllerBrowser.clearFocus();
} }
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
} }
@@ -39,7 +39,7 @@ class ComposerView extends GetWidget<ComposerController> {
Widget _buildComposerViewForMobile(BuildContext context) { Widget _buildComposerViewForMobile(BuildContext context) {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
controller.saveEmailAsDrafts(context); controller.saveEmailAsDrafts(context, canPop: false);
return true; return true;
}, },
child: GestureDetector( child: GestureDetector(
@@ -68,7 +68,7 @@ class ComposerView extends GetWidget<ComposerController> {
Widget _buildComposerViewForTablet(BuildContext context) { Widget _buildComposerViewForTablet(BuildContext context) {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
controller.saveEmailAsDrafts(context); controller.saveEmailAsDrafts(context, canPop: false);
return true; return true;
}, },
child: GestureDetector( child: GestureDetector(
@@ -119,12 +119,9 @@ class ComposerView extends GetWidget<ComposerController> {
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).close,
iconPadding: EdgeInsets.zero, iconPadding: EdgeInsets.zero,
onTap: () { onTap: () => controller.saveEmailAsDrafts(context)),
controller.saveEmailAsDrafts(context);
controller.closeComposer();
}),
Expanded(child: _buildTitleComposer(context)), Expanded(child: _buildTitleComposer(context)),
if (responsiveUtils.isMobile(context)) if (responsiveUtils.isScreenWithShortestSide(context))
buildIconWeb( buildIconWeb(
icon: SvgPicture.asset( icon: SvgPicture.asset(
isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendDisable, isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendDisable,
@@ -158,10 +155,7 @@ class ComposerView extends GetWidget<ComposerController> {
width: 150, width: 150,
height: 44, height: 44,
radius: 10, radius: 10,
onTap: () { onTap: () => controller.saveEmailAsDrafts(context)),
controller.saveEmailAsDrafts(context);
controller.closeComposer();
}),
const SizedBox(width: 12), const SizedBox(width: 12),
buildTextButton( buildTextButton(
AppLocalizations.of(context).send, AppLocalizations.of(context).send,
@@ -487,7 +481,7 @@ class ComposerView extends GetWidget<ComposerController> {
return HtmlEditor( return HtmlEditor(
key: const Key('composer_editor'), key: const Key('composer_editor'),
minHeight: 550, minHeight: 550,
initialContent: '<p><br><br><br></p>', initialContent: ''.addEditorDefaultSpace(),
onCreated: (editorApi) => controller.htmlEditorApi = editorApi); onCreated: (editorApi) => controller.htmlEditorApi = editorApi);
} else { } else {
final message = controller.getContentEmail(context); final message = controller.getContentEmail(context);
@@ -91,10 +91,7 @@ class ComposerView extends GetWidget<ComposerController> {
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).close,
onTap: () { onTap: () => controller.saveEmailAsDrafts(context)
controller.saveEmailAsDrafts(context);
controller.closeComposerWeb();
}
)), )),
buildIconWeb( buildIconWeb(
icon: SvgPicture.asset(imagePaths.icFullScreenComposer, fit: BoxFit.fill), icon: SvgPicture.asset(imagePaths.icFullScreenComposer, fit: BoxFit.fill),
@@ -174,10 +171,7 @@ class ComposerView extends GetWidget<ComposerController> {
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).close,
onTap: () { onTap: () => controller.saveEmailAsDrafts(context)),
controller.saveEmailAsDrafts(context);
controller.closeComposerWeb();
}),
if (responsiveUtils.isDesktop(context)) if (responsiveUtils.isDesktop(context))
Obx(() => buildIconWeb( Obx(() => buildIconWeb(
icon: SvgPicture.asset( icon: SvgPicture.asset(
@@ -210,10 +204,7 @@ class ComposerView extends GetWidget<ComposerController> {
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).close,
iconPadding: EdgeInsets.zero, iconPadding: EdgeInsets.zero,
onTap: () { onTap: () => controller.saveEmailAsDrafts(context)),
controller.saveEmailAsDrafts(context);
controller.closeComposerWeb();
}),
Expanded(child: _buildTitleComposer(context)), Expanded(child: _buildTitleComposer(context)),
buildIconWeb( buildIconWeb(
icon: SvgPicture.asset( icon: SvgPicture.asset(
@@ -248,10 +239,7 @@ class ComposerView extends GetWidget<ComposerController> {
width: 150, width: 150,
height: 44, height: 44,
radius: 10, radius: 10,
onTap: () { onTap: () => controller.saveEmailAsDrafts(context)),
controller.saveEmailAsDrafts(context);
controller.closeComposerWeb();
}),
const SizedBox(width: 12), const SizedBox(width: 12),
buildTextButton( buildTextButton(
AppLocalizations.of(context).send, AppLocalizations.of(context).send,
@@ -518,7 +506,7 @@ class ComposerView extends GetWidget<ComposerController> {
Obx(() { Obx(() {
if (controller.composerArguments.value != null) { if (controller.composerArguments.value != null) {
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) { if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
final initContent = controller.textEditorWeb ?? '<p><br><br><br></p>'; final initContent = controller.textEditorWeb ?? ''.addEditorDefaultSpace();
return Expanded(child: Padding( return Expanded(child: Padding(
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10), padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
child: _buildEditor(context, initContent))); child: _buildEditor(context, initContent)));