TF-2597 Handles the ability to click the editor close button only once

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2024-02-27 17:05:44 +07:00
committed by Dat H. Pham
parent 2b3de4c47f
commit 49a3f7b70f
4 changed files with 63 additions and 54 deletions
@@ -34,6 +34,7 @@ import 'package:rich_text_composer/rich_text_composer.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:super_tag_editor/tag_editor.dart'; import 'package:super_tag_editor/tag_editor.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/base/state/button_state.dart';
import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.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/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/download_image_as_base64_state.dart';
@@ -167,9 +168,11 @@ class ComposerController extends BaseController {
double? maxWithEditor; double? maxWithEditor;
EmailId? _emailIdEditing; EmailId? _emailIdEditing;
bool isAttachmentCollapsed = false; bool isAttachmentCollapsed = false;
ButtonState _closeComposerButtonState = ButtonState.enabled;
late Worker uploadInlineImageWorker; late Worker uploadInlineImageWorker;
late Worker dashboardViewStateWorker; late Worker dashboardViewStateWorker;
late bool _isEmailBodyLoaded;
ComposerController( ComposerController(
this._deviceInfoPlugin, this._deviceInfoPlugin,
@@ -408,12 +411,14 @@ class ComposerController extends BaseController {
} }
void onLoadCompletedMobileEditorAction(HtmlEditorApi editorApi, WebUri? url) { void onLoadCompletedMobileEditorAction(HtmlEditorApi editorApi, WebUri? url) {
_isEmailBodyLoaded = true;
if (identitySelected.value == null) { if (identitySelected.value == null) {
_getAllIdentities(); _getAllIdentities();
} }
} }
void _initEmail() { void _initEmail() {
_isEmailBodyLoaded = false;
final arguments = PlatformInfo.isWeb final arguments = PlatformInfo.isWeb
? mailboxDashBoardController.composerArguments ? mailboxDashBoardController.composerArguments
: Get.arguments; : Get.arguments;
@@ -785,7 +790,7 @@ class ComposerController extends BaseController {
return; return;
} }
clearFocusEditor(context); clearFocus(context);
isSendEmailLoading.value = true; isSendEmailLoading.value = true;
@@ -1025,7 +1030,7 @@ class ComposerController extends BaseController {
} }
void openPickAttachmentMenu(BuildContext context, List<Widget> actionTiles) { void openPickAttachmentMenu(BuildContext context, List<Widget> actionTiles) {
clearFocusEditor(context); clearFocus(context);
(ContextMenuBuilder(context) (ContextMenuBuilder(context)
..addHeader((ContextMenuHeaderBuilder(const Key('attachment_picker_context_menu_header_builder')) ..addHeader((ContextMenuHeaderBuilder(const Key('attachment_picker_context_menu_header_builder'))
@@ -1083,18 +1088,16 @@ class ComposerController extends BaseController {
uploadController.deleteFileUploaded(uploadId); uploadController.deleteFileUploaded(uploadId);
} }
Future<bool> _isEmailChanged({ Future<bool> _validateEmailChange({
required BuildContext context, required BuildContext context,
required EmailActionType emailActionType, required EmailActionType emailActionType,
PresentationEmail? presentationEmail, PresentationEmail? presentationEmail,
Role? mailboxRole, Role? mailboxRole,
}) async { }) async {
final newEmailBody = await _getEmailBodyText(context, asDrafts: true); final newEmailBody = await _getEmailBodyText(context, asDrafts: true);
log('ComposerController::_isEmailChanged(): newEmailBody: $newEmailBody');
final oldEmailBody = _initTextEditor ?? ''; final oldEmailBody = _initTextEditor ?? '';
log('ComposerController::_isEmailChanged(): oldEmailBody: $oldEmailBody');
final isEmailBodyChanged = !oldEmailBody.trim().isSame(newEmailBody.trim()); final isEmailBodyChanged = !oldEmailBody.trim().isSame(newEmailBody.trim());
log('ComposerController::_isEmailChanged(): isEmailBodyChanged: $isEmailBodyChanged');
final newEmailSubject = subjectEmail.value ?? ''; final newEmailSubject = subjectEmail.value ?? '';
final oldEmailSubject = emailActionType == EmailActionType.editDraft final oldEmailSubject = emailActionType == EmailActionType.editDraft
? presentationEmail?.getEmailTitle().trim() ?? '' ? presentationEmail?.getEmailTitle().trim() ?? ''
@@ -1120,7 +1123,7 @@ class ComposerController extends BaseController {
final isBccEmailAddressChanged = !oldBccEmailAddress.isSame(newBccEmailAddress); final isBccEmailAddressChanged = !oldBccEmailAddress.isSame(newBccEmailAddress);
final isAttachmentsChanged = !initialAttachments.isSame(uploadController.attachmentsUploaded.toList()); final isAttachmentsChanged = !initialAttachments.isSame(uploadController.attachmentsUploaded.toList());
log('ComposerController::_validateChangeEmail: isEmailBodyChanged = $isEmailBodyChanged | isEmailSubjectChanged = $isEmailSubjectChanged | isToEmailAddressChanged = $isToEmailAddressChanged | isCcEmailAddressChanged = $isCcEmailAddressChanged | isBccEmailAddressChanged = $isBccEmailAddressChanged | isAttachmentsChanged = $isAttachmentsChanged');
if (isEmailBodyChanged || isEmailSubjectChanged if (isEmailBodyChanged || isEmailSubjectChanged
|| isToEmailAddressChanged || isCcEmailAddressChanged || isToEmailAddressChanged || isCcEmailAddressChanged
|| isBccEmailAddressChanged || isAttachmentsChanged) { || isBccEmailAddressChanged || isAttachmentsChanged) {
@@ -1130,10 +1133,8 @@ class ComposerController extends BaseController {
return false; return false;
} }
void saveToDraftAndClose(BuildContext context) async { Future<SaveToDraftArguments?> _handleSaveAsDrafts(BuildContext context) async {
log('ComposerController::saveToDraftAndClose:'); log('ComposerController::_handleSaveAsDrafts:');
clearFocusEditor(context);
final arguments = composerArguments.value; final arguments = composerArguments.value;
final userProfile = mailboxDashBoardController.userProfile.value; final userProfile = mailboxDashBoardController.userProfile.value;
final accountId = mailboxDashBoardController.accountId.value; final accountId = mailboxDashBoardController.accountId.value;
@@ -1146,9 +1147,7 @@ class ComposerController extends BaseController {
session == null || session == null ||
accountId == null accountId == null
) { ) {
logError('ComposerController::saveToDraftAndClose: Param is NULL'); return null;
_closeComposerAction();
return;
} }
if (_emailIdEditing != null && _emailIdEditing != arguments.presentationEmail?.id) { if (_emailIdEditing != null && _emailIdEditing != arguments.presentationEmail?.id) {
@@ -1160,20 +1159,19 @@ class ComposerController extends BaseController {
arguments: arguments, arguments: arguments,
); );
_closeComposerAction(result: SaveToDraftArguments( return SaveToDraftArguments(
session: session, session: session,
accountId: accountId, accountId: accountId,
newEmail: newEmail, newEmail: newEmail,
oldEmailId: _emailIdEditing! oldEmailId: _emailIdEditing!);
));
} else { } else {
final isChanged = await _isEmailChanged( final isChanged = await _validateEmailChange(
context: context, context: context,
emailActionType: arguments.emailActionType, emailActionType: arguments.emailActionType,
presentationEmail: arguments.presentationEmail, presentationEmail: arguments.presentationEmail,
mailboxRole: arguments.mailboxRole mailboxRole: arguments.mailboxRole
); );
log('ComposerController::saveToDraftAndClose: isChanged: $isChanged');
if (isChanged && context.mounted) { if (isChanged && context.mounted) {
final newEmail = await _generateEmail( final newEmail = await _generateEmail(
context, context,
@@ -1183,16 +1181,15 @@ class ComposerController extends BaseController {
arguments: arguments, arguments: arguments,
); );
_closeComposerAction(result: SaveToDraftArguments( return SaveToDraftArguments(
session: session, session: session,
accountId: accountId, accountId: accountId,
newEmail: newEmail, newEmail: newEmail,
oldEmailId: arguments.emailActionType == EmailActionType.editDraft oldEmailId: arguments.emailActionType == EmailActionType.editDraft
? arguments.presentationEmail?.id ? arguments.presentationEmail?.id
: null : null);
));
} else { } else {
_closeComposerAction(); return null;
} }
} }
} }
@@ -1413,7 +1410,8 @@ class ComposerController extends BaseController {
return ''; return '';
} }
void clearFocusEditor(BuildContext context) { void clearFocus(BuildContext context) {
log('ComposerController::clearFocus:');
if (PlatformInfo.isMobile) { if (PlatformInfo.isMobile) {
htmlEditorApi?.unfocus(); htmlEditorApi?.unfocus();
KeyboardUtils.hideSystemKeyboardMobile(); KeyboardUtils.hideSystemKeyboardMobile();
@@ -1422,21 +1420,16 @@ class ComposerController extends BaseController {
} }
void _closeComposerAction({dynamic result}) { void _closeComposerAction({dynamic result}) {
uploadController.clearInlineFileUploaded(); log('ComposerController::_closeComposerAction:');
isSendEmailLoading.value = false;
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
_closeComposerWeb(result: result); mailboxDashBoardController.closeComposerOverlay(result: result);
} else { } else {
isSendEmailLoading.value = false;
popBack(result: result); popBack(result: result);
} }
} }
void _closeComposerWeb({dynamic result}) {
isSendEmailLoading.value = false;
mailboxDashBoardController.closeComposerOverlay(result: result);
}
void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) async { void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) async {
createFocusNodeInput(); createFocusNodeInput();
_updateTextForEditor(); _updateTextForEditor();
@@ -1722,7 +1715,7 @@ class ComposerController extends BaseController {
} }
void insertImage(BuildContext context, double maxWith) async { void insertImage(BuildContext context, double maxWith) async {
clearFocusEditor(context); clearFocus(context);
if (responsiveUtils.isMobile(context)) { if (responsiveUtils.isMobile(context)) {
maxWithEditor = maxWith - 40; maxWithEditor = maxWith - 40;
@@ -1915,6 +1908,8 @@ class ComposerController extends BaseController {
subjectEmailInputFocusNode?.hasFocus == true; subjectEmailInputFocusNode?.hasFocus == true;
void handleInitHtmlEditorWeb(String initContent) { void handleInitHtmlEditorWeb(String initContent) {
log('ComposerController::handleInitHtmlEditorWeb:');
_isEmailBodyLoaded = true;
richTextWebController.editorController.setFullScreen(); richTextWebController.editorController.setFullScreen();
onChangeTextEditorWeb(initContent); onChangeTextEditorWeb(initContent);
richTextWebController.setEnableCodeView(); richTextWebController.setEnableCodeView();
@@ -2156,4 +2151,25 @@ class ComposerController extends BaseController {
..onTextSearchChangedAction((searchText) => _searchIdentities(searchText)) ..onTextSearchChangedAction((searchText) => _searchIdentities(searchText))
).build(); ).build();
} }
void handleClickCloseComposer(BuildContext context) async {
log('ComposerController::handleClickCloseComposer:');
if (_closeComposerButtonState == ButtonState.disabled) {
log('ComposerController::handleClickCloseComposer: _closeComposerButtonState = disabled');
return;
}
if (!_isEmailBodyLoaded) {
log('ComposerController::handleClickCloseComposer: _isEmailBodyLoaded = false');
clearFocus(context);
_closeComposerAction();
return;
}
_closeComposerButtonState = ButtonState.disabled;
clearFocus(context);
final draftArgs = await _handleSaveAsDrafts(context);
_closeComposerAction(result: draftArgs);
_closeComposerButtonState = ButtonState.enabled;
}
} }
@@ -37,8 +37,8 @@ class ComposerView extends GetWidget<ComposerController> {
responsiveUtils: controller.responsiveUtils, responsiveUtils: controller.responsiveUtils,
mobile: MobileContainerView( mobile: MobileContainerView(
keyboardRichTextController: controller.keyboardRichTextController, keyboardRichTextController: controller.keyboardRichTextController,
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
onClearFocusAction: () => controller.clearFocusEditor(context), onClearFocusAction: () => controller.clearFocus(context),
onAttachFileAction: () => controller.isNetworkConnectionAvailable onAttachFileAction: () => controller.isNetworkConnectionAvailable
? controller.openPickAttachmentMenu( ? controller.openPickAttachmentMenu(
context, context,
@@ -59,7 +59,7 @@ class ComposerView extends GetWidget<ComposerController> {
if (controller.responsiveUtils.isLandscapeMobile(context)) if (controller.responsiveUtils.isLandscapeMobile(context))
Obx(() => LandscapeAppBarComposerWidget( Obx(() => LandscapeAppBarComposerWidget(
isSendButtonEnabled: controller.isEnableEmailSendButton.value, isSendButtonEnabled: controller.isEnableEmailSendButton.value,
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
sendMessageAction: () => controller.validateInformationBeforeSending(context), sendMessageAction: () => controller.validateInformationBeforeSending(context),
openContextMenuAction: (position) { openContextMenuAction: (position) {
controller.openPopupMenuAction( controller.openPopupMenuAction(
@@ -73,7 +73,7 @@ class ComposerView extends GetWidget<ComposerController> {
else else
Obx(() => AppBarComposerWidget( Obx(() => AppBarComposerWidget(
isSendButtonEnabled: controller.isEnableEmailSendButton.value, isSendButtonEnabled: controller.isEnableEmailSendButton.value,
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
sendMessageAction: () => controller.validateInformationBeforeSending(context), sendMessageAction: () => controller.validateInformationBeforeSending(context),
openContextMenuAction: (position) { openContextMenuAction: (position) {
controller.openPopupMenuAction( controller.openPopupMenuAction(
@@ -222,8 +222,8 @@ class ComposerView extends GetWidget<ComposerController> {
), ),
tablet: TabletContainerView( tablet: TabletContainerView(
keyboardRichTextController: controller.keyboardRichTextController, keyboardRichTextController: controller.keyboardRichTextController,
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
onClearFocusAction: () => controller.clearFocusEditor(context), onClearFocusAction: () => controller.clearFocus(context),
onAttachFileAction: () => controller.isNetworkConnectionAvailable onAttachFileAction: () => controller.isNetworkConnectionAvailable
? controller.openPickAttachmentMenu( ? controller.openPickAttachmentMenu(
context, context,
@@ -239,7 +239,7 @@ class ComposerView extends GetWidget<ComposerController> {
children: [ children: [
Obx(() => DesktopAppBarComposerWidget( Obx(() => DesktopAppBarComposerWidget(
emailSubject: controller.subjectEmail.value ?? '', emailSubject: controller.subjectEmail.value ?? '',
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
constraints: constraints, constraints: constraints,
)), )),
Expanded( Expanded(
@@ -37,7 +37,7 @@ class ComposerView extends GetWidget<ComposerController> {
mobile: MobileResponsiveContainerView( mobile: MobileResponsiveContainerView(
childBuilder: (context, constraints) { childBuilder: (context, constraints) {
return GestureDetector( return GestureDetector(
onTap: () => controller.clearFocusEditor(context), onTap: () => controller.clearFocus(context),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -46,7 +46,7 @@ class ComposerView extends GetWidget<ComposerController> {
isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled, isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled,
openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions, openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions,
isSendButtonEnabled: controller.isEnableEmailSendButton.value, isSendButtonEnabled: controller.isEnableEmailSendButton.value,
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
attachFileAction: () => controller.openFilePickerByType(context, FileType.any), attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
insertImageAction: () => controller.insertImage(context, constraints.maxWidth), insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
sendMessageAction: () => controller.validateInformationBeforeSending(context), sendMessageAction: () => controller.validateInformationBeforeSending(context),
@@ -231,15 +231,12 @@ class ComposerView extends GetWidget<ComposerController> {
desktop: Obx(() => DesktopResponsiveContainerView( desktop: Obx(() => DesktopResponsiveContainerView(
childBuilder: (context, constraints) { childBuilder: (context, constraints) {
return GestureDetector( return GestureDetector(
onTap: () => controller.clearFocusEditor(context), onTap: () => controller.clearFocus(context),
child: Column(children: [ child: Column(children: [
Obx(() => DesktopAppBarComposerWidget( Obx(() => DesktopAppBarComposerWidget(
emailSubject: controller.subjectEmail.value ?? '', emailSubject: controller.subjectEmail.value ?? '',
displayMode: controller.screenDisplayMode.value, displayMode: controller.screenDisplayMode.value,
onCloseViewAction: () { onCloseViewAction: () => controller.handleClickCloseComposer(context),
controller.clearFocusEditor(context);
controller.saveToDraftAndClose(context);
},
onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, onChangeDisplayModeAction: controller.displayScreenTypeComposerAction,
constraints: constraints, constraints: constraints,
)), )),
@@ -461,17 +458,17 @@ class ComposerView extends GetWidget<ComposerController> {
}, },
displayMode: controller.screenDisplayMode.value, displayMode: controller.screenDisplayMode.value,
emailSubject: controller.subjectEmail.value ?? '', emailSubject: controller.subjectEmail.value ?? '',
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, onChangeDisplayModeAction: controller.displayScreenTypeComposerAction,
)), )),
tablet: TabletResponsiveContainerView( tablet: TabletResponsiveContainerView(
childBuilder: (context, constraints) { childBuilder: (context, constraints) {
return GestureDetector( return GestureDetector(
onTap: () => controller.clearFocusEditor(context), onTap: () => controller.clearFocus(context),
child: Column(children: [ child: Column(children: [
Obx(() => DesktopAppBarComposerWidget( Obx(() => DesktopAppBarComposerWidget(
emailSubject: controller.subjectEmail.value ?? '', emailSubject: controller.subjectEmail.value ?? '',
onCloseViewAction: () => controller.saveToDraftAndClose(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
constraints: constraints, constraints: constraints,
)), )),
ConstrainedBox( ConstrainedBox(
@@ -304,10 +304,6 @@ class UploadController extends BaseController {
_uploadingStateInlineFiles.deleteElementByUploadTaskId(uploadId); _uploadingStateInlineFiles.deleteElementByUploadTaskId(uploadId);
} }
void clearInlineFileUploaded() {
_uploadingStateInlineFiles.clear();
}
void _handleUploadInlineAttachmentsSuccess(SuccessAttachmentUploadState success) { void _handleUploadInlineAttachmentsSuccess(SuccessAttachmentUploadState success) {
uploadInlineViewState.value = Right(success); uploadInlineViewState.value = Right(success);
} }