313 lines
15 KiB
Dart
313 lines
15 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:core/data/network/download/download_manager.dart';
|
|
import 'package:core/presentation/state/failure.dart';
|
|
import 'package:debounce_throttle/debounce_throttle.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.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/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:model/email/email_property.dart';
|
|
import 'package:model/email/presentation_email.dart';
|
|
import 'package:model/extensions/keyword_identifier_extension.dart';
|
|
import 'package:model/mailbox/presentation_mailbox.dart';
|
|
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
|
import 'package:tmail_ui_user/features/email/domain/state/add_a_label_to_a_thread_state.dart';
|
|
import 'package:tmail_ui_user/features/email/domain/state/labels/remove_a_label_from_a_thread_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/print_email_state.dart';
|
|
import 'package:tmail_ui_user/features/email/domain/usecases/add_a_label_to_a_thread_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/labels/remove_a_label_from_a_thread_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/action/email_ui_action.dart';
|
|
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.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/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/network_connection/presentation/network_connection_controller.dart'
|
|
if (dart.library.html) 'package:tmail_ui_user/features/network_connection/presentation/web_network_connection_controller.dart';
|
|
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
|
|
import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart';
|
|
import 'package:tmail_ui_user/features/thread/domain/state/mark_as_star_multiple_email_state.dart';
|
|
import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart';
|
|
import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/domain/model/email_in_thread_detail_info.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_emails_by_ids_state.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_by_id_state.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_emails_by_ids_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/presentation/action/thread_detail_ui_action.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_email_moved_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_emails_by_ids_success.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_get_thread_by_id_failure.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_mark_multiple_emails_read_success.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_mail_shortcut_actions_extension.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/handle_refresh_thread_detail_action.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/initialize_thread_detail_emails.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/labels/add_label_to_thread_extension.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/labels/remove_label_from_thread_extension.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';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_on_selected_email_updated.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/model/mail_view_shortcut_action_view_event.dart';
|
|
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_manager.dart';
|
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
|
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
|
|
|
class ThreadDetailController extends BaseController {
|
|
final GetThreadByIdInteractor _getEmailIdsByThreadIdInteractor;
|
|
final GetEmailsByIdsInteractor getEmailsByIdsInteractor;
|
|
final MarkAsEmailReadInteractor _markAsEmailReadInteractor;
|
|
final MarkAsStarEmailInteractor _markAsStarEmailInteractor;
|
|
final PrintEmailInteractor _printEmailInteractor;
|
|
final GetEmailContentInteractor _getEmailContentInteractor;
|
|
final MarkAsStarMultipleEmailInteractor markAsStarMultipleEmailInteractor;
|
|
final MarkAsMultipleEmailReadInteractor markAsMultipleEmailReadInteractor;
|
|
final AddALabelToAThreadInteractor addALabelToAThreadInteractor;
|
|
final RemoveALabelFromAThreadInteractor removeALabelFromAThreadInteractor;
|
|
|
|
ThreadDetailController(
|
|
this._getEmailIdsByThreadIdInteractor,
|
|
this.getEmailsByIdsInteractor,
|
|
this._markAsEmailReadInteractor,
|
|
this._markAsStarEmailInteractor,
|
|
this._printEmailInteractor,
|
|
this._getEmailContentInteractor,
|
|
this.markAsStarMultipleEmailInteractor,
|
|
this.markAsMultipleEmailReadInteractor,
|
|
this.addALabelToAThreadInteractor,
|
|
this.removeALabelFromAThreadInteractor,
|
|
);
|
|
|
|
final emailIdsPresentation = <EmailId, PresentationEmail?>{}.obs;
|
|
final currentExpandedEmailId = Rxn<EmailId>();
|
|
final currentEmailLoaded = Rxn<EmailLoaded>();
|
|
final emailsInThreadDetailInfo = RxList<EmailInThreadDetailInfo>();
|
|
|
|
late final EmailActionReactor emailActionReactor;
|
|
final additionalProperties = Properties({
|
|
IndividualHeaderIdentifier.listPostHeader.value,
|
|
EmailProperty.references,
|
|
EmailProperty.messageId,
|
|
});
|
|
final cachedEmailLoaded = <EmailId, EmailLoaded>{};
|
|
late final _threadGetDebouncer = Debouncer<({ThreadId? threadId, bool isSentMailbox})?>(
|
|
const Duration(milliseconds: 500),
|
|
initialValue: null,
|
|
checkEquality: false,
|
|
onChanged: (value) {
|
|
if (_validateLoadThread(value?.threadId)) {
|
|
consumeState(_getEmailIdsByThreadIdInteractor.execute(
|
|
value!.threadId!,
|
|
session!,
|
|
accountId!,
|
|
sentMailboxId!,
|
|
ownEmailAddress,
|
|
isSentMailbox: value.isSentMailbox,
|
|
));
|
|
}
|
|
},
|
|
);
|
|
|
|
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
|
final searchEmailController = Get.find<SearchEmailController>();
|
|
final networkConnectionController = Get.find<NetworkConnectionController>();
|
|
final threadDetailManager = Get.find<ThreadDetailManager>();
|
|
final downloadManager = Get.find<DownloadManager>();
|
|
|
|
ScrollController? scrollController;
|
|
CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor;
|
|
bool loadThreadOnThreadChanged = false;
|
|
bool isDisplayAllAttachments = false;
|
|
FocusNode? keyboardShortcutFocusNode;
|
|
StreamController<MailViewShortcutActionViewEvent>? shortcutActionEventController;
|
|
StreamSubscription<MailViewShortcutActionViewEvent>? shortcutActionEventSubscription;
|
|
|
|
AccountId? get accountId => mailboxDashBoardController.accountId.value;
|
|
Session? get session => mailboxDashBoardController.sessionCurrent;
|
|
MailboxId? get sentMailboxId => mailboxDashBoardController.getMailboxIdByRole(
|
|
PresentationMailbox.roleSent,
|
|
);
|
|
|
|
String get ownEmailAddress =>
|
|
mailboxDashBoardController.ownEmailAddress.value;
|
|
|
|
bool get isSearchRunning {
|
|
final isWebSearchRunning = mailboxDashBoardController
|
|
.searchController
|
|
.isSearchEmailRunning;
|
|
final isMobileSearchRunning = searchEmailController
|
|
.searchIsRunning
|
|
.value == true;
|
|
return isWebSearchRunning || isMobileSearchRunning;
|
|
}
|
|
bool get networkConnected =>
|
|
networkConnectionController.isNetworkConnectionAvailable();
|
|
bool get isThreadDetailEnabled =>
|
|
threadDetailManager.isThreadDetailEnabled;
|
|
GlobalObjectKey? get expandedEmailHtmlViewKey => currentExpandedEmailId.value != null
|
|
? GlobalObjectKey(currentExpandedEmailId.value!)
|
|
: null;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
ever(mailboxDashBoardController.accountId, (accountId) {
|
|
if (accountId == null) return;
|
|
|
|
injectRuleFilterBindings(session, accountId);
|
|
_createNewEmailRuleFilterInteractor = getBinding<CreateNewEmailRuleFilterInteractor>();
|
|
emailActionReactor = EmailActionReactor(
|
|
_markAsEmailReadInteractor,
|
|
_markAsStarEmailInteractor,
|
|
_createNewEmailRuleFilterInteractor,
|
|
_printEmailInteractor,
|
|
_getEmailContentInteractor,
|
|
);
|
|
});
|
|
ever(mailboxDashBoardController.selectedEmail, (presentationEmail) async {
|
|
onSelectedEmailUpdated(
|
|
presentationEmail,
|
|
currentContext,
|
|
);
|
|
});
|
|
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();
|
|
}
|
|
} else if (action is EmailMovedAction) {
|
|
handleEmailMovedAction(action);
|
|
} else if (action is LoadThreadDetailAfterSelectedEmailAction) {
|
|
_threadGetDebouncer.value = (
|
|
threadId: action.threadId,
|
|
isSentMailbox: action.isSentMailbox,
|
|
);
|
|
} else if (action is ReclaimMailViewKeyboardShortcutFocusAction) {
|
|
refocusMailShortcutFocus();
|
|
} else if (action is ClearMailViewKeyboardShortcutFocusAction) {
|
|
clearMailShortcutFocus();
|
|
} else if (action is ResyncThreadDetailWhenSettingChangedAction) {
|
|
resyncThreadDetailWhenSettingChanged();
|
|
}
|
|
// Reset [threadDetailUIAction] to original value
|
|
mailboxDashBoardController.dispatchThreadDetailUIAction(
|
|
ThreadDetailUIAction(),
|
|
);
|
|
});
|
|
ever(mailboxDashBoardController.emailUIAction, (action) {
|
|
if (action is RefreshThreadDetailAction) {
|
|
mailboxDashBoardController.dispatchEmailUIAction(EmailUIAction());
|
|
handleRefreshThreadDetailAction(
|
|
action,
|
|
_getEmailIdsByThreadIdInteractor,
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
bool _validateLoadThread(ThreadId? threadId) {
|
|
return mailboxDashBoardController.selectedEmail.value?.threadId != null &&
|
|
threadId == mailboxDashBoardController.selectedEmail.value?.threadId &&
|
|
session != null &&
|
|
accountId != null &&
|
|
sentMailboxId != null &&
|
|
ownEmailAddress.isNotEmpty &&
|
|
networkConnected &&
|
|
isThreadDetailEnabled;
|
|
}
|
|
|
|
void reset() {
|
|
emailIdsPresentation.clear();
|
|
emailsInThreadDetailInfo.clear();
|
|
scrollController?.dispose();
|
|
scrollController = null;
|
|
currentExpandedEmailId.value = null;
|
|
currentEmailLoaded.value = null;
|
|
cachedEmailLoaded.clear();
|
|
_threadGetDebouncer.value = null;
|
|
isDisplayAllAttachments = false;
|
|
}
|
|
|
|
@override
|
|
void handleSuccessViewState(success) {
|
|
if (success is GetThreadByIdSuccess) {
|
|
handleGetEmailIdsByThreadIdSuccess(success);
|
|
initializeThreadDetailEmails(success);
|
|
} else if (success is GetEmailsByIdsSuccess) {
|
|
handleGetEmailsByIdsSuccess(success);
|
|
} else if (success is MarkAsEmailReadSuccess) {
|
|
markCollapsedEmailReadSuccess(success);
|
|
} else if (success is MarkAsMultipleEmailReadAllSuccess) {
|
|
handleMarkMultipleEmailsReadSuccess(
|
|
success,
|
|
success.readActions,
|
|
success.emailIds,
|
|
);
|
|
} else if (success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
|
|
handleMarkMultipleEmailsReadSuccess(
|
|
success,
|
|
success.readActions,
|
|
success.successEmailIds,
|
|
);
|
|
} else if (success is CreateNewRuleFilterSuccess) {
|
|
quickCreateRuleFromCollapsedEmailSuccess(success);
|
|
} else if (success is AddALabelToAThreadSuccess) {
|
|
handleAddLabelToThreadSuccess(success);
|
|
} else if (success is RemoveALabelFromAThreadSuccess) {
|
|
handleRemoveLabelFromThreadSuccess(success);
|
|
} else {
|
|
super.handleSuccessViewState(success);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void handleFailureViewState(failure) {
|
|
if (failure is GetThreadByIdFailure) {
|
|
handleGetThreadByIdFailure(failure);
|
|
} else if (failure is GetEmailsByIdsFailure) {
|
|
if (failure.updateCurrentThreadDetail) return;
|
|
showRetryToast(failure);
|
|
} else if (failure is PrintEmailFailure) {
|
|
if (currentOverlayContext != null && currentContext != null) {
|
|
appToast.showToastErrorMessage(
|
|
currentOverlayContext!,
|
|
AppLocalizations.of(currentContext!).unknownError,
|
|
);
|
|
}
|
|
} else if (failure is MarkAsMultipleEmailReadFailure ||
|
|
failure is MarkAsStarMultipleEmailFailure) {
|
|
toastManager.showMessageFailure(failure as FeatureFailure);
|
|
} else if (failure is AddALabelToAThreadFailure) {
|
|
handleAddLabelToThreadFailure(failure);
|
|
} else if (failure is RemoveALabelFromAThreadFailure) {
|
|
handleRemoveLabelFromThreadFailure(failure);
|
|
} else {
|
|
super.handleFailureViewState(failure);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
onKeyboardShortcutDispose();
|
|
super.onClose();
|
|
}
|
|
} |