TF-3911 Support mail keyboard shortcut actions in email detailed view on web
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
|
||||
extension CloseThreadDetailAction on ThreadDetailController {
|
||||
void closeThreadDetailAction(BuildContext? context) {
|
||||
void closeThreadDetailAction() {
|
||||
if (isSearchRunning) {
|
||||
mailboxDashBoardController.dispatchRoute(DashboardRoutes.searchEmail);
|
||||
} else {
|
||||
|
||||
+9
-2
@@ -1,12 +1,13 @@
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:model/email/email_in_thread_status.dart';
|
||||
import 'package:model/extensions/presentation_email_extension.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
|
||||
import 'package:model/email/email_in_thread_status.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_mail_shortcut_actions_extension.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/load_more_thread_detail_emails.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_load_more_segments.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_on_email_action_click.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_open_email_address_detail_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_load_more_segments.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/toggle_thread_detail_collapse_expand.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/widgets/thread_detail_collapsed_email.dart';
|
||||
@@ -78,6 +79,9 @@ extension GetThreadDetailEmailViews on ThreadDetailController {
|
||||
onToggleThreadDetailCollapseExpand: () {
|
||||
toggleThreadDetailCollapseExpand(presentationEmail);
|
||||
},
|
||||
onIFrameKeyboardShortcutAction: keyboardShortcutFocusNode != null
|
||||
? onIFrameKeyboardShortcutAction
|
||||
: null,
|
||||
scrollController: scrollController,
|
||||
);
|
||||
}
|
||||
@@ -91,6 +95,9 @@ extension GetThreadDetailEmailViews on ThreadDetailController {
|
||||
onToggleThreadDetailCollapseExpand: () {
|
||||
toggleThreadDetailCollapseExpand(presentationEmail);
|
||||
},
|
||||
onIFrameKeyboardShortcutAction: keyboardShortcutFocusNode != null
|
||||
? onIFrameKeyboardShortcutAction
|
||||
: null,
|
||||
scrollController: scrollController,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:core/presentation/views/shortcut/key_shortcut.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/app_shortcut_manager.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/mail/mail_view_action_shortcut_type.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/key_shortcut_extension.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/model/mail_view_shortcut_action_view_event.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
|
||||
extension HandleMailShortcutActionsExtension on ThreadDetailController {
|
||||
|
||||
void onKeyDownEventAction(KeyEvent event) {
|
||||
final shortcutType = AppShortcutManager.getMailViewActionFromEvent(event);
|
||||
log('$runtimeType::onKeyDownEventAction:🔥Shortcut triggered: $shortcutType');
|
||||
if (shortcutType == null) return;
|
||||
handleMailShortcutAction(shortcutType);
|
||||
}
|
||||
|
||||
PresentationEmail? get currentExpandedEmail {
|
||||
final expandedEmailId = currentExpandedEmailId.value;
|
||||
if (expandedEmailId == null) return null;
|
||||
|
||||
final expandedPresentationEmail = emailIdsPresentation[expandedEmailId];
|
||||
if (expandedPresentationEmail == null) return null;
|
||||
|
||||
return expandedPresentationEmail;
|
||||
}
|
||||
|
||||
void onKeyboardShortcutInit() {
|
||||
if (PlatformInfo.isWeb) {
|
||||
keyboardShortcutFocusNode = FocusNode();
|
||||
keyboardShortcutFocusNode?.addListener(() {
|
||||
log('$runtimeType::onInit:keyboardShortcutFocusNode: ${keyboardShortcutFocusNode?.hasFocus}');
|
||||
});
|
||||
shortcutActionEventController =
|
||||
StreamController<MailViewShortcutActionViewEvent>();
|
||||
shortcutActionEventSubscription = shortcutActionEventController
|
||||
?.stream
|
||||
.debounceTime(const Duration(milliseconds: 300))
|
||||
.listen(_onShortcutActionViewEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void _onShortcutActionViewEvent(MailViewShortcutActionViewEvent event) {
|
||||
mailboxDashBoardController.dispatchEmailUIAction(
|
||||
TriggerMailViewKeyboardShortcutAction(
|
||||
event.actionType,
|
||||
event.presentationEmail,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void onKeyboardShortcutDispose() {
|
||||
if (PlatformInfo.isWeb) {
|
||||
keyboardShortcutFocusNode?.dispose();
|
||||
shortcutActionEventSubscription?.cancel();
|
||||
shortcutActionEventController?.close();
|
||||
}
|
||||
}
|
||||
|
||||
void handleMailShortcutAction(MailViewActionShortcutType shortcutType) {
|
||||
log('$runtimeType::handleMailShortcutAction:🔥ShortcutType: $shortcutType');
|
||||
final expandedEmail = currentExpandedEmail;
|
||||
|
||||
if (expandedEmail == null) return;
|
||||
|
||||
final emailActionType = shortcutType.getEmailActionType(
|
||||
currentEmail: expandedEmail,
|
||||
ownerEmailAddress: mailboxDashBoardController.ownEmailAddress.value,
|
||||
);
|
||||
log('$runtimeType::onKeyDownEventAction:🔥EmailActionType: $emailActionType');
|
||||
if (emailActionType == null) return;
|
||||
|
||||
shortcutActionEventController?.add(
|
||||
MailViewShortcutActionViewEvent(emailActionType, expandedEmail),
|
||||
);
|
||||
}
|
||||
|
||||
void clearMailShortcutFocus() {
|
||||
if (keyboardShortcutFocusNode?.hasFocus == true) {
|
||||
keyboardShortcutFocusNode?.unfocus();
|
||||
}
|
||||
}
|
||||
|
||||
void refocusMailShortcutFocus() {
|
||||
if (keyboardShortcutFocusNode?.hasFocus == false) {
|
||||
keyboardShortcutFocusNode?.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void onIFrameKeyboardShortcutAction(KeyShortcut keyShortcut) {
|
||||
log('$runtimeType::onIFrameKeyboardShortcutAction: ${keyShortcut.toString()}');
|
||||
final shortcutType = keyShortcut.mailViewActionShortcutType;
|
||||
log('$runtimeType::onIFrameKeyboardShortcutAction:🔥MailViewActionShortcutType: $shortcutType');
|
||||
if (shortcutType == null) return;
|
||||
handleMailShortcutAction(shortcutType);
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -5,7 +5,6 @@ import 'package:model/email/read_actions.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/close_thread_detail_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/toggle_thread_detail_collapse_expand.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
extension HandleMarkMultipleEmailsReadSuccess on ThreadDetailController {
|
||||
void handleMarkMultipleEmailsReadSuccess(
|
||||
@@ -17,7 +16,7 @@ extension HandleMarkMultipleEmailsReadSuccess on ThreadDetailController {
|
||||
if (readActions == ReadActions.markAsRead) return;
|
||||
|
||||
if (emailsInThreadDetailInfo.length == 1) {
|
||||
closeThreadDetailAction(currentContext);
|
||||
closeThreadDetailAction();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -14,7 +14,6 @@ import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/close_thread_detail_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/utils/thread_detail_presentation_utils.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
extension HandleRefreshThreadDetailAction on ThreadDetailController {
|
||||
void handleRefreshThreadDetailAction(
|
||||
@@ -86,7 +85,7 @@ extension HandleRefreshThreadDetailAction on ThreadDetailController {
|
||||
);
|
||||
|
||||
if (afterRefreshedEmailIds.isEmpty) {
|
||||
closeThreadDetailAction(currentContext);
|
||||
closeThreadDetailAction();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
import 'package:core/presentation/views/shortcut/key_shortcut.dart';
|
||||
import 'package:tmail_ui_user/features/base/shortcut/mail/mail_view_action_shortcut_type.dart';
|
||||
|
||||
extension KeyShortcutExtension on KeyShortcut {
|
||||
MailViewActionShortcutType? get mailViewActionShortcutType {
|
||||
if (matches('r')) {
|
||||
return MailViewActionShortcutType.reply;
|
||||
} else if (matches('r', shift: true)) {
|
||||
return MailViewActionShortcutType.replyAll;
|
||||
} else if (matches('f')) {
|
||||
return MailViewActionShortcutType.forward;
|
||||
} else if (matches('u')) {
|
||||
return MailViewActionShortcutType.markAsUnread;
|
||||
} else if (matches('n')) {
|
||||
return MailViewActionShortcutType.newMessage;
|
||||
} else if (matches('backspace') || matches('delete')) {
|
||||
return MailViewActionShortcutType.delete;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -5,7 +5,6 @@ import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_sta
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/close_thread_detail_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
extension MarkCollapsedEmailReadSuccess on ThreadDetailController {
|
||||
void markCollapsedEmailReadSuccess(MarkAsEmailReadSuccess success) {
|
||||
@@ -41,7 +40,7 @@ extension MarkCollapsedEmailReadSuccess on ThreadDetailController {
|
||||
) {
|
||||
if (success.readActions == ReadActions.markAsRead) return;
|
||||
if (emailIdsPresentation.length == 1) {
|
||||
closeThreadDetailAction(currentContext);
|
||||
closeThreadDetailAction();
|
||||
} else {
|
||||
emailIdsPresentation[success.emailId] = emailIdsPresentation
|
||||
[success.emailId]
|
||||
|
||||
+2
-2
@@ -72,7 +72,7 @@ extension OnThreadDetailActionClick on ThreadDetailController {
|
||||
case EmailActionType.deletePermanently:
|
||||
mailboxDashBoardController.permanentDeleteMultipleEmailInThreadDetail(
|
||||
emailsInThreadDetailInfo,
|
||||
onConfirm: () => closeThreadDetailAction(currentContext),
|
||||
onConfirm: closeThreadDetailAction,
|
||||
);
|
||||
break;
|
||||
case EmailActionType.moveToMailbox:
|
||||
@@ -183,7 +183,7 @@ extension OnThreadDetailActionClick on ThreadDetailController {
|
||||
}
|
||||
|
||||
void _moveToMailbox(MailboxId mailboxId, EmailActionType emailActionType) {
|
||||
closeThreadDetailAction(currentContext);
|
||||
closeThreadDetailAction();
|
||||
mailboxDashBoardController.moveMultipleEmailInThreadDetail(
|
||||
emailsInThreadDetailInfo,
|
||||
destinationMailboxId: mailboxId,
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ extension ThreadDetailOnSelectedEmailUpdated on ThreadDetailController {
|
||||
BuildContext? context,
|
||||
) {
|
||||
if (selectedEmail?.id == null) {
|
||||
closeThreadDetailAction(context);
|
||||
closeThreadDetailAction();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user