Skip to content

TF-3804 Thread Detail Load selected email in parallel #3813

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: feature/thread-master-0.16.0
Choose a base branch
from
10 changes: 10 additions & 0 deletions lib/features/email/presentation/action/email_ui_action.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
Expand Down Expand Up @@ -58,4 +59,13 @@ class RefreshThreadDetailAction extends EmailUIAction {

@override
List<Object?> get props => [emailChangeResponse];
}

class DisposePreviousExpandedEmailAction extends EmailUIAction {
DisposePreviousExpandedEmailAction(this.emailId);

final EmailId emailId;

@override
List<Object?> get props => [emailId];
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new
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/search/email/presentation/search_email_controller.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/focus_thread_detail_expanded_email.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/mark_collapsed_email_unread_success.dart';
Expand Down Expand Up @@ -399,6 +400,12 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
action.emailActionType,
action.presentationEmail,
);
} else if (action is DisposePreviousExpandedEmailAction) {
if (_currentEmailId == null || _currentEmailId != action.emailId) return;
for (var worker in obxListeners) {
worker.dispose();
}
Get.delete<SingleEmailController>(tag: action.emailId.id.value);
} else if (action is CloseEmailInThreadDetailAction) {
if (_currentEmailId == null) return;
closeEmailView(context: currentContext);
Expand Down Expand Up @@ -664,6 +671,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
emailUnsubscribe.value = null;
}
}
if (currentEmail?.threadId != null) {
mailboxDashBoardController.dispatchThreadDetailUIAction(
LoadThreadDetailAfterSelectedEmailAction(
currentEmail!.threadId!,
)
);
}
}

void _getEmailContentSuccess(GetEmailContentSuccess success) {
Expand Down Expand Up @@ -729,6 +743,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
if ((_threadDetailController?.emailIdsPresentation.keys.length ?? 0) > 1 == true) {
_jumpScrollViewToTopOfEmail();
}
if (currentEmail?.threadId != null) {
mailboxDashBoardController.dispatchThreadDetailUIAction(
LoadThreadDetailAfterSelectedEmailAction(
currentEmail!.threadId!,
)
);
}
}

void _jumpScrollViewToTopOfEmail() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ class GetEmailsByIdsSuccess extends UIState {
List<Object?> get props => [presentationEmails, updateCurrentThreadDetail];
}

class PreloadEmailsByIdsSuccess extends GetEmailsByIdsSuccess {
PreloadEmailsByIdsSuccess(super.presentationEmails);
}

class GetEmailsByIdsFailure extends FeatureFailure {
GetEmailsByIdsFailure({
super.exception,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class GetThreadByIdSuccess extends UIState {
List<Object> get props => [emailIds, updateCurrentThreadDetail];
}

class PreloadEmailIdsInThreadSuccess extends GetThreadByIdSuccess {
PreloadEmailIdsInThreadSuccess(super.emailIds);
}

class GetThreadByIdFailure extends FeatureFailure {
GetThreadByIdFailure({
super.exception,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ class EmailMovedAction extends ThreadDetailUIAction {

@override
List<Object?> get props => [emailId, originalMailboxId, targetMailboxId];
}

class LoadThreadDetailAfterSelectedEmailAction extends ThreadDetailUIAction {
LoadThreadDetailAfterSelectedEmailAction(this.threadId);

final ThreadId threadId;

@override
List<Object?> get props => [threadId];
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
import 'package:jmap_dart_client/jmap/mail/email/email.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/thread_detail_controller.dart';

extension HandleGetEmailIdsByThreadIdSuccess on ThreadDetailController {
void handleGetEmailIdsByThreadIdSuccess(
GetThreadByIdSuccess success,
) {
final newEmailsInThreadDetail = <EmailId>[];
if (success.emailIds.isNotEmpty) {
if (success.updateCurrentThreadDetail) {
newEmailsInThreadDetail.addAll(success
.emailIds
.where(
(emailId) => !emailIdsPresentation.keys.contains(emailId),
)
if (success.emailIds.isEmpty) {
return;
}

final allEmailIds = success.emailIds;
if (success.updateCurrentThreadDetail) {
final newEmailIds = allEmailIds.where(
(emailId) => !emailIdsPresentation.keys.contains(emailId),
);
emailIdsPresentation
..removeWhere((key, _) => !allEmailIds.contains(key))
..addEntries(
newEmailIds.map((emailId) => MapEntry(emailId, null)),
);
emailIdsPresentation
..removeWhere(
(key, value) => !success.emailIds.contains(key),
)
..addAll(Map.fromEntries(
newEmailsInThreadDetail.map((emailId) => MapEntry(emailId, null)),
));
} else {
emailIdsPresentation.value = Map.fromEntries(success.emailIds.map(
(emailId) => MapEntry(emailId, null),
));
}
} else if (mailboxDashBoardController.selectedEmail.value?.id != null) {
emailIdsPresentation.value = {
mailboxDashBoardController.selectedEmail.value!.id!: null,
};
return;
}

final selectedEmail = mailboxDashBoardController.selectedEmail.value;
final selectedEmailId = selectedEmail?.id;
emailIdsPresentation.value = {
for (final id in allEmailIds)
id: id == selectedEmailId
? emailIdsPresentation[id] ?? selectedEmail
: null,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ extension HandleGetEmailsByIdsSuccess on ThreadDetailController {
);
}

if (!isLoadMore) return;
if (_skipScrollJump(isLoadMore)) return;

final currentExpandedEmailIndex = currentExpandedEmailId.value == null
? -1
Expand Down Expand Up @@ -72,4 +72,7 @@ extension HandleGetEmailsByIdsSuccess on ThreadDetailController {
});
}
}

bool _skipScrollJump(bool isLoadMore) =>
!isLoadMore || emailIdsPresentation.length == 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/utils/thread_d

extension InitializeThreadDetailEmails on ThreadDetailController {
void initializeThreadDetailEmails(GetThreadByIdSuccess success) {
final threadDetailEnabled = isThreadDetailEnabled;
final selectedEmail = mailboxDashBoardController.selectedEmail.value;
if (!threadDetailEnabled &&
selectedEmail != null &&
!success.updateCurrentThreadDetail) {
consumeState(Stream.value(Right(GetEmailsByIdsSuccess([selectedEmail]))));
return;
}
final selectedEmailId = mailboxDashBoardController.selectedEmail.value?.id;
if (skipLoadThreadMetaData(
selectedEmailId: selectedEmailId,
updateCurrentThreadDetail: success.updateCurrentThreadDetail,
)) return;

final existingEmailIds = emailIdsPresentation.keys.toList();
final selectedEmailId = mailboxDashBoardController.selectedEmail.value?.id;

List<EmailId> emailIdsToLoadMetaData = [];
if (success.updateCurrentThreadDetail) {
Expand All @@ -36,6 +32,7 @@ extension InitializeThreadDetailEmails on ThreadDetailController {
existingEmailIds,
selectedEmailId: selectedEmailId,
);
emailIdsToLoadMetaData.remove(selectedEmailId);
}

if (accountId == null || session == null) {
Expand All @@ -45,6 +42,8 @@ extension InitializeThreadDetailEmails on ThreadDetailController {
))));
return;
}
if (_currentThreadOnlyContainsSelectedEmail(selectedEmailId)) return;

consumeState(getEmailsByIdsInteractor.execute(
session!,
accountId!,
Expand All @@ -56,4 +55,18 @@ extension InitializeThreadDetailEmails on ThreadDetailController {
updateCurrentThreadDetail: success.updateCurrentThreadDetail,
));
}

bool _currentThreadOnlyContainsSelectedEmail(EmailId? selectedEmailId) {
return selectedEmailId != null &&
emailIdsPresentation.length == 1 &&
emailIdsPresentation.keys.contains(selectedEmailId);
}

bool skipLoadThreadMetaData({
EmailId? selectedEmailId,
bool updateCurrentThreadDetail = false,
}) {
return selectedEmailId == null ||
(!isThreadDetailEnabled && !updateCurrentThreadDetail);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:dartz/dartz.dart';
import 'package:flutter/widgets.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_emails_by_ids_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/state/get_thread_by_id_state.dart';
import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_by_id_interactor.dart';
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';

extension ThreadDetailOnSelectedEmailUpdated on ThreadDetailController {
void onSelectedEmailUpdated(
PresentationEmail? selectedEmail,
GetThreadByIdInteractor getThreadByIdInteractor,
BuildContext? context,
) {
if (selectedEmail?.id == null) {
closeThreadDetailAction(context);
return;
}

if (currentExpandedEmailId.value != null) {
mailboxDashBoardController.dispatchEmailUIAction(
DisposePreviousExpandedEmailAction(
currentExpandedEmailId.value!,
),
);
}

_preloadSelectedEmail(selectedEmail!);
}

void _preloadSelectedEmail(PresentationEmail selectedEmail) {
consumeState(Stream.fromIterable([
Right(PreloadEmailIdsInThreadSuccess([selectedEmail.id!])),
Right(PreloadEmailsByIdsSuccess([selectedEmail])),
]));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ import 'package:tmail_ui_user/features/thread_detail/domain/usecases/get_thread_
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/domain/usecases/get_thread_detail_status_interactor.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_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_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/refresh_thread_detail_on_setting_changed.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/thread_detail_setting_status.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
Expand Down Expand Up @@ -146,32 +146,11 @@ class ThreadDetailController extends BaseController {
});
downloadProgressState.stream.listen(handleDownloadProgressState);
ever(mailboxDashBoardController.selectedEmail, (presentationEmail) async {
if (presentationEmail?.threadId == null) {
closeThreadDetailAction(currentContext);
return;
}

if (!isThreadDetailEnabled && presentationEmail?.id != null) {
consumeState(Stream.value(Right(GetThreadByIdSuccess([
presentationEmail!.id!,
]))));
return;
}

if (session != null &&
accountId != null &&
sentMailboxId != null &&
ownEmailAddress != null) {
scrollController = ScrollController();
consumeState(_getEmailIdsByThreadIdInteractor.execute(
presentationEmail!.threadId!,
session!,
accountId!,
sentMailboxId!,
ownEmailAddress!,
selectedEmailId: presentationEmail.id,
));
}
onSelectedEmailUpdated(
presentationEmail,
_getEmailIdsByThreadIdInteractor,
currentContext,
);
});
ever(mailboxDashBoardController.threadDetailUIAction, (action) {
if (action is UpdatedEmailKeywordsAction) {
Expand All @@ -191,6 +170,24 @@ class ThreadDetailController extends BaseController {
consumeState(_getThreadDetailStatusInteractor.execute());
} else if (action is EmailMovedAction) {
handleEmailMovedAction(action);
} else if (action is LoadThreadDetailAfterSelectedEmailAction) {
if (mailboxDashBoardController.selectedEmail.value?.threadId != null &&
action.threadId == mailboxDashBoardController.selectedEmail.value?.threadId &&
session != null &&
accountId != null &&
sentMailboxId != null &&
ownEmailAddress != null &&
isThreadDetailEnabled) {
scrollController = ScrollController();
consumeState(_getEmailIdsByThreadIdInteractor.execute(
action.threadId,
session!,
accountId!,
sentMailboxId!,
ownEmailAddress!,
selectedEmailId: mailboxDashBoardController.selectedEmail.value?.id,
));
}
}
// Reset [threadDetailUIAction] to original value
mailboxDashBoardController.dispatchThreadDetailUIAction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class ThreadDetailView extends GetWidget<ThreadDetailController> {

return Obx(() {
if (showLoadingView(controller.viewState.value) &&
controller.emailIdsPresentation.isEmpty &&
controller.responsiveUtils.isTabletLarge(context)) {
return controller.getThreadDetailLoadingView(
isResponsiveDesktop: false,
Expand Down
Loading
Loading