TF-475 Fix save a draft email
This commit is contained in:
@@ -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)));
|
||||||
|
|||||||
Reference in New Issue
Block a user