TF-3911 Support keyboard shortcut actions ESC to close composer on web
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:tmail_ui_user/features/base/extensions/logical_key_set_helper.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/composer/composer_action_shortcut_type.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/mail/mail_list_action_shortcut_type.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/mail/mail_view_action_shortcut_type.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/search/search_action_shortcut_type.dart';
|
||||
|
||||
class AppShortcutManager {
|
||||
static const int escapeKeyCode = 27;
|
||||
|
||||
static MailViewActionShortcutType? getMailViewActionFromEvent(KeyEvent event) {
|
||||
final keysPressed = HardwareKeyboard.instance.logicalKeysPressed;
|
||||
log('AppShortcutManager::getMailViewActionFromEvent: Keys pressed: $keysPressed');
|
||||
@@ -53,4 +56,23 @@ class AppShortcutManager {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static ComposerActionShortcutType? getComposerActionFromEvent(KeyEvent event) {
|
||||
final keysPressed = HardwareKeyboard.instance.logicalKeysPressed;
|
||||
log('AppShortcutManager::getComposerActionFromEvent: Keys pressed: $keysPressed');
|
||||
if (keysPressed.isOnly(LogicalKeyboardKey.escape)) {
|
||||
return ComposerActionShortcutType.closeView;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static ComposerActionShortcutType? getComposerActionFromKeyCode(int? keyCode) {
|
||||
log('AppShortcutManager::getComposerActionFromKeyCode: Keys pressed: $keyCode');
|
||||
if (keyCode == escapeKeyCode) {
|
||||
return ComposerActionShortcutType.closeView;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
enum ComposerActionShortcutType {
|
||||
closeView;
|
||||
}
|
||||
@@ -61,6 +61,7 @@ import 'package:tmail_ui_user/features/composer/presentation/extensions/auto_cre
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/get_draft_mailbox_id_for_composer_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/get_outbox_mailbox_id_for_composer_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/get_sent_mailbox_id_for_composer_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_keyboard_shortcut_actions_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_message_failure_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_recipients_collapsed_extensions.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/list_identities_extension.dart';
|
||||
@@ -208,6 +209,7 @@ class ComposerController extends BaseController
|
||||
FocusNode? ccAddressFocusNodeKeyboard;
|
||||
FocusNode? bccAddressFocusNodeKeyboard;
|
||||
FocusNode? replyToAddressFocusNodeKeyboard;
|
||||
FocusNode? keyboardShortcutFocusNode;
|
||||
|
||||
StreamSubscription<html.Event>? _subscriptionOnDragEnter;
|
||||
StreamSubscription<html.Event>? _subscriptionOnDragOver;
|
||||
@@ -258,7 +260,6 @@ class ComposerController extends BaseController
|
||||
mailboxDashBoardController.ownEmailAddress.value;
|
||||
|
||||
late Worker uploadInlineImageWorker;
|
||||
late Worker dashboardViewStateWorker;
|
||||
late bool _isEmailBodyLoaded;
|
||||
|
||||
ComposerController(
|
||||
@@ -299,6 +300,7 @@ class ComposerController extends BaseController
|
||||
_listenStreamEvent();
|
||||
_beforeReconnectManager.addListener(onBeforeReconnect);
|
||||
_injectBinding();
|
||||
onKeyboardShortcutInit();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -343,6 +345,7 @@ class ComposerController extends BaseController
|
||||
} else {
|
||||
richTextMobileTabletController = null;
|
||||
}
|
||||
onKeyboardShortcutDispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@@ -374,7 +377,6 @@ class ComposerController extends BaseController
|
||||
bccEmailAddressController.dispose();
|
||||
replyToEmailAddressController.dispose();
|
||||
uploadInlineImageWorker.dispose();
|
||||
dashboardViewStateWorker.dispose();
|
||||
scrollController.dispose();
|
||||
scrollControllerEmailAddress.removeListener(_scrollControllerEmailAddressListener);
|
||||
scrollControllerEmailAddress.dispose();
|
||||
@@ -560,18 +562,7 @@ class ComposerController extends BaseController
|
||||
}
|
||||
|
||||
void _scrollControllerEmailAddressListener() {
|
||||
if (toEmailAddressController.text.isNotEmpty) {
|
||||
keyToEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
if (ccEmailAddressController.text.isNotEmpty) {
|
||||
keyCcEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
if (bccEmailAddressController.text.isNotEmpty) {
|
||||
keyBccEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
if (replyToEmailAddressController.text.isNotEmpty) {
|
||||
keyReplyToEmailTagEditor.currentState?.closeSuggestionBox();
|
||||
}
|
||||
_closeSuggestionBox();
|
||||
}
|
||||
|
||||
void createFocusNodeInput() {
|
||||
@@ -767,7 +758,7 @@ class ComposerController extends BaseController
|
||||
}
|
||||
_sendButtonState = ButtonState.disabled;
|
||||
|
||||
clearFocus(context);
|
||||
clearFocus();
|
||||
|
||||
if (toEmailAddressController.text.isNotEmpty
|
||||
|| ccEmailAddressController.text.isNotEmpty
|
||||
@@ -1142,7 +1133,7 @@ class ComposerController extends BaseController
|
||||
}
|
||||
|
||||
void openPickAttachmentMenu(BuildContext context, List<Widget> actionTiles) {
|
||||
clearFocus(context);
|
||||
clearFocus();
|
||||
|
||||
(ContextMenuBuilder(context)
|
||||
..addHeader((ContextMenuHeaderBuilder(const Key('attachment_picker_context_menu_header_builder'))
|
||||
@@ -1428,17 +1419,24 @@ class ComposerController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
void clearFocus(BuildContext context) {
|
||||
log('ComposerController::clearFocus:');
|
||||
void clearFocus() {
|
||||
if (PlatformInfo.isMobile) {
|
||||
htmlEditorApi?.unfocus();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
} else {
|
||||
toAddressFocusNode?.unfocus();
|
||||
ccAddressFocusNode?.unfocus();
|
||||
bccAddressFocusNode?.unfocus();
|
||||
replyToAddressFocusNode?.unfocus();
|
||||
}
|
||||
FocusScope.of(context).unfocus();
|
||||
}
|
||||
|
||||
void clickOutsideComposer(BuildContext context) {
|
||||
clearFocus(context);
|
||||
void clickOutsideComposer() {
|
||||
clearFocus();
|
||||
triggerHideRecipientsFiledsWhenUnfocus();
|
||||
if (PlatformInfo.isWeb) {
|
||||
refocusKeyboardShortcutFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void _closeComposerAction({dynamic result, bool closeOverlays = false}) {
|
||||
@@ -1655,8 +1653,8 @@ class ComposerController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
void insertImage(BuildContext context, double maxWith) async {
|
||||
clearFocus(context);
|
||||
void insertImage(BuildContext context, double maxWith) {
|
||||
clearFocus();
|
||||
|
||||
if (responsiveUtils.isMobile(context)) {
|
||||
maxWithEditor = maxWith - 40;
|
||||
@@ -1693,8 +1691,8 @@ class ComposerController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
void handleClickDeleteComposer(BuildContext context) {
|
||||
clearFocus(context);
|
||||
void handleClickDeleteComposer() {
|
||||
clearFocus();
|
||||
_closeComposerAction();
|
||||
}
|
||||
|
||||
@@ -1944,11 +1942,12 @@ class ComposerController extends BaseController
|
||||
}
|
||||
|
||||
_closeComposerButtonState = ButtonState.disabled;
|
||||
autoCreateEmailTag();
|
||||
|
||||
if (_validateCloseComposerWithoutSave()) {
|
||||
log('ComposerController::handleClickCloseComposer: ARGUMENTS is NULL or EMAIL NOT LOADED');
|
||||
_closeComposerButtonState = ButtonState.enabled;
|
||||
clearFocus(context);
|
||||
clearFocus();
|
||||
_closeComposerAction();
|
||||
return;
|
||||
}
|
||||
@@ -1956,16 +1955,14 @@ class ComposerController extends BaseController
|
||||
final isChanged = await _validateEmailChange();
|
||||
|
||||
if (isChanged && context.mounted) {
|
||||
clearFocus(context);
|
||||
clearFocus();
|
||||
await _showConfirmDialogSaveMessage(context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
_closeComposerButtonState = ButtonState.enabled;
|
||||
clearFocus(context);
|
||||
_closeComposerAction();
|
||||
}
|
||||
_closeComposerButtonState = ButtonState.enabled;
|
||||
clearFocus();
|
||||
_closeComposerAction();
|
||||
}
|
||||
|
||||
bool _validateCloseComposerWithoutSave() {
|
||||
|
||||
@@ -45,7 +45,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
responsiveUtils: controller.responsiveUtils,
|
||||
mobile: MobileContainerView(
|
||||
onCloseViewAction: () => controller.handleClickCloseComposer(context),
|
||||
onClearFocusAction: () => controller.clearFocus(context),
|
||||
onClearFocusAction: controller.clearFocus,
|
||||
backgroundColor: MobileAppBarComposerWidgetStyle.backgroundColor,
|
||||
childBuilder: (_, constraints) => SafeArea(
|
||||
left: !controller.responsiveUtils.isLandscapeMobile(context),
|
||||
@@ -248,7 +248,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
if (controller.isContentHeightExceeded.isTrue && PlatformInfo.isIOS) {
|
||||
return ViewEntireMessageWithMessageClippedWidget(
|
||||
buttonActionName: AppLocalizations.of(context).viewEntireMessage.toUpperCase(),
|
||||
onViewEntireMessageAction: () => controller.viewEntireContent(context),
|
||||
onViewEntireMessageAction: controller.viewEntireContent,
|
||||
topPadding: 12,
|
||||
);
|
||||
} else {
|
||||
@@ -268,7 +268,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
tablet: TabletContainerView(
|
||||
keyboardRichTextController: controller.richTextMobileTabletController!.richTextController,
|
||||
onCloseViewAction: () => controller.handleClickCloseComposer(context),
|
||||
onClearFocusAction: () => controller.clearFocus(context),
|
||||
onClearFocusAction: controller.clearFocus,
|
||||
childBuilder: (_, constraints) => ColoredBox(
|
||||
color: ComposerStyle.mobileBackgroundColor,
|
||||
child: Column(
|
||||
@@ -427,7 +427,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
if (controller.isContentHeightExceeded.isTrue && PlatformInfo.isIOS) {
|
||||
return ViewEntireMessageWithMessageClippedWidget(
|
||||
buttonActionName: AppLocalizations.of(context).viewEntireMessage.toUpperCase(),
|
||||
onViewEntireMessageAction: () => controller.viewEntireContent(context),
|
||||
onViewEntireMessageAction: controller.viewEntireContent,
|
||||
topPadding: 12,
|
||||
);
|
||||
} else {
|
||||
@@ -443,7 +443,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
imagePaths: controller.imagePaths,
|
||||
hasReadReceipt: controller.hasRequestReadReceipt.value,
|
||||
isMarkAsImportant: controller.isMarkAsImportant.value,
|
||||
deleteComposerAction: () => controller.handleClickDeleteComposer(context),
|
||||
deleteComposerAction: controller.handleClickDeleteComposer,
|
||||
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
|
||||
sendMessageAction: () => controller.handleClickSendButton(context),
|
||||
requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context),
|
||||
|
||||
@@ -7,10 +7,12 @@ import 'package:model/email/prefix_email_address.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_manager.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/dialog_picker/color_dialog_picker.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/keyboard/keyboard_handler_wrapper.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/composer_print_draft_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_edit_recipient_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_recipients_collapsed_extensions.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/handle_keyboard_shortcut_actions_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/mark_as_important_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/remove_draggable_email_address_between_recipient_fields_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart';
|
||||
@@ -67,12 +69,12 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
}
|
||||
});
|
||||
|
||||
return ResponsiveWidget(
|
||||
final bodyWidget = ResponsiveWidget(
|
||||
responsiveUtils: controller.responsiveUtils,
|
||||
mobile: MobileResponsiveContainerView(
|
||||
childBuilder: (_, constraints) {
|
||||
return GestureDetector(
|
||||
onTap: () => controller.clickOutsideComposer(context),
|
||||
onTap: controller.clickOutsideComposer,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -96,7 +98,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
toggleMarkAsImportantAction: () => controller.toggleMarkAsImportant(context),
|
||||
saveToDraftsAction: () => controller.handleClickSaveAsDraftsButton(context),
|
||||
saveToTemplateAction: () => controller.handleClickSaveAsTemplateButton(context),
|
||||
deleteComposerAction: () => controller.handleClickDeleteComposer(context),
|
||||
deleteComposerAction: controller.handleClickDeleteComposer,
|
||||
)),
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
@@ -231,6 +233,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
uploadError: uploadError
|
||||
),
|
||||
onInitialContentLoadComplete: controller.onInitialContentLoadCompleteWeb,
|
||||
onKeyDownEditorAction: controller.onKeyDownEditorAction,
|
||||
));
|
||||
}
|
||||
),
|
||||
@@ -318,7 +321,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
desktop: Obx(() => DesktopResponsiveContainerView(
|
||||
childBuilder: (_, constraints) {
|
||||
return GestureDetector(
|
||||
onTap: () => controller.clickOutsideComposer(context),
|
||||
onTap: controller.clickOutsideComposer,
|
||||
child: Column(children: [
|
||||
Obx(() => DesktopAppBarComposerWidget(
|
||||
imagePaths: controller.imagePaths,
|
||||
@@ -468,6 +471,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
uploadError: uploadError
|
||||
),
|
||||
onInitialContentLoadComplete: controller.onInitialContentLoadCompleteWeb,
|
||||
onKeyDownEditorAction: controller.onKeyDownEditorAction,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -514,7 +518,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
|
||||
attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
|
||||
insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
|
||||
deleteComposerAction: () => controller.handleClickDeleteComposer(context),
|
||||
deleteComposerAction: controller.handleClickDeleteComposer,
|
||||
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
|
||||
sendMessageAction: () => controller.handleClickSendButton(context),
|
||||
isEmailChanged: controller.isEmailChanged.isTrue,
|
||||
@@ -588,7 +592,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
tablet: TabletResponsiveContainerView(
|
||||
childBuilder: (_, constraints) {
|
||||
return GestureDetector(
|
||||
onTap: () => controller.clickOutsideComposer(context),
|
||||
onTap: controller.clickOutsideComposer,
|
||||
child: Column(children: [
|
||||
Obx(() => DesktopAppBarComposerWidget(
|
||||
imagePaths: controller.imagePaths,
|
||||
@@ -735,6 +739,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
uploadError: uploadError
|
||||
),
|
||||
onInitialContentLoadComplete: controller.onInitialContentLoadCompleteWeb,
|
||||
onKeyDownEditorAction: controller.onKeyDownEditorAction,
|
||||
));
|
||||
}
|
||||
),
|
||||
@@ -780,7 +785,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
|
||||
attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
|
||||
insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
|
||||
deleteComposerAction: () => controller.handleClickDeleteComposer(context),
|
||||
deleteComposerAction: controller.handleClickDeleteComposer,
|
||||
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
|
||||
sendMessageAction: () => controller.handleClickSendButton(context),
|
||||
isEmailChanged: controller.isEmailChanged.isTrue,
|
||||
@@ -844,6 +849,16 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
if (controller.keyboardShortcutFocusNode != null) {
|
||||
return KeyboardHandlerWrapper(
|
||||
focusNode: controller.keyboardShortcutFocusNode!,
|
||||
onKeyDownEventAction: controller.onKeyDownEventAction,
|
||||
child: bodyWidget,
|
||||
);
|
||||
} else {
|
||||
return bodyWidget;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildRecipientComposerWidget({
|
||||
|
||||
+2
-3
@@ -2,7 +2,6 @@
|
||||
import 'package:core/presentation/constants/constants_ui.dart';
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/editor_fullscreen_dialog_view.dart';
|
||||
@@ -14,8 +13,8 @@ extension HandleContentHeightExceededExtension on ComposerController {
|
||||
isContentHeightExceeded.value = height == ConstantsUI.composerHtmlContentMaxHeight;
|
||||
}
|
||||
|
||||
Future<void> viewEntireContent(BuildContext context) async {
|
||||
clearFocus(context);
|
||||
Future<void> viewEntireContent() async {
|
||||
clearFocus();
|
||||
|
||||
final currentContent = await getContentInEditor();
|
||||
log('HandleContentHeightExceededExtension::showComposerFullscreen:currentContent = $currentContent');
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/material.dart' hide SearchController;
|
||||
import 'package:tmail_ui_user/features/base/shortcut/app_shortcut_manager.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/composer/composer_action_shortcut_type.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
extension HandleKeyboardShortcutActionsExtension on ComposerController {
|
||||
void onKeyDownEditorAction(int? keyCode) {
|
||||
log('$runtimeType::onKeyDownEditorAction:🔥keyCode: $keyCode');
|
||||
final shortcutType = AppShortcutManager.getComposerActionFromKeyCode(keyCode);
|
||||
log('$runtimeType::onKeyDownEditorAction:🔥Shortcut triggered: $shortcutType');
|
||||
if (shortcutType == null) return;
|
||||
handleComposerShortcutAction(shortcutType);
|
||||
}
|
||||
|
||||
void onKeyboardShortcutInit() {
|
||||
if (PlatformInfo.isWeb) {
|
||||
keyboardShortcutFocusNode = FocusNode();
|
||||
keyboardShortcutFocusNode?.addListener(() {
|
||||
log('$runtimeType::onKeyboardShortcutInit: keyboardShortcutFocusNode: ${keyboardShortcutFocusNode?.hasFocus}');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void onKeyboardShortcutDispose() {
|
||||
if (PlatformInfo.isWeb) {
|
||||
keyboardShortcutFocusNode?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void refocusKeyboardShortcutFocus() {
|
||||
if (keyboardShortcutFocusNode?.hasFocus == false) {
|
||||
keyboardShortcutFocusNode?.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void onKeyDownEventAction(KeyEvent event) {
|
||||
final shortcutType = AppShortcutManager.getComposerActionFromEvent(event);
|
||||
log('$runtimeType::onKeyDownEventAction:🔥Shortcut triggered: $shortcutType');
|
||||
if (shortcutType == null) return;
|
||||
handleComposerShortcutAction(shortcutType);
|
||||
}
|
||||
|
||||
void handleComposerShortcutAction(ComposerActionShortcutType shortcutType) {
|
||||
log('$runtimeType::handleComposerShortcutAction: 🔥 Shortcut triggered: $shortcutType');
|
||||
if (currentContext == null) return;
|
||||
handleClickCloseComposer(currentContext!);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -57,7 +57,7 @@ extension HandleOpenContextMenuExtension on ComposerController {
|
||||
handleClickSaveAsTemplateButton(context);
|
||||
break;
|
||||
case ComposerActionType.delete:
|
||||
handleClickDeleteComposer(context);
|
||||
handleClickDeleteComposer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
final OnPasteImageSuccessAction? onPasteImageSuccessAction;
|
||||
final OnPasteImageFailureAction? onPasteImageFailureAction;
|
||||
final OnInitialContentLoadComplete? onInitialContentLoadComplete;
|
||||
final OnKeyDownEditorAction? onKeyDownEditorAction;
|
||||
|
||||
const WebEditorView({
|
||||
super.key,
|
||||
@@ -55,6 +56,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
this.onPasteImageSuccessAction,
|
||||
this.onPasteImageFailureAction,
|
||||
this.onInitialContentLoadComplete,
|
||||
this.onKeyDownEditorAction,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -85,6 +87,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
onPasteImageSuccessAction: onPasteImageSuccessAction,
|
||||
onPasteImageFailureAction: onPasteImageFailureAction,
|
||||
onInitialContentLoadComplete: onInitialContentLoadComplete,
|
||||
onKeyDownEditorAction: onKeyDownEditorAction,
|
||||
);
|
||||
case EmailActionType.editDraft:
|
||||
case EmailActionType.editSendingEmail:
|
||||
@@ -115,6 +118,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
onPasteImageSuccessAction: onPasteImageSuccessAction,
|
||||
onPasteImageFailureAction: onPasteImageFailureAction,
|
||||
onInitialContentLoadComplete: onInitialContentLoadComplete,
|
||||
onKeyDownEditorAction: onKeyDownEditorAction,
|
||||
),
|
||||
(success) {
|
||||
if (success is GetEmailContentLoading) {
|
||||
@@ -147,6 +151,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
onPasteImageSuccessAction: onPasteImageSuccessAction,
|
||||
onPasteImageFailureAction: onPasteImageFailureAction,
|
||||
onInitialContentLoadComplete: onInitialContentLoadComplete,
|
||||
onKeyDownEditorAction: onKeyDownEditorAction,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -185,6 +190,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
onPasteImageSuccessAction: onPasteImageSuccessAction,
|
||||
onPasteImageFailureAction: onPasteImageFailureAction,
|
||||
onInitialContentLoadComplete: onInitialContentLoadComplete,
|
||||
onKeyDownEditorAction: onKeyDownEditorAction,
|
||||
);
|
||||
},
|
||||
(success) {
|
||||
@@ -218,6 +224,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
onPasteImageSuccessAction: onPasteImageSuccessAction,
|
||||
onPasteImageFailureAction: onPasteImageFailureAction,
|
||||
onInitialContentLoadComplete: onInitialContentLoadComplete,
|
||||
onKeyDownEditorAction: onKeyDownEditorAction,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -241,6 +248,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
|
||||
onPasteImageSuccessAction: onPasteImageSuccessAction,
|
||||
onPasteImageFailureAction: onPasteImageFailureAction,
|
||||
onInitialContentLoadComplete: onInitialContentLoadComplete,
|
||||
onKeyDownEditorAction: onKeyDownEditorAction,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ typedef OnPasteImageFailureAction = Function(
|
||||
String? base64,
|
||||
UploadError uploadError);
|
||||
typedef OnInitialContentLoadComplete = Function(String text);
|
||||
typedef OnKeyDownEditorAction = Function(int? keyCode);
|
||||
|
||||
class WebEditorWidget extends StatefulWidget {
|
||||
|
||||
@@ -43,6 +44,7 @@ class WebEditorWidget extends StatefulWidget {
|
||||
final OnPasteImageSuccessAction? onPasteImageSuccessAction;
|
||||
final OnPasteImageFailureAction? onPasteImageFailureAction;
|
||||
final OnInitialContentLoadComplete? onInitialContentLoadComplete;
|
||||
final OnKeyDownEditorAction? onKeyDownEditorAction;
|
||||
|
||||
const WebEditorWidget({
|
||||
super.key,
|
||||
@@ -63,6 +65,7 @@ class WebEditorWidget extends StatefulWidget {
|
||||
this.onPasteImageSuccessAction,
|
||||
this.onPasteImageFailureAction,
|
||||
this.onInitialContentLoadComplete,
|
||||
this.onKeyDownEditorAction,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -76,7 +79,7 @@ class _WebEditorState extends State<WebEditorWidget> {
|
||||
late HtmlEditorController _editorController;
|
||||
bool _dropListenerRegistered = false;
|
||||
Function(Event)? _dropListener;
|
||||
|
||||
|
||||
OverlayEntry? _signatureTooltipEntry;
|
||||
final GlobalKey _signatureTooltipKey = GlobalKey();
|
||||
double _signatureTooltipLeft = 0;
|
||||
@@ -197,7 +200,7 @@ class _WebEditorState extends State<WebEditorWidget> {
|
||||
_showSignatureTooltipAtPosition(
|
||||
position,
|
||||
isContentVisible
|
||||
? AppLocalizations.of(context).hideSignature
|
||||
? AppLocalizations.of(context).hideSignature
|
||||
: AppLocalizations.of(context).showSignature,
|
||||
);
|
||||
},
|
||||
@@ -205,6 +208,7 @@ class _WebEditorState extends State<WebEditorWidget> {
|
||||
log('_WebEditorState::build: onSignatureHoverOut');
|
||||
_hideSignatureTooltip();
|
||||
},
|
||||
onKeyDown: widget.onKeyDownEditorAction,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user