TF-3699 Thread Detail Next previous actions (#3843)
This commit is contained in:
@@ -1,36 +0,0 @@
|
||||
import 'package:core/presentation/views/loading/cupertino_loading_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
|
||||
extension GetThreadDetailLoadingView on ThreadDetailController {
|
||||
Widget getThreadDetailLoadingView({
|
||||
required bool isResponsiveDesktop,
|
||||
required bool isLoading,
|
||||
bool isExpanded = true,
|
||||
}) {
|
||||
if (!isLoading) return const SizedBox.shrink();
|
||||
|
||||
final child = Container(
|
||||
alignment: Alignment.center,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
margin: isResponsiveDesktop
|
||||
? const EdgeInsetsDirectional.only(end: 16)
|
||||
: null,
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CupertinoLoadingWidget(),
|
||||
),
|
||||
);
|
||||
|
||||
if (isExpanded) {
|
||||
return Expanded(child: child);
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-5
@@ -98,16 +98,29 @@ extension GetThreadDetailEmailViews on ThreadDetailController {
|
||||
);
|
||||
}
|
||||
|
||||
if (isFirstEmailInThreadDetail) {
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(bottom: 16),
|
||||
child: EmailView(
|
||||
key: GlobalObjectKey('${presentationEmail.id?.id.value ?? ''}firstInThread'),
|
||||
isInsideThreadDetailView: true,
|
||||
emailId: presentationEmail.id,
|
||||
isFirstEmailInThreadDetail: true,
|
||||
threadSubject: emailIdsPresentation.values.last?.subject,
|
||||
onToggleThreadDetailCollapseExpand: () {
|
||||
toggleThreadDetailCollapeExpand(presentationEmail);
|
||||
},
|
||||
scrollController: scrollController,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsetsDirectional.only(bottom: 16),
|
||||
child: EmailView(
|
||||
key: GlobalObjectKey(presentationEmail.id?.id.value ?? ''),
|
||||
isInsideThreadDetailView: emailIdsPresentation.length > 1,
|
||||
isInsideThreadDetailView: true,
|
||||
emailId: presentationEmail.id,
|
||||
isFirstEmailInThreadDetail: isFirstEmailInThreadDetail,
|
||||
threadSubject: isFirstEmailInThreadDetail
|
||||
? emailIdsPresentation.values.last?.subject
|
||||
: null,
|
||||
onToggleThreadDetailCollapseExpand: () {
|
||||
toggleThreadDetailCollapeExpand(presentationEmail);
|
||||
},
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ extension HandleGetEmailIdsByThreadIdSuccess on ThreadDetailController {
|
||||
void handleGetEmailIdsByThreadIdSuccess(
|
||||
GetThreadByIdSuccess success,
|
||||
) {
|
||||
if (success.emailIds.isEmpty) {
|
||||
final currentThreadId = mailboxDashBoardController.selectedEmail.value?.threadId;
|
||||
if (success.emailIds.isEmpty || success.threadId != currentThreadId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -37,6 +37,7 @@ extension HandleGetEmailsByIdsSuccess on ThreadDetailController {
|
||||
: EmailInThreadStatus.collapsed,
|
||||
);
|
||||
}
|
||||
threadDetailManager.currentMobilePageViewIndex.refresh();
|
||||
|
||||
if (_skipScrollJump(isLoadMore)) return;
|
||||
|
||||
|
||||
+2
@@ -32,6 +32,7 @@ extension HandleRefreshThreadDetailAction on ThreadDetailController {
|
||||
consumeState(Stream.value(Right(GetThreadByIdSuccess(
|
||||
[currentEmailId],
|
||||
updateCurrentThreadDetail: true,
|
||||
threadId: mailboxDashBoardController.selectedEmail.value?.threadId,
|
||||
))));
|
||||
}
|
||||
|
||||
@@ -74,6 +75,7 @@ extension HandleRefreshThreadDetailAction on ThreadDetailController {
|
||||
|
||||
consumeState(Stream.value(Right(GetThreadByIdSuccess(
|
||||
afterRefreshedEmailIds,
|
||||
threadId: currentThreadId,
|
||||
updateCurrentThreadDetail: true,
|
||||
))));
|
||||
consumeState(Stream.value(Right(GetEmailsByIdsSuccess(
|
||||
|
||||
@@ -9,6 +9,9 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/utils/thread_d
|
||||
|
||||
extension InitializeThreadDetailEmails on ThreadDetailController {
|
||||
void initializeThreadDetailEmails(GetThreadByIdSuccess success) {
|
||||
final currentThreadId = mailboxDashBoardController.selectedEmail.value?.threadId;
|
||||
if (success.skipLoadingMetadata || currentThreadId != success.threadId) return;
|
||||
|
||||
final selectedEmailId = mailboxDashBoardController.selectedEmail.value?.id;
|
||||
if (skipLoadThreadMetaData(
|
||||
selectedEmailId: selectedEmailId,
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_manager.dart';
|
||||
|
||||
extension InitializeThreadDetailManager on ThreadDetailManager {
|
||||
void initializeThreadDetailManager(
|
||||
List<PresentationEmail> currentDisplayedEmails,
|
||||
) {
|
||||
availableThreadIds.value = currentDisplayedEmails
|
||||
.map((presentationEmail) => presentationEmail.threadId)
|
||||
.toSet()
|
||||
.whereNotNull()
|
||||
.toList();
|
||||
if (availableThreadIds.isEmpty) return;
|
||||
|
||||
final selectedEmail = mailboxDashBoardController.selectedEmail.value;
|
||||
if (isThreadDetailEnabled && selectedEmail?.threadId != null) {
|
||||
final currentThreadIndex = availableThreadIds.indexOf(
|
||||
selectedEmail!.threadId!,
|
||||
);
|
||||
currentMobilePageViewIndex.value = currentThreadIndex;
|
||||
} else if (selectedEmail?.id != null) {
|
||||
final currentEmailIndex = currentDisplayedEmails.indexOf(
|
||||
selectedEmail!,
|
||||
);
|
||||
currentMobilePageViewIndex.value = currentEmailIndex;
|
||||
}
|
||||
|
||||
pageController ??= PageController(
|
||||
initialPage: currentMobilePageViewIndex.value,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_next_previous_actions.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
|
||||
extension OnThreadPageChanged on ThreadDetailController {
|
||||
void onThreadPageChanged(int index) {
|
||||
if (index > threadDetailManager.currentMobilePageViewIndex.value) {
|
||||
onNext();
|
||||
} else if (index < threadDetailManager.currentMobilePageViewIndex.value) {
|
||||
onPrevious();
|
||||
}
|
||||
}
|
||||
|
||||
bool get nextAvailable =>
|
||||
PlatformInfo.isWeb && threadDetailManager.nextAvailable;
|
||||
bool get previousAvailable =>
|
||||
PlatformInfo.isWeb && threadDetailManager.previousAvailable;
|
||||
|
||||
void onNext() {
|
||||
if (currentExpandedEmailId.value != null) {
|
||||
mailboxDashBoardController.dispatchEmailUIAction(
|
||||
CollapseEmailInThreadDetailAction(currentExpandedEmailId.value!),
|
||||
);
|
||||
}
|
||||
loadThreadOnThreadChanged = isThreadDetailEnabled;
|
||||
threadDetailManager.onNext();
|
||||
}
|
||||
|
||||
void onNextMobile() {
|
||||
if (currentExpandedEmailId.value != null) {
|
||||
mailboxDashBoardController.dispatchEmailUIAction(
|
||||
CollapseEmailInThreadDetailAction(currentExpandedEmailId.value!),
|
||||
);
|
||||
}
|
||||
loadThreadOnThreadChanged = isThreadDetailEnabled;
|
||||
threadDetailManager.pageController?.nextPage(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.linear,
|
||||
);
|
||||
}
|
||||
|
||||
void onPrevious() {
|
||||
if (currentExpandedEmailId.value != null) {
|
||||
mailboxDashBoardController.dispatchEmailUIAction(
|
||||
CollapseEmailInThreadDetailAction(currentExpandedEmailId.value!),
|
||||
);
|
||||
}
|
||||
loadThreadOnThreadChanged = isThreadDetailEnabled;
|
||||
threadDetailManager.onPrevious();
|
||||
}
|
||||
|
||||
void onPreviousMobile() {
|
||||
if (currentExpandedEmailId.value != null) {
|
||||
mailboxDashBoardController.dispatchEmailUIAction(
|
||||
CollapseEmailInThreadDetailAction(currentExpandedEmailId.value!),
|
||||
);
|
||||
}
|
||||
loadThreadOnThreadChanged = isThreadDetailEnabled;
|
||||
threadDetailManager.pageController?.previousPage(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.linear,
|
||||
);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_manager.dart';
|
||||
|
||||
extension RefreshThreadDetailOnSettingChanged on ThreadDetailController {
|
||||
extension RefreshThreadDetailOnSettingChanged on ThreadDetailManager {
|
||||
void refreshThreadDetailOnSettingChanged() {
|
||||
if (threadDetailWasEnabled != isThreadDetailEnabled) {
|
||||
threadDetailWasEnabled = isThreadDetailEnabled;
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_manager.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_utils.dart';
|
||||
|
||||
extension ThreadDetailNextPreviousActions on ThreadDetailManager {
|
||||
bool get nextAvailable => isThreadDetailEnabled
|
||||
? currentThreadId != availableThreadIds.lastOrNull
|
||||
: currentEmailId != currentDisplayedEmails.lastOrNull?.id;
|
||||
|
||||
void onNext() {
|
||||
if (!nextAvailable) return;
|
||||
|
||||
final currentIndex = isThreadDetailEnabled
|
||||
? availableThreadIds.indexOf(currentThreadId!)
|
||||
: currentDisplayedEmails
|
||||
.indexOf(mailboxDashBoardController.selectedEmail.value!);
|
||||
_navigate(currentIndex + 1, isThreadDetailEnabled);
|
||||
}
|
||||
|
||||
bool get previousAvailable => isThreadDetailEnabled
|
||||
? currentThreadId != availableThreadIds.firstOrNull
|
||||
: currentEmailId != currentDisplayedEmails.firstOrNull?.id;
|
||||
|
||||
void onPrevious() {
|
||||
if (!previousAvailable) return;
|
||||
|
||||
final currentIndex = isThreadDetailEnabled
|
||||
? availableThreadIds.indexOf(currentThreadId!)
|
||||
: currentDisplayedEmails
|
||||
.indexOf(mailboxDashBoardController.selectedEmail.value!);
|
||||
_navigate(currentIndex - 1, isThreadDetailEnabled);
|
||||
}
|
||||
|
||||
void _preparePageWithIndex(int index) {
|
||||
currentMobilePageViewIndex.value = index;
|
||||
pageController?.dispose();
|
||||
pageController = PageController(initialPage: index);
|
||||
}
|
||||
|
||||
void _goToPageWithEmail(PresentationEmail? presentationEmail) {
|
||||
mailboxDashBoardController.setSelectedEmail(presentationEmail);
|
||||
if (PlatformInfo.isWeb && presentationEmail?.routeWeb != null) {
|
||||
RouteUtils.replaceBrowserHistory(
|
||||
title: 'Email-${presentationEmail?.id?.id.value ?? ''}',
|
||||
url: presentationEmail!.routeWeb!);
|
||||
}
|
||||
}
|
||||
|
||||
void _navigateToEmail(int emailIndex) {
|
||||
final email = currentDisplayedEmails[emailIndex];
|
||||
_preparePageWithIndex(emailIndex);
|
||||
_goToPageWithEmail(email);
|
||||
}
|
||||
|
||||
void _navigateToThread(int threadIndex) {
|
||||
final threadId = availableThreadIds[threadIndex];
|
||||
final email = currentDisplayedEmails.firstWhereOrNull(
|
||||
(presentationEmail) => presentationEmail.threadId == threadId,
|
||||
);
|
||||
_preparePageWithIndex(threadIndex);
|
||||
_goToPageWithEmail(email);
|
||||
}
|
||||
|
||||
void _navigate(int index, bool isThreadDetailEnabled) {
|
||||
isThreadDetailEnabled ? _navigateToThread(index) : _navigateToEmail(index);
|
||||
}
|
||||
}
|
||||
+32
-8
@@ -5,6 +5,7 @@ import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action
|
||||
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/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/thread_detail_controller.dart';
|
||||
|
||||
@@ -19,20 +20,43 @@ extension ThreadDetailOnSelectedEmailUpdated on ThreadDetailController {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentExpandedEmailId.value != null) {
|
||||
mailboxDashBoardController.dispatchEmailUIAction(
|
||||
DisposePreviousExpandedEmailAction(
|
||||
currentExpandedEmailId.value!,
|
||||
),
|
||||
);
|
||||
scrollController ??= ScrollController();
|
||||
|
||||
if (currentExpandedEmailId.value == null) {
|
||||
loadThreadOnThreadChanged = isThreadDetailEnabled;
|
||||
_preloadSelectedEmail(selectedEmail!);
|
||||
return;
|
||||
}
|
||||
|
||||
_preloadSelectedEmail(selectedEmail!);
|
||||
// Thread setting updated, no need to dispose current single email controller
|
||||
if (currentExpandedEmailId.value == selectedEmail!.id) {
|
||||
_preloadSelectedEmail(selectedEmail);
|
||||
|
||||
if (isThreadDetailEnabled && selectedEmail.threadId != null) {
|
||||
mailboxDashBoardController.dispatchThreadDetailUIAction(
|
||||
LoadThreadDetailAfterSelectedEmailAction(
|
||||
selectedEmail.threadId!,
|
||||
)
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mailboxDashBoardController.dispatchEmailUIAction(
|
||||
DisposePreviousExpandedEmailAction(
|
||||
currentExpandedEmailId.value!,
|
||||
),
|
||||
);
|
||||
loadThreadOnThreadChanged = isThreadDetailEnabled;
|
||||
_preloadSelectedEmail(selectedEmail);
|
||||
}
|
||||
|
||||
void _preloadSelectedEmail(PresentationEmail selectedEmail) {
|
||||
consumeState(Stream.fromIterable([
|
||||
Right(PreloadEmailIdsInThreadSuccess([selectedEmail.id!])),
|
||||
Right(PreloadEmailIdsInThreadSuccess(
|
||||
[selectedEmail.id!],
|
||||
threadId: selectedEmail.threadId,
|
||||
)),
|
||||
Right(PreloadEmailsByIdsSuccess([selectedEmail])),
|
||||
]));
|
||||
}
|
||||
|
||||
+4
@@ -11,6 +11,8 @@ extension ToggleThreadDetailCollapeExpand on ThreadDetailController {
|
||||
if (emailId == null || expansionStatus == null) return;
|
||||
|
||||
if (expansionStatus == EmailInThreadStatus.expanded) {
|
||||
if (emailIdsPresentation.length == 1) return;
|
||||
|
||||
emailIdsPresentation[emailId] = presentationEmail.copyWith(
|
||||
emailInThreadStatus: EmailInThreadStatus.collapsed,
|
||||
);
|
||||
@@ -18,6 +20,7 @@ extension ToggleThreadDetailCollapeExpand on ThreadDetailController {
|
||||
CollapseEmailInThreadDetailAction(emailId),
|
||||
);
|
||||
currentExpandedEmailId.value = null;
|
||||
threadDetailManager.currentMobilePageViewIndex.refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,5 +45,6 @@ extension ToggleThreadDetailCollapeExpand on ThreadDetailController {
|
||||
);
|
||||
}
|
||||
}
|
||||
threadDetailManager.currentMobilePageViewIndex.refresh();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user