TF-3715 Thread Detail create resuable actions

TF-3715 Thread Detail refactor actions for expanded email view

TF-3715 Thread Detail apply actions for collapsed email view

TF-3715 Thread Detail fix unit tests

TF-3715 Thread Detail add await for _getEmailContent in composer

TF-3715 Thread Detail remove unused emailLoaded in ThreadDetailAppBar

TF-3715 Thread Detail hide print action when isMobile

TF-3715 Thread Detail allow mark as read in EmailActionReactor

TF-3715 Thread Detail fix loadMoreThreadDetailEmails unit test

TF-3715 Thread Detail fix action small tap region

TF-3715 Thread Detail fix cannot permanent delete email

TF-3715 Thread Detail prevent close when move email

TF-3715 Thread Detail fix refresh when mark star selected collapsed email

TF-3715 Thread Detail update print action display logic

TF-3715 Thread Detail fix duplicate mark star in app bar

TF-3715 Thread Detail create new transformer for reply forward empty content email

TF-3715 Thread Detail fix email not load after open multiple times

TF-3715 Thread Detail fix close when move expanded email

TF-3715 Thread Detail fix duplicate and missing actions

TF-3715 Thread Detail restore editAsNewEmail action to _getEmailContent in setupEmailContent

TF-3715 Thread Detail update print action name

TF-3715 Thread Detail handle move and delete email with 1 item in thread detail

TF-3715 Thread Detail fix tap outside to close context menu

TF-3715 Thread Detail fix create rule and compose from recipient info

TF-3715 Thread Detail handle move and delete email with 1 item in thread detail

TF-3715 Thread Detail Fix cannot create email rule

TF-3715 Thread Detail Fix crash composer

TF-3715 Thread Detail Fix cannot unsubscribe

TF-3715 Thread Detail Fix duplicate actions on single email

TF-3715 Thread Detail Fix refresh view when reply/forward

TF-3715 Thread Detail Revert old logic to _getEmailContent

TF-3715 Thread Detail Update specific cases for UpdatedEmailKeywordsAction

TF-3715 Thread Detail Fix concurrent modification during iteration

TF-3715 Thread Detail Fix unsubscribe for all thread detail emails

TF-3715 Thread Detail Remove unnecessary Future in reactor

TF-3715 Thread Detail Remove dependency from SingleEmailController

TF-3715 Thread Detail Apply individual list post and unsubscribe header

TF-3715 Thread Detail Fix unsubscribe collapsed email

TF-3715 Thread Detail Conditionally inject rule filter interactor
This commit is contained in:
DatDang
2025-05-16 15:37:07 +07:00
committed by Dat H. Pham
parent 421fa321ba
commit 8a2ea62987
38 changed files with 2135 additions and 715 deletions
+33 -127
View File
@@ -11,22 +11,15 @@ import 'package:jmap_dart_client/jmap/mail/calendar/calendar_event.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart';
import 'package:model/extensions/email_extension.dart';
import 'package:model/extensions/list_email_address_extension.dart';
import 'package:model/extensions/presentation_email_extension.dart';
import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
import 'package:tmail_ui_user/features/base/widget/optional_expanded.dart';
import 'package:tmail_ui_user/features/base/widget/optional_scroll.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart';
import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_event_extension.dart';
import 'package:tmail_ui_user/features/email/presentation/model/context_item_email_action.dart';
import 'package:tmail_ui_user/features/email/presentation/model/popup_menu_item_email_action.dart';
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
import 'package:tmail_ui_user/features/email/presentation/styles/email_view_styles.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_action_banner_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_detail_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_information_widget.dart';
@@ -39,12 +32,10 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_loa
import 'package:tmail_ui_user/features/email/presentation/widgets/information_sender_and_receiver_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/mail_unsubscribed_banner.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/view_entire_message_with_message_clipped_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_open_context_menu_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/verify_display_overlay_view_on_iframe_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
class EmailView extends GetWidget<SingleEmailController> {
@@ -97,11 +88,15 @@ class EmailView extends GetWidget<SingleEmailController> {
isSearchActivated: controller.mailboxDashBoardController.searchController.isSearchEmailRunning,
onBackAction: () => controller.closeEmailView(context: context),
onEmailActionClick: (email, action) => controller.handleEmailAction(context, email, action),
onMoreActionClick: (presentationEmail, position) => _handleMoreEmailAction(
context: context,
onMoreActionClick: (presentationEmail, position) => controller.emailActionReactor.handleMoreEmailAction(
mailboxContain: controller.getMailboxContain(presentationEmail),
presentationEmail: presentationEmail,
position: position,
emailLoaded: controller.currentEmailLoaded.value,
responsiveUtils: controller.responsiveUtils,
imagePaths: controller.imagePaths,
username: controller.session?.username,
handleEmailAction: (email, action) => controller.handleEmailAction(context, email, action),
additionalActions: [],
),
supportBackAction: !isInsideThreadDetailView,
appBarDecoration: isInsideThreadDetailView
@@ -278,18 +273,38 @@ class EmailView extends GetWidget<SingleEmailController> {
sMimeStatus: controller.currentEmailLoaded.value?.sMimeStatus,
emailUnsubscribe: controller.emailUnsubscribe.value,
maxBodyHeight: maxBodyHeight,
openEmailAddressDetailAction: controller.openEmailAddressDialog,
openEmailAddressDetailAction: (_, emailAddress) => controller.openEmailAddressDialog(emailAddress),
onEmailActionClick: (presentationEmail, actionType) => controller.handleEmailAction(context, presentationEmail, actionType),
isInsideThreadDetailView: isInsideThreadDetailView,
emailLoaded: controller.currentEmailLoaded.value,
onMoreActionClick: (email, position) => _handleMoreEmailAction(
context: context,
presentationEmail: email,
onMoreActionClick: (presentationEmail, position) => controller.emailActionReactor.handleMoreEmailAction(
mailboxContain: controller.getMailboxContain(presentationEmail),
presentationEmail: presentationEmail,
position: position,
emailLoaded: controller.currentEmailLoaded.value,
responsiveUtils: controller.responsiveUtils,
imagePaths: controller.imagePaths,
username: controller.session?.username,
handleEmailAction: (email, action) => controller.handleEmailAction(context, email, action),
additionalActions: [
EmailActionType.forward,
EmailActionType.replyAll,
EmailActionType.replyToList,
EmailActionType.printAll,
if (controller.responsiveUtils.isMobile(context))
EmailActionType.moveToMailbox,
if (!controller.responsiveUtils.isDesktop(context)) ...[
EmailActionType.markAsStarred,
EmailActionType.unMarkAsStarred,
EmailActionType.moveToTrash,
EmailActionType.deletePermanently,
],
],
),
onToggleThreadDetailCollapseExpand: onToggleThreadDetailCollapseExpand,
onTapAvatarActionClick: onToggleThreadDetailCollapseExpand,
mailboxContain: presentationEmail.findMailboxContain(
controller.mailboxDashBoardController.mapMailboxById,
),
)),
Obx(() => MailUnsubscribedBanner(
presentationEmail: controller.currentEmail,
@@ -340,7 +355,7 @@ class EmailView extends GetWidget<SingleEmailController> {
.ownEmailAddress
.value,
onMailtoAttendeesAction: controller.handleMailToAttendees,
openEmailAddressDetailAction: controller.openEmailAddressDialog,
openEmailAddressDetailAction: (_, emailAddress) => controller.openEmailAddressDialog(emailAddress),
isFree: controller.isCalendarEventFree,
listEmailAddressSender: emailAddressSender ?? [],
isPortraitMobile: controller
@@ -496,113 +511,4 @@ class EmailView extends GetWidget<SingleEmailController> {
return usernameEvent.isNotEmpty && titleEvent.isNotEmpty;
}
bool canDeletePermanently(PresentationEmail email) {
return email.mailboxContain?.isTrash
?? email.mailboxContain?.isSpam
?? false;
}
void _handleMoreEmailAction({
required BuildContext context,
required PresentationEmail presentationEmail,
RelativeRect? position,
EmailLoaded? emailLoaded,
}) {
final mailboxContain = controller.getMailboxContain(presentationEmail);
final isChildOfTeamMailboxes = mailboxContain?.isChildOfTeamMailboxes ?? false;
final isSpam = mailboxContain?.isSpam ?? false;
final isArchive = mailboxContain?.isArchive ?? false;
final isTemplates = mailboxContain?.isTemplates ?? false;
final isUnsubscribeEnabled = !presentationEmail.isSubscribed &&
controller.emailUnsubscribe.value != null;
final isCreateRuleEnabled = presentationEmail.from?.isNotEmpty == true;
final isDownloadMessageAsEMLEnabled =
PlatformInfo.isWeb && PlatformInfo.isCanvasKit;
final emailActions = [
if (isInsideThreadDetailView) ...[
EmailActionType.forward,
if (presentationEmail.getCountMailAddressWithoutMe(controller.session?.username.value ?? '') > 1)
EmailActionType.replyAll,
if (EmailUtils.isReplyToListEnabled(emailLoaded?.emailCurrent?.listPost ?? ''))
EmailActionType.replyToList,
if (PlatformInfo.isWeb && PlatformInfo.isCanvasKit)
EmailActionType.printAll,
if (controller.responsiveUtils.isMobile(context))
EmailActionType.moveToMailbox,
if (!controller.responsiveUtils.isDesktop(context)) ...[
presentationEmail.hasStarred
? EmailActionType.unMarkAsStarred
: EmailActionType.markAsStarred,
canDeletePermanently(presentationEmail)
? EmailActionType.deletePermanently
: EmailActionType.moveToTrash,
],
],
EmailActionType.markAsUnread,
if (!isChildOfTeamMailboxes)
isSpam ? EmailActionType.unSpam : EmailActionType.moveToSpam,
if (isCreateRuleEnabled)
EmailActionType.createRule,
if (isUnsubscribeEnabled)
EmailActionType.unsubscribe,
if (!isArchive)
EmailActionType.archiveMessage,
if (isDownloadMessageAsEMLEnabled)
EmailActionType.downloadMessageAsEML,
if (!isTemplates)
EmailActionType.editAsNewEmail,
];
if (position == null) {
final contextMenuActions = emailActions
.map((action) => ContextItemEmailAction(
action,
AppLocalizations.of(context),
controller.imagePaths,
))
.toList();
controller.mailboxDashBoardController.openBottomSheetContextMenu(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
popBack();
controller.handleEmailAction(
context,
presentationEmail,
menuAction.action,
);
},
);
} else {
final popupMenuItems = emailActions.map((actionType) {
return PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
menuAction: PopupMenuItemEmailAction(
actionType,
AppLocalizations.of(context),
controller.imagePaths,
),
menuActionClick: (menuAction) {
popBack();
controller.handleEmailAction(
context,
presentationEmail,
menuAction.action,
);
},
),
);
}).toList();
controller.mailboxDashBoardController.openPopupMenu(
context,
position,
popupMenuItems,
);
}
}
}