TF-3924 Thread Detail Delay selected email content render
This commit is contained in:
@@ -124,7 +124,6 @@ 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/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/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/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/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/extension/mark_collapsed_email_unread_success.dart';
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/mark_collapsed_email_unread_success.dart';
|
||||||
@@ -690,7 +689,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
emailUnsubscribe.value = null;
|
emailUnsubscribe.value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_loadThreadOnGetEmailContentSuccess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _getEmailContentSuccess(GetEmailContentSuccess success) {
|
void _getEmailContentSuccess(GetEmailContentSuccess success) {
|
||||||
@@ -761,20 +759,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
if ((_threadDetailController?.emailIdsPresentation.keys.length ?? 0) > 1 == true) {
|
if ((_threadDetailController?.emailIdsPresentation.keys.length ?? 0) > 1 == true) {
|
||||||
_jumpScrollViewToTopOfEmail();
|
_jumpScrollViewToTopOfEmail();
|
||||||
}
|
}
|
||||||
_loadThreadOnGetEmailContentSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _loadThreadOnGetEmailContentSuccess() {
|
|
||||||
if (currentEmail?.threadId != null &&
|
|
||||||
currentEmail?.id == mailboxDashBoardController.selectedEmail.value?.id &&
|
|
||||||
_threadDetailController?.loadThreadOnThreadChanged == true) {
|
|
||||||
_threadDetailController?.loadThreadOnThreadChanged = false;
|
|
||||||
mailboxDashBoardController.dispatchThreadDetailUIAction(
|
|
||||||
LoadThreadDetailAfterSelectedEmailAction(
|
|
||||||
currentEmail!.threadId!,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _jumpScrollViewToTopOfEmail() {
|
void _jumpScrollViewToTopOfEmail() {
|
||||||
|
|||||||
+1
-6
@@ -5,7 +5,6 @@ import 'package:model/email/email_in_thread_status.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_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/thread_detail_open_email_address_detail_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/presentation/extension/thread_detail_load_more_segments.dart';
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/thread_detail_load_more_segments.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';
|
||||||
@@ -32,11 +31,7 @@ extension GetThreadDetailEmailViews on ThreadDetailController {
|
|||||||
loadMoreCount: loadMoreSegments[indexOfEmailId]!,
|
loadMoreCount: loadMoreSegments[indexOfEmailId]!,
|
||||||
),
|
),
|
||||||
imagePaths: imagePaths,
|
imagePaths: imagePaths,
|
||||||
isLoading: viewState.value.fold(
|
loadingIndex: indexOfEmailId,
|
||||||
(failure) => false,
|
|
||||||
(success) => success is GettingEmailsByIds &&
|
|
||||||
success.loadingIndex == indexOfEmailId,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-9
@@ -1,17 +1,42 @@
|
|||||||
|
import 'package:core/utils/platform_info.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/bindings/email_bindings.dart';
|
import 'package:tmail_ui_user/features/email/presentation/bindings/email_bindings.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:model/email/email_in_thread_status.dart';
|
import 'package:model/email/email_in_thread_status.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/presentation/action/thread_detail_ui_action.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';
|
||||||
|
|
||||||
extension HandleGetEmailsByIdsSuccess on ThreadDetailController {
|
extension HandleGetEmailsByIdsSuccess on ThreadDetailController {
|
||||||
void handleGetEmailsByIdsSuccess(GetEmailsByIdsSuccess success) {
|
Future<void> handleGetEmailsByIdsSuccess(GetEmailsByIdsSuccess success) async {
|
||||||
final currentRoute = mailboxDashBoardController.dashboardRoute.value;
|
final currentRoute = mailboxDashBoardController.dashboardRoute.value;
|
||||||
if (currentRoute != DashboardRoutes.threadDetailed) {
|
if (currentRoute != DashboardRoutes.threadDetailed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (success is PreloadEmailsByIdsSuccess &&
|
||||||
|
success.presentationEmails.isNotEmpty) {
|
||||||
|
final email = success.presentationEmails.first;
|
||||||
|
final emailId = email.id;
|
||||||
|
if (emailId == null) return;
|
||||||
|
EmailBindings(currentEmailId: emailId).dependencies();
|
||||||
|
currentExpandedEmailId.value = emailId;
|
||||||
|
final isInternetConnected = await networkConnectionController.hasInternetConnection();
|
||||||
|
|
||||||
|
if (isThreadDetailEnabled && isInternetConnected) {
|
||||||
|
loadThreadOnThreadChanged = false;
|
||||||
|
mailboxDashBoardController.dispatchThreadDetailUIAction(
|
||||||
|
LoadThreadDetailAfterSelectedEmailAction(email.threadId!),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
emailIdsPresentation[emailId] = emailIdsPresentation[emailId]?.copyWith(
|
||||||
|
emailInThreadStatus: EmailInThreadStatus.expanded,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final selectedEmailId = mailboxDashBoardController.selectedEmail.value?.id;
|
final selectedEmailId = mailboxDashBoardController.selectedEmail.value?.id;
|
||||||
|
if (selectedEmailId == null) return;
|
||||||
|
|
||||||
for (var presentationEmail in success.presentationEmails) {
|
for (var presentationEmail in success.presentationEmails) {
|
||||||
if (presentationEmail.id == null) continue;
|
if (presentationEmail.id == null) continue;
|
||||||
@@ -24,16 +49,17 @@ extension HandleGetEmailsByIdsSuccess on ThreadDetailController {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (presentationEmail.id == selectedEmailId) {
|
|
||||||
EmailBindings(currentEmailId: presentationEmail.id).dependencies();
|
|
||||||
currentExpandedEmailId.value = presentationEmail.id;
|
|
||||||
}
|
|
||||||
emailIdsPresentation[presentationEmail.id!] = presentationEmail.copyWith(
|
emailIdsPresentation[presentationEmail.id!] = presentationEmail.copyWith(
|
||||||
emailInThreadStatus: presentationEmail.id == selectedEmailId
|
emailInThreadStatus: EmailInThreadStatus.collapsed,
|
||||||
? EmailInThreadStatus.expanded
|
|
||||||
: EmailInThreadStatus.collapsed,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
threadDetailManager.currentMobilePageViewIndex.refresh();
|
if (currentExpandedEmailId.value != null) {
|
||||||
|
emailIdsPresentation[currentExpandedEmailId.value!] = emailIdsPresentation[currentExpandedEmailId.value!]?.copyWith(
|
||||||
|
emailInThreadStatus: EmailInThreadStatus.expanded,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (PlatformInfo.isMobile) {
|
||||||
|
threadDetailManager.currentMobilePageViewIndex.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+9
-1
@@ -34,7 +34,15 @@ extension InitializeThreadDetailEmails on ThreadDetailController {
|
|||||||
))));
|
))));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_currentThreadOnlyContainsSelectedEmail(selectedEmailId)) return;
|
if (_currentThreadOnlyContainsSelectedEmail(selectedEmailId) &&
|
||||||
|
mailboxDashBoardController.selectedEmail.value != null) {
|
||||||
|
if (!loadThreadOnThreadChanged) {
|
||||||
|
consumeState(Stream.value(Right(GetEmailsByIdsSuccess(
|
||||||
|
[mailboxDashBoardController.selectedEmail.value!],
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
consumeState(getEmailsByIdsInteractor.execute(
|
consumeState(getEmailsByIdsInteractor.execute(
|
||||||
session!,
|
session!,
|
||||||
|
|||||||
+1
@@ -21,6 +21,7 @@ extension ThreadDetailOnSelectedEmailUpdated on ThreadDetailController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emailIdsPresentation.clear();
|
||||||
scrollController ??= ScrollController();
|
scrollController ??= ScrollController();
|
||||||
|
|
||||||
if (currentExpandedEmailId.value == null) {
|
if (currentExpandedEmailId.value == null) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import 'package:tmail_ui_user/features/thread_detail/presentation/extension/on_t
|
|||||||
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/on_thread_page_changed.dart';
|
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/on_thread_page_changed.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/features/thread_detail/presentation/widgets/thread_detail_cupertino_loading_widget.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
|
||||||
import '../../manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
|
import '../../manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
|
||||||
@@ -109,9 +110,16 @@ class ThreadDetailView extends GetWidget<ThreadDetailController> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final nonPageViewThread = Expanded(
|
final nonPageViewThread = Expanded(
|
||||||
child: SingleChildScrollView(
|
child: Stack(
|
||||||
controller: controller.scrollController,
|
children: [
|
||||||
child: threadBody,
|
SingleChildScrollView(
|
||||||
|
controller: controller.scrollController,
|
||||||
|
child: threadBody,
|
||||||
|
),
|
||||||
|
ThreadDetailCupertinoLoadingWidget(
|
||||||
|
threadDetailController: controller,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -122,18 +130,25 @@ class ThreadDetailView extends GetWidget<ThreadDetailController> {
|
|||||||
if (currentIndex == -1) return nonPageViewThread;
|
if (currentIndex == -1) return nonPageViewThread;
|
||||||
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: PageView.builder(
|
child: Stack(
|
||||||
controller: manager.pageController,
|
children: [
|
||||||
itemCount: manager.isThreadDetailEnabled
|
PageView.builder(
|
||||||
? manager.availableThreadIds.length
|
controller: manager.pageController,
|
||||||
: manager.currentDisplayedEmails.length,
|
itemCount: manager.isThreadDetailEnabled
|
||||||
itemBuilder: (context, index) {
|
? manager.availableThreadIds.length
|
||||||
if (index != currentIndex) {
|
: manager.currentDisplayedEmails.length,
|
||||||
return const SizedBox.shrink();
|
itemBuilder: (context, index) {
|
||||||
}
|
if (index != currentIndex) {
|
||||||
return SingleChildScrollView(child: threadBody);
|
return const SizedBox.shrink();
|
||||||
},
|
}
|
||||||
onPageChanged: controller.onThreadPageChanged,
|
return SingleChildScrollView(child: threadBody);
|
||||||
|
},
|
||||||
|
onPageChanged: controller.onThreadPageChanged,
|
||||||
|
),
|
||||||
|
ThreadDetailCupertinoLoadingWidget(
|
||||||
|
threadDetailController: controller,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:core/presentation/views/loading/cupertino_loading_widget.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.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/presentation/thread_detail_controller.dart';
|
||||||
|
|
||||||
|
class ThreadDetailCupertinoLoadingWidget extends StatelessWidget {
|
||||||
|
const ThreadDetailCupertinoLoadingWidget({
|
||||||
|
super.key,
|
||||||
|
required this.threadDetailController,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ThreadDetailController threadDetailController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Obx(() {
|
||||||
|
return threadDetailController.viewState.value.fold(
|
||||||
|
(failure) => const SizedBox.shrink(),
|
||||||
|
(success) =>
|
||||||
|
success is GettingThreadById || success is GettingEmailsByIds
|
||||||
|
? const Center(child: CupertinoLoadingWidget())
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
-19
@@ -3,6 +3,10 @@ import 'package:core/presentation/resources/image_paths.dart';
|
|||||||
import 'package:core/presentation/views/loading/cupertino_loading_widget.dart';
|
import 'package:core/presentation/views/loading/cupertino_loading_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:get/instance_manager.dart';
|
||||||
|
import 'package:get/state_manager.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/presentation/thread_detail_controller.dart';
|
||||||
|
|
||||||
class ThreadDetailLoadMoreCircle extends StatefulWidget {
|
class ThreadDetailLoadMoreCircle extends StatefulWidget {
|
||||||
const ThreadDetailLoadMoreCircle({
|
const ThreadDetailLoadMoreCircle({
|
||||||
@@ -10,13 +14,13 @@ class ThreadDetailLoadMoreCircle extends StatefulWidget {
|
|||||||
required this.count,
|
required this.count,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
required this.imagePaths,
|
required this.imagePaths,
|
||||||
required this.isLoading,
|
required this.loadingIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
final int count;
|
final int count;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final ImagePaths imagePaths;
|
final ImagePaths imagePaths;
|
||||||
final bool isLoading;
|
final int loadingIndex;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ThreadDetailLoadMoreCircle> createState() => _ThreadDetailLoadMoreCircleState();
|
State<ThreadDetailLoadMoreCircle> createState() => _ThreadDetailLoadMoreCircleState();
|
||||||
@@ -24,6 +28,7 @@ class ThreadDetailLoadMoreCircle extends StatefulWidget {
|
|||||||
|
|
||||||
class _ThreadDetailLoadMoreCircleState extends State<ThreadDetailLoadMoreCircle> {
|
class _ThreadDetailLoadMoreCircleState extends State<ThreadDetailLoadMoreCircle> {
|
||||||
final _isHover = ValueNotifier(false);
|
final _isHover = ValueNotifier(false);
|
||||||
|
final threadDetailController = Get.find<ThreadDetailController>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@@ -67,26 +72,34 @@ class _ThreadDetailLoadMoreCircleState extends State<ThreadDetailLoadMoreCircle>
|
|||||||
child: ValueListenableBuilder(
|
child: ValueListenableBuilder(
|
||||||
valueListenable: _isHover,
|
valueListenable: _isHover,
|
||||||
builder: (context, isHover, child) {
|
builder: (context, isHover, child) {
|
||||||
if (widget.isLoading) {
|
return Obx(() {
|
||||||
return const SizedBox(
|
final isLoading = threadDetailController.viewState.value.fold(
|
||||||
width: 24,
|
(failure) => false,
|
||||||
height: 24,
|
(success) => success is GettingEmailsByIds &&
|
||||||
child: CupertinoLoadingWidget(),
|
success.loadingIndex == widget.loadingIndex,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (isHover) {
|
if (isLoading) {
|
||||||
return child ?? const SizedBox.shrink();
|
return const SizedBox(
|
||||||
}
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: CupertinoLoadingWidget(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Text(
|
if (isHover) {
|
||||||
'${widget.count}',
|
return child ?? const SizedBox.shrink();
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
}
|
||||||
fontWeight: FontWeight.normal,
|
|
||||||
height: 24 / 16,
|
return Text(
|
||||||
letterSpacing: -0.1,
|
'${widget.count}',
|
||||||
),
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
);
|
fontWeight: FontWeight.normal,
|
||||||
|
height: 24 / 16,
|
||||||
|
letterSpacing: -0.1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
child: SvgPicture.asset(widget.imagePaths.icExpandArrows),
|
child: SvgPicture.asset(widget.imagePaths.icExpandArrows),
|
||||||
),
|
),
|
||||||
|
|||||||
+2
@@ -70,6 +70,8 @@ void main() {
|
|||||||
threadId: ThreadId(Id('1')),
|
threadId: ThreadId(Id('1')),
|
||||||
);
|
);
|
||||||
when(threadDetailController.currentExpandedEmailId).thenReturn(Rxn());
|
when(threadDetailController.currentExpandedEmailId).thenReturn(Rxn());
|
||||||
|
when(threadDetailController.emailIdsPresentation)
|
||||||
|
.thenReturn(<EmailId, PresentationEmail?>{}.obs);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
threadDetailController.onSelectedEmailUpdated(
|
threadDetailController.onSelectedEmailUpdated(
|
||||||
|
|||||||
Reference in New Issue
Block a user