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:
@@ -245,7 +245,6 @@ extension AppColor on Color {
|
|||||||
static const blue400 = Color(0xFF80BDFF);
|
static const blue400 = Color(0xFF80BDFF);
|
||||||
static const blue900 = Color(0xFF0F76E7);
|
static const blue900 = Color(0xFF0F76E7);
|
||||||
static const m3Tertiary = Color(0xFF8C9CAF);
|
static const m3Tertiary = Color(0xFF8C9CAF);
|
||||||
static const lightIconTertiary = Color(0xFFB8C1CC);
|
|
||||||
static const m3Neutral70 = Color(0xFFAEAAAE);
|
static const m3Neutral70 = Color(0xFFAEAAAE);
|
||||||
static const m3Neutral90 = Color(0xFFE6E1E5);
|
static const m3Neutral90 = Color(0xFFE6E1E5);
|
||||||
static const grayBackgroundColor = Color(0xFFF3F6F9);
|
static const grayBackgroundColor = Color(0xFFF3F6F9);
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ class TransformConfiguration {
|
|||||||
const RemoveCollapsedSignatureButtonTransformer(),
|
const RemoveCollapsedSignatureButtonTransformer(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
factory TransformConfiguration.forReplyForwardEmptyEmail() => TransformConfiguration.fromDomTransformers([
|
||||||
|
...TransformConfiguration.forReplyForwardEmail().domTransformers,
|
||||||
|
const ImageTransformer(),
|
||||||
|
]);
|
||||||
|
|
||||||
factory TransformConfiguration.forDraftsEmail() => TransformConfiguration.create(
|
factory TransformConfiguration.forDraftsEmail() => TransformConfiguration.create(
|
||||||
customDomTransformers: [const ImageTransformer()]
|
customDomTransformers: [const ImageTransformer()]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ extension EmailActionTypeExtension on EmailActionType {
|
|||||||
case EmailActionType.openInNewTab:
|
case EmailActionType.openInNewTab:
|
||||||
return appLocalizations.openInNewTab;
|
return appLocalizations.openInNewTab;
|
||||||
case EmailActionType.printAll:
|
case EmailActionType.printAll:
|
||||||
return appLocalizations.printAll;
|
return appLocalizations.print;
|
||||||
case EmailActionType.forward:
|
case EmailActionType.forward:
|
||||||
return appLocalizations.forward;
|
return appLocalizations.forward;
|
||||||
case EmailActionType.replyAll:
|
case EmailActionType.replyAll:
|
||||||
|
|||||||
@@ -27,78 +27,13 @@ extension SetupEmailContentExtension on ComposerController {
|
|||||||
switch(currentEmailActionType) {
|
switch(currentEmailActionType) {
|
||||||
case EmailActionType.editAsNewEmail:
|
case EmailActionType.editAsNewEmail:
|
||||||
case EmailActionType.editDraft:
|
case EmailActionType.editDraft:
|
||||||
final session = mailboxDashBoardController.sessionCurrent;
|
await _getEmailContent(
|
||||||
final accountId = mailboxDashBoardController.accountId.value;
|
arguments,
|
||||||
final emailId = arguments.presentationEmail?.id;
|
transformConfiguration: TransformConfiguration.forEditDraftsEmail(),
|
||||||
|
|
||||||
if (session == null) {
|
|
||||||
emailContentsViewState.value = Left(GetEmailContentFailure(NotFoundSessionException()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accountId == null) {
|
|
||||||
emailContentsViewState.value = Left(GetEmailContentFailure(NotFoundAccountIdException()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (emailId == null) {
|
|
||||||
emailContentsViewState.value = Left(GetEmailContentFailure(NotFoundEmailException()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final resultState = await getEmailContentInteractor.execute(
|
|
||||||
session,
|
|
||||||
accountId,
|
|
||||||
emailId,
|
|
||||||
mailboxDashBoardController.baseDownloadUrl,
|
|
||||||
TransformConfiguration.forEditDraftsEmail(),
|
|
||||||
additionalProperties: Properties({
|
additionalProperties: Properties({
|
||||||
IndividualHeaderIdentifier.identityHeader.value,
|
IndividualHeaderIdentifier.identityHeader.value,
|
||||||
}),
|
}),
|
||||||
).last;
|
);
|
||||||
|
|
||||||
final uiState = resultState.fold((failure) => failure, (success) => success);
|
|
||||||
|
|
||||||
if (uiState is GetEmailContentSuccess) {
|
|
||||||
initAttachmentsAndInlineImages(
|
|
||||||
attachments: uiState.attachments,
|
|
||||||
inlineImages: uiState.inlineImages,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (currentEmailActionType == EmailActionType.editDraft ||
|
|
||||||
currentEmailActionType == EmailActionType.editAsNewEmail) {
|
|
||||||
setupEmailRequestReadReceiptFlag(
|
|
||||||
uiState.emailCurrent!.hasRequestReadReceipt,
|
|
||||||
);
|
|
||||||
setupSelectedIdentityForEditDraft(
|
|
||||||
uiState.emailCurrent!.identityIdFromHeader,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
emailContentsViewState.value = Right(uiState);
|
|
||||||
} else if (uiState is GetEmailContentFromCacheSuccess) {
|
|
||||||
initAttachmentsAndInlineImages(
|
|
||||||
attachments: uiState.attachments,
|
|
||||||
inlineImages: uiState.inlineImages,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (currentEmailActionType == EmailActionType.editDraft ||
|
|
||||||
currentEmailActionType == EmailActionType.editAsNewEmail) {
|
|
||||||
setupEmailRequestReadReceiptFlag(
|
|
||||||
uiState.emailCurrent.hasRequestReadReceipt,
|
|
||||||
);
|
|
||||||
setupSelectedIdentityForEditDraft(
|
|
||||||
uiState.emailCurrent.identityIdFromHeader,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
emailContentsViewState.value = Right(uiState);
|
|
||||||
} else if (uiState is GetEmailContentFailure) {
|
|
||||||
emailContentsViewState.value = Left(uiState);
|
|
||||||
consumeState(Stream.value(Left(uiState)));
|
|
||||||
} else {
|
|
||||||
emailContentsViewState.value = Right(LoadEmailContentCompleted());
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case EmailActionType.editSendingEmail:
|
case EmailActionType.editSendingEmail:
|
||||||
final sendingEmail = arguments.sendingEmail;
|
final sendingEmail = arguments.sendingEmail;
|
||||||
@@ -130,7 +65,10 @@ extension SetupEmailContentExtension on ComposerController {
|
|||||||
case EmailActionType.replyAll:
|
case EmailActionType.replyAll:
|
||||||
case EmailActionType.forward:
|
case EmailActionType.forward:
|
||||||
if (arguments.emailContents?.trim().isNotEmpty != true) {
|
if (arguments.emailContents?.trim().isNotEmpty != true) {
|
||||||
emailContentsViewState.value = Left(GetEmailContentFailure(EmptyEmailContentException()));
|
await _getEmailContent(
|
||||||
|
arguments,
|
||||||
|
transformConfiguration: TransformConfiguration.forReplyForwardEmptyEmail(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
final resultState = await transformHtmlEmailContentInteractor.execute(
|
final resultState = await transformHtmlEmailContentInteractor.execute(
|
||||||
arguments.emailContents ?? '',
|
arguments.emailContents ?? '',
|
||||||
@@ -224,4 +162,81 @@ extension SetupEmailContentExtension on ComposerController {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _getEmailContent(
|
||||||
|
ComposerArguments arguments, {
|
||||||
|
required TransformConfiguration transformConfiguration,
|
||||||
|
Properties? additionalProperties,
|
||||||
|
}) async {
|
||||||
|
final session = mailboxDashBoardController.sessionCurrent;
|
||||||
|
final accountId = mailboxDashBoardController.accountId.value;
|
||||||
|
final emailId = arguments.presentationEmail?.id;
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
emailContentsViewState.value = Left(GetEmailContentFailure(NotFoundSessionException()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountId == null) {
|
||||||
|
emailContentsViewState.value = Left(GetEmailContentFailure(NotFoundAccountIdException()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emailId == null) {
|
||||||
|
emailContentsViewState.value = Left(GetEmailContentFailure(NotFoundEmailException()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final resultState = await getEmailContentInteractor.execute(
|
||||||
|
session,
|
||||||
|
accountId,
|
||||||
|
emailId,
|
||||||
|
mailboxDashBoardController.baseDownloadUrl,
|
||||||
|
transformConfiguration,
|
||||||
|
additionalProperties: additionalProperties,
|
||||||
|
).last;
|
||||||
|
|
||||||
|
final uiState = resultState.fold((failure) => failure, (success) => success);
|
||||||
|
|
||||||
|
if (uiState is GetEmailContentSuccess) {
|
||||||
|
initAttachmentsAndInlineImages(
|
||||||
|
attachments: uiState.attachments,
|
||||||
|
inlineImages: uiState.inlineImages,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentEmailActionType == EmailActionType.editDraft ||
|
||||||
|
currentEmailActionType == EmailActionType.editAsNewEmail) {
|
||||||
|
setupEmailRequestReadReceiptFlag(
|
||||||
|
uiState.emailCurrent!.hasRequestReadReceipt,
|
||||||
|
);
|
||||||
|
setupSelectedIdentityForEditDraft(
|
||||||
|
uiState.emailCurrent!.identityIdFromHeader,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
emailContentsViewState.value = Right(uiState);
|
||||||
|
} else if (uiState is GetEmailContentFromCacheSuccess) {
|
||||||
|
initAttachmentsAndInlineImages(
|
||||||
|
attachments: uiState.attachments,
|
||||||
|
inlineImages: uiState.inlineImages,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentEmailActionType == EmailActionType.editDraft
|
||||||
|
|| currentEmailActionType == EmailActionType.editAsNewEmail) {
|
||||||
|
setupEmailRequestReadReceiptFlag(
|
||||||
|
uiState.emailCurrent.hasRequestReadReceipt,
|
||||||
|
);
|
||||||
|
setupSelectedIdentityForEditDraft(
|
||||||
|
uiState.emailCurrent.identityIdFromHeader,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
emailContentsViewState.value = Right(uiState);
|
||||||
|
} else if (uiState is GetEmailContentFailure) {
|
||||||
|
emailContentsViewState.value = Left(uiState);
|
||||||
|
consumeState(Stream.value(Left(uiState)));
|
||||||
|
} else {
|
||||||
|
emailContentsViewState.value = Right(LoadEmailContentCompleted());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
import 'package:core/presentation/state/failure.dart';
|
import 'package:core/presentation/state/failure.dart';
|
||||||
import 'package:core/presentation/state/success.dart';
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
|
||||||
class UnsubscribeEmailLoading extends LoadingState {}
|
class UnsubscribeEmailLoading extends LoadingState {}
|
||||||
|
|
||||||
class UnsubscribeEmailSuccess extends UIState {}
|
class UnsubscribeEmailSuccess extends UIState {
|
||||||
|
UnsubscribeEmailSuccess(this.emailId);
|
||||||
|
|
||||||
|
final EmailId emailId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [emailId];
|
||||||
|
}
|
||||||
|
|
||||||
class UnsubscribeEmailFailure extends FeatureFailure {
|
class UnsubscribeEmailFailure extends FeatureFailure {
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class UnsubscribeEmailInteractor {
|
|||||||
try {
|
try {
|
||||||
yield Right(UnsubscribeEmailLoading());
|
yield Right(UnsubscribeEmailLoading());
|
||||||
await emailRepository.unsubscribeMail(session, accountId, emailId);
|
await emailRepository.unsubscribeMail(session, accountId, emailId);
|
||||||
yield Right(UnsubscribeEmailSuccess());
|
yield Right(UnsubscribeEmailSuccess(emailId));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
yield Left(UnsubscribeEmailFailure(exception: e));
|
yield Left(UnsubscribeEmailFailure(exception: e));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,11 +43,9 @@ import 'package:tmail_ui_user/features/base/base_controller.dart';
|
|||||||
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
||||||
import 'package:tmail_ui_user/features/base/state/button_state.dart';
|
import 'package:tmail_ui_user/features/base/state/button_state.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart';
|
import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/email_print.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/event_action.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/event_action.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
||||||
@@ -110,39 +108,35 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen
|
|||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_bottom_sheet_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_bottom_sheet_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_dialog_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_dialog_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_dialog_builder.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/html_attachment_previewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/html_attachment_previewer.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/pdf_viewer/pdf_viewer.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/pdf_viewer/pdf_viewer.dart';
|
||||||
import 'package:tmail_ui_user/features/email_previewer/email_previewer_dialog_view.dart';
|
import 'package:tmail_ui_user/features/email_previewer/email_previewer_dialog_view.dart';
|
||||||
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
|
||||||
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
|
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_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/extensions/get_mailbox_contain_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_email_rule_filter_request.dart';
|
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/state/create_new_rule_filter_state.dart';
|
import 'package:tmail_ui_user/features/manage_account/domain/state/create_new_rule_filter_state.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart';
|
import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_email_rule_filter_interactor.dart';
|
import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_email_rule_filter_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart';
|
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart';
|
|
||||||
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
|
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.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/focus_thread_detail_expanded_email.dart';
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/focus_thread_detail_expanded_email.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/localization_service.dart';
|
import 'package:tmail_ui_user/main/localizations/localization_service.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/dialog_router.dart';
|
|
||||||
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
|
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
||||||
@@ -203,6 +197,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
Identity? _identitySelected;
|
Identity? _identitySelected;
|
||||||
ButtonState? _printEmailButtonState;
|
ButtonState? _printEmailButtonState;
|
||||||
final obxListeners = <Worker>[];
|
final obxListeners = <Worker>[];
|
||||||
|
late final EmailActionReactor emailActionReactor;
|
||||||
|
|
||||||
final StreamController<Either<Failure, Success>> _downloadProgressStateController =
|
final StreamController<Either<Failure, Success>> _downloadProgressStateController =
|
||||||
StreamController<Either<Failure, Success>>.broadcast();
|
StreamController<Either<Failure, Success>>.broadcast();
|
||||||
@@ -254,6 +249,14 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
_injectCalendarEventBindings(session, accountId);
|
_injectCalendarEventBindings(session, accountId);
|
||||||
_registerObxStreamListener();
|
_registerObxStreamListener();
|
||||||
_listenDownloadAttachmentProgressState();
|
_listenDownloadAttachmentProgressState();
|
||||||
|
emailActionReactor = EmailActionReactor(
|
||||||
|
_markAsEmailReadInteractor,
|
||||||
|
_markAsStarEmailInteractor,
|
||||||
|
_createNewEmailRuleFilterInteractor,
|
||||||
|
_printEmailInteractor,
|
||||||
|
_getEmailContentInteractor,
|
||||||
|
_downloadAttachmentForWebInteractor,
|
||||||
|
);
|
||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +411,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
obxListeners.add(ever(mailboxDashBoardController.viewState, (viewState) {
|
obxListeners.add(ever(mailboxDashBoardController.viewState, (viewState) {
|
||||||
viewState.map((success) {
|
viewState.map((success) {
|
||||||
if (success is UnsubscribeEmailSuccess) {
|
if (success is UnsubscribeEmailSuccess) {
|
||||||
|
if (success.emailId != _currentEmailId) return;
|
||||||
emailUnsubscribe.value = null;
|
emailUnsubscribe.value = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -766,13 +770,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PresentationMailbox? getMailboxContain(PresentationEmail email) {
|
PresentationMailbox? getMailboxContain(PresentationEmail email) {
|
||||||
if (mailboxDashBoardController.selectedMailbox.value == null) {
|
return mailboxDashBoardController.getMailboxContain(email);
|
||||||
return email.findMailboxContain(mailboxDashBoardController.mapMailboxById);
|
|
||||||
} else {
|
|
||||||
return mailboxDashBoardController.searchController.isSearchEmailRunning
|
|
||||||
? email.findMailboxContain(mailboxDashBoardController.mapMailboxById)
|
|
||||||
: mailboxDashBoardController.selectedMailbox.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void markAsEmailRead(
|
void markAsEmailRead(
|
||||||
@@ -1200,81 +1198,28 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moveToMailbox(BuildContext context, PresentationEmail email) async {
|
void moveToMailbox(BuildContext context, PresentationEmail email) async {
|
||||||
final currentMailbox = getMailboxContain(email);
|
if (session != null && accountId != null) {
|
||||||
|
final moveActionRequest = await emailActionReactor.moveToMailbox(
|
||||||
if (currentMailbox != null && accountId != null) {
|
session!,
|
||||||
final arguments = DestinationPickerArguments(
|
|
||||||
accountId!,
|
accountId!,
|
||||||
MailboxActions.moveEmail,
|
email,
|
||||||
session,
|
mapMailbox: mailboxDashBoardController.mapMailboxById,
|
||||||
mailboxIdSelected: currentMailbox.mailboxId
|
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
|
||||||
|
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
|
||||||
);
|
);
|
||||||
|
if (!context.mounted || moveActionRequest == null) return;
|
||||||
final destinationMailbox = PlatformInfo.isWeb
|
mailboxDashBoardController.moveToMailbox(
|
||||||
? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.destinationPicker, arguments: arguments)
|
session!,
|
||||||
: await push(AppRoutes.destinationPicker, arguments: arguments);
|
accountId!,
|
||||||
|
moveActionRequest.moveRequest,
|
||||||
if (destinationMailbox != null &&
|
moveActionRequest.emailIdsWithReadStatus,
|
||||||
destinationMailbox is PresentationMailbox &&
|
);
|
||||||
session != null &&
|
if (_threadDetailController?.emailIdsPresentation.length == 1) {
|
||||||
context.mounted
|
_threadDetailController?.closeThreadDetailAction(context);
|
||||||
) {
|
|
||||||
_dispatchMoveToAction(
|
|
||||||
context,
|
|
||||||
accountId!,
|
|
||||||
session!,
|
|
||||||
email,
|
|
||||||
currentMailbox,
|
|
||||||
destinationMailbox);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _dispatchMoveToAction(
|
|
||||||
BuildContext context,
|
|
||||||
AccountId accountId,
|
|
||||||
Session session,
|
|
||||||
PresentationEmail emailSelected,
|
|
||||||
PresentationMailbox currentMailbox,
|
|
||||||
PresentationMailbox destinationMailbox
|
|
||||||
) {
|
|
||||||
if (destinationMailbox.isTrash) {
|
|
||||||
_moveToTrashAction(
|
|
||||||
context,
|
|
||||||
session,
|
|
||||||
accountId,
|
|
||||||
MoveToMailboxRequest(
|
|
||||||
{currentMailbox.id: [emailSelected.id!]},
|
|
||||||
destinationMailbox.id,
|
|
||||||
MoveAction.moving,
|
|
||||||
EmailActionType.moveToTrash),
|
|
||||||
{emailSelected.id!: emailSelected.hasRead});
|
|
||||||
} else if (destinationMailbox.isSpam) {
|
|
||||||
_moveToSpamAction(
|
|
||||||
context,
|
|
||||||
session,
|
|
||||||
accountId,
|
|
||||||
MoveToMailboxRequest(
|
|
||||||
{currentMailbox.id: [emailSelected.id!]},
|
|
||||||
destinationMailbox.id,
|
|
||||||
MoveAction.moving,
|
|
||||||
EmailActionType.moveToSpam),
|
|
||||||
{emailSelected.id!: emailSelected.hasRead});
|
|
||||||
} else {
|
|
||||||
_moveToMailbox(
|
|
||||||
context,
|
|
||||||
session,
|
|
||||||
accountId,
|
|
||||||
MoveToMailboxRequest(
|
|
||||||
{currentMailbox.id: [emailSelected.id!]},
|
|
||||||
destinationMailbox.id,
|
|
||||||
MoveAction.moving,
|
|
||||||
EmailActionType.moveToMailbox,
|
|
||||||
destinationPath: destinationMailbox.mailboxPath),
|
|
||||||
{emailSelected.id!: emailSelected.hasRead});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _moveToMailbox(
|
void _moveToMailbox(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Session session,
|
Session session,
|
||||||
@@ -1282,7 +1227,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
MoveToMailboxRequest moveRequest,
|
MoveToMailboxRequest moveRequest,
|
||||||
Map<EmailId, bool> emailIdsWithReadStatus,
|
Map<EmailId, bool> emailIdsWithReadStatus,
|
||||||
) {
|
) {
|
||||||
closeEmailView(context: context);
|
|
||||||
consumeState(_moveToMailboxInteractor.execute(
|
consumeState(_moveToMailboxInteractor.execute(
|
||||||
session,
|
session,
|
||||||
accountId,
|
accountId,
|
||||||
@@ -1332,94 +1276,71 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moveToTrash(BuildContext context, PresentationEmail email) {
|
void moveToTrash(BuildContext context, PresentationEmail email) {
|
||||||
final trashMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleTrash);
|
if (session != null && accountId != null) {
|
||||||
final currentMailbox = getMailboxContain(email);
|
final moveActionRequest = emailActionReactor.moveToTrash(
|
||||||
|
email,
|
||||||
if (session != null && accountId != null && currentMailbox != null && trashMailboxId != null) {
|
mapMailbox: mailboxDashBoardController.mapMailboxById,
|
||||||
_moveToTrashAction(
|
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
|
||||||
context,
|
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
|
||||||
|
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
|
||||||
|
);
|
||||||
|
if (!context.mounted || moveActionRequest == null) return;
|
||||||
|
mailboxDashBoardController.moveToMailbox(
|
||||||
session!,
|
session!,
|
||||||
accountId!,
|
accountId!,
|
||||||
MoveToMailboxRequest(
|
moveActionRequest.moveRequest,
|
||||||
{currentMailbox.id: [email.id!]},
|
moveActionRequest.emailIdsWithReadStatus,
|
||||||
trashMailboxId,
|
|
||||||
MoveAction.moving,
|
|
||||||
EmailActionType.moveToTrash),
|
|
||||||
{email.id!: email.hasRead},
|
|
||||||
);
|
);
|
||||||
|
if (_threadDetailController?.emailIdsPresentation.length == 1) {
|
||||||
|
_threadDetailController?.closeThreadDetailAction(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _moveToTrashAction(
|
|
||||||
BuildContext context,
|
|
||||||
Session session,
|
|
||||||
AccountId accountId,
|
|
||||||
MoveToMailboxRequest moveRequest,
|
|
||||||
Map<EmailId, bool> emailIdsWithReadStatus,
|
|
||||||
) {
|
|
||||||
closeEmailView(context: context);
|
|
||||||
mailboxDashBoardController.moveToMailbox(
|
|
||||||
session,
|
|
||||||
accountId,
|
|
||||||
moveRequest,
|
|
||||||
emailIdsWithReadStatus,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveToSpam(BuildContext context, PresentationEmail email) {
|
void moveToSpam(BuildContext context, PresentationEmail email) {
|
||||||
final spamMailboxId = mailboxDashBoardController.spamMailboxId;
|
if (session != null && accountId != null) {
|
||||||
final currentMailbox = getMailboxContain(email);
|
final moveActionRequest = emailActionReactor.moveToSpam(
|
||||||
|
email,
|
||||||
if (session != null && accountId != null && currentMailbox != null && spamMailboxId != null) {
|
mapMailbox: mailboxDashBoardController.mapMailboxById,
|
||||||
_moveToSpamAction(
|
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
|
||||||
context,
|
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
|
||||||
|
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
|
||||||
|
);
|
||||||
|
if (!context.mounted || moveActionRequest == null) return;
|
||||||
|
mailboxDashBoardController.moveToMailbox(
|
||||||
session!,
|
session!,
|
||||||
accountId!,
|
accountId!,
|
||||||
MoveToMailboxRequest(
|
moveActionRequest.moveRequest,
|
||||||
{currentMailbox.id: [email.id!]},
|
moveActionRequest.emailIdsWithReadStatus,
|
||||||
spamMailboxId,
|
|
||||||
MoveAction.moving,
|
|
||||||
EmailActionType.moveToSpam),
|
|
||||||
{email.id!: email.hasRead},
|
|
||||||
);
|
);
|
||||||
|
if (_threadDetailController?.emailIdsPresentation.length == 1) {
|
||||||
|
_threadDetailController?.closeThreadDetailAction(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unSpam(BuildContext context, PresentationEmail email) {
|
void unSpam(BuildContext context, PresentationEmail email) {
|
||||||
final spamMailboxId = mailboxDashBoardController.spamMailboxId;
|
if (session != null && accountId != null) {
|
||||||
final inboxMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleInbox);
|
final moveActionRequest = emailActionReactor.unSpam(
|
||||||
|
email,
|
||||||
if (session != null && accountId != null && spamMailboxId != null && inboxMailboxId != null) {
|
mapMailbox: mailboxDashBoardController.mapMailboxById,
|
||||||
_moveToSpamAction(
|
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
|
||||||
context,
|
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
|
||||||
|
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
|
||||||
|
);
|
||||||
|
if (!context.mounted || moveActionRequest == null) return;
|
||||||
|
mailboxDashBoardController.moveToMailbox(
|
||||||
session!,
|
session!,
|
||||||
accountId!,
|
accountId!,
|
||||||
MoveToMailboxRequest(
|
moveActionRequest.moveRequest,
|
||||||
{spamMailboxId: [email.id!]},
|
moveActionRequest.emailIdsWithReadStatus,
|
||||||
inboxMailboxId,
|
|
||||||
MoveAction.moving,
|
|
||||||
EmailActionType.unSpam),
|
|
||||||
{email.id!: email.hasRead},
|
|
||||||
);
|
);
|
||||||
|
if (_threadDetailController?.emailIdsPresentation.length == 1) {
|
||||||
|
_threadDetailController?.closeThreadDetailAction(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _moveToSpamAction(
|
|
||||||
BuildContext context,
|
|
||||||
Session session,
|
|
||||||
AccountId accountId,
|
|
||||||
MoveToMailboxRequest moveRequest,
|
|
||||||
Map<EmailId, bool> emailIdsWithReadStatus,
|
|
||||||
) {
|
|
||||||
closeEmailView(context: context);
|
|
||||||
mailboxDashBoardController.moveToMailbox(
|
|
||||||
session,
|
|
||||||
accountId,
|
|
||||||
moveRequest,
|
|
||||||
emailIdsWithReadStatus,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void markAsStarEmail(
|
void markAsStarEmail(
|
||||||
PresentationEmail presentationEmail,
|
PresentationEmail presentationEmail,
|
||||||
MarkStarAction markStarAction,
|
MarkStarAction markStarAction,
|
||||||
@@ -1451,13 +1372,34 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
void handleEmailAction(BuildContext context, PresentationEmail presentationEmail, EmailActionType actionType) {
|
void handleEmailAction(BuildContext context, PresentationEmail presentationEmail, EmailActionType actionType) {
|
||||||
switch(actionType) {
|
switch(actionType) {
|
||||||
case EmailActionType.markAsUnread:
|
case EmailActionType.markAsUnread:
|
||||||
markAsEmailRead(presentationEmail, ReadActions.markAsUnread, MarkReadAction.tap);
|
if (session != null && accountId != null) {
|
||||||
|
consumeState(emailActionReactor.markAsEmailRead(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
presentationEmail,
|
||||||
|
readAction: ReadActions.markAsUnread,
|
||||||
|
));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EmailActionType.markAsStarred:
|
case EmailActionType.markAsStarred:
|
||||||
markAsStarEmail(presentationEmail, MarkStarAction.markStar);
|
if (session != null && accountId != null) {
|
||||||
|
consumeState(emailActionReactor.markAsStarEmail(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
presentationEmail,
|
||||||
|
markStarAction: MarkStarAction.markStar,
|
||||||
|
));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EmailActionType.unMarkAsStarred:
|
case EmailActionType.unMarkAsStarred:
|
||||||
markAsStarEmail(presentationEmail, MarkStarAction.unMarkStar);
|
if (session != null && accountId != null) {
|
||||||
|
consumeState(emailActionReactor.markAsStarEmail(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
presentationEmail,
|
||||||
|
markStarAction: MarkStarAction.unMarkStar,
|
||||||
|
));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EmailActionType.moveToMailbox:
|
case EmailActionType.moveToMailbox:
|
||||||
moveToMailbox(context, presentationEmail);
|
moveToMailbox(context, presentationEmail);
|
||||||
@@ -1495,69 +1437,38 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
case EmailActionType.reply:
|
case EmailActionType.reply:
|
||||||
_replyEmail(presentationEmail);
|
_replyEmail(presentationEmail);
|
||||||
break;
|
break;
|
||||||
|
case EmailActionType.replyAll:
|
||||||
|
case EmailActionType.replyToList:
|
||||||
|
case EmailActionType.forward:
|
||||||
|
pressEmailAction(actionType, presentationEmail);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void openEmailAddressDialog(BuildContext context, EmailAddress emailAddress) {
|
void openEmailAddressDialog(EmailAddress emailAddress) {
|
||||||
if (responsiveUtils.isScreenWithShortestSide(context)) {
|
if (session == null || accountId == null) return;
|
||||||
Get.bottomSheet(
|
|
||||||
PointerInterceptor(
|
|
||||||
child: EmailAddressBottomSheetBuilder(
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
emailAddress: emailAddress,
|
|
||||||
onCloseDialogAction: popBack,
|
|
||||||
onCopyEmailAddressAction: (emailAddress) =>
|
|
||||||
copyEmailAddress(context, emailAddress),
|
|
||||||
onComposeEmailAction: composeEmailFromEmailAddress,
|
|
||||||
onQuickCreatingRuleEmailDialogAction: (emailAddress) =>
|
|
||||||
quickCreatingRule(context, emailAddress),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
useRootNavigator: true,
|
|
||||||
shape: const RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadiusDirectional.only(
|
|
||||||
topStart: Radius.circular(16.0),
|
|
||||||
topEnd: Radius.circular(16.0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
isScrollControlled: true,
|
|
||||||
enableDrag: false,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Get.dialog(
|
|
||||||
PointerInterceptor(
|
|
||||||
child: EmailAddressDialogBuilder(
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
emailAddress: emailAddress,
|
|
||||||
onCloseDialogAction: popBack,
|
|
||||||
onCopyEmailAddressAction: (emailAddress) =>
|
|
||||||
copyEmailAddress(context, emailAddress),
|
|
||||||
onComposeEmailAction: composeEmailFromEmailAddress,
|
|
||||||
onQuickCreatingRuleEmailDialogAction: (emailAddress) =>
|
|
||||||
quickCreatingRule(context, emailAddress),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void copyEmailAddress(BuildContext context, EmailAddress emailAddress) {
|
emailActionReactor.openEmailAddressDialog(
|
||||||
Clipboard.setData(ClipboardData(text: emailAddress.emailAddress));
|
session!,
|
||||||
appToast.showToastSuccessMessage(
|
accountId!,
|
||||||
context,
|
emailAddress: emailAddress,
|
||||||
AppLocalizations.of(context).email_address_copied_to_clipboard,
|
responsiveUtils: responsiveUtils,
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
appToast: appToast,
|
||||||
|
onComposeEmailFromEmailAddressRequest: (emailAddress) {
|
||||||
|
popBack();
|
||||||
|
mailboxDashBoardController.openComposer(
|
||||||
|
ComposerArguments.fromEmailAddress(emailAddress),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onQuickCreateRuleRequest: (quickCreateRuleStream) {
|
||||||
|
consumeState(quickCreateRuleStream);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void composeEmailFromEmailAddress(EmailAddress emailAddress) {
|
|
||||||
popBack();
|
|
||||||
mailboxDashBoardController.openComposer(ComposerArguments.fromEmailAddress(emailAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> openMailToLink(Uri? uri) async {
|
Future<void> openMailToLink(Uri? uri) async {
|
||||||
if (uri == null) return;
|
if (uri == null) return;
|
||||||
|
|
||||||
@@ -1577,34 +1488,18 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void deleteEmailPermanently(BuildContext context, PresentationEmail email) {
|
void deleteEmailPermanently(BuildContext context, PresentationEmail email) {
|
||||||
if (responsiveUtils.isMobile(context)) {
|
emailActionReactor.deleteEmailPermanently(
|
||||||
(ConfirmationDialogActionSheetBuilder(context)
|
email,
|
||||||
..messageText(DeleteActionType.single.getContentDialog(context))
|
onDeleteEmailRequest: (email) {
|
||||||
..onCancelAction(AppLocalizations.of(context).cancel, () => popBack())
|
popBack();
|
||||||
..onConfirmAction(DeleteActionType.single.getConfirmActionName(context), () => _deleteEmailPermanentlyAction(context, email)))
|
mailboxDashBoardController.deleteEmailPermanently(email);
|
||||||
.show();
|
if (_threadDetailController?.emailIdsPresentation.length == 1) {
|
||||||
} else {
|
_threadDetailController?.closeThreadDetailAction(context);
|
||||||
Get.dialog(
|
}
|
||||||
PointerInterceptor(child: ConfirmationDialogBuilder(
|
},
|
||||||
key: const Key('confirm_dialog_delete_email_permanently'),
|
responsiveUtils: responsiveUtils,
|
||||||
imagePath: imagePaths,
|
imagePaths: imagePaths,
|
||||||
title: DeleteActionType.single.getTitleDialog(context),
|
);
|
||||||
textContent: DeleteActionType.single.getContentDialog(context),
|
|
||||||
confirmText: DeleteActionType.single.getConfirmActionName(context),
|
|
||||||
cancelText: AppLocalizations.of(context).cancel,
|
|
||||||
onConfirmButtonAction: () => _deleteEmailPermanentlyAction(context, email),
|
|
||||||
onCancelButtonAction: popBack,
|
|
||||||
onCloseButtonAction: popBack,
|
|
||||||
)),
|
|
||||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _deleteEmailPermanentlyAction(BuildContext context, PresentationEmail email) {
|
|
||||||
popBack();
|
|
||||||
closeEmailView(context: context);
|
|
||||||
mailboxDashBoardController.deleteEmailPermanently(email);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleSendReceiptToSenderAction(BuildContext context) {
|
void _handleSendReceiptToSenderAction(BuildContext context) {
|
||||||
@@ -1793,32 +1688,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
popBack();
|
popBack();
|
||||||
|
|
||||||
if (accountId != null && session != null) {
|
if (accountId != null && session != null) {
|
||||||
final arguments = RulesFilterCreatorArguments(
|
consumeState(emailActionReactor.quickCreateRule(
|
||||||
accountId!,
|
|
||||||
session!,
|
session!,
|
||||||
emailAddress: emailAddress);
|
accountId!,
|
||||||
|
emailAddress: emailAddress,
|
||||||
final newRuleFilterRequest = PlatformInfo.isWeb
|
));
|
||||||
? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.rulesFilterCreator, arguments: arguments)
|
|
||||||
: await push(AppRoutes.rulesFilterCreator, arguments: arguments);
|
|
||||||
|
|
||||||
if (newRuleFilterRequest is CreateNewEmailRuleFilterRequest) {
|
|
||||||
_createNewRuleFilterAction(accountId!, newRuleFilterRequest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _createNewRuleFilterAction(
|
|
||||||
AccountId accountId,
|
|
||||||
CreateNewEmailRuleFilterRequest ruleFilterRequest
|
|
||||||
) async {
|
|
||||||
try {
|
|
||||||
_createNewEmailRuleFilterInteractor = Get.find<CreateNewEmailRuleFilterInteractor>();
|
|
||||||
} catch (e) {
|
|
||||||
logError('SingleEmailController::onInit(): ${e.toString()}');
|
|
||||||
}
|
|
||||||
if (_createNewEmailRuleFilterInteractor != null) {
|
|
||||||
consumeState(_createNewEmailRuleFilterInteractor!.execute(accountId, ruleFilterRequest));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,70 +1803,30 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _unsubscribeEmail(BuildContext context, PresentationEmail presentationEmail) {
|
void _unsubscribeEmail(BuildContext context, PresentationEmail presentationEmail) {
|
||||||
showConfirmDialogAction(
|
emailActionReactor.unsubscribeEmail(
|
||||||
context,
|
presentationEmail,
|
||||||
'',
|
emailUnsubscribe: emailUnsubscribe.value,
|
||||||
AppLocalizations.of(context).unsubscribe,
|
onUnsubscribeByHttpsLink: mailboxDashBoardController.unsubscribeMail,
|
||||||
onConfirmAction: () {
|
onUnsubscribeByMailtoLink: (emailId, navigationRouter) {
|
||||||
if (emailUnsubscribe.value?.httpLinks.isNotEmpty == true) {
|
mailboxDashBoardController.openComposer(
|
||||||
_handleUnsubscribeMailByHttpsLink(
|
ComposerArguments.fromUnsubscribeMailtoLink(
|
||||||
context: context,
|
listEmailAddress: navigationRouter.listEmailAddress,
|
||||||
emailId: presentationEmail.id!,
|
subject: navigationRouter.subject,
|
||||||
httpLinks: emailUnsubscribe.value!.httpLinks
|
body: navigationRouter.body,
|
||||||
);
|
previousEmailId: emailId,
|
||||||
} else if (emailUnsubscribe.value?.mailtoLinks.isNotEmpty == true) {
|
)
|
||||||
_handleUnsubscribeMailByMailtoLink(
|
);
|
||||||
context: context,
|
|
||||||
emailId: presentationEmail.id!,
|
|
||||||
mailtoLinks: emailUnsubscribe.value!.mailtoLinks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
showAsBottomSheet: true,
|
|
||||||
dialogMargin: MediaQuery.paddingOf(context).add(const EdgeInsets.only(bottom: 12)),
|
|
||||||
title: AppLocalizations.of(context).unsubscribeMail,
|
|
||||||
listTextSpan: [
|
|
||||||
TextSpan(text: AppLocalizations.of(context).unsubscribeMailDialogMessage),
|
|
||||||
TextSpan(
|
|
||||||
text: ' ${presentationEmail.getSenderName()}',
|
|
||||||
style: ThemeUtils.textStyleM3BodyMedium1.copyWith(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const TextSpan(text: ' ?'),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleUnsubscribeMailByHttpsLink({
|
|
||||||
required BuildContext context,
|
|
||||||
required EmailId emailId,
|
|
||||||
required List<String> httpLinks
|
|
||||||
}) {
|
|
||||||
log('SingleEmailController::_handleUnsubscribeMailByHttpsLink:httpLinks: $httpLinks');
|
|
||||||
mailboxDashBoardController.unsubscribeMail(emailId);
|
|
||||||
AppUtils.launchLink(httpLinks.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleUnsubscribeMailByMailtoLink({
|
|
||||||
required BuildContext context,
|
|
||||||
required EmailId emailId,
|
|
||||||
required List<String> mailtoLinks
|
|
||||||
}) {
|
|
||||||
log('SingleEmailController::_handleUnsubscribeMailByMailtoLink:mailtoLinks: $mailtoLinks');
|
|
||||||
final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(mailtoLinks.first);
|
|
||||||
mailboxDashBoardController.openComposer(
|
|
||||||
ComposerArguments.fromUnsubscribeMailtoLink(
|
|
||||||
listEmailAddress: navigationRouter.listEmailAddress,
|
|
||||||
subject: navigationRouter.subject,
|
|
||||||
body: navigationRouter.body,
|
|
||||||
previousEmailId: emailId,
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void archiveMessage(BuildContext context, PresentationEmail email) {
|
void archiveMessage(BuildContext context, PresentationEmail email) {
|
||||||
mailboxDashBoardController.archiveMessage(context, email);
|
emailActionReactor.archiveMessage(
|
||||||
|
email,
|
||||||
|
onArchiveEmailRequest: (presentationEmail) {
|
||||||
|
mailboxDashBoardController.archiveMessage(context, presentationEmail);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _printEmail(BuildContext context, PresentationEmail email) {
|
void _printEmail(BuildContext context, PresentationEmail email) {
|
||||||
@@ -2003,40 +1837,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
|
|
||||||
_printEmailButtonState = ButtonState.disabled;
|
_printEmailButtonState = ButtonState.disabled;
|
||||||
|
|
||||||
final locale = Localizations.localeOf(context);
|
consumeState(emailActionReactor.printEmail(
|
||||||
final appLocalizations = AppLocalizations.of(context);
|
email,
|
||||||
|
ownEmailAddress: mailboxDashBoardController.ownEmailAddress.value,
|
||||||
consumeState(
|
emailLoaded: currentEmailLoaded.value!,
|
||||||
_printEmailInteractor.execute(
|
));
|
||||||
EmailPrint(
|
|
||||||
appName: appLocalizations.app_name,
|
|
||||||
userName: mailboxDashBoardController.ownEmailAddress.value,
|
|
||||||
attachments: currentEmailLoaded.value!.attachments,
|
|
||||||
emailContent: currentEmailLoaded.value!.htmlContent,
|
|
||||||
fromPrefix: appLocalizations.from_email_address_prefix,
|
|
||||||
toPrefix: appLocalizations.to_email_address_prefix,
|
|
||||||
ccPrefix: appLocalizations.cc_email_address_prefix,
|
|
||||||
bccPrefix: appLocalizations.bcc_email_address_prefix,
|
|
||||||
replyToPrefix: appLocalizations.replyToEmailAddressPrefix,
|
|
||||||
titleAttachment: appLocalizations.attachments.toLowerCase(),
|
|
||||||
toAddress: email.to?.listEmailAddressToString(isFullEmailAddress: true),
|
|
||||||
ccAddress: email.cc?.listEmailAddressToString(isFullEmailAddress: true),
|
|
||||||
bccAddress: email.bcc?.listEmailAddressToString(isFullEmailAddress: true),
|
|
||||||
replyToAddress: email.replyTo?.listEmailAddressToString(isFullEmailAddress: true),
|
|
||||||
sender: email.from?.isNotEmpty == true
|
|
||||||
? email.from!.first
|
|
||||||
: null,
|
|
||||||
receiveTime: email.getReceivedAt(
|
|
||||||
locale.toLanguageTag(),
|
|
||||||
pattern: email.receivedAt
|
|
||||||
?.value
|
|
||||||
.toLocal()
|
|
||||||
.toPatternForPrinting(locale.toLanguageTag()),
|
|
||||||
),
|
|
||||||
subject: email.subject,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showMessageWhenStartingEmailPrinting() {
|
void _showMessageWhenStartingEmailPrinting() {
|
||||||
@@ -2181,34 +1986,46 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _downloadMessageAsEML(PresentationEmail presentationEmail) {
|
void _downloadMessageAsEML(PresentationEmail presentationEmail) {
|
||||||
final emlAttachment = presentationEmail.createEMLAttachment();
|
if (accountId == null || session == null) return;
|
||||||
if (emlAttachment.blobId == null) {
|
|
||||||
consumeState(Stream.value(Left(DownloadAttachmentForWebFailure(exception: NotFoundEmailBlobIdException()))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadAttachmentForWeb(emlAttachment);
|
consumeState(emailActionReactor.downloadMessageAsEML(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
presentationEmail,
|
||||||
|
downloadProgressStateController: _downloadProgressStateController,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _editAsNewEmail(PresentationEmail presentationEmail) {
|
void _editAsNewEmail(PresentationEmail presentationEmail) {
|
||||||
if (accountId == null || session == null) return;
|
if (accountId == null || session == null) return;
|
||||||
|
|
||||||
mailboxDashBoardController.openComposer(
|
emailActionReactor.editAsNewEmail(
|
||||||
ComposerArguments.editAsNewEmail(presentationEmail),
|
presentationEmail,
|
||||||
|
onEditAsEmailRequest: (presentationEmail) {
|
||||||
|
mailboxDashBoardController.openComposer(
|
||||||
|
ComposerArguments.editAsNewEmail(presentationEmail),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _replyEmail(PresentationEmail presentationEmail) {
|
void _replyEmail(PresentationEmail presentationEmail) {
|
||||||
mailboxDashBoardController.openComposer(
|
emailActionReactor.replyEmail(
|
||||||
ComposerArguments.replyEmail(
|
presentationEmail,
|
||||||
presentationEmail: presentationEmail,
|
emailLoaded: currentEmailLoaded.value,
|
||||||
content: currentEmailLoaded.value?.htmlContent ?? '',
|
onReplyEmailRequest: (presentationEmail, emailLoaded) {
|
||||||
inlineImages: currentEmailLoaded.value?.inlineImages ?? [],
|
mailboxDashBoardController.openComposer(
|
||||||
mailboxRole: presentationEmail.mailboxContain?.role,
|
ComposerArguments.replyEmail(
|
||||||
messageId: currentEmailLoaded.value?.emailCurrent?.messageId,
|
presentationEmail: presentationEmail,
|
||||||
references: currentEmailLoaded.value?.emailCurrent?.references,
|
content: emailLoaded?.htmlContent,
|
||||||
listPost: currentEmailLoaded.value?.emailCurrent?.listPost,
|
inlineImages: emailLoaded?.inlineImages,
|
||||||
)
|
mailboxRole: presentationEmail.mailboxContain?.role,
|
||||||
|
messageId: emailLoaded?.emailCurrent?.messageId,
|
||||||
|
references: emailLoaded?.emailCurrent?.references,
|
||||||
|
listPost: emailLoaded?.emailCurrent?.listPost,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:model/email/email_action_type.dart';
|
import 'package:model/email/email_action_type.dart';
|
||||||
import 'package:model/email/presentation_email.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/list_email_address_extension.dart';
|
||||||
import 'package:model/extensions/presentation_email_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:model/mailbox/presentation_mailbox.dart';
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.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_expanded.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/optional_scroll.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/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/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/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_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_detail_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/calendar_event_information_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/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/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/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/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/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/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/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
|
||||||
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
||||||
|
|
||||||
class EmailView extends GetWidget<SingleEmailController> {
|
class EmailView extends GetWidget<SingleEmailController> {
|
||||||
@@ -97,11 +88,15 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
isSearchActivated: controller.mailboxDashBoardController.searchController.isSearchEmailRunning,
|
isSearchActivated: controller.mailboxDashBoardController.searchController.isSearchEmailRunning,
|
||||||
onBackAction: () => controller.closeEmailView(context: context),
|
onBackAction: () => controller.closeEmailView(context: context),
|
||||||
onEmailActionClick: (email, action) => controller.handleEmailAction(context, email, action),
|
onEmailActionClick: (email, action) => controller.handleEmailAction(context, email, action),
|
||||||
onMoreActionClick: (presentationEmail, position) => _handleMoreEmailAction(
|
onMoreActionClick: (presentationEmail, position) => controller.emailActionReactor.handleMoreEmailAction(
|
||||||
context: context,
|
mailboxContain: controller.getMailboxContain(presentationEmail),
|
||||||
presentationEmail: presentationEmail,
|
presentationEmail: presentationEmail,
|
||||||
position: position,
|
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,
|
supportBackAction: !isInsideThreadDetailView,
|
||||||
appBarDecoration: isInsideThreadDetailView
|
appBarDecoration: isInsideThreadDetailView
|
||||||
@@ -278,18 +273,38 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
sMimeStatus: controller.currentEmailLoaded.value?.sMimeStatus,
|
sMimeStatus: controller.currentEmailLoaded.value?.sMimeStatus,
|
||||||
emailUnsubscribe: controller.emailUnsubscribe.value,
|
emailUnsubscribe: controller.emailUnsubscribe.value,
|
||||||
maxBodyHeight: maxBodyHeight,
|
maxBodyHeight: maxBodyHeight,
|
||||||
openEmailAddressDetailAction: controller.openEmailAddressDialog,
|
openEmailAddressDetailAction: (_, emailAddress) => controller.openEmailAddressDialog(emailAddress),
|
||||||
onEmailActionClick: (presentationEmail, actionType) => controller.handleEmailAction(context, presentationEmail, actionType),
|
onEmailActionClick: (presentationEmail, actionType) => controller.handleEmailAction(context, presentationEmail, actionType),
|
||||||
isInsideThreadDetailView: isInsideThreadDetailView,
|
isInsideThreadDetailView: isInsideThreadDetailView,
|
||||||
emailLoaded: controller.currentEmailLoaded.value,
|
emailLoaded: controller.currentEmailLoaded.value,
|
||||||
onMoreActionClick: (email, position) => _handleMoreEmailAction(
|
onMoreActionClick: (presentationEmail, position) => controller.emailActionReactor.handleMoreEmailAction(
|
||||||
context: context,
|
mailboxContain: controller.getMailboxContain(presentationEmail),
|
||||||
presentationEmail: email,
|
presentationEmail: presentationEmail,
|
||||||
position: position,
|
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,
|
onToggleThreadDetailCollapseExpand: onToggleThreadDetailCollapseExpand,
|
||||||
onTapAvatarActionClick: onToggleThreadDetailCollapseExpand,
|
onTapAvatarActionClick: onToggleThreadDetailCollapseExpand,
|
||||||
|
mailboxContain: presentationEmail.findMailboxContain(
|
||||||
|
controller.mailboxDashBoardController.mapMailboxById,
|
||||||
|
),
|
||||||
)),
|
)),
|
||||||
Obx(() => MailUnsubscribedBanner(
|
Obx(() => MailUnsubscribedBanner(
|
||||||
presentationEmail: controller.currentEmail,
|
presentationEmail: controller.currentEmail,
|
||||||
@@ -340,7 +355,7 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
.ownEmailAddress
|
.ownEmailAddress
|
||||||
.value,
|
.value,
|
||||||
onMailtoAttendeesAction: controller.handleMailToAttendees,
|
onMailtoAttendeesAction: controller.handleMailToAttendees,
|
||||||
openEmailAddressDetailAction: controller.openEmailAddressDialog,
|
openEmailAddressDetailAction: (_, emailAddress) => controller.openEmailAddressDialog(emailAddress),
|
||||||
isFree: controller.isCalendarEventFree,
|
isFree: controller.isCalendarEventFree,
|
||||||
listEmailAddressSender: emailAddressSender ?? [],
|
listEmailAddressSender: emailAddressSender ?? [],
|
||||||
isPortraitMobile: controller
|
isPortraitMobile: controller
|
||||||
@@ -496,113 +511,4 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
|
|
||||||
return usernameEvent.isNotEmpty && titleEvent.isNotEmpty;
|
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -144,8 +144,8 @@ class ComposerArguments extends RouterArguments {
|
|||||||
|
|
||||||
factory ComposerArguments.replyEmail({
|
factory ComposerArguments.replyEmail({
|
||||||
required PresentationEmail presentationEmail,
|
required PresentationEmail presentationEmail,
|
||||||
required String content,
|
required String? content,
|
||||||
required List<Attachment> inlineImages,
|
required List<Attachment>? inlineImages,
|
||||||
Role? mailboxRole,
|
Role? mailboxRole,
|
||||||
MessageIdsHeaderValue? messageId,
|
MessageIdsHeaderValue? messageId,
|
||||||
MessageIdsHeaderValue? references,
|
MessageIdsHeaderValue? references,
|
||||||
@@ -163,8 +163,8 @@ class ComposerArguments extends RouterArguments {
|
|||||||
|
|
||||||
factory ComposerArguments.replyToListEmail({
|
factory ComposerArguments.replyToListEmail({
|
||||||
required PresentationEmail presentationEmail,
|
required PresentationEmail presentationEmail,
|
||||||
required String content,
|
required String? content,
|
||||||
required List<Attachment> inlineImages,
|
required List<Attachment>? inlineImages,
|
||||||
Role? mailboxRole,
|
Role? mailboxRole,
|
||||||
MessageIdsHeaderValue? messageId,
|
MessageIdsHeaderValue? messageId,
|
||||||
MessageIdsHeaderValue? references,
|
MessageIdsHeaderValue? references,
|
||||||
@@ -182,8 +182,8 @@ class ComposerArguments extends RouterArguments {
|
|||||||
|
|
||||||
factory ComposerArguments.replyAllEmail({
|
factory ComposerArguments.replyAllEmail({
|
||||||
required PresentationEmail presentationEmail,
|
required PresentationEmail presentationEmail,
|
||||||
required String content,
|
required String? content,
|
||||||
required List<Attachment> inlineImages,
|
required List<Attachment>? inlineImages,
|
||||||
Role? mailboxRole,
|
Role? mailboxRole,
|
||||||
MessageIdsHeaderValue? messageId,
|
MessageIdsHeaderValue? messageId,
|
||||||
MessageIdsHeaderValue? references,
|
MessageIdsHeaderValue? references,
|
||||||
@@ -201,9 +201,9 @@ class ComposerArguments extends RouterArguments {
|
|||||||
|
|
||||||
factory ComposerArguments.forwardEmail({
|
factory ComposerArguments.forwardEmail({
|
||||||
required PresentationEmail presentationEmail,
|
required PresentationEmail presentationEmail,
|
||||||
required String content,
|
required String? content,
|
||||||
required List<Attachment> attachments,
|
required List<Attachment>? attachments,
|
||||||
required List<Attachment> inlineImages,
|
required List<Attachment>? inlineImages,
|
||||||
MessageIdsHeaderValue? messageId,
|
MessageIdsHeaderValue? messageId,
|
||||||
MessageIdsHeaderValue? references,
|
MessageIdsHeaderValue? references,
|
||||||
}) => ComposerArguments(
|
}) => ComposerArguments(
|
||||||
|
|||||||
@@ -0,0 +1,886 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:core/data/network/config/dynamic_url_interceptors.dart';
|
||||||
|
import 'package:core/domain/extensions/datetime_extension.dart';
|
||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:core/presentation/resources/image_paths.dart';
|
||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:core/presentation/utils/app_toast.dart';
|
||||||
|
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
||||||
|
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||||
|
import 'package:core/presentation/utils/theme_utils.dart';
|
||||||
|
import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart';
|
||||||
|
import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:core/utils/platform_info.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/user_name.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||||
|
import 'package:model/download/download_task_id.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/email_address_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/extensions/session_extension.dart';
|
||||||
|
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||||
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/model/email_print.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.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/get_email_content_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';
|
||||||
|
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/email/presentation/model/email_loaded.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_dialog_builder.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_email_rule_filter_request.dart';
|
||||||
|
import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_email_rule_filter_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart';
|
||||||
|
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
|
||||||
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/dialog_router.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
||||||
|
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
class EmailActionReactor with MessageDialogActionMixin, PopupContextMenuActionMixin {
|
||||||
|
const EmailActionReactor(
|
||||||
|
this._markAsEmailReadInteractor,
|
||||||
|
this._markAsStarEmailInteractor,
|
||||||
|
this._createNewEmailRuleFilterInteractor,
|
||||||
|
this._printEmailInteractor,
|
||||||
|
this._getEmailContentInteractor,
|
||||||
|
this._downloadAttachmentForWebInteractor,
|
||||||
|
);
|
||||||
|
|
||||||
|
final MarkAsEmailReadInteractor _markAsEmailReadInteractor;
|
||||||
|
final MarkAsStarEmailInteractor _markAsStarEmailInteractor;
|
||||||
|
final CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor;
|
||||||
|
final PrintEmailInteractor _printEmailInteractor;
|
||||||
|
final GetEmailContentInteractor _getEmailContentInteractor;
|
||||||
|
final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor;
|
||||||
|
|
||||||
|
Stream<Either<Failure, Success>> markAsEmailRead(
|
||||||
|
Session session,
|
||||||
|
AccountId accountId,
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required ReadActions readAction,
|
||||||
|
}) {
|
||||||
|
return _markAsEmailReadInteractor.execute(
|
||||||
|
session,
|
||||||
|
accountId,
|
||||||
|
presentationEmail.id!,
|
||||||
|
readAction,
|
||||||
|
MarkReadAction.tap,
|
||||||
|
presentationEmail.mailboxContain?.mailboxId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<Either<Failure, Success>> markAsStarEmail(
|
||||||
|
Session session,
|
||||||
|
AccountId accountId,
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required MarkStarAction markStarAction,
|
||||||
|
}) {
|
||||||
|
return _markAsStarEmailInteractor.execute(
|
||||||
|
session,
|
||||||
|
accountId,
|
||||||
|
presentationEmail.id!,
|
||||||
|
markStarAction,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<({
|
||||||
|
MoveToMailboxRequest moveRequest,
|
||||||
|
Map<EmailId, bool> emailIdsWithReadStatus
|
||||||
|
})?> moveToMailbox(
|
||||||
|
Session session,
|
||||||
|
AccountId accountId,
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required Map<MailboxId, PresentationMailbox> mapMailbox,
|
||||||
|
required PresentationMailbox? selectedMailbox,
|
||||||
|
required bool isSearchEmailRunning,
|
||||||
|
}) async {
|
||||||
|
final moveRequest = await _moveToMailbox(
|
||||||
|
session,
|
||||||
|
accountId,
|
||||||
|
presentationEmail,
|
||||||
|
mapMailbox: mapMailbox,
|
||||||
|
isSearchEmailRunning: isSearchEmailRunning,
|
||||||
|
selectedMailbox: selectedMailbox,
|
||||||
|
);
|
||||||
|
if (moveRequest == null) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
moveRequest: moveRequest.moveRequest,
|
||||||
|
emailIdsWithReadStatus: moveRequest.emailIdsWithReadStatus,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
({
|
||||||
|
MoveToMailboxRequest moveRequest,
|
||||||
|
Map<EmailId, bool> emailIdsWithReadStatus
|
||||||
|
})? moveToTrash(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required Map<MailboxId, PresentationMailbox> mapMailbox,
|
||||||
|
required PresentationMailbox? selectedMailbox,
|
||||||
|
required bool isSearchEmailRunning,
|
||||||
|
required Map<Role, MailboxId> mapDefaultMailboxIdByRole,
|
||||||
|
}) {
|
||||||
|
final trashMailboxId = mapDefaultMailboxIdByRole[
|
||||||
|
PresentationMailbox.roleTrash
|
||||||
|
];
|
||||||
|
final currentMailbox = _getMailboxContain(
|
||||||
|
presentationEmail,
|
||||||
|
mapMailbox: mapMailbox,
|
||||||
|
isSearchEmailRunning: isSearchEmailRunning,
|
||||||
|
selectedMailbox: selectedMailbox,
|
||||||
|
);
|
||||||
|
if (trashMailboxId == null || currentMailbox == null) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
moveRequest: MoveToMailboxRequest(
|
||||||
|
{currentMailbox.id: [presentationEmail.id!]},
|
||||||
|
trashMailboxId,
|
||||||
|
MoveAction.moving,
|
||||||
|
EmailActionType.moveToTrash),
|
||||||
|
emailIdsWithReadStatus: {presentationEmail.id!: presentationEmail.hasRead},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteEmailPermanently(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required void Function(PresentationEmail email) onDeleteEmailRequest,
|
||||||
|
required ResponsiveUtils responsiveUtils,
|
||||||
|
required ImagePaths imagePaths,
|
||||||
|
}) async {
|
||||||
|
if (currentContext == null || !currentContext!.mounted) return;
|
||||||
|
if (responsiveUtils.isMobile(currentContext!)) {
|
||||||
|
await (ConfirmationDialogActionSheetBuilder(currentContext!)
|
||||||
|
..messageText(DeleteActionType.single.getContentDialog(currentContext!))
|
||||||
|
..onCancelAction(AppLocalizations.of(currentContext!).cancel, () => popBack())
|
||||||
|
..onConfirmAction(
|
||||||
|
DeleteActionType.single.getConfirmActionName(currentContext!),
|
||||||
|
() => onDeleteEmailRequest.call(presentationEmail)
|
||||||
|
)
|
||||||
|
).show();
|
||||||
|
} else {
|
||||||
|
await Get.dialog(
|
||||||
|
PointerInterceptor(child: ConfirmationDialogBuilder(
|
||||||
|
key: const Key('confirm_dialog_delete_email_permanently'),
|
||||||
|
imagePath: imagePaths,
|
||||||
|
title: DeleteActionType.single.getTitleDialog(currentContext!),
|
||||||
|
textContent: DeleteActionType.single.getContentDialog(currentContext!),
|
||||||
|
cancelText: DeleteActionType.single.getConfirmActionName(currentContext!),
|
||||||
|
confirmText: AppLocalizations.of(currentContext!).cancel,
|
||||||
|
onCancelButtonAction: () => onDeleteEmailRequest.call(presentationEmail),
|
||||||
|
onConfirmButtonAction: popBack,
|
||||||
|
onCloseButtonAction: popBack,
|
||||||
|
)),
|
||||||
|
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
({
|
||||||
|
MoveToMailboxRequest moveRequest,
|
||||||
|
Map<EmailId, bool> emailIdsWithReadStatus
|
||||||
|
})? moveToSpam(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required Map<MailboxId, PresentationMailbox> mapMailbox,
|
||||||
|
required PresentationMailbox? selectedMailbox,
|
||||||
|
required bool isSearchEmailRunning,
|
||||||
|
required Map<Role, MailboxId> mapDefaultMailboxIdByRole,
|
||||||
|
}) {
|
||||||
|
final spamMailboxId = _spamMailboxId(mapDefaultMailboxIdByRole);
|
||||||
|
final currentMailbox = _getMailboxContain(
|
||||||
|
presentationEmail,
|
||||||
|
mapMailbox: mapMailbox,
|
||||||
|
isSearchEmailRunning: isSearchEmailRunning,
|
||||||
|
selectedMailbox: selectedMailbox,
|
||||||
|
);
|
||||||
|
if (spamMailboxId == null || currentMailbox == null) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
moveRequest: MoveToMailboxRequest(
|
||||||
|
{currentMailbox.id: [presentationEmail.id!]},
|
||||||
|
spamMailboxId,
|
||||||
|
MoveAction.moving,
|
||||||
|
EmailActionType.moveToSpam),
|
||||||
|
emailIdsWithReadStatus: {presentationEmail.id!: presentationEmail.hasRead},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
({
|
||||||
|
MoveToMailboxRequest moveRequest,
|
||||||
|
Map<EmailId, bool> emailIdsWithReadStatus
|
||||||
|
})? unSpam(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required Map<MailboxId, PresentationMailbox> mapMailbox,
|
||||||
|
required PresentationMailbox? selectedMailbox,
|
||||||
|
required bool isSearchEmailRunning,
|
||||||
|
required Map<Role, MailboxId> mapDefaultMailboxIdByRole,
|
||||||
|
}) {
|
||||||
|
final spamMailboxId = _spamMailboxId(mapDefaultMailboxIdByRole);
|
||||||
|
final inboxMailboxId = mapDefaultMailboxIdByRole[
|
||||||
|
PresentationMailbox.roleInbox
|
||||||
|
];
|
||||||
|
if (spamMailboxId == null || inboxMailboxId == null) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
moveRequest: MoveToMailboxRequest(
|
||||||
|
{spamMailboxId: [presentationEmail.id!]},
|
||||||
|
inboxMailboxId,
|
||||||
|
MoveAction.moving,
|
||||||
|
EmailActionType.unSpam
|
||||||
|
),
|
||||||
|
emailIdsWithReadStatus: {presentationEmail.id!: presentationEmail.hasRead},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MailboxId? _spamMailboxId(
|
||||||
|
Map<Role, MailboxId> mapDefaultMailboxIdByRole
|
||||||
|
) {
|
||||||
|
return mapDefaultMailboxIdByRole[
|
||||||
|
PresentationMailbox.roleSpam
|
||||||
|
] ?? mapDefaultMailboxIdByRole[
|
||||||
|
PresentationMailbox.roleJunk
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<Either<Failure, Success>> quickCreateRule(
|
||||||
|
Session session,
|
||||||
|
AccountId accountId, {
|
||||||
|
required EmailAddress? emailAddress,
|
||||||
|
}) async* {
|
||||||
|
Get.back();
|
||||||
|
final arguments = RulesFilterCreatorArguments(
|
||||||
|
accountId,
|
||||||
|
session,
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
);
|
||||||
|
|
||||||
|
final newRuleFilterRequest = PlatformInfo.isWeb
|
||||||
|
? await DialogRouter.pushGeneralDialog(
|
||||||
|
routeName: AppRoutes.rulesFilterCreator,
|
||||||
|
arguments: arguments,
|
||||||
|
)
|
||||||
|
: await push(AppRoutes.rulesFilterCreator, arguments: arguments);
|
||||||
|
|
||||||
|
if (newRuleFilterRequest is! CreateNewEmailRuleFilterRequest) return;
|
||||||
|
|
||||||
|
yield* _createNewEmailRuleFilterInteractor?.execute(
|
||||||
|
accountId,
|
||||||
|
newRuleFilterRequest
|
||||||
|
) ?? const Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> unsubscribeEmail(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required EmailUnsubscribe? emailUnsubscribe,
|
||||||
|
required void Function(EmailId emailId) onUnsubscribeByHttpsLink,
|
||||||
|
required void Function(
|
||||||
|
EmailId emailId,
|
||||||
|
NavigationRouter navigationRouter,
|
||||||
|
) onUnsubscribeByMailtoLink,
|
||||||
|
}) async {
|
||||||
|
if (currentContext == null || !currentContext!.mounted) return;
|
||||||
|
|
||||||
|
await showConfirmDialogAction(
|
||||||
|
currentContext!,
|
||||||
|
'',
|
||||||
|
AppLocalizations.of(currentContext!).unsubscribe,
|
||||||
|
onConfirmAction: () {
|
||||||
|
if (emailUnsubscribe?.httpLinks.isNotEmpty == true) {
|
||||||
|
onUnsubscribeByHttpsLink(presentationEmail.id!);
|
||||||
|
AppUtils.launchLink(emailUnsubscribe!.httpLinks.first);
|
||||||
|
} else if (emailUnsubscribe?.mailtoLinks.isNotEmpty == true) {
|
||||||
|
final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(
|
||||||
|
emailUnsubscribe!.mailtoLinks.first,
|
||||||
|
);
|
||||||
|
onUnsubscribeByMailtoLink(presentationEmail.id!, navigationRouter);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showAsBottomSheet: true,
|
||||||
|
title: AppLocalizations.of(currentContext!).unsubscribeMail,
|
||||||
|
listTextSpan: [
|
||||||
|
TextSpan(text: AppLocalizations.of(currentContext!).unsubscribeMailDialogMessage),
|
||||||
|
TextSpan(
|
||||||
|
text: ' ${presentationEmail.getSenderName()}',
|
||||||
|
style: ThemeUtils.textStyleBodyBody2(
|
||||||
|
color: AppColor.steelGray400,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' ?'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void archiveMessage(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
) onArchiveEmailRequest,
|
||||||
|
}) => onArchiveEmailRequest(presentationEmail);
|
||||||
|
|
||||||
|
Stream<Either<Failure, Success>> printEmail(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required String ownEmailAddress,
|
||||||
|
required EmailLoaded? emailLoaded,
|
||||||
|
VoidCallback? onGetEmailContentFailure,
|
||||||
|
Session? session,
|
||||||
|
AccountId? accountId,
|
||||||
|
String? baseDownloadUrl,
|
||||||
|
TransformConfiguration? transformConfiguration,
|
||||||
|
}) async* {
|
||||||
|
emailLoaded ??= await _getEmailLoaded(
|
||||||
|
session,
|
||||||
|
accountId,
|
||||||
|
presentationEmail.id,
|
||||||
|
baseDownloadUrl,
|
||||||
|
transformConfiguration,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (emailLoaded == null) {
|
||||||
|
onGetEmailContentFailure?.call();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentContext == null || !currentContext!.mounted) return;
|
||||||
|
final locale = Localizations.localeOf(currentContext!);
|
||||||
|
final appLocalizations = AppLocalizations.of(currentContext!);
|
||||||
|
|
||||||
|
yield* _printEmailInteractor.execute(
|
||||||
|
EmailPrint(
|
||||||
|
appName: appLocalizations.app_name,
|
||||||
|
userName: ownEmailAddress,
|
||||||
|
attachments: emailLoaded.attachments,
|
||||||
|
emailContent: emailLoaded.htmlContent,
|
||||||
|
fromPrefix: appLocalizations.from_email_address_prefix,
|
||||||
|
toPrefix: appLocalizations.to_email_address_prefix,
|
||||||
|
ccPrefix: appLocalizations.cc_email_address_prefix,
|
||||||
|
bccPrefix: appLocalizations.bcc_email_address_prefix,
|
||||||
|
replyToPrefix: appLocalizations.replyToEmailAddressPrefix,
|
||||||
|
titleAttachment: appLocalizations.attachments.toLowerCase(),
|
||||||
|
toAddress: presentationEmail.to?.listEmailAddressToString(isFullEmailAddress: true),
|
||||||
|
ccAddress: presentationEmail.cc?.listEmailAddressToString(isFullEmailAddress: true),
|
||||||
|
bccAddress: presentationEmail.bcc?.listEmailAddressToString(isFullEmailAddress: true),
|
||||||
|
replyToAddress: presentationEmail.replyTo?.listEmailAddressToString(isFullEmailAddress: true),
|
||||||
|
sender: presentationEmail.from?.isNotEmpty == true
|
||||||
|
? presentationEmail.from!.first
|
||||||
|
: null,
|
||||||
|
receiveTime: presentationEmail.getReceivedAt(
|
||||||
|
locale.toLanguageTag(),
|
||||||
|
pattern: presentationEmail.receivedAt
|
||||||
|
?.value
|
||||||
|
.toLocal()
|
||||||
|
.toPatternForPrinting(locale.toLanguageTag()),
|
||||||
|
),
|
||||||
|
subject: presentationEmail.subject,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<Either<Failure, Success>> downloadMessageAsEML(
|
||||||
|
Session session,
|
||||||
|
AccountId accountId,
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required StreamController<Either<Failure, Success>> downloadProgressStateController,
|
||||||
|
}) async* {
|
||||||
|
final emlAttachment = presentationEmail.createEMLAttachment();
|
||||||
|
if (emlAttachment.blobId == null) {
|
||||||
|
yield* Stream.value(Left(DownloadAttachmentForWebFailure(
|
||||||
|
exception: NotFoundEmailBlobIdException(),
|
||||||
|
)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final generateTaskId = DownloadTaskId(const Uuid().v4());
|
||||||
|
try {
|
||||||
|
final baseDownloadUrl = session.getDownloadUrl(
|
||||||
|
jmapUrl: getBinding<DynamicUrlInterceptors>()?.jmapUrl,
|
||||||
|
);
|
||||||
|
final cancelToken = CancelToken();
|
||||||
|
yield* _downloadAttachmentForWebInteractor.execute(
|
||||||
|
generateTaskId,
|
||||||
|
emlAttachment,
|
||||||
|
accountId,
|
||||||
|
baseDownloadUrl,
|
||||||
|
downloadProgressStateController,
|
||||||
|
cancelToken: cancelToken,
|
||||||
|
previewerSupported: false,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
logError('SingleEmailController::downloadAttachmentForWeb(): $e');
|
||||||
|
yield* Stream.value(Left(DownloadAttachmentForWebFailure(
|
||||||
|
attachment: emlAttachment,
|
||||||
|
taskId: generateTaskId,
|
||||||
|
exception: e,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void editAsNewEmail(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
) onEditAsEmailRequest,
|
||||||
|
}) => onEditAsEmailRequest(presentationEmail);
|
||||||
|
|
||||||
|
void replyEmail(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailLoaded? emailLoaded,
|
||||||
|
) onReplyEmailRequest,
|
||||||
|
required EmailLoaded? emailLoaded,
|
||||||
|
}) {
|
||||||
|
onReplyEmailRequest(presentationEmail, emailLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void replyAll(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailLoaded? emailLoaded,
|
||||||
|
) onReplyAllRequest,
|
||||||
|
required EmailLoaded? emailLoaded,
|
||||||
|
}) {
|
||||||
|
onReplyAllRequest(presentationEmail, emailLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void replyToList(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailLoaded? emailLoaded,
|
||||||
|
) onReplyToListRequest,
|
||||||
|
required EmailLoaded? emailLoaded,
|
||||||
|
}) {
|
||||||
|
onReplyToListRequest(presentationEmail, emailLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forward(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailLoaded? emailLoaded,
|
||||||
|
) onForwardRequest,
|
||||||
|
required EmailLoaded? emailLoaded,
|
||||||
|
}) {
|
||||||
|
onForwardRequest(presentationEmail, emailLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleMoreEmailAction({
|
||||||
|
required PresentationEmail presentationEmail,
|
||||||
|
required PresentationMailbox? mailboxContain,
|
||||||
|
required RelativeRect? position,
|
||||||
|
required ResponsiveUtils responsiveUtils,
|
||||||
|
required ImagePaths imagePaths,
|
||||||
|
required UserName? username,
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailActionType action,
|
||||||
|
) handleEmailAction,
|
||||||
|
required List<EmailActionType> additionalActions,
|
||||||
|
}) {
|
||||||
|
if (currentContext == null) return;
|
||||||
|
|
||||||
|
final moreActions = [
|
||||||
|
if (additionalActions.contains(EmailActionType.forward))
|
||||||
|
EmailActionType.forward,
|
||||||
|
if (presentationEmail.getCountMailAddressWithoutMe(username?.value ?? '') > 1 &&
|
||||||
|
additionalActions.contains(EmailActionType.replyAll))
|
||||||
|
EmailActionType.replyAll,
|
||||||
|
if (EmailUtils.isReplyToListEnabled(presentationEmail.listPost ?? '') &&
|
||||||
|
additionalActions.contains(EmailActionType.replyToList))
|
||||||
|
EmailActionType.replyToList,
|
||||||
|
if (PlatformInfo.isWeb &&
|
||||||
|
PlatformInfo.isCanvasKit &&
|
||||||
|
additionalActions.contains(EmailActionType.printAll))
|
||||||
|
EmailActionType.printAll,
|
||||||
|
if (additionalActions.contains(EmailActionType.moveToMailbox))
|
||||||
|
EmailActionType.moveToMailbox,
|
||||||
|
if (additionalActions.contains(EmailActionType.markAsStarred) &&
|
||||||
|
additionalActions.contains(EmailActionType.unMarkAsStarred))
|
||||||
|
presentationEmail.hasStarred
|
||||||
|
? EmailActionType.unMarkAsStarred
|
||||||
|
: EmailActionType.markAsStarred,
|
||||||
|
if (additionalActions.contains(EmailActionType.moveToTrash) &&
|
||||||
|
additionalActions.contains(EmailActionType.deletePermanently))
|
||||||
|
_canDeletePermanently(presentationEmail)
|
||||||
|
? EmailActionType.deletePermanently
|
||||||
|
: EmailActionType.moveToTrash,
|
||||||
|
EmailActionType.markAsUnread,
|
||||||
|
if (mailboxContain?.isChildOfTeamMailboxes == false)
|
||||||
|
if (mailboxContain?.isSpam == true)
|
||||||
|
EmailActionType.unSpam
|
||||||
|
else
|
||||||
|
EmailActionType.moveToSpam,
|
||||||
|
if (presentationEmail.from?.isNotEmpty == true)
|
||||||
|
EmailActionType.createRule,
|
||||||
|
if (!presentationEmail.isSubscribed && presentationEmail.listUnsubscribe != null)
|
||||||
|
EmailActionType.unsubscribe,
|
||||||
|
if (mailboxContain?.isArchive == false)
|
||||||
|
EmailActionType.archiveMessage,
|
||||||
|
if (PlatformInfo.isWeb && PlatformInfo.isCanvasKit)
|
||||||
|
EmailActionType.downloadMessageAsEML,
|
||||||
|
EmailActionType.editAsNewEmail,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (position == null) {
|
||||||
|
openContextMenuAction(
|
||||||
|
currentContext!,
|
||||||
|
_emailActionMoreActionTile(
|
||||||
|
currentContext!,
|
||||||
|
presentationEmail,
|
||||||
|
moreActions,
|
||||||
|
responsiveUtils,
|
||||||
|
imagePaths,
|
||||||
|
handleEmailAction: handleEmailAction,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
openPopupMenuAction(
|
||||||
|
currentContext!,
|
||||||
|
position,
|
||||||
|
_popupMenuEmailActionTile(
|
||||||
|
currentContext!,
|
||||||
|
presentationEmail,
|
||||||
|
moreActions,
|
||||||
|
imagePaths,
|
||||||
|
handleEmailAction: handleEmailAction,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _canDeletePermanently(PresentationEmail email) {
|
||||||
|
return email.mailboxContain?.isTrash
|
||||||
|
?? email.mailboxContain?.isSpam
|
||||||
|
?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _emailActionMoreActionTile(
|
||||||
|
BuildContext context,
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
List<EmailActionType> actionTypes,
|
||||||
|
ResponsiveUtils responsiveUtils,
|
||||||
|
ImagePaths imagePaths, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailActionType action,
|
||||||
|
) handleEmailAction
|
||||||
|
}) {
|
||||||
|
return actionTypes.map((action) {
|
||||||
|
return (EmailActionCupertinoActionSheetActionBuilder(
|
||||||
|
Key('${action.name}_action'),
|
||||||
|
SvgPicture.asset(
|
||||||
|
action.getIcon(imagePaths),
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
colorFilter: AppColor.colorTextButton.asFilter()
|
||||||
|
),
|
||||||
|
action.getTitle(AppLocalizations.of(context)),
|
||||||
|
presentationEmail,
|
||||||
|
iconLeftPadding: responsiveUtils.isScreenWithShortestSide(context)
|
||||||
|
? const EdgeInsetsDirectional.only(start: 12, end: 16)
|
||||||
|
: const EdgeInsetsDirectional.only(end: 12),
|
||||||
|
iconRightPadding: responsiveUtils.isScreenWithShortestSide(context)
|
||||||
|
? const EdgeInsetsDirectional.only(end: 12)
|
||||||
|
: EdgeInsets.zero
|
||||||
|
)
|
||||||
|
..onActionClick((presentationEmail) {
|
||||||
|
popBack();
|
||||||
|
handleEmailAction(presentationEmail, action);
|
||||||
|
})).build();
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PopupMenuEntry> _popupMenuEmailActionTile(
|
||||||
|
BuildContext context,
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
List<EmailActionType> actionTypes,
|
||||||
|
ImagePaths imagePaths, {
|
||||||
|
required void Function(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailActionType action,
|
||||||
|
) handleEmailAction,
|
||||||
|
}) {
|
||||||
|
return actionTypes.map((action) {
|
||||||
|
return PopupMenuItem(
|
||||||
|
key: Key('${action.name}_action'),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
child: PopupItemWidget(
|
||||||
|
iconAction: action.getIcon(imagePaths),
|
||||||
|
nameAction: action.getTitle(AppLocalizations.of(context)),
|
||||||
|
colorIcon: AppColor.colorTextButton,
|
||||||
|
padding: const EdgeInsetsDirectional.only(start: 12),
|
||||||
|
styleName: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.black
|
||||||
|
),
|
||||||
|
onCallbackAction: () {
|
||||||
|
popBack();
|
||||||
|
handleEmailAction(presentationEmail, action);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void openEmailAddressDialog(
|
||||||
|
Session session,
|
||||||
|
AccountId accountId, {
|
||||||
|
required EmailAddress emailAddress,
|
||||||
|
required ResponsiveUtils responsiveUtils,
|
||||||
|
required ImagePaths imagePaths,
|
||||||
|
required AppToast appToast,
|
||||||
|
required void Function(EmailAddress emailAddress) onComposeEmailFromEmailAddressRequest,
|
||||||
|
required void Function(Stream<Either<Failure, Success>> quickCreateRuleStream) onQuickCreateRuleRequest,
|
||||||
|
}) {
|
||||||
|
if (currentContext?.mounted != true) return;
|
||||||
|
|
||||||
|
if (responsiveUtils.isScreenWithShortestSide(currentContext!)) {
|
||||||
|
Get.bottomSheet(
|
||||||
|
PointerInterceptor(
|
||||||
|
child: EmailAddressBottomSheetBuilder(
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
onCloseDialogAction: popBack,
|
||||||
|
onCopyEmailAddressAction: (emailAddress) =>
|
||||||
|
_copyEmailAddress(currentContext!, emailAddress, appToast),
|
||||||
|
onComposeEmailAction: (emailAddress) =>
|
||||||
|
onComposeEmailFromEmailAddressRequest(emailAddress),
|
||||||
|
onQuickCreatingRuleEmailDialogAction: (emailAddress) =>
|
||||||
|
onQuickCreateRuleRequest(
|
||||||
|
quickCreateRule(session, accountId, emailAddress: emailAddress),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
useRootNavigator: true,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadiusDirectional.only(
|
||||||
|
topStart: Radius.circular(16.0),
|
||||||
|
topEnd: Radius.circular(16.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
isScrollControlled: true,
|
||||||
|
enableDrag: false,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Get.dialog(
|
||||||
|
PointerInterceptor(
|
||||||
|
child: EmailAddressDialogBuilder(
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
onCloseDialogAction: popBack,
|
||||||
|
onCopyEmailAddressAction: (emailAddress) =>
|
||||||
|
_copyEmailAddress(currentContext!, emailAddress, appToast),
|
||||||
|
onComposeEmailAction: (emailAddress) =>
|
||||||
|
onComposeEmailFromEmailAddressRequest(emailAddress),
|
||||||
|
onQuickCreatingRuleEmailDialogAction: (emailAddress) =>
|
||||||
|
onQuickCreateRuleRequest(
|
||||||
|
quickCreateRule(session, accountId, emailAddress: emailAddress),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _copyEmailAddress(
|
||||||
|
BuildContext context,
|
||||||
|
EmailAddress emailAddress,
|
||||||
|
AppToast appToast,
|
||||||
|
) {
|
||||||
|
Clipboard.setData(ClipboardData(text: emailAddress.emailAddress));
|
||||||
|
appToast.showToastSuccessMessage(
|
||||||
|
context,
|
||||||
|
AppLocalizations.of(context).email_address_copied_to_clipboard,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<({
|
||||||
|
Map<EmailId, bool> emailIdsWithReadStatus,
|
||||||
|
MoveToMailboxRequest moveRequest,
|
||||||
|
})?> _moveToMailbox(
|
||||||
|
Session session,
|
||||||
|
AccountId accountId,
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required Map<MailboxId, PresentationMailbox> mapMailbox,
|
||||||
|
PresentationMailbox? selectedMailbox,
|
||||||
|
bool isSearchEmailRunning = false,
|
||||||
|
}) async {
|
||||||
|
final currentMailbox = _getMailboxContain(
|
||||||
|
presentationEmail,
|
||||||
|
mapMailbox: mapMailbox,
|
||||||
|
selectedMailbox: selectedMailbox,
|
||||||
|
isSearchEmailRunning: isSearchEmailRunning,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentMailbox == null) return null;
|
||||||
|
|
||||||
|
final arguments = DestinationPickerArguments(
|
||||||
|
accountId,
|
||||||
|
MailboxActions.moveEmail,
|
||||||
|
session,
|
||||||
|
mailboxIdSelected: currentMailbox.mailboxId
|
||||||
|
);
|
||||||
|
|
||||||
|
final destinationMailbox = PlatformInfo.isWeb
|
||||||
|
? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.destinationPicker, arguments: arguments)
|
||||||
|
: await push(AppRoutes.destinationPicker, arguments: arguments);
|
||||||
|
|
||||||
|
if (destinationMailbox is PresentationMailbox) {
|
||||||
|
return _generateMoveMailboxRequest(
|
||||||
|
accountId,
|
||||||
|
session,
|
||||||
|
presentationEmail,
|
||||||
|
currentMailbox,
|
||||||
|
destinationMailbox,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PresentationMailbox? _getMailboxContain(
|
||||||
|
PresentationEmail presentationEmail, {
|
||||||
|
required Map<MailboxId, PresentationMailbox> mapMailbox,
|
||||||
|
PresentationMailbox? selectedMailbox,
|
||||||
|
bool isSearchEmailRunning = false,
|
||||||
|
}) {
|
||||||
|
if (selectedMailbox == null || isSearchEmailRunning) {
|
||||||
|
return presentationEmail.findMailboxContain(mapMailbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedMailbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
({
|
||||||
|
MoveToMailboxRequest moveRequest,
|
||||||
|
Map<EmailId, bool> emailIdsWithReadStatus,
|
||||||
|
}) _generateMoveMailboxRequest(
|
||||||
|
AccountId accountId,
|
||||||
|
Session session,
|
||||||
|
PresentationEmail emailSelected,
|
||||||
|
PresentationMailbox currentMailbox,
|
||||||
|
PresentationMailbox destinationMailbox
|
||||||
|
) {
|
||||||
|
if (destinationMailbox.isTrash) {
|
||||||
|
return (
|
||||||
|
moveRequest: MoveToMailboxRequest(
|
||||||
|
{currentMailbox.id: [emailSelected.id!]},
|
||||||
|
destinationMailbox.id,
|
||||||
|
MoveAction.moving,
|
||||||
|
EmailActionType.moveToTrash,
|
||||||
|
),
|
||||||
|
emailIdsWithReadStatus: {emailSelected.id!: emailSelected.hasRead},
|
||||||
|
);
|
||||||
|
} else if (destinationMailbox.isSpam) {
|
||||||
|
return (
|
||||||
|
moveRequest: MoveToMailboxRequest(
|
||||||
|
{currentMailbox.id: [emailSelected.id!]},
|
||||||
|
destinationMailbox.id,
|
||||||
|
MoveAction.moving,
|
||||||
|
EmailActionType.moveToSpam,
|
||||||
|
),
|
||||||
|
emailIdsWithReadStatus: {emailSelected.id!: emailSelected.hasRead},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
moveRequest: MoveToMailboxRequest(
|
||||||
|
{currentMailbox.id: [emailSelected.id!]},
|
||||||
|
destinationMailbox.id,
|
||||||
|
MoveAction.moving,
|
||||||
|
EmailActionType.moveToMailbox,
|
||||||
|
destinationPath: destinationMailbox.mailboxPath),
|
||||||
|
emailIdsWithReadStatus: {emailSelected.id!: emailSelected.hasRead},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<EmailLoaded?> _getEmailLoaded(
|
||||||
|
Session? session,
|
||||||
|
AccountId? accountId,
|
||||||
|
EmailId? emailId,
|
||||||
|
String? baseDownloadUrl,
|
||||||
|
TransformConfiguration? transformConfiguration,
|
||||||
|
) {
|
||||||
|
if (session == null ||
|
||||||
|
accountId == null ||
|
||||||
|
emailId == null ||
|
||||||
|
baseDownloadUrl == null ||
|
||||||
|
transformConfiguration == null
|
||||||
|
) {
|
||||||
|
return Future.value(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _getEmailContentInteractor
|
||||||
|
.execute(
|
||||||
|
session,
|
||||||
|
accountId,
|
||||||
|
emailId,
|
||||||
|
baseDownloadUrl,
|
||||||
|
transformConfiguration,
|
||||||
|
)
|
||||||
|
.last
|
||||||
|
.then(
|
||||||
|
(value) {
|
||||||
|
return value.fold(
|
||||||
|
(failure) => null,
|
||||||
|
(success) => success is GetEmailContentSuccess
|
||||||
|
? EmailLoaded(
|
||||||
|
htmlContent: success.htmlEmailContent,
|
||||||
|
attachments: List.of(success.attachments ?? []),
|
||||||
|
inlineImages: List.of(success.inlineImages ?? []),
|
||||||
|
emailCurrent: success.emailCurrent,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onError: (error) {
|
||||||
|
logError('EmailActionReactor::_getEmailLoaded(): error: $error');
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,6 @@ class EmailViewAppBarWidget extends StatelessWidget {
|
|||||||
final BoxDecoration? appBarDecoration;
|
final BoxDecoration? appBarDecoration;
|
||||||
final EmailLoaded? emailLoaded;
|
final EmailLoaded? emailLoaded;
|
||||||
final bool isInsideThreadDetailView;
|
final bool isInsideThreadDetailView;
|
||||||
final double? height;
|
|
||||||
final EdgeInsetsGeometry? iconPadding;
|
final EdgeInsetsGeometry? iconPadding;
|
||||||
final EdgeInsetsGeometry? iconMargin;
|
final EdgeInsetsGeometry? iconMargin;
|
||||||
final EdgeInsetsGeometry? padding;
|
final EdgeInsetsGeometry? padding;
|
||||||
@@ -49,7 +48,6 @@ class EmailViewAppBarWidget extends StatelessWidget {
|
|||||||
this.supportBackAction = true,
|
this.supportBackAction = true,
|
||||||
this.appBarDecoration,
|
this.appBarDecoration,
|
||||||
this.isInsideThreadDetailView = false,
|
this.isInsideThreadDetailView = false,
|
||||||
this.height,
|
|
||||||
this.iconPadding,
|
this.iconPadding,
|
||||||
this.iconMargin,
|
this.iconMargin,
|
||||||
this.padding,
|
this.padding,
|
||||||
@@ -59,9 +57,9 @@ class EmailViewAppBarWidget extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final child = LayoutBuilder(builder: (context, constraints) {
|
final child = LayoutBuilder(builder: (context, constraints) {
|
||||||
return Container(
|
return Container(
|
||||||
height: height ?? (PlatformInfo.isIOS
|
height: PlatformInfo.isIOS
|
||||||
? EmailViewAppBarWidgetStyles.heightIOS(context, _responsiveUtils)
|
? EmailViewAppBarWidgetStyles.heightIOS(context, _responsiveUtils)
|
||||||
: EmailViewAppBarWidgetStyles.height),
|
: EmailViewAppBarWidgetStyles.height,
|
||||||
padding: padding ?? (PlatformInfo.isIOS
|
padding: padding ?? (PlatformInfo.isIOS
|
||||||
? EmailViewAppBarWidgetStyles.paddingIOS(context, _responsiveUtils)
|
? EmailViewAppBarWidgetStyles.paddingIOS(context, _responsiveUtils)
|
||||||
: EmailViewAppBarWidgetStyles.padding),
|
: EmailViewAppBarWidgetStyles.padding),
|
||||||
@@ -248,7 +246,8 @@ class EmailViewAppBarWidget extends StatelessWidget {
|
|||||||
}) {
|
}) {
|
||||||
if (!isInsideThreadDetailView) {
|
if (!isInsideThreadDetailView) {
|
||||||
return [
|
return [
|
||||||
_getPrintButton(appLocalizations),
|
if (PlatformInfo.isWeb && PlatformInfo.isCanvasKit)
|
||||||
|
_getPrintButton(appLocalizations),
|
||||||
_getMoveEmailButton(appLocalizations),
|
_getMoveEmailButton(appLocalizations),
|
||||||
_getMarkStarButton(appLocalizations),
|
_getMarkStarButton(appLocalizations),
|
||||||
_getDeleteButton(appLocalizations),
|
_getDeleteButton(appLocalizations),
|
||||||
|
|||||||
+29
-14
@@ -5,15 +5,19 @@ import 'package:core/presentation/utils/responsive_utils.dart';
|
|||||||
import 'package:core/presentation/utils/theme_utils.dart';
|
import 'package:core/presentation/utils/theme_utils.dart';
|
||||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||||
import 'package:core/presentation/views/image/avatar_builder.dart';
|
import 'package:core/presentation/views/image/avatar_builder.dart';
|
||||||
|
import 'package:core/utils/platform_info.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:model/email/email_action_type.dart';
|
import 'package:model/email/email_action_type.dart';
|
||||||
import 'package:model/email/presentation_email.dart';
|
import 'package:model/email/presentation_email.dart';
|
||||||
import 'package:model/extensions/presentation_email_extension.dart';
|
import 'package:model/extensions/presentation_email_extension.dart';
|
||||||
|
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/email_avatar_builder.dart';
|
import 'package:tmail_ui_user/features/base/widget/email_avatar_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/smime_signature_status.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/smime_signature_status.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_receiver_widget.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_receiver_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_sender_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_sender_builder.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_app_bar_widget.dart';
|
||||||
@@ -36,6 +40,7 @@ class InformationSenderAndReceiverBuilder extends StatelessWidget {
|
|||||||
final bool showRecipients;
|
final bool showRecipients;
|
||||||
final VoidCallback? onToggleThreadDetailCollapseExpand;
|
final VoidCallback? onToggleThreadDetailCollapseExpand;
|
||||||
final OnTapAvatarActionClick? onTapAvatarActionClick;
|
final OnTapAvatarActionClick? onTapAvatarActionClick;
|
||||||
|
final PresentationMailbox? mailboxContain;
|
||||||
|
|
||||||
const InformationSenderAndReceiverBuilder({
|
const InformationSenderAndReceiverBuilder({
|
||||||
Key? key,
|
Key? key,
|
||||||
@@ -53,6 +58,7 @@ class InformationSenderAndReceiverBuilder extends StatelessWidget {
|
|||||||
this.showRecipients = true,
|
this.showRecipients = true,
|
||||||
this.onToggleThreadDetailCollapseExpand,
|
this.onToggleThreadDetailCollapseExpand,
|
||||||
this.onTapAvatarActionClick,
|
this.onTapAvatarActionClick,
|
||||||
|
this.mailboxContain,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -127,21 +133,30 @@ class InformationSenderAndReceiverBuilder extends StatelessWidget {
|
|||||||
padding: const EdgeInsetsDirectional.only(start: 16, top: 2),
|
padding: const EdgeInsetsDirectional.only(start: 16, top: 2),
|
||||||
),
|
),
|
||||||
if (isInsideThreadDetailView)
|
if (isInsideThreadDetailView)
|
||||||
EmailViewAppBarWidget(
|
SizedBox(
|
||||||
key: const Key('email_view_app_bar_widget'),
|
|
||||||
presentationEmail: emailSelected,
|
|
||||||
isSearchActivated: false,
|
|
||||||
onBackAction: () {},
|
|
||||||
onEmailActionClick: onEmailActionClick,
|
|
||||||
onMoreActionClick: onMoreActionClick,
|
|
||||||
supportBackAction: false,
|
|
||||||
appBarDecoration: const BoxDecoration(),
|
|
||||||
emailLoaded: emailLoaded,
|
|
||||||
isInsideThreadDetailView: isInsideThreadDetailView,
|
|
||||||
height: IconUtils.defaultIconSize,
|
height: IconUtils.defaultIconSize,
|
||||||
iconPadding: EdgeInsets.zero,
|
child: OverflowBox(
|
||||||
iconMargin: const EdgeInsetsDirectional.only(start: 16),
|
maxHeight: PlatformInfo.isIOS
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
? EmailViewAppBarWidgetStyles.heightIOS(context, responsiveUtils)
|
||||||
|
: EmailViewAppBarWidgetStyles.height,
|
||||||
|
fit: OverflowBoxFit.deferToChild,
|
||||||
|
child: EmailViewAppBarWidget(
|
||||||
|
key: const Key('email_view_app_bar_widget'),
|
||||||
|
presentationEmail: emailSelected,
|
||||||
|
mailboxContain: mailboxContain,
|
||||||
|
isSearchActivated: false,
|
||||||
|
onBackAction: () {},
|
||||||
|
onEmailActionClick: onEmailActionClick,
|
||||||
|
onMoreActionClick: onMoreActionClick,
|
||||||
|
supportBackAction: false,
|
||||||
|
appBarDecoration: const BoxDecoration(),
|
||||||
|
emailLoaded: emailLoaded,
|
||||||
|
isInsideThreadDetailView: isInsideThreadDetailView,
|
||||||
|
iconPadding: const EdgeInsets.all(8),
|
||||||
|
iconMargin: EdgeInsets.zero,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
+2
-2
@@ -151,10 +151,10 @@ class MailboxDashBoardBindings extends BaseBindings {
|
|||||||
SendingQueueBindings().dependencies();
|
SendingQueueBindings().dependencies();
|
||||||
MailboxBindings().dependencies();
|
MailboxBindings().dependencies();
|
||||||
ThreadBindings().dependencies();
|
ThreadBindings().dependencies();
|
||||||
SearchEmailBindings().dependencies();
|
|
||||||
ThreadDetailBindings().dependencies();
|
|
||||||
EmailBindings().dependencies();
|
EmailBindings().dependencies();
|
||||||
|
SearchEmailBindings().dependencies();
|
||||||
QuotasBindings().dependencies();
|
QuotasBindings().dependencies();
|
||||||
|
ThreadDetailBindings().dependencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
+24
-4
@@ -174,6 +174,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_e
|
|||||||
import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_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/domain/usecases/move_multiple_email_to_mailbox_interactor.dart';
|
import 'package:tmail_ui_user/features/thread/domain/usecases/move_multiple_email_to_mailbox_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
|
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
|
||||||
|
import 'package:tmail_ui_user/features/thread_detail/presentation/action/thread_detail_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/main/deep_links/deep_link_data.dart';
|
import 'package:tmail_ui_user/main/deep_links/deep_link_data.dart';
|
||||||
import 'package:tmail_ui_user/main/deep_links/deep_links_manager.dart';
|
import 'package:tmail_ui_user/main/deep_links/deep_links_manager.dart';
|
||||||
import 'package:tmail_ui_user/main/deep_links/open_app_deep_link_data.dart';
|
import 'package:tmail_ui_user/main/deep_links/open_app_deep_link_data.dart';
|
||||||
@@ -252,6 +253,7 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
final dashBoardAction = Rxn<UIAction>();
|
final dashBoardAction = Rxn<UIAction>();
|
||||||
final mailboxUIAction = Rxn<MailboxUIAction>();
|
final mailboxUIAction = Rxn<MailboxUIAction>();
|
||||||
final emailUIAction = Rxn<EmailUIAction>();
|
final emailUIAction = Rxn<EmailUIAction>();
|
||||||
|
final threadDetailUIAction = Rxn<ThreadDetailUIAction>();
|
||||||
final dashboardRoute = DashboardRoutes.waiting.obs;
|
final dashboardRoute = DashboardRoutes.waiting.obs;
|
||||||
final currentSelectMode = SelectMode.INACTIVE.obs;
|
final currentSelectMode = SelectMode.INACTIVE.obs;
|
||||||
final filterMessageOption = FilterMessageOption.all.obs;
|
final filterMessageOption = FilterMessageOption.all.obs;
|
||||||
@@ -447,7 +449,7 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
} else if (success is DeleteSendingEmailSuccess) {
|
} else if (success is DeleteSendingEmailSuccess) {
|
||||||
getAllSendingEmails();
|
getAllSendingEmails();
|
||||||
} else if (success is UnsubscribeEmailSuccess) {
|
} else if (success is UnsubscribeEmailSuccess) {
|
||||||
_handleUnsubscribeMailSuccess();
|
_handleUnsubscribeMailSuccess(success.emailId);
|
||||||
} else if (success is RestoreDeletedMessageSuccess) {
|
} else if (success is RestoreDeletedMessageSuccess) {
|
||||||
_handleRestoreDeletedMessageSuccess(success.emailRecoveryAction.id!);
|
_handleRestoreDeletedMessageSuccess(success.emailRecoveryAction.id!);
|
||||||
} else if (success is GetRestoredDeletedMessageSuccess) {
|
} else if (success is GetRestoredDeletedMessageSuccess) {
|
||||||
@@ -1766,6 +1768,11 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
emailUIAction.value = newAction;
|
emailUIAction.value = newAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dispatchThreadDetailUIAction(ThreadDetailUIAction newAction) {
|
||||||
|
log('MailboxDashBoardController::dispatchThreadDetailUIAction():newAction: ${newAction.runtimeType}');
|
||||||
|
threadDetailUIAction.value = newAction;
|
||||||
|
}
|
||||||
|
|
||||||
void dispatchRoute(DashboardRoutes route) {
|
void dispatchRoute(DashboardRoutes route) {
|
||||||
log('MailboxDashBoardController::dispatchRoute(): $route');
|
log('MailboxDashBoardController::dispatchRoute(): $route');
|
||||||
dashboardRoute.value = route;
|
dashboardRoute.value = route;
|
||||||
@@ -2848,16 +2855,29 @@ class MailboxDashBoardController extends ReloadableController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleUnsubscribeMailSuccess() {
|
void _handleUnsubscribeMailSuccess(EmailId emailId) {
|
||||||
if (currentContext != null && currentOverlayContext != null) {
|
if (currentContext != null && currentOverlayContext != null) {
|
||||||
appToast.showToastSuccessMessage(
|
appToast.showToastSuccessMessage(
|
||||||
currentOverlayContext!,
|
currentOverlayContext!,
|
||||||
AppLocalizations.of(currentContext!).unsubscribedFromThisMailingList);
|
AppLocalizations.of(currentContext!).unsubscribedFromThisMailingList);
|
||||||
}
|
}
|
||||||
final newEmail = selectedEmail.value?.updateKeywords({
|
dispatchThreadDetailUIAction(UpdatedEmailKeywordsAction(
|
||||||
|
emailId,
|
||||||
|
KeyWordIdentifierExtension.unsubscribeMail,
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
// Reset threadDetailUIAction
|
||||||
|
dispatchThreadDetailUIAction(ThreadDetailUIAction());
|
||||||
|
|
||||||
|
final listEmail = searchController.isSearchEmailRunning
|
||||||
|
? listResultSearch
|
||||||
|
: emailsInCurrentMailbox;
|
||||||
|
var newEmailIndex = listEmail.indexWhere((email) => email.id == emailId);
|
||||||
|
if (newEmailIndex == -1) return;
|
||||||
|
|
||||||
|
listEmail[newEmailIndex] = listEmail[newEmailIndex].updateKeywords({
|
||||||
KeyWordIdentifierExtension.unsubscribeMail: true,
|
KeyWordIdentifierExtension.unsubscribeMail: true,
|
||||||
});
|
});
|
||||||
setSelectedEmail(newEmail);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _replaceBrowserHistory({Uri? uri}) {
|
void _replaceBrowserHistory({Uri? uri}) {
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
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/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
|
|
||||||
|
extension GetMailboxContainExtension on MailboxDashBoardController {
|
||||||
|
PresentationMailbox? getMailboxContain(PresentationEmail email) {
|
||||||
|
if (selectedMailbox.value == null) {
|
||||||
|
return email.findMailboxContain(mapMailboxById);
|
||||||
|
} else {
|
||||||
|
return searchController.isSearchEmailRunning
|
||||||
|
? email.findMailboxContain(mapMailboxById)
|
||||||
|
: selectedMailbox.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-13
@@ -3,9 +3,9 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
|||||||
import 'package:model/email/mark_star_action.dart';
|
import 'package:model/email/mark_star_action.dart';
|
||||||
import 'package:model/email/presentation_email.dart';
|
import 'package:model/email/presentation_email.dart';
|
||||||
import 'package:model/email/read_actions.dart';
|
import 'package:model/email/read_actions.dart';
|
||||||
import 'package:model/extensions/presentation_email_extension.dart';
|
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_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/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
||||||
|
import 'package:tmail_ui_user/features/thread_detail/presentation/action/thread_detail_ui_action.dart';
|
||||||
|
|
||||||
extension UpdateCurrentEmailsFlagsExtension on MailboxDashBoardController {
|
extension UpdateCurrentEmailsFlagsExtension on MailboxDashBoardController {
|
||||||
void updateEmailFlagByEmailIds(
|
void updateEmailFlagByEmailIds(
|
||||||
@@ -76,23 +76,25 @@ extension UpdateCurrentEmailsFlagsExtension on MailboxDashBoardController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateEmailAnswered(EmailId emailId) {
|
void updateEmailAnswered(EmailId emailId) {
|
||||||
if (selectedEmail.value != null) {
|
dispatchThreadDetailUIAction(UpdatedEmailKeywordsAction(
|
||||||
final newEmail = selectedEmail.value!.updateKeywords({
|
emailId,
|
||||||
KeyWordIdentifier.emailAnswered: true,
|
KeyWordIdentifier.emailAnswered,
|
||||||
});
|
true,
|
||||||
setSelectedEmail(newEmail);
|
));
|
||||||
}
|
// Reset threadDetailUIAction
|
||||||
|
dispatchThreadDetailUIAction(ThreadDetailUIAction());
|
||||||
|
|
||||||
updateEmailFlagByEmailIds([emailId], markAsAnswered: true);
|
updateEmailFlagByEmailIds([emailId], markAsAnswered: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateEmailForwarded(EmailId emailId) {
|
void updateEmailForwarded(EmailId emailId) {
|
||||||
if (selectedEmail.value != null) {
|
dispatchThreadDetailUIAction(UpdatedEmailKeywordsAction(
|
||||||
final newEmail = selectedEmail.value!.updateKeywords({
|
emailId,
|
||||||
KeyWordIdentifier.emailForwarded: true,
|
KeyWordIdentifier.emailForwarded,
|
||||||
});
|
true,
|
||||||
setSelectedEmail(newEmail);
|
));
|
||||||
}
|
// Reset threadDetailUIAction
|
||||||
|
dispatchThreadDetailUIAction(ThreadDetailUIAction());
|
||||||
|
|
||||||
updateEmailFlagByEmailIds([emailId], markAsForwarded: true);
|
updateEmailFlagByEmailIds([emailId], markAsForwarded: true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
|
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
|
||||||
|
|
||||||
|
class ThreadDetailUIAction extends UIAction {
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdatedEmailKeywordsAction extends ThreadDetailUIAction {
|
||||||
|
UpdatedEmailKeywordsAction(
|
||||||
|
this.emailId,
|
||||||
|
this.updatedKeyword,
|
||||||
|
this.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
final EmailId emailId;
|
||||||
|
final KeyWordIdentifier updatedKeyword;
|
||||||
|
final bool value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [emailId, updatedKeyword, value];
|
||||||
|
}
|
||||||
@@ -10,10 +10,11 @@ extension CloseThreadDetailAction on ThreadDetailController {
|
|||||||
} else {
|
} else {
|
||||||
mailboxDashBoardController.dispatchRoute(DashboardRoutes.thread);
|
mailboxDashBoardController.dispatchRoute(DashboardRoutes.thread);
|
||||||
}
|
}
|
||||||
for (var emailId in emailIdsPresentation.keys) {
|
final cleanUpEmailIds = List.from(emailIdsPresentation.keys);
|
||||||
mailboxDashBoardController.dispatchEmailUIAction(
|
for (var emailId in cleanUpEmailIds) {
|
||||||
CloseEmailInThreadDetailAction(emailId),
|
mailboxDashBoardController
|
||||||
);
|
..dispatchEmailUIAction(CloseEmailInThreadDetailAction(emailId))
|
||||||
|
..dispatchEmailUIAction(EmailUIAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
|||||||
+36
-3
@@ -1,12 +1,18 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
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:tmail_ui_user/features/email/presentation/email_view.dart';
|
||||||
import 'package:model/email/email_in_thread_status.dart';
|
import 'package:model/email/email_in_thread_status.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/get_mailbox_contain_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/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';
|
||||||
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/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/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_collapsed_email.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/presentation/widgets/thread_detail_load_more_circle.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 {
|
extension GetThreadDetailEmailViews on ThreadDetailController {
|
||||||
List<Widget> getThreadDetailEmailViews() {
|
List<Widget> getThreadDetailEmailViews() {
|
||||||
@@ -58,10 +64,37 @@ extension GetThreadDetailEmailViews on ThreadDetailController {
|
|||||||
showSubject: isFirstEmailInThreadDetail,
|
showSubject: isFirstEmailInThreadDetail,
|
||||||
imagePaths: imagePaths,
|
imagePaths: imagePaths,
|
||||||
responsiveUtils: responsiveUtils,
|
responsiveUtils: responsiveUtils,
|
||||||
mailboxContain: presentationEmail.mailboxContain,
|
mailboxContain: presentationEmail.findMailboxContain(
|
||||||
|
mailboxDashBoardController.mapMailboxById,
|
||||||
|
),
|
||||||
emailLoaded: null,
|
emailLoaded: null,
|
||||||
openEmailAddressDetailAction: (context, emailAddress) {
|
onEmailActionClick: threadDetailOnEmailActionClick,
|
||||||
// TODO: Next PR
|
onMoreActionClick: (presentationEmail, position) => emailActionReactor.handleMoreEmailAction(
|
||||||
|
mailboxContain: mailboxDashBoardController.getMailboxContain(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,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
openEmailAddressDetailAction: (_, emailAddress) {
|
||||||
|
openEmailAddressDetailAction(emailAddress);
|
||||||
},
|
},
|
||||||
onToggleThreadDetailCollapseExpand: () {
|
onToggleThreadDetailCollapseExpand: () {
|
||||||
toggleThreadDetailCollapeExpand(presentationEmail);
|
toggleThreadDetailCollapeExpand(presentationEmail);
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
import 'package:core/presentation/extensions/color_extension.dart';
|
||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/state/download_attachment_for_web_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.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 HandleCollapsedEmailDownloadStates on ThreadDetailController {
|
||||||
|
void handleDownloadProgressState(Either<Failure, Success> state) {
|
||||||
|
state.fold(
|
||||||
|
(failure) => null,
|
||||||
|
(success) {
|
||||||
|
if (success is StartDownloadAttachmentForWeb &&
|
||||||
|
!success.previewerSupported
|
||||||
|
) {
|
||||||
|
mailboxDashBoardController.addDownloadTask(
|
||||||
|
DownloadTaskState(
|
||||||
|
taskId: success.taskId,
|
||||||
|
attachment: success.attachment,
|
||||||
|
onCancel: () => success.cancelToken?.cancel(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentOverlayContext != null &&
|
||||||
|
currentContext != null &&
|
||||||
|
!success.previewerSupported
|
||||||
|
) {
|
||||||
|
appToast.showToastMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).your_download_has_started,
|
||||||
|
leadingSVGIconColor: AppColor.primaryColor,
|
||||||
|
leadingSVGIcon: imagePaths.icDownload,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (success is DownloadingAttachmentForWeb) {
|
||||||
|
mailboxDashBoardController.updateDownloadTask(
|
||||||
|
success.taskId,
|
||||||
|
(currentTask) {
|
||||||
|
final newTask = currentTask.copyWith(
|
||||||
|
progress: success.progress,
|
||||||
|
downloaded: success.downloaded,
|
||||||
|
total: success.total,
|
||||||
|
);
|
||||||
|
|
||||||
|
return newTask;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDownloadSuccess(DownloadAttachmentForWebSuccess success) {
|
||||||
|
mailboxDashBoardController.deleteDownloadTask(success.taskId);
|
||||||
|
|
||||||
|
downloadManager.createAnchorElementDownloadFileWeb(
|
||||||
|
success.bytes,
|
||||||
|
success.attachment.generateFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDownloadFailure(DownloadAttachmentForWebFailure failure) {
|
||||||
|
if (failure.taskId != null) {
|
||||||
|
mailboxDashBoardController.deleteDownloadTask(failure.taskId!);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentOverlayContext == null || currentContext == null) return;
|
||||||
|
|
||||||
|
final message = AppLocalizations.of(currentContext!).downloadMessageAsEMLFailed;
|
||||||
|
appToast.showToastErrorMessage(currentOverlayContext!, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -25,7 +25,7 @@ extension InitializeThreadDetailEmails on ThreadDetailController {
|
|||||||
properties: EmailUtils.getPropertiesForEmailGetMethod(
|
properties: EmailUtils.getPropertiesForEmailGetMethod(
|
||||||
session!,
|
session!,
|
||||||
accountId!,
|
accountId!,
|
||||||
),
|
).union(additionalProperties),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -26,7 +26,7 @@ extension LoadMoreThreadDetailEmails on ThreadDetailController {
|
|||||||
properties: EmailUtils.getPropertiesForEmailGetMethod(
|
properties: EmailUtils.getPropertiesForEmailGetMethod(
|
||||||
session!,
|
session!,
|
||||||
accountId!,
|
accountId!,
|
||||||
),
|
).union(additionalProperties),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||||
|
import 'package:model/email/mark_star_action.dart';
|
||||||
|
import 'package:model/extensions/presentation_email_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart';
|
||||||
|
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/thread_detail_controller.dart';
|
||||||
|
|
||||||
|
extension MarkCollapsedEmailStarSuccess on ThreadDetailController {
|
||||||
|
void markCollapsedEmailStarSuccess(MarkAsStarEmailSuccess success) {
|
||||||
|
final updatedMarkedEmail = emailIdsPresentation[success.emailId]
|
||||||
|
?.updateKeywords({
|
||||||
|
KeyWordIdentifier.emailFlagged: success.markStarAction == MarkStarAction.markStar,
|
||||||
|
});
|
||||||
|
if (updatedMarkedEmail == null) return;
|
||||||
|
|
||||||
|
if (mailboxDashBoardController.selectedEmail.value?.id == success.emailId) {
|
||||||
|
mailboxDashBoardController.updateEmailFlagByEmailIds(
|
||||||
|
[success.emailId],
|
||||||
|
markStarAction: success.markStarAction,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
emailIdsPresentation[success.emailId] = updatedMarkedEmail;
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:model/email/read_actions.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
|
||||||
|
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) {
|
||||||
|
mailboxDashBoardController.updateEmailFlagByEmailIds(
|
||||||
|
[success.emailId],
|
||||||
|
readAction: success.readActions,
|
||||||
|
);
|
||||||
|
if (success.readActions == ReadActions.markAsUnread) {
|
||||||
|
closeThreadDetailAction(currentContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:tmail_ui_user/features/manage_account/domain/state/create_new_rule_filter_state.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 QuickCreateRuleFromCollapsedEmailSuccess on ThreadDetailController {
|
||||||
|
void quickCreateRuleFromCollapsedEmailSuccess(
|
||||||
|
CreateNewRuleFilterSuccess success,
|
||||||
|
) {
|
||||||
|
if (success.newListRules.isEmpty ||
|
||||||
|
currentContext == null ||
|
||||||
|
currentOverlayContext == null) return;
|
||||||
|
|
||||||
|
appToast.showToastSuccessMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).newFilterWasCreated,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+376
@@ -0,0 +1,376 @@
|
|||||||
|
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/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/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 ThreadDetailOnEmailActionClick on ThreadDetailController {
|
||||||
|
void threadDetailOnEmailActionClick(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
EmailActionType emailActionType,
|
||||||
|
) {
|
||||||
|
switch(emailActionType) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _markRead(PresentationEmail presentationEmail) {
|
||||||
|
if (session == null || accountId == null) return;
|
||||||
|
|
||||||
|
consumeState(emailActionReactor.markAsEmailRead(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
presentationEmail,
|
||||||
|
readAction: ReadActions.markAsRead,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _unRead(PresentationEmail presentationEmail) {
|
||||||
|
if (session == null || accountId == null) return;
|
||||||
|
|
||||||
|
consumeState(emailActionReactor.markAsEmailRead(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
presentationEmail,
|
||||||
|
readAction: ReadActions.markAsUnread,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _markStar(
|
||||||
|
PresentationEmail presentationEmail,
|
||||||
|
MarkStarAction markStarAction,
|
||||||
|
) {
|
||||||
|
if (session == null || accountId == null) 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: mailboxDashBoardController.selectedMailbox.value,
|
||||||
|
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (moveActionRequest == null) return;
|
||||||
|
|
||||||
|
mailboxDashBoardController.moveToMailbox(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
moveActionRequest.moveRequest,
|
||||||
|
moveActionRequest.emailIdsWithReadStatus,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _deleteEmailPermanently(PresentationEmail email) {
|
||||||
|
emailActionReactor.deleteEmailPermanently(
|
||||||
|
email,
|
||||||
|
onDeleteEmailRequest: (email) {
|
||||||
|
popBack();
|
||||||
|
mailboxDashBoardController.deleteEmailPermanently(email);
|
||||||
|
},
|
||||||
|
responsiveUtils: responsiveUtils,
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
onGetEmailContentFailure: _showUnknownErrorToast,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
onReplyEmailRequest: (presentationEmail, emailLoaded) {
|
||||||
|
mailboxDashBoardController.openComposer(
|
||||||
|
ComposerArguments.replyEmail(
|
||||||
|
presentationEmail: presentationEmail,
|
||||||
|
content: emailLoaded?.htmlContent,
|
||||||
|
inlineImages: emailLoaded?.inlineImages,
|
||||||
|
mailboxRole: presentationEmail.mailboxContain?.role,
|
||||||
|
messageId: emailLoaded?.emailCurrent?.messageId,
|
||||||
|
references: emailLoaded?.emailCurrent?.references,
|
||||||
|
listPost: emailLoaded?.emailCurrent?.listPost,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
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: emailLoaded?.emailCurrent?.messageId,
|
||||||
|
references: emailLoaded?.emailCurrent?.references,
|
||||||
|
listPost: emailLoaded?.emailCurrent?.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: emailLoaded?.emailCurrent?.messageId,
|
||||||
|
references: emailLoaded?.emailCurrent?.references,
|
||||||
|
listPost: emailLoaded?.emailCurrent?.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: emailLoaded?.emailCurrent?.messageId,
|
||||||
|
references: emailLoaded?.emailCurrent?.references,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
emailLoaded: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_showUnknownErrorToast() {
|
||||||
|
if (currentOverlayContext != null && currentContext != null) {
|
||||||
|
appToast.showToastErrorMessage(
|
||||||
|
currentOverlayContext!,
|
||||||
|
AppLocalizations.of(currentContext!).unknownError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.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/thread_detail_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||||
|
|
||||||
|
extension ThreadDetailOpenEmailAddressDetailAction on ThreadDetailController {
|
||||||
|
void openEmailAddressDetailAction(EmailAddress emailAddress) {
|
||||||
|
if (session == null || accountId == null) return;
|
||||||
|
|
||||||
|
emailActionReactor.openEmailAddressDialog(
|
||||||
|
session!,
|
||||||
|
accountId!,
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
responsiveUtils: responsiveUtils,
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
appToast: appToast,
|
||||||
|
onComposeEmailFromEmailAddressRequest: (emailAddress) {
|
||||||
|
popBack();
|
||||||
|
mailboxDashBoardController.openComposer(
|
||||||
|
ComposerArguments.fromEmailAddress(emailAddress),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onQuickCreateRuleRequest: (quickCreateRuleStream) {
|
||||||
|
consumeState(quickCreateRuleStream);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,11 @@ import 'package:core/data/model/source_type/data_source_type.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/http/http_client.dart';
|
import 'package:jmap_dart_client/http/http_client.dart';
|
||||||
import 'package:tmail_ui_user/features/base/base_bindings.dart';
|
import 'package:tmail_ui_user/features/base/base_bindings.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';
|
||||||
|
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/thread_detail/data/data_source/thread_detail_data_source.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_remote_data_source_impl.dart';
|
import 'package:tmail_ui_user/features/thread_detail/data/data_source/thread_detail_remote_data_source_impl.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/data/network/thread_detail_api.dart';
|
import 'package:tmail_ui_user/features/thread_detail/data/network/thread_detail_api.dart';
|
||||||
@@ -25,6 +30,11 @@ class ThreadDetailBindings extends BaseBindings {
|
|||||||
Get.put(ThreadDetailController(
|
Get.put(ThreadDetailController(
|
||||||
Get.find<GetThreadByIdInteractor>(),
|
Get.find<GetThreadByIdInteractor>(),
|
||||||
Get.find<GetEmailsByIdsInteractor>(),
|
Get.find<GetEmailsByIdsInteractor>(),
|
||||||
|
Get.find<MarkAsEmailReadInteractor>(),
|
||||||
|
Get.find<MarkAsStarEmailInteractor>(),
|
||||||
|
Get.find<PrintEmailInteractor>(),
|
||||||
|
Get.find<GetEmailContentInteractor>(),
|
||||||
|
Get.find<DownloadAttachmentForWebInteractor>(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,88 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:core/data/network/download/download_manager.dart';
|
||||||
|
import 'package:core/presentation/state/failure.dart';
|
||||||
|
import 'package:core/presentation/state/success.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||||
|
import 'package:model/email/email_property.dart';
|
||||||
import 'package:model/email/presentation_email.dart';
|
import 'package:model/email/presentation_email.dart';
|
||||||
|
import 'package:model/extensions/keyword_identifier_extension.dart';
|
||||||
import 'package:model/extensions/session_extension.dart';
|
import 'package:model/extensions/session_extension.dart';
|
||||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
|
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';
|
||||||
|
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/email/presentation/utils/email_action_reactor/email_action_reactor.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||||
|
import 'package:tmail_ui_user/features/manage_account/domain/state/create_new_rule_filter_state.dart';
|
||||||
|
import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_email_rule_filter_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
|
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.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_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/state/get_emails_by_ids_state.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_by_id_interactor.dart';
|
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_by_id_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_emails_by_ids_interactor.dart';
|
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_emails_by_ids_interactor.dart';
|
||||||
|
import 'package:tmail_ui_user/features/thread_detail/presentation/action/thread_detail_ui_action.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/close_thread_detail_action.dart';
|
||||||
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_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_emails_by_ids_success.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/initialize_thread_detail_emails.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.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';
|
||||||
|
|
||||||
class ThreadDetailController extends BaseController {
|
class ThreadDetailController extends BaseController {
|
||||||
final GetThreadByIdInteractor _getEmailIdsByThreadIdInteractor;
|
final GetThreadByIdInteractor _getEmailIdsByThreadIdInteractor;
|
||||||
final GetEmailsByIdsInteractor getEmailsByIdsInteractor;
|
final GetEmailsByIdsInteractor getEmailsByIdsInteractor;
|
||||||
|
final MarkAsEmailReadInteractor _markAsEmailReadInteractor;
|
||||||
|
final MarkAsStarEmailInteractor _markAsStarEmailInteractor;
|
||||||
|
final PrintEmailInteractor _printEmailInteractor;
|
||||||
|
final GetEmailContentInteractor _getEmailContentInteractor;
|
||||||
|
final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor;
|
||||||
|
|
||||||
ThreadDetailController(
|
ThreadDetailController(
|
||||||
this._getEmailIdsByThreadIdInteractor,
|
this._getEmailIdsByThreadIdInteractor,
|
||||||
this.getEmailsByIdsInteractor,
|
this.getEmailsByIdsInteractor,
|
||||||
|
this._markAsEmailReadInteractor,
|
||||||
|
this._markAsStarEmailInteractor,
|
||||||
|
this._printEmailInteractor,
|
||||||
|
this._getEmailContentInteractor,
|
||||||
|
this._downloadAttachmentForWebInteractor,
|
||||||
);
|
);
|
||||||
|
|
||||||
final emailIdsPresentation = <EmailId, PresentationEmail?>{}.obs;
|
final emailIdsPresentation = <EmailId, PresentationEmail?>{}.obs;
|
||||||
final currentExpandedEmailId = Rxn<EmailId>();
|
final currentExpandedEmailId = Rxn<EmailId>();
|
||||||
final currentEmailLoaded = Rxn<EmailLoaded>();
|
final currentEmailLoaded = Rxn<EmailLoaded>();
|
||||||
|
|
||||||
|
late final EmailActionReactor emailActionReactor;
|
||||||
|
final additionalProperties = Properties({
|
||||||
|
IndividualHeaderIdentifier.listPostHeader.value,
|
||||||
|
IndividualHeaderIdentifier.listUnsubscribeHeader.value,
|
||||||
|
});
|
||||||
|
|
||||||
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||||
final searchEmailController = Get.find<SearchEmailController>();
|
final searchEmailController = Get.find<SearchEmailController>();
|
||||||
|
final downloadManager = Get.find<DownloadManager>();
|
||||||
|
final downloadProgressState = StreamController<Either<Failure, Success>>();
|
||||||
|
|
||||||
ScrollController? scrollController;
|
ScrollController? scrollController;
|
||||||
|
CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor;
|
||||||
|
|
||||||
AccountId? get accountId => mailboxDashBoardController.accountId.value;
|
AccountId? get accountId => mailboxDashBoardController.accountId.value;
|
||||||
Session? get session => mailboxDashBoardController.sessionCurrent;
|
Session? get session => mailboxDashBoardController.sessionCurrent;
|
||||||
@@ -67,6 +112,17 @@ class ThreadDetailController extends BaseController {
|
|||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
injectRuleFilterBindings(session, accountId);
|
||||||
|
_createNewEmailRuleFilterInteractor = getBinding<CreateNewEmailRuleFilterInteractor>();
|
||||||
|
emailActionReactor = EmailActionReactor(
|
||||||
|
_markAsEmailReadInteractor,
|
||||||
|
_markAsStarEmailInteractor,
|
||||||
|
_createNewEmailRuleFilterInteractor,
|
||||||
|
_printEmailInteractor,
|
||||||
|
_getEmailContentInteractor,
|
||||||
|
_downloadAttachmentForWebInteractor,
|
||||||
|
);
|
||||||
|
downloadProgressState.stream.listen(handleDownloadProgressState);
|
||||||
ever(mailboxDashBoardController.selectedEmail, (presentationEmail) {
|
ever(mailboxDashBoardController.selectedEmail, (presentationEmail) {
|
||||||
if (presentationEmail?.threadId == null) {
|
if (presentationEmail?.threadId == null) {
|
||||||
closeThreadDetailAction(currentContext);
|
closeThreadDetailAction(currentContext);
|
||||||
@@ -86,6 +142,22 @@ class ThreadDetailController extends BaseController {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ever(mailboxDashBoardController.threadDetailUIAction, (action) {
|
||||||
|
if (action is UpdatedEmailKeywordsAction) {
|
||||||
|
emailIdsPresentation
|
||||||
|
[action.emailId]
|
||||||
|
?.keywords
|
||||||
|
?[action.updatedKeyword] = action.value;
|
||||||
|
if (action.updatedKeyword == KeyWordIdentifierExtension.unsubscribeMail) {
|
||||||
|
emailIdsPresentation
|
||||||
|
[action.emailId]
|
||||||
|
?..emailHeader?.removeWhere((element) {
|
||||||
|
return element.name == EmailProperty.headerUnsubscribeKey;
|
||||||
|
})
|
||||||
|
..listUnsubscribeHeader?.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
@@ -103,6 +175,14 @@ class ThreadDetailController extends BaseController {
|
|||||||
initializeThreadDetailEmails();
|
initializeThreadDetailEmails();
|
||||||
} else if (success is GetEmailsByIdsSuccess) {
|
} else if (success is GetEmailsByIdsSuccess) {
|
||||||
handleGetEmailsByIdsSuccess(success);
|
handleGetEmailsByIdsSuccess(success);
|
||||||
|
} else if (success is MarkAsEmailReadSuccess) {
|
||||||
|
markCollapsedEmailReadSuccess(success);
|
||||||
|
} else if (success is MarkAsStarEmailSuccess) {
|
||||||
|
markCollapsedEmailStarSuccess(success);
|
||||||
|
} else if (success is CreateNewRuleFilterSuccess) {
|
||||||
|
quickCreateRuleFromCollapsedEmailSuccess(success);
|
||||||
|
} else if (success is DownloadAttachmentForWebSuccess) {
|
||||||
|
handleDownloadSuccess(success);
|
||||||
} else {
|
} else {
|
||||||
super.handleSuccessViewState(success);
|
super.handleSuccessViewState(success);
|
||||||
}
|
}
|
||||||
@@ -118,6 +198,10 @@ class ThreadDetailController extends BaseController {
|
|||||||
showRetryToast(failure);
|
showRetryToast(failure);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (failure is DownloadAttachmentForWebFailure) {
|
||||||
|
handleDownloadFailure(failure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
super.handleFailureViewState(failure);
|
super.handleFailureViewState(failure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,18 +4,19 @@ import 'package:dartz/dartz.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:model/extensions/session_extension.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: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/action/email_ui_action.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
|
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_bottom_bar_widget.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/get_mailbox_contain_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/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/close_thread_detail_action.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/get_thread_detail_loading_view.dart';
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/get_thread_detail_loading_view.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/get_thread_details_email_views.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/thread_detail_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/thread_detail/presentation/widgets/thread_detail_app_bar.dart';
|
import 'package:tmail_ui_user/features/thread_detail/presentation/widgets/thread_detail_app_bar.dart';
|
||||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
|
||||||
|
|
||||||
class ThreadDetailView extends GetWidget<ThreadDetailController> {
|
class ThreadDetailView extends GetWidget<ThreadDetailController> {
|
||||||
const ThreadDetailView({super.key});
|
const ThreadDetailView({super.key});
|
||||||
@@ -39,15 +40,29 @@ class ThreadDetailView extends GetWidget<ThreadDetailController> {
|
|||||||
lastEmailOfThread: controller.emailIdsPresentation.values.lastOrNull,
|
lastEmailOfThread: controller.emailIdsPresentation.values.lastOrNull,
|
||||||
ownUserName: controller.session?.getOwnEmailAddress() ?? '',
|
ownUserName: controller.session?.getOwnEmailAddress() ?? '',
|
||||||
mailboxContain: _getMailboxContain(),
|
mailboxContain: _getMailboxContain(),
|
||||||
emailLoaded: getBinding<SingleEmailController>(
|
onEmailActionClick: controller.threadDetailOnEmailActionClick,
|
||||||
tag: controller.emailIdsPresentation.keys.lastOrNull?.id.value
|
onMoreActionClick: (presentationEmail, position) => controller.emailActionReactor.handleMoreEmailAction(
|
||||||
)?.currentEmailLoaded.value,
|
mailboxContain: controller.mailboxDashBoardController.getMailboxContain(presentationEmail),
|
||||||
onEmailActionClick: (email, action) {
|
presentationEmail: presentationEmail,
|
||||||
// TODO: Next PR
|
position: position,
|
||||||
},
|
responsiveUtils: controller.responsiveUtils,
|
||||||
onMoreActionClick: (p0, p1) {
|
imagePaths: controller.imagePaths,
|
||||||
// TODO: Next PR
|
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,
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Obx(() => controller.getThreadDetailLoadingView(
|
Obx(() => controller.getThreadDetailLoadingView(
|
||||||
|
|||||||
@@ -5,10 +5,8 @@ import 'package:core/utils/platform_info.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:model/email/email_action_type.dart';
|
import 'package:model/email/email_action_type.dart';
|
||||||
import 'package:model/email/presentation_email.dart';
|
import 'package:model/email/presentation_email.dart';
|
||||||
import 'package:model/extensions/email_extension.dart';
|
|
||||||
import 'package:model/extensions/presentation_email_extension.dart';
|
import 'package:model/extensions/presentation_email_extension.dart';
|
||||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.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/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/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_app_bar_widget.dart';
|
||||||
@@ -28,7 +26,6 @@ class ThreadDetailAppBar extends StatelessWidget {
|
|||||||
this.optionWidgets = const [],
|
this.optionWidgets = const [],
|
||||||
this.onEmailActionClick,
|
this.onEmailActionClick,
|
||||||
this.onMoreActionClick,
|
this.onMoreActionClick,
|
||||||
this.emailLoaded,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final ResponsiveUtils responsiveUtils;
|
final ResponsiveUtils responsiveUtils;
|
||||||
@@ -41,16 +38,31 @@ class ThreadDetailAppBar extends StatelessWidget {
|
|||||||
final List<Widget> optionWidgets;
|
final List<Widget> optionWidgets;
|
||||||
final OnEmailActionClick? onEmailActionClick;
|
final OnEmailActionClick? onEmailActionClick;
|
||||||
final OnMoreActionClick? onMoreActionClick;
|
final OnMoreActionClick? onMoreActionClick;
|
||||||
final EmailLoaded? emailLoaded;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(
|
final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(
|
||||||
emailLoaded?.emailCurrent?.listPost ?? '',
|
lastEmailOfThread?.listPost ?? '',
|
||||||
);
|
);
|
||||||
|
|
||||||
final child = LayoutBuilder(
|
final child = LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
|
Widget backButton = EmailViewBackButton(
|
||||||
|
imagePaths: imagePaths,
|
||||||
|
onBackAction: () => closeThreadDetailAction(context),
|
||||||
|
mailboxContain: mailboxContain,
|
||||||
|
isSearchActivated: isSearchRunning,
|
||||||
|
maxWidth: constraints.maxWidth,
|
||||||
|
);
|
||||||
|
if (responsiveUtils.isMobile(context)) {
|
||||||
|
backButton = Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: backButton,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: PlatformInfo.isIOS
|
height: PlatformInfo.isIOS
|
||||||
? EmailViewAppBarWidgetStyles.heightIOS(context, responsiveUtils)
|
? EmailViewAppBarWidgetStyles.heightIOS(context, responsiveUtils)
|
||||||
@@ -76,20 +88,7 @@ class ThreadDetailAppBar extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
if (_supportDisplayMailboxNameTitle(context))
|
if (_supportDisplayMailboxNameTitle(context)) backButton,
|
||||||
Expanded(
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: EmailViewBackButton(
|
|
||||||
imagePaths: imagePaths,
|
|
||||||
onBackAction: () => closeThreadDetailAction(context),
|
|
||||||
mailboxContain: mailboxContain,
|
|
||||||
isSearchActivated: isSearchRunning,
|
|
||||||
maxWidth: constraints.maxWidth,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
...optionWidgets,
|
|
||||||
if (lastEmailOfThread != null) ...[
|
if (lastEmailOfThread != null) ...[
|
||||||
TMailButtonWidget.fromIcon(
|
TMailButtonWidget.fromIcon(
|
||||||
icon: imagePaths.icReply,
|
icon: imagePaths.icReply,
|
||||||
@@ -102,60 +101,45 @@ class ThreadDetailAppBar extends StatelessWidget {
|
|||||||
EmailActionType.reply,
|
EmailActionType.reply,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (lastEmailOfThread!.getCountMailAddressWithoutMe(ownUserName) > 1)
|
if (!responsiveUtils.isMobile(context)) ...[
|
||||||
|
if (lastEmailOfThread!.getCountMailAddressWithoutMe(ownUserName) > 1)
|
||||||
|
TMailButtonWidget.fromIcon(
|
||||||
|
icon: imagePaths.icReplyAll,
|
||||||
|
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
||||||
|
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
||||||
|
tooltipMessage: AppLocalizations.of(context).reply_all,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
onTapActionCallback: () => onEmailActionClick?.call(
|
||||||
|
lastEmailOfThread!,
|
||||||
|
EmailActionType.replyAll,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (isReplyToListEnabled)
|
||||||
|
TMailButtonWidget.fromIcon(
|
||||||
|
icon: imagePaths.icReply,
|
||||||
|
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
||||||
|
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
||||||
|
tooltipMessage: AppLocalizations.of(context).replyToList,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
onTapActionCallback: () => onEmailActionClick?.call(
|
||||||
|
lastEmailOfThread!,
|
||||||
|
EmailActionType.replyToList,
|
||||||
|
),
|
||||||
|
),
|
||||||
TMailButtonWidget.fromIcon(
|
TMailButtonWidget.fromIcon(
|
||||||
icon: imagePaths.icReplyAll,
|
icon: imagePaths.icForward,
|
||||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
||||||
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
||||||
tooltipMessage: AppLocalizations.of(context).reply_all,
|
tooltipMessage: AppLocalizations.of(context).forward,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
onTapActionCallback: () => onEmailActionClick?.call(
|
onTapActionCallback: () => onEmailActionClick?.call(
|
||||||
lastEmailOfThread!,
|
lastEmailOfThread!,
|
||||||
EmailActionType.replyAll,
|
EmailActionType.forward,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isReplyToListEnabled)
|
],
|
||||||
TMailButtonWidget.fromIcon(
|
if (!responsiveUtils.isMobile(context)) const Spacer(),
|
||||||
icon: imagePaths.icReply,
|
...optionWidgets,
|
||||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
|
||||||
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
|
||||||
tooltipMessage: AppLocalizations.of(context).replyToList,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
onTapActionCallback: () => onEmailActionClick?.call(
|
|
||||||
lastEmailOfThread!,
|
|
||||||
EmailActionType.replyToList,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TMailButtonWidget.fromIcon(
|
|
||||||
icon: imagePaths.icForward,
|
|
||||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
|
||||||
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
|
||||||
tooltipMessage: AppLocalizations.of(context).forward,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
onTapActionCallback: () => onEmailActionClick?.call(
|
|
||||||
lastEmailOfThread!,
|
|
||||||
EmailActionType.forward,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TMailButtonWidget.fromIcon(
|
|
||||||
icon: lastEmailOfThread!.hasStarred
|
|
||||||
? imagePaths.icStar
|
|
||||||
: imagePaths.icUnStar,
|
|
||||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
|
||||||
iconColor: lastEmailOfThread!.hasStarred
|
|
||||||
? null
|
|
||||||
: EmailViewAppBarWidgetStyles.iconColor,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
tooltipMessage: lastEmailOfThread!.hasStarred
|
|
||||||
? AppLocalizations.of(context).not_starred
|
|
||||||
: AppLocalizations.of(context).mark_as_starred,
|
|
||||||
onTapActionCallback: () => onEmailActionClick?.call(
|
|
||||||
lastEmailOfThread!,
|
|
||||||
lastEmailOfThread!.hasStarred
|
|
||||||
? EmailActionType.unMarkAsStarred
|
|
||||||
: EmailActionType.markAsStarred
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TMailButtonWidget.fromIcon(
|
TMailButtonWidget.fromIcon(
|
||||||
icon: imagePaths.icMoreVertical,
|
icon: imagePaths.icMoreVertical,
|
||||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
||||||
@@ -169,7 +153,7 @@ class ThreadDetailAppBar extends StatelessWidget {
|
|||||||
? (position) => onMoreActionClick?.call(lastEmailOfThread!, position)
|
? (position) => onMoreActionClick?.call(lastEmailOfThread!, position)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
],
|
] else const Spacer(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ class ThreadDetailCollapsedEmail extends StatelessWidget {
|
|||||||
openEmailAddressDetailAction: openEmailAddressDetailAction,
|
openEmailAddressDetailAction: openEmailAddressDetailAction,
|
||||||
showRecipients: false,
|
showRecipients: false,
|
||||||
onTapAvatarActionClick: onToggleThreadDetailCollapseExpand,
|
onTapAvatarActionClick: onToggleThreadDetailCollapseExpand,
|
||||||
|
mailboxContain: mailboxContain,
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import 'package:model/email/email_in_thread_status.dart';
|
|||||||
import 'package:model/email/mail_priority_header.dart';
|
import 'package:model/email/mail_priority_header.dart';
|
||||||
import 'package:model/extensions/email_address_extension.dart';
|
import 'package:model/extensions/email_address_extension.dart';
|
||||||
import 'package:model/extensions/keyword_identifier_extension.dart';
|
import 'package:model/extensions/keyword_identifier_extension.dart';
|
||||||
|
import 'package:model/extensions/list_email_header_extension.dart';
|
||||||
import 'package:model/extensions/media_type_nullable_extension.dart';
|
import 'package:model/extensions/media_type_nullable_extension.dart';
|
||||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||||
import 'package:model/mailbox/select_mode.dart';
|
import 'package:model/mailbox/select_mode.dart';
|
||||||
@@ -50,6 +51,8 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin {
|
|||||||
final Map<IndividualHeaderIdentifier, String?>? xPriorityHeader;
|
final Map<IndividualHeaderIdentifier, String?>? xPriorityHeader;
|
||||||
final Map<IndividualHeaderIdentifier, String?>? importanceHeader;
|
final Map<IndividualHeaderIdentifier, String?>? importanceHeader;
|
||||||
final Map<IndividualHeaderIdentifier, String?>? priorityHeader;
|
final Map<IndividualHeaderIdentifier, String?>? priorityHeader;
|
||||||
|
final Map<IndividualHeaderIdentifier, String?>? listPostHeader;
|
||||||
|
final Map<IndividualHeaderIdentifier, String?>? listUnsubscribeHeader;
|
||||||
final EmailInThreadStatus? emailInThreadStatus;
|
final EmailInThreadStatus? emailInThreadStatus;
|
||||||
|
|
||||||
PresentationEmail({
|
PresentationEmail({
|
||||||
@@ -79,6 +82,8 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin {
|
|||||||
this.xPriorityHeader,
|
this.xPriorityHeader,
|
||||||
this.importanceHeader,
|
this.importanceHeader,
|
||||||
this.priorityHeader,
|
this.priorityHeader,
|
||||||
|
this.listPostHeader,
|
||||||
|
this.listUnsubscribeHeader,
|
||||||
this.emailInThreadStatus,
|
this.emailInThreadStatus,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -141,6 +146,12 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin {
|
|||||||
|
|
||||||
bool get hasCalendarEvent => headerCalendarEvent?[IndividualHeaderIdentifier.headerCalendarEvent]?.isNotEmpty == true;
|
bool get hasCalendarEvent => headerCalendarEvent?[IndividualHeaderIdentifier.headerCalendarEvent]?.isNotEmpty == true;
|
||||||
|
|
||||||
|
String? get listPost => emailHeader?.toSet().listPost?.trim()
|
||||||
|
?? listPostHeader?[IndividualHeaderIdentifier.listPostHeader]?.trim();
|
||||||
|
|
||||||
|
String? get listUnsubscribe => emailHeader?.toSet().listUnsubscribe?.trim()
|
||||||
|
?? listUnsubscribeHeader?[IndividualHeaderIdentifier.listUnsubscribeHeader]?.trim();
|
||||||
|
|
||||||
bool get isMarkAsImportant {
|
bool get isMarkAsImportant {
|
||||||
final xPriority = xPriorityHeader?[IndividualHeaderIdentifier.xPriorityHeader]
|
final xPriority = xPriorityHeader?[IndividualHeaderIdentifier.xPriorityHeader]
|
||||||
?.trim()
|
?.trim()
|
||||||
@@ -201,6 +212,8 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin {
|
|||||||
xPriorityHeader,
|
xPriorityHeader,
|
||||||
importanceHeader,
|
importanceHeader,
|
||||||
priorityHeader,
|
priorityHeader,
|
||||||
|
listPostHeader,
|
||||||
|
listUnsubscribeHeader,
|
||||||
emailInThreadStatus,
|
emailInThreadStatus,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -231,6 +244,8 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin {
|
|||||||
Map<IndividualHeaderIdentifier, String?>? xPriorityHeader,
|
Map<IndividualHeaderIdentifier, String?>? xPriorityHeader,
|
||||||
Map<IndividualHeaderIdentifier, String?>? importanceHeader,
|
Map<IndividualHeaderIdentifier, String?>? importanceHeader,
|
||||||
Map<IndividualHeaderIdentifier, String?>? priorityHeader,
|
Map<IndividualHeaderIdentifier, String?>? priorityHeader,
|
||||||
|
Map<IndividualHeaderIdentifier, String?>? listPostHeader,
|
||||||
|
Map<IndividualHeaderIdentifier, String?>? listUnsubscribeHeader,
|
||||||
EmailInThreadStatus? emailInThreadStatus,
|
EmailInThreadStatus? emailInThreadStatus,
|
||||||
}) {
|
}) {
|
||||||
return PresentationEmail(
|
return PresentationEmail(
|
||||||
@@ -260,6 +275,8 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin {
|
|||||||
xPriorityHeader: xPriorityHeader ?? this.xPriorityHeader,
|
xPriorityHeader: xPriorityHeader ?? this.xPriorityHeader,
|
||||||
importanceHeader: importanceHeader ?? this.importanceHeader,
|
importanceHeader: importanceHeader ?? this.importanceHeader,
|
||||||
priorityHeader: priorityHeader ?? this.priorityHeader,
|
priorityHeader: priorityHeader ?? this.priorityHeader,
|
||||||
|
listPostHeader: listPostHeader ?? this.listPostHeader,
|
||||||
|
listUnsubscribeHeader: listUnsubscribeHeader ?? this.listUnsubscribeHeader,
|
||||||
emailInThreadStatus: emailInThreadStatus ?? this.emailInThreadStatus,
|
emailInThreadStatus: emailInThreadStatus ?? this.emailInThreadStatus,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ extension EmailExtension on Email {
|
|||||||
|
|
||||||
bool get withAttachments => hasAttachment == true;
|
bool get withAttachments => hasAttachment == true;
|
||||||
|
|
||||||
String get listUnsubscribe => headers.listUnsubscribe;
|
String get listUnsubscribe => headers.listUnsubscribe
|
||||||
|
?? listUnsubscribeHeader?[IndividualHeaderIdentifier.listUnsubscribeHeader]
|
||||||
|
?? '';
|
||||||
|
|
||||||
bool get hasRequestReadReceipt => headers.readReceiptHasBeenRequested ||
|
bool get hasRequestReadReceipt => headers.readReceiptHasBeenRequested ||
|
||||||
headerMdn?.containsKey(IndividualHeaderIdentifier.headerMdn) == true;
|
headerMdn?.containsKey(IndividualHeaderIdentifier.headerMdn) == true;
|
||||||
@@ -42,7 +44,9 @@ extension EmailExtension on Email {
|
|||||||
|
|
||||||
String get sMimeStatusHeaderParsed => sMimeStatusHeader?[IndividualHeaderIdentifier.sMimeStatusHeader]?.trim() ?? '';
|
String get sMimeStatusHeaderParsed => sMimeStatusHeader?[IndividualHeaderIdentifier.sMimeStatusHeader]?.trim() ?? '';
|
||||||
|
|
||||||
String get listPost => headers.listPost.trim();
|
String get listPost => headers.listPost?.trim()
|
||||||
|
?? listPostHeader?[IndividualHeaderIdentifier.listPostHeader]?.trim()
|
||||||
|
?? '';
|
||||||
|
|
||||||
IdentityId? get identityIdFromHeader {
|
IdentityId? get identityIdFromHeader {
|
||||||
final rawIdentityId = identityHeader?[IndividualHeaderIdentifier.identityHeader];
|
final rawIdentityId = identityHeader?[IndividualHeaderIdentifier.identityHeader];
|
||||||
@@ -125,6 +129,8 @@ extension EmailExtension on Email {
|
|||||||
xPriorityHeader: xPriorityHeader,
|
xPriorityHeader: xPriorityHeader,
|
||||||
importanceHeader: importanceHeader,
|
importanceHeader: importanceHeader,
|
||||||
priorityHeader: priorityHeader,
|
priorityHeader: priorityHeader,
|
||||||
|
listPostHeader: listPostHeader,
|
||||||
|
listUnsubscribeHeader: listUnsubscribeHeader,
|
||||||
)
|
)
|
||||||
..searchSnippetSubject = searchSnippetSubject
|
..searchSnippetSubject = searchSnippetSubject
|
||||||
..searchSnippetPreview = searchSnippetPreview;
|
..searchSnippetPreview = searchSnippetPreview;
|
||||||
@@ -158,6 +164,12 @@ extension EmailExtension on Email {
|
|||||||
priorityHeader: updatedProperties.contain(IndividualHeaderIdentifier.priorityHeader.value)
|
priorityHeader: updatedProperties.contain(IndividualHeaderIdentifier.priorityHeader.value)
|
||||||
? newEmail.priorityHeader
|
? newEmail.priorityHeader
|
||||||
: priorityHeader,
|
: priorityHeader,
|
||||||
|
listPostHeader: updatedProperties.contain(IndividualHeaderIdentifier.listPostHeader.value)
|
||||||
|
? newEmail.listPostHeader
|
||||||
|
: listPostHeader,
|
||||||
|
listUnsubscribeHeader: updatedProperties.contain(IndividualHeaderIdentifier.listUnsubscribeHeader.value)
|
||||||
|
? newEmail.listUnsubscribeHeader
|
||||||
|
: listUnsubscribeHeader,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,6 +258,8 @@ extension EmailExtension on Email {
|
|||||||
Map<IndividualHeaderIdentifier, String?>? xPriorityHeader,
|
Map<IndividualHeaderIdentifier, String?>? xPriorityHeader,
|
||||||
Map<IndividualHeaderIdentifier, String?>? importanceHeader,
|
Map<IndividualHeaderIdentifier, String?>? importanceHeader,
|
||||||
Map<IndividualHeaderIdentifier, String?>? priorityHeader,
|
Map<IndividualHeaderIdentifier, String?>? priorityHeader,
|
||||||
|
Map<IndividualHeaderIdentifier, String?>? listPostHeader,
|
||||||
|
Map<IndividualHeaderIdentifier, String?>? listUnsubscribeHeader,
|
||||||
}) {
|
}) {
|
||||||
return Email(
|
return Email(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -283,6 +297,8 @@ extension EmailExtension on Email {
|
|||||||
xPriorityHeader: xPriorityHeader ?? this.xPriorityHeader,
|
xPriorityHeader: xPriorityHeader ?? this.xPriorityHeader,
|
||||||
importanceHeader: importanceHeader ?? this.importanceHeader,
|
importanceHeader: importanceHeader ?? this.importanceHeader,
|
||||||
priorityHeader: priorityHeader ?? this.priorityHeader,
|
priorityHeader: priorityHeader ?? this.priorityHeader,
|
||||||
|
listPostHeader: listPostHeader ?? this.listPostHeader,
|
||||||
|
listUnsubscribeHeader: listUnsubscribeHeader ?? this.listUnsubscribeHeader,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,9 +14,9 @@ extension ListEmailHeaderExtension on Set<EmailHeader>? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String get listUnsubscribe {
|
String? get listUnsubscribe {
|
||||||
final listUnsubscribe = this?.firstWhereOrNull((header) => header.name == EmailProperty.headerUnsubscribeKey);
|
final listUnsubscribe = this?.firstWhereOrNull((header) => header.name == EmailProperty.headerUnsubscribeKey);
|
||||||
return listUnsubscribe?.value ?? '';
|
return listUnsubscribe?.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get sMimeStatus {
|
String get sMimeStatus {
|
||||||
@@ -25,8 +25,8 @@ extension ListEmailHeaderExtension on Set<EmailHeader>? {
|
|||||||
return sMimeStatus?.value.trim() ?? '';
|
return sMimeStatus?.value.trim() ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
String get listPost {
|
String? get listPost {
|
||||||
final listPost = this?.firstWhereOrNull((header) => header.name == EmailProperty.headerListPostKey);
|
final listPost = this?.firstWhereOrNull((header) => header.name == EmailProperty.headerListPostKey);
|
||||||
return listPost?.value ?? '';
|
return listPost?.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,6 +111,9 @@ extension PresentationEmailExtension on PresentationEmail {
|
|||||||
xPriorityHeader: xPriorityHeader,
|
xPriorityHeader: xPriorityHeader,
|
||||||
importanceHeader: importanceHeader,
|
importanceHeader: importanceHeader,
|
||||||
priorityHeader: priorityHeader,
|
priorityHeader: priorityHeader,
|
||||||
|
listPostHeader: listPostHeader,
|
||||||
|
listUnsubscribeHeader: listUnsubscribeHeader,
|
||||||
|
threadId: threadId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -2,6 +2,7 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:mockito/annotations.dart';
|
import 'package:mockito/annotations.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
@@ -40,6 +41,7 @@ void main() {
|
|||||||
Map.fromEntries(emailIds.map((emailId) => MapEntry(emailId, null))).obs,
|
Map.fromEntries(emailIds.map((emailId) => MapEntry(emailId, null))).obs,
|
||||||
);
|
);
|
||||||
when(threadDetailController.getEmailsByIdsInteractor).thenReturn(getEmailsByIdsInteractor);
|
when(threadDetailController.getEmailsByIdsInteractor).thenReturn(getEmailsByIdsInteractor);
|
||||||
|
when(threadDetailController.additionalProperties).thenReturn(Properties.empty());
|
||||||
when(getEmailsByIdsInteractor.execute(
|
when(getEmailsByIdsInteractor.execute(
|
||||||
any,
|
any,
|
||||||
any,
|
any,
|
||||||
|
|||||||
+3
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/id.dart';
|
import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||||
|
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:mockito/annotations.dart';
|
import 'package:mockito/annotations.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
@@ -37,6 +38,7 @@ void main() {
|
|||||||
when(controller.session).thenReturn(SessionFixtures.aliceSession);
|
when(controller.session).thenReturn(SessionFixtures.aliceSession);
|
||||||
when(controller.accountId).thenReturn(AccountFixtures.aliceAccountId);
|
when(controller.accountId).thenReturn(AccountFixtures.aliceAccountId);
|
||||||
when(controller.getEmailsByIdsInteractor).thenReturn(getEmailsByIdsInteractor);
|
when(controller.getEmailsByIdsInteractor).thenReturn(getEmailsByIdsInteractor);
|
||||||
|
when(controller.additionalProperties).thenReturn(Properties.empty());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
controller.loadMoreThreadDetailEmails();
|
controller.loadMoreThreadDetailEmails();
|
||||||
@@ -86,6 +88,7 @@ void main() {
|
|||||||
when(controller.session).thenReturn(SessionFixtures.aliceSession);
|
when(controller.session).thenReturn(SessionFixtures.aliceSession);
|
||||||
when(controller.accountId).thenReturn(AccountFixtures.aliceAccountId);
|
when(controller.accountId).thenReturn(AccountFixtures.aliceAccountId);
|
||||||
when(controller.getEmailsByIdsInteractor).thenReturn(getEmailsByIdsInteractor);
|
when(controller.getEmailsByIdsInteractor).thenReturn(getEmailsByIdsInteractor);
|
||||||
|
when(controller.additionalProperties).thenReturn(Properties.empty());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
controller.loadMoreThreadDetailEmails();
|
controller.loadMoreThreadDetailEmails();
|
||||||
|
|||||||
Reference in New Issue
Block a user