TF-3941 Thread Detail Thread level mark read/star, archive and spam

This commit is contained in:
DatDang
2025-08-05 14:15:03 +07:00
committed by Dat H. Pham
parent f44118af48
commit b7cd3f7179
35 changed files with 902 additions and 552 deletions
@@ -0,0 +1,49 @@
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
extension GetThreadDetailActionStatus on ThreadDetailController {
bool get threadDetailIsStarred {
return emailsInThreadDetailInfo.every(
(email) {
return email.keywords?.containsKey(KeyWordIdentifier.emailFlagged) ==
true;
},
);
}
bool get threadDetailIsRead {
return emailsInThreadDetailInfo.every(
(email) {
return email.keywords?.containsKey(KeyWordIdentifier.emailSeen) == true;
},
);
}
MailboxId? getMailboxIdByRole(Role role) {
return mailboxDashBoardController.mapDefaultMailboxIdByRole[role];
}
bool get threadDetailIsArchived {
final archiveMailboxId = getMailboxIdByRole(
PresentationMailbox.roleArchive,
);
return emailsInThreadDetailInfo.every(
(email) {
return email.mailboxIds?[archiveMailboxId] == true;
},
);
}
bool get threadDetailIsSpam {
final spamMailboxId =
getMailboxIdByRole(PresentationMailbox.roleJunk) ??
getMailboxIdByRole(PresentationMailbox.roleSpam);
return emailsInThreadDetailInfo.every(
(email) {
return email.mailboxIds?[spamMailboxId] == true;
},
);
}
}
@@ -1,10 +1,7 @@
import 'package:flutter/material.dart';
import 'package:model/email/email_action_type.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/mailbox_dashboard/presentation/extensions/handle_open_context_menu_extension.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/get_thread_detail_email_mailbox_contains.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_on_email_action_click.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_open_email_address_detail_action.dart';
@@ -14,7 +11,6 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/extension/togg
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';
import 'package:tmail_ui_user/features/thread_detail/presentation/widgets/thread_detail_load_more_circle.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension GetThreadDetailEmailViews on ThreadDetailController {
List<Widget> getThreadDetailEmailViews() {
@@ -65,33 +61,6 @@ extension GetThreadDetailEmailViews on ThreadDetailController {
),
emailLoaded: null,
onEmailActionClick: threadDetailOnEmailActionClick,
onMoreActionClick: (presentationEmail, position) => emailActionReactor.handleMoreEmailAction(
mailboxContain: getThreadDetailEmailMailboxContains(presentationEmail),
presentationEmail: presentationEmail,
position: position,
responsiveUtils: responsiveUtils,
imagePaths: imagePaths,
username: session?.username,
handleEmailAction: threadDetailOnEmailActionClick,
additionalActions: [
EmailActionType.forward,
EmailActionType.replyAll,
EmailActionType.replyToList,
EmailActionType.printAll,
if (currentContext != null &&
responsiveUtils.isMobile(currentContext!))
EmailActionType.moveToMailbox,
if (!responsiveUtils.isDesktop(currentContext!)) ...[
EmailActionType.markAsStarred,
EmailActionType.unMarkAsStarred,
EmailActionType.moveToTrash,
EmailActionType.deletePermanently,
],
],
emailIsRead: presentationEmail.hasRead,
openBottomSheetContextMenu: mailboxDashBoardController.openBottomSheetContextMenu,
openPopupMenu: mailboxDashBoardController.openPopupMenu,
),
openEmailAddressDetailAction: (_, emailAddress) {
openEmailAddressDetailAction(emailAddress);
},
@@ -11,15 +11,22 @@ extension HandleGetEmailIdsByThreadIdSuccess on ThreadDetailController {
}
final allEmailIds = success.emailIds;
final allEmailsInThreadDetailInfo = success.emailsInThreadDetailInfo;
if (success.updateCurrentThreadDetail) {
final newEmailIds = allEmailIds.where(
(emailId) => !emailIdsPresentation.keys.contains(emailId),
);
final newEmailsInThreadDetailInfo = allEmailsInThreadDetailInfo.where(
(email) => !emailsInThreadDetailInfo.contains(email),
);
emailIdsPresentation
..removeWhere((key, _) => !allEmailIds.contains(key))
..addEntries(
newEmailIds.map((emailId) => MapEntry(emailId, null)),
);
emailsInThreadDetailInfo
..removeWhere((e) => !allEmailsInThreadDetailInfo.contains(e))
..addAll(newEmailsInThreadDetailInfo);
return;
}
@@ -31,5 +38,9 @@ extension HandleGetEmailIdsByThreadIdSuccess on ThreadDetailController {
? emailIdsPresentation[id] ?? selectedEmail
: null,
};
if ((isThreadDetailEnabled && success is! PreloadEmailIdsInThreadSuccess) ||
(!isThreadDetailEnabled && success is PreloadEmailIdsInThreadSuccess)) {
emailsInThreadDetailInfo.value = allEmailsInThreadDetailInfo;
}
}
}
@@ -0,0 +1,32 @@
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
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_collape_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(
UIState success,
ReadActions readActions,
List<EmailId> emailIds,
) {
mailboxDashBoardController.consumeState(Stream.value(Right(success)));
if (readActions == ReadActions.markAsRead) return;
if (emailsInThreadDetailInfo.length == 1) {
closeThreadDetailAction(currentContext);
return;
}
final expandedEmailId = currentExpandedEmailId.value;
if (expandedEmailId == null) return;
final expandedEmail = emailIdsPresentation[expandedEmailId];
if (emailIds.contains(expandedEmailId) && expandedEmail != null) {
toggleThreadDetailCollapeExpand(expandedEmail);
}
}
}
@@ -7,6 +7,7 @@ import 'package:model/extensions/keyword_identifier_extension.dart';
import 'package:model/extensions/list_email_extension.dart';
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
import 'package:tmail_ui_user/features/email/presentation/extensions/email_extension.dart';
import 'package:tmail_ui_user/features/thread/data/extensions/list_email_extension.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_emails_by_ids_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_by_id_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_by_id_interactor.dart';
@@ -34,6 +35,10 @@ extension HandleRefreshThreadDetailAction on ThreadDetailController {
[currentEmailId],
updateCurrentThreadDetail: true,
threadId: mailboxDashBoardController.selectedEmail.value?.threadId,
emailsInThreadDetailInfo: action.emailChangeResponse.updated?.toEmailsInThreadDetailInfo(
sentMailboxId: sentMailboxId,
ownEmailAddress: ownEmailAddress,
) ?? [],
))));
}
@@ -71,6 +76,14 @@ extension HandleRefreshThreadDetailAction on ThreadDetailController {
updated: emailsUpdated,
destroyed: emailIdsDestroyed.toList(),
);
final afterRefreshedThreadDetailInfo = ThreadDetailPresentationUtils.refreshThreadDetailInfo(
original: emailsInThreadDetailInfo,
created: emailsCreated,
updated: emailsUpdated,
destroyed: emailIdsDestroyed.toList(),
sentMailboxId: sentMailboxId,
ownEmailAddress: ownEmailAddress,
);
if (afterRefreshedEmailIds.isEmpty) {
closeThreadDetailAction(currentContext);
@@ -81,6 +94,7 @@ extension HandleRefreshThreadDetailAction on ThreadDetailController {
afterRefreshedEmailIds,
threadId: currentThreadId,
updateCurrentThreadDetail: true,
emailsInThreadDetailInfo: afterRefreshedThreadDetailInfo,
))));
consumeState(Stream.value(Right(GetEmailsByIdsSuccess(
afterRefreshedEmails,
@@ -0,0 +1,160 @@
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/mark_star_action.dart';
import 'package:model/email/read_actions.dart';
import 'package:model/mailbox/presentation_mailbox.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/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/home/data/exceptions/session_exceptions.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_open_context_menu_extension.dart';
import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/mark_as_star_multiple_email_state.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/get_thread_detail_action_status.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension OnThreadDetailActionClick on ThreadDetailController {
void onThreadDetailActionClick(EmailActionType threadDetailActionType) {
switch (threadDetailActionType) {
case EmailActionType.markAsRead:
case EmailActionType.markAsUnread:
if (session == null || accountId == null) {
consumeState(Stream.value(Left(MarkAsMultipleEmailReadFailure(
threadDetailActionType == EmailActionType.markAsRead
? ReadActions.markAsRead
: ReadActions.markAsUnread,
NotFoundSessionException(),
))));
return;
}
consumeState(markAsMultipleEmailReadInteractor.execute(
session!,
accountId!,
emailsInThreadDetailInfo.map((e) => e.emailId).toList(),
threadDetailActionType == EmailActionType.markAsRead
? ReadActions.markAsRead
: ReadActions.markAsUnread,
{},
));
break;
case EmailActionType.markAsStarred:
case EmailActionType.unMarkAsStarred:
if (session == null || accountId == null) {
consumeState(Stream.value(Left(MarkAsStarMultipleEmailFailure(
threadDetailActionType == EmailActionType.markAsStarred
? MarkStarAction.markStar
: MarkStarAction.unMarkStar,
NotFoundSessionException(),
))));
return;
}
consumeState(markAsStarMultipleEmailInteractor.execute(
session!,
accountId!,
emailsInThreadDetailInfo.map((e) => e.emailId).toList(),
threadDetailActionType == EmailActionType.markAsStarred
? MarkStarAction.markStar
: MarkStarAction.unMarkStar,
));
break;
case EmailActionType.archiveMessage:
final mailboxId = mailboxDashBoardController.getMailboxIdByRole(
PresentationMailbox.roleArchive,
);
if (mailboxId == null) return;
_moveToMailbox(mailboxId, threadDetailActionType);
break;
case EmailActionType.moveToSpam:
final mailboxId = mailboxDashBoardController.getMailboxIdByRole(
PresentationMailbox.roleJunk,
) ?? mailboxDashBoardController.getMailboxIdByRole(
PresentationMailbox.roleSpam,
);
if (mailboxId == null) return;
_moveToMailbox(mailboxId, threadDetailActionType);
break;
case EmailActionType.unSpam:
final mailboxId = mailboxDashBoardController.getMailboxIdByRole(
PresentationMailbox.roleInbox,
);
if (mailboxId == null) return;
_moveToMailbox(mailboxId, threadDetailActionType);
break;
default:
break;
}
}
void onThreadDetailMoreActionClick(RelativeRect? position) {
if (currentContext == null) return;
final moreActions = [
threadDetailIsRead
? EmailActionType.markAsUnread
: EmailActionType.markAsRead,
threadDetailIsStarred
? EmailActionType.unMarkAsStarred
: EmailActionType.markAsStarred,
if (!threadDetailIsArchived) EmailActionType.archiveMessage,
threadDetailIsSpam ? EmailActionType.unSpam : EmailActionType.moveToSpam,
];
if (position == null) {
mailboxDashBoardController.openBottomSheetContextMenu(
context: currentContext!,
itemActions: moreActions
.map(
(action) => ContextItemEmailAction(
action,
AppLocalizations.of(currentContext!),
imagePaths,
),
)
.toList(),
onContextMenuActionClick: (action) {
popBack();
onThreadDetailActionClick(action.action);
},
);
} else {
mailboxDashBoardController.openPopupMenu(
currentContext!,
position,
moreActions.map((action) {
return PopupMenuItem(
key: Key('${action.name}_action'),
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
menuAction: PopupMenuItemEmailAction(
action,
AppLocalizations.of(currentContext!),
imagePaths,
),
menuActionClick: (_) {
popBack();
onThreadDetailActionClick(action);
},
),
);
}).toList(),
);
}
}
void _moveToMailbox(MailboxId mailboxId, EmailActionType emailActionType) {
closeThreadDetailAction(currentContext);
mailboxDashBoardController.moveMultipleEmailInThreadDetail(
emailsInThreadDetailInfo,
destinationMailboxId: mailboxId,
emailActionType: emailActionType,
);
}
}
@@ -1,18 +1,10 @@
import 'dart:async';
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/mark_star_action.dart';
import 'package:model/email/presentation_email.dart';
import 'package:model/email/read_actions.dart';
import 'package:model/extensions/presentation_email_extension.dart';
import 'package:model/extensions/session_extension.dart';
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_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 ThreadDetailOnEmailActionClick on ThreadDetailController {
void threadDetailOnEmailActionClick(
@@ -23,60 +15,9 @@ extension ThreadDetailOnEmailActionClick on ThreadDetailController {
case EmailActionType.markAsRead:
_markRead(presentationEmail);
break;
case EmailActionType.markAsUnread:
_unRead(presentationEmail);
break;
case EmailActionType.markAsStarred:
_markStar(presentationEmail, MarkStarAction.markStar);
break;
case EmailActionType.unMarkAsStarred:
_markStar(presentationEmail, MarkStarAction.unMarkStar);
break;
case EmailActionType.moveToMailbox:
_moveEmail(presentationEmail);
break;
case EmailActionType.moveToTrash:
_trashEmail(presentationEmail);
break;
case EmailActionType.deletePermanently:
_deleteEmailPermanently(presentationEmail);
break;
case EmailActionType.moveToSpam:
_markEmailSpam(presentationEmail);
break;
case EmailActionType.unSpam:
_unSpamEmail(presentationEmail);
break;
case EmailActionType.createRule:
_quickCreateRule(presentationEmail);
break;
case EmailActionType.unsubscribe:
_unsubscribeEmail(presentationEmail);
break;
case EmailActionType.archiveMessage:
_archiveMessage(presentationEmail);
break;
case EmailActionType.printAll:
_printEmail(presentationEmail);
break;
case EmailActionType.downloadMessageAsEML:
_downloadMessageAsEML(presentationEmail);
break;
case EmailActionType.editAsNewEmail:
_editAsNewEmail(presentationEmail);
break;
case EmailActionType.reply:
_replyEmail(presentationEmail);
break;
case EmailActionType.replyAll:
_replyAll(presentationEmail);
break;
case EmailActionType.replyToList:
_replyToList(presentationEmail);
break;
case EmailActionType.forward:
_forward(presentationEmail);
break;
default:
break;
}
@@ -93,212 +34,6 @@ extension ThreadDetailOnEmailActionClick on ThreadDetailController {
));
}
void _unRead(PresentationEmail presentationEmail) {
if (session == null || accountId == null || !presentationEmail.hasRead) return;
consumeState(emailActionReactor.markAsEmailRead(
session!,
accountId!,
presentationEmail,
readAction: ReadActions.markAsUnread,
));
}
void _markStar(
PresentationEmail presentationEmail,
MarkStarAction markStarAction,
) {
if (session == null ||
accountId == null ||
(presentationEmail.hasStarred && markStarAction == MarkStarAction.markStar) ||
(!presentationEmail.hasStarred && markStarAction == MarkStarAction.unMarkStar)) {
return;
}
consumeState(emailActionReactor.markAsStarEmail(
session!,
accountId!,
presentationEmail,
markStarAction: markStarAction,
));
}
Future<void> _moveEmail(PresentationEmail presentationEmail) async {
if (session == null || accountId == null) return;
final moveActionRequest = await emailActionReactor.moveToMailbox(
session!,
accountId!,
presentationEmail,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: presentationEmail.findMailboxContain(
mailboxDashBoardController.mapMailboxById,
),
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
);
if (moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (emailIdsPresentation.length == 1) closeThreadDetailAction(currentContext);
}
void _trashEmail(PresentationEmail presentationEmail) {
if (session == null || accountId == null) return;
final moveActionRequest = emailActionReactor.moveToTrash(
presentationEmail,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
);
if (moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (emailIdsPresentation.length == 1) closeThreadDetailAction(currentContext);
}
void _markEmailSpam(PresentationEmail presentationEmail) {
if (session == null || accountId == null) return;
final moveActionRequest = emailActionReactor.moveToSpam(
presentationEmail,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
);
if (moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (emailIdsPresentation.length == 1) closeThreadDetailAction(currentContext);
}
void _unSpamEmail(PresentationEmail presentationEmail) {
if (session == null || accountId == null) return;
final moveActionRequest = emailActionReactor.unSpam(
presentationEmail,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
);
if (moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (emailIdsPresentation.length == 1) closeThreadDetailAction(currentContext);
}
void _deleteEmailPermanently(PresentationEmail email) {
emailActionReactor.deleteEmailPermanently(
email,
onDeleteEmailRequest: (email) {
popBack();
mailboxDashBoardController.deleteEmailPermanently(email);
},
responsiveUtils: responsiveUtils,
imagePaths: imagePaths,
);
if (emailIdsPresentation.length == 1) closeThreadDetailAction(currentContext);
}
void _quickCreateRule(PresentationEmail presentationEmail) {
final emailAddress = presentationEmail.from?.first;
if (session == null || accountId == null || emailAddress == null) return;
consumeState(emailActionReactor.quickCreateRule(
session!,
accountId!,
emailAddress: emailAddress,
));
}
void _unsubscribeEmail(PresentationEmail presentationEmail) {
emailActionReactor.unsubscribeEmail(
presentationEmail,
emailUnsubscribe: EmailUtils.parsingUnsubscribe(
presentationEmail.listUnsubscribe ?? '',
),
onUnsubscribeByHttpsLink: mailboxDashBoardController.unsubscribeMail,
onUnsubscribeByMailtoLink: (emailId, navigationRouter) {
mailboxDashBoardController.openComposer(
ComposerArguments.fromUnsubscribeMailtoLink(
listEmailAddress: navigationRouter.listEmailAddress,
subject: navigationRouter.subject,
body: navigationRouter.body,
previousEmailId: emailId,
)
);
},
);
}
void _archiveMessage(PresentationEmail presentationEmail) {
if (currentContext == null) return;
emailActionReactor.archiveMessage(
presentationEmail,
onArchiveEmailRequest: (presentationEmail) {
mailboxDashBoardController.archiveMessage(currentContext!, presentationEmail);
},
);
}
void _printEmail(PresentationEmail presentationEmail) {
consumeState(emailActionReactor.printEmail(
presentationEmail,
ownEmailAddress: mailboxDashBoardController.ownEmailAddress.value,
emailLoaded: null,
session: session,
accountId: accountId,
baseDownloadUrl: session?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl),
transformConfiguration: TransformConfiguration.forPreviewEmailOnWeb(),
));
}
void _downloadMessageAsEML(PresentationEmail presentationEmail) {
if (accountId == null || session == null) return;
consumeState(emailActionReactor.downloadMessageAsEML(
session!,
accountId!,
presentationEmail,
downloadProgressStateController: downloadProgressState,
));
}
void _editAsNewEmail(PresentationEmail presentationEmail) {
if (accountId == null || session == null) return;
emailActionReactor.editAsNewEmail(
presentationEmail,
onEditAsEmailRequest: (presentationEmail) {
mailboxDashBoardController.openComposer(
ComposerArguments.editAsNewEmail(presentationEmail),
);
},
);
}
void _replyEmail(PresentationEmail presentationEmail) {
emailActionReactor.replyEmail(
presentationEmail,
@@ -318,61 +53,4 @@ extension ThreadDetailOnEmailActionClick on ThreadDetailController {
emailLoaded: null,
);
}
void _replyAll(PresentationEmail presentationEmail) {
emailActionReactor.replyAll(
presentationEmail,
onReplyAllRequest: (presentationEmail, emailLoaded) {
mailboxDashBoardController.openComposer(
ComposerArguments.replyAllEmail(
presentationEmail: presentationEmail,
content: emailLoaded?.htmlContent,
inlineImages: emailLoaded?.inlineImages,
mailboxRole: presentationEmail.mailboxContain?.role,
messageId: presentationEmail.messageId,
references: presentationEmail.references,
listPost: presentationEmail.listPost,
)
);
},
emailLoaded: null,
);
}
void _replyToList(PresentationEmail presentationEmail) {
emailActionReactor.replyToList(
presentationEmail,
onReplyToListRequest: (presentationEmail, emailLoaded) {
mailboxDashBoardController.openComposer(
ComposerArguments.replyToListEmail(
presentationEmail: presentationEmail,
content: emailLoaded?.htmlContent,
inlineImages: emailLoaded?.inlineImages,
mailboxRole: presentationEmail.mailboxContain?.role,
messageId: presentationEmail.messageId,
references: presentationEmail.references,
listPost: presentationEmail.listPost,
)
);
},
emailLoaded: null,
);
}
void _forward(PresentationEmail presentationEmail) {
emailActionReactor.forward(
presentationEmail,
onForwardRequest: (presentationEmail, emailLoaded) {
mailboxDashBoardController.openComposer(
ComposerArguments.forwardEmail(
presentationEmail: presentationEmail,
content: emailLoaded?.htmlContent,
attachments: emailLoaded?.attachments,
inlineImages: emailLoaded?.inlineImages,
messageId: presentationEmail.messageId,
references: presentationEmail.references,
)
);
},
emailLoaded: null,
);
}
}
@@ -2,6 +2,7 @@ import 'package:dartz/dartz.dart';
import 'package:flutter/widgets.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/list_presentation_email_extensions.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_emails_by_ids_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_by_id_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_by_id_interactor.dart';
@@ -56,6 +57,10 @@ extension ThreadDetailOnSelectedEmailUpdated on ThreadDetailController {
Right(PreloadEmailIdsInThreadSuccess(
[selectedEmail.id!],
threadId: selectedEmail.threadId,
emailsInThreadDetailInfo: [selectedEmail].toEmailsInThreadDetailInfo(
sentMailboxId: sentMailboxId,
ownEmailAddress: ownEmailAddress,
),
)),
Right(PreloadEmailsByIdsSuccess([selectedEmail])),
]));
@@ -8,6 +8,8 @@ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart';
import 'package:tmail_ui_user/features/manage_account/data/local/local_setting_cache_manager.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart';
import 'package:tmail_ui_user/features/thread_detail/data/data_source/thread_detail_data_source.dart';
import 'package:tmail_ui_user/features/thread_detail/data/data_source/thread_detail_local_data_source_impl.dart';
import 'package:tmail_ui_user/features/thread_detail/data/data_source/thread_detail_remote_data_source_impl.dart';
@@ -43,6 +45,8 @@ class ThreadDetailBindings extends BaseBindings {
Get.find<PrintEmailInteractor>(),
Get.find<GetEmailContentInteractor>(),
Get.find<DownloadAttachmentForWebInteractor>(),
Get.find<MarkAsStarMultipleEmailInteractor>(),
Get.find<MarkAsMultipleEmailReadInteractor>(),
));
}
@@ -24,7 +24,6 @@ import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/download_attachment_for_web_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart';
@@ -37,6 +36,11 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new
import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart'
if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart';
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/mark_as_star_multiple_email_state.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_by_id_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_emails_by_ids_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_by_id_interactor.dart';
@@ -46,6 +50,7 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/extension/hand
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_get_email_ids_by_thread_id_success.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_get_emails_by_ids_success.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_get_thread_by_id_failure.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_mark_multiple_emails_read_success.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_refresh_thread_detail_action.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/initialize_thread_detail_emails.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_on_selected_email_updated.dart';
@@ -53,7 +58,6 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_
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/features/thread_detail/presentation/extension/handle_collapsed_email_download_states.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/mark_collapsed_email_star_success.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/mark_collapsed_email_unread_success.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/quick_create_rule_from_collapsed_email_success.dart';
@@ -65,6 +69,8 @@ class ThreadDetailController extends BaseController {
final PrintEmailInteractor _printEmailInteractor;
final GetEmailContentInteractor _getEmailContentInteractor;
final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor;
final MarkAsStarMultipleEmailInteractor markAsStarMultipleEmailInteractor;
final MarkAsMultipleEmailReadInteractor markAsMultipleEmailReadInteractor;
ThreadDetailController(
this._getEmailIdsByThreadIdInteractor,
@@ -74,16 +80,18 @@ class ThreadDetailController extends BaseController {
this._printEmailInteractor,
this._getEmailContentInteractor,
this._downloadAttachmentForWebInteractor,
this.markAsStarMultipleEmailInteractor,
this.markAsMultipleEmailReadInteractor,
);
final emailIdsPresentation = <EmailId, PresentationEmail?>{}.obs;
final currentExpandedEmailId = Rxn<EmailId>();
final currentEmailLoaded = Rxn<EmailLoaded>();
final emailsInThreadDetailInfo = RxList<EmailInThreadDetailInfo>();
late final EmailActionReactor emailActionReactor;
final additionalProperties = Properties({
IndividualHeaderIdentifier.listPostHeader.value,
IndividualHeaderIdentifier.listUnsubscribeHeader.value,
EmailProperty.references,
EmailProperty.messageId,
});
@@ -100,7 +108,6 @@ class ThreadDetailController extends BaseController {
accountId!,
sentMailboxId!,
ownEmailAddress!,
selectedEmailId: mailboxDashBoardController.selectedEmail.value?.id,
));
}
},
@@ -227,8 +234,18 @@ class ThreadDetailController extends BaseController {
handleGetEmailsByIdsSuccess(success);
} else if (success is MarkAsEmailReadSuccess) {
markCollapsedEmailReadSuccess(success);
} else if (success is MarkAsStarEmailSuccess) {
markCollapsedEmailStarSuccess(success);
} else if (success is MarkAsMultipleEmailReadAllSuccess) {
handleMarkMultipleEmailsReadSuccess(
success,
success.readActions,
success.emailIds,
);
} else if (success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
handleMarkMultipleEmailsReadSuccess(
success,
success.readActions,
success.successEmailIds,
);
} else if (success is CreateNewRuleFilterSuccess) {
quickCreateRuleFromCollapsedEmailSuccess(success);
} else if (success is DownloadAttachmentForWebSuccess) {
@@ -261,6 +278,10 @@ class ThreadDetailController extends BaseController {
}
return;
}
if (failure is MarkAsMultipleEmailReadFailure ||
failure is MarkAsStarMultipleEmailFailure) {
toastManager.showMessageFailure(failure as FeatureFailure);
}
super.handleFailureViewState(failure);
}
}
@@ -4,9 +4,10 @@ import 'package:core/utils/platform_info.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get_instance/get_instance.dart';
import 'package:get/state_manager.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_detail_status_state.dart';
@@ -16,7 +17,7 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/extension/init
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/refresh_thread_detail_on_setting_changed.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/model/thread_detail_setting_status.dart';
class ThreadDetailManager extends BaseController {
class ThreadDetailManager extends ReloadableController {
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
final GetThreadDetailStatusInteractor _getThreadDetailStatusInteractor;
@@ -86,6 +87,12 @@ class ThreadDetailManager extends BaseController {
);
}
@override
void handleReloaded(Session session) {
super.handleReloaded(session);
consumeState(_getThreadDetailStatusInteractor.execute());
}
@override
void handleSuccessViewState(Success success) {
if (success is GetThreadDetailStatusSuccess) {
@@ -1,4 +1,3 @@
import 'package:collection/collection.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
@@ -8,19 +7,17 @@ import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:model/extensions/session_extension.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
import 'package:tmail_ui_user/features/email/presentation/styles/email_view_app_bar_widget_styles.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_bottom_bar_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_open_context_menu_extension.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_by_id_state.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/get_thread_detail_email_mailbox_contains.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/get_thread_detail_action_status.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/get_thread_details_email_views.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/on_thread_detail_action_click.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/on_thread_page_changed.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/thread_detail_controller.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/widgets/thread_detail_app_bar.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
@@ -35,49 +32,18 @@ class ThreadDetailView extends GetWidget<ThreadDetailController> {
Widget bodyWidget = Column(
children: [
Obx(() {
final isLoading = showLoadingView(controller.viewState.value);
return ThreadDetailAppBar(
responsiveUtils: controller.responsiveUtils,
imagePaths: controller.imagePaths,
isSearchRunning: controller.isSearchRunning,
closeThreadDetailAction: controller.closeThreadDetailAction,
lastEmailOfThread: controller.emailIdsPresentation.values.lastOrNull,
ownUserName: controller.session?.getOwnEmailAddress() ?? '',
isThreadDetailEnabled: controller.isThreadDetailEnabled,
mailboxContain: _getMailboxContain(),
onEmailActionClick: isLoading
? null
: controller.threadDetailOnEmailActionClick,
onMoreActionClick: (presentationEmail, position) => isLoading
? null
: controller.emailActionReactor.handleMoreEmailAction(
mailboxContain: controller.getThreadDetailEmailMailboxContains(
presentationEmail,
),
presentationEmail: presentationEmail,
position: position,
responsiveUtils: controller.responsiveUtils,
imagePaths: controller.imagePaths,
username: controller.session?.username,
handleEmailAction: controller.threadDetailOnEmailActionClick,
additionalActions: [
if (controller.responsiveUtils.isMobile(context)) ...[
EmailActionType.forward,
EmailActionType.replyAll,
EmailActionType.replyToList,
],
EmailActionType.markAsStarred,
EmailActionType.unMarkAsStarred,
EmailActionType.moveToTrash,
EmailActionType.deletePermanently,
EmailActionType.printAll,
EmailActionType.moveToMailbox,
],
emailIsRead: presentationEmail.hasRead,
openBottomSheetContextMenu: controller.mailboxDashBoardController.openBottomSheetContextMenu,
openPopupMenu: controller.mailboxDashBoardController.openPopupMenu,
),
threadActionReady: controller.emailsInThreadDetailInfo.isNotEmpty &&
controller.emailIdsPresentation.length > 1,
threadDetailIsStarred: controller.threadDetailIsStarred,
onThreadActionClick: controller.onThreadDetailActionClick,
onThreadMoreActionClick: controller.onThreadDetailMoreActionClick,
optionWidgets: [
if (controller.previousAvailable)
TMailButtonWidget.fromIcon(
@@ -3,7 +3,10 @@ import 'dart:math';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/list_presentation_email_extensions.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
class ThreadDetailPresentationUtils {
const ThreadDetailPresentationUtils._();
@@ -90,4 +93,32 @@ class ThreadDetailPresentationUtils {
...created,
];
}
static List<EmailInThreadDetailInfo> refreshThreadDetailInfo({
required List<EmailInThreadDetailInfo> original,
required List<PresentationEmail> created,
required List<PresentationEmail> updated,
required List<EmailId> destroyed,
required MailboxId? sentMailboxId,
required String? ownEmailAddress,
}) {
return [
...original
.whereNot((email) => destroyed.contains(email.emailId))
.map((email) {
final updatedInOriginal = updated.firstWhereOrNull(
(updatedEmail) => updatedEmail.id == email.emailId,
);
return email.copyWith(
keywords: updatedInOriginal?.keywords,
mailboxIds: updatedInOriginal?.mailboxIds,
);
}),
...created.toEmailsInThreadDetailInfo(
sentMailboxId: sentMailboxId,
ownEmailAddress: ownEmailAddress,
),
];
}
}
@@ -4,16 +4,15 @@ import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart';
import 'package:model/extensions/presentation_email_extension.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/email/presentation/styles/email_view_app_bar_widget_styles.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_app_bar_widget.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_back_button.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/utils/app_utils.dart';
typedef OnThreadActionClick = void Function(EmailActionType);
typedef OnThreadMoreActionClick = void Function(RelativeRect?);
class ThreadDetailAppBar extends StatelessWidget {
const ThreadDetailAppBar({
super.key,
@@ -21,33 +20,29 @@ class ThreadDetailAppBar extends StatelessWidget {
required this.imagePaths,
required this.isSearchRunning,
required this.closeThreadDetailAction,
required this.lastEmailOfThread,
required this.ownUserName,
required this.threadActionReady,
required this.threadDetailIsStarred,
required this.isThreadDetailEnabled,
this.mailboxContain,
this.optionWidgets = const [],
this.onEmailActionClick,
this.onMoreActionClick,
this.onThreadActionClick,
this.onThreadMoreActionClick,
});
final ResponsiveUtils responsiveUtils;
final ImagePaths imagePaths;
final bool isSearchRunning;
final void Function(BuildContext context) closeThreadDetailAction;
final PresentationEmail? lastEmailOfThread;
final String ownUserName;
final bool threadActionReady;
final bool threadDetailIsStarred;
final bool isThreadDetailEnabled;
final PresentationMailbox? mailboxContain;
final List<Widget> optionWidgets;
final OnEmailActionClick? onEmailActionClick;
final OnMoreActionClick? onMoreActionClick;
final OnThreadActionClick? onThreadActionClick;
final OnThreadMoreActionClick? onThreadMoreActionClick;
@override
Widget build(BuildContext context) {
final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(
lastEmailOfThread?.listPost ?? '',
);
final child = LayoutBuilder(
builder: (context, constraints) {
Widget backButton = EmailViewBackButton(
@@ -86,61 +81,31 @@ class ThreadDetailAppBar extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_supportDisplayMailboxNameTitle(context)) backButton,
if (lastEmailOfThread != null && isThreadDetailEnabled) ...[
if (isThreadDetailEnabled && threadActionReady)
_ThreadDetailAppBarButton(
icon: imagePaths.icReply,
tooltipMessage: AppLocalizations.of(context).reply,
icon: threadDetailIsStarred
? imagePaths.icStar
: imagePaths.icUnStar,
tooltipMessage: threadDetailIsStarred
? AppLocalizations.of(context).not_starred
: AppLocalizations.of(context).mark_as_starred,
responsiveUtils: responsiveUtils,
onTapActionCallback: (_) => onEmailActionClick?.call(
lastEmailOfThread!,
EmailActionType.reply,
),
iconColor: null,
onTapActionCallback: threadDetailIsStarred
? (_) => onThreadActionClick?.call(EmailActionType.unMarkAsStarred)
: (_) => onThreadActionClick?.call(EmailActionType.markAsStarred),
),
if (!responsiveUtils.isMobile(context)) ...[
if (lastEmailOfThread!.getCountMailAddressWithoutMe(ownUserName) > 1)
_ThreadDetailAppBarButton(
icon: imagePaths.icReplyAll,
tooltipMessage: AppLocalizations.of(context).reply_all,
responsiveUtils: responsiveUtils,
onTapActionCallback: (_) => onEmailActionClick?.call(
lastEmailOfThread!,
EmailActionType.replyAll,
),
),
if (isReplyToListEnabled)
_ThreadDetailAppBarButton(
icon: imagePaths.icReply,
tooltipMessage: AppLocalizations.of(context).replyToList,
responsiveUtils: responsiveUtils,
onTapActionCallback: (_) => onEmailActionClick?.call(
lastEmailOfThread!,
EmailActionType.replyToList,
),
),
_ThreadDetailAppBarButton(
icon: imagePaths.icForward,
tooltipMessage: AppLocalizations.of(context).forward,
responsiveUtils: responsiveUtils,
onTapActionCallback: (_) => onEmailActionClick?.call(
lastEmailOfThread!,
EmailActionType.forward,
),
),
],
if (!responsiveUtils.isMobile(context)) const Spacer(),
] else const Spacer(),
if (!responsiveUtils.isMobile(context)) const Spacer(),
if (AppUtils.getCurrentDirection(context) == TextDirection.rtl)
...optionWidgets.reversed
else
...optionWidgets,
if (lastEmailOfThread != null)
if (isThreadDetailEnabled && threadActionReady)
_ThreadDetailAppBarButton(
icon: imagePaths.icMoreVertical,
tooltipMessage: AppLocalizations.of(context).more,
responsiveUtils: responsiveUtils,
onTapActionCallback: lastEmailOfThread != null
? (position) => onMoreActionClick?.call(lastEmailOfThread!, position)
: null,
onTapActionCallback: onThreadMoreActionClick,
),
],
),
@@ -175,22 +140,25 @@ class _ThreadDetailAppBarButton extends StatelessWidget {
required this.tooltipMessage,
required this.onTapActionCallback,
required this.responsiveUtils,
this.iconColor = EmailViewAppBarWidgetStyles.iconColor,
});
final String icon;
final String tooltipMessage;
final void Function(RelativeRect? position)? onTapActionCallback;
final ResponsiveUtils responsiveUtils;
final Color? iconColor;
@override
Widget build(BuildContext context) {
final smallScreen = responsiveUtils.isScreenWithShortestSide(context);
return TMailButtonWidget.fromIcon(
icon: icon,
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
iconColor: EmailViewAppBarWidgetStyles.iconColor,
iconColor: iconColor,
backgroundColor: Colors.transparent,
tooltipMessage: AppLocalizations.of(context).more,
tooltipMessage: tooltipMessage,
onTapActionCallback:
smallScreen ? () => onTapActionCallback?.call(null) : null,
onTapActionAtPositionCallback: !smallScreen
@@ -198,4 +166,4 @@ class _ThreadDetailAppBarButton extends StatelessWidget {
: null,
);
}
}
}
@@ -23,7 +23,6 @@ class ThreadDetailCollapsedEmail extends StatelessWidget {
this.mailboxContain,
this.emailLoaded,
this.onEmailActionClick,
this.onMoreActionClick,
this.onToggleThreadDetailCollapseExpand,
});
@@ -35,7 +34,6 @@ class ThreadDetailCollapsedEmail extends StatelessWidget {
final PresentationMailbox? mailboxContain;
final EmailLoaded? emailLoaded;
final OnEmailActionClick? onEmailActionClick;
final OnMoreActionClick? onMoreActionClick;
final VoidCallback? onToggleThreadDetailCollapseExpand;
String get preview => presentationEmail.getPartialContent();
@@ -69,7 +67,6 @@ class ThreadDetailCollapsedEmail extends StatelessWidget {
emailLoaded: emailLoaded,
isInsideThreadDetailView: true,
onEmailActionClick: onEmailActionClick,
onMoreActionClick: onMoreActionClick,
openEmailAddressDetailAction: openEmailAddressDetailAction,
showRecipients: false,
onTapAvatarActionClick: onToggleThreadDetailCollapseExpand,