TF-3643 Thread Detail get emails meta data method
TF-3643 Thread Detail cache email with thread id TF-3643 Thread Detail view thread detail TF-3643 Thread Detail [Part 2 fixup] remove ThreadDetailController dependency from MailboxDashboardController TF-3643 Thread Detail [Part 2 fixup] remove EmailSupervisorController dependency from ThreadDetailController TF-3643 Thread Detail [Part 2 fixup] move isSearchRunning check into ThreadDetailController TF-3643 Thread Detail [Part 2 fixup] ensure GetEmailsByIdsInteractor performance TF-3643 Thread Detail [Part 2 fixup] unit test loadMoreThreadDetailEmails TF-3643 Thread Detail [Part 2 fixup] unit test getEmailIdsToLoad TF-3643 Thread Detail [Part 2 fixup] optimize ThreadDetailBinding bindingsDataSource TF-3643 Thread Detail [Part 2 fixup] optimize getThreadDetailLoadingView TF-3643 Thread Detail [Part 2 fixup] readd unique ValueKey for HtmlContentViewerOnWebWidget TF-3643 Thread Detail [Part 2 fixup] unit test initializeThreadDetailEmails TF-3643 Thread Detail [Part 3 fixup] Update private action button methods TF-3643 Thread Detail [Part 4 fixup] Collapsed email preview 65 characters max TF-3643 Thread Detail [Part 4 fixup] Remove personal scripts TF-3643 Thread Detail move EmailInThreadStatus into PresentationEmail TF-3643 Thread Detail refactor toggle collapse expand TF-3643 Thread Detail EmailViewAppBarWidget required parameters TF-3643 Thread Detail tap avatar toggle expansion TF-3643 Thread Detail fix cannot open single email TF-3643 Thread Detail fix open thread first time blank view TF-3643 Thread Detail fix thread detail UI TF-3643 Thread Detail fix round bottom view TF-3643 Thread Detail fix round bottom view TF-3643 Thread Detail bottom actions depend on current expanded email TF-3643 Thread Detail hide next previous actions TF-3643 Thread Detail fix load more show initial loading view TF-3643 Thread Detail fix cannot view single email TF-3643 Thread Detail fix bottom place holder not aligned TF-3643 Thread Detail fix back to search view TF-3643 Thread Detail fix display 65 character preview collapsed email TF-3643 Thread Detail fix search not work TF-3643 Thread Detail fix bottom place holder UI TF-3643 Thread Detail fix expand view TF-3643 Thread Detail jump to top of last email view TF-3643 Thread Detail remove toMe condition of filtering thread TF-3643 Thread Detail fix sort thread detail TF-3643 Thread Detail fix assert not work in release TF-3643 Thread Detail add load more test case <20 TF-3643 Thread Detail remove the use of currentThreadId TF-3643 Thread Detail remove the use of selectedEmail in SingleEmailController TF-3643 Thread Detail fix unit test SingleEmailController calendar TF-3643 Thread Detail disable 2 way scroll control TF-3643 Thread Detail allow thread to load sent email incase thread only contains 1 email TF-3643 Thread Detail disable single email page view TF-3643 Thread Detail update emailsNotLoadedCount name TF-3643 Thread Detail remove collapsed email char limit TF-3643 Thread Detail fix CI TF-3643 Thread Detail unit test handleGetEmailIdsByThreadIdSuccess TF-3643 Thread Detail make _currentEmailId private TF-3643 Thread Detail fix search click users TF-3643 Thread Detail fix scroll jump TF-3643 Thread Detail fix scroll jump TF-3643 Thread Detail fix web back action TF-3643 Thread Detail round bottom actions TF-3643 Thread Detail fix tablet large empty email TF-3643 Thread Detail fix email subject selectable TF-3643 Thread Detail fix email single view with top divider TF-3643 Thread Detail fix email cache threadId missing TF-3643 Thread Detail fix filter sent email in thread details TF-3643 Thread Detail fix select text TF-3643 Thread Detail fix subject alignment TF-3643 Thread Detail fix subject alignment TF-3643 Thread Detail fix tablet large empty email TF-3643 Thread Detail add nullcheck for _jumpScrollViewToTopOfEmail TF-3643 Thread Detail decouple ThreadDetailController from SingleEmailController TF-3643 Thread Detail combine emailIds to emailIdsPresentation TF-3643 Thread Detail remove currentEmailLoaded obx listener of SingleEmailController TF-3643 Thread Detail replace threadAction with an email ui action TF-3643 Thread Detail fix top and bottom bar delay displaying TF-3643 Thread Detail update ReplyForwardBottomBarAction to PerformEmailActionInThreadDetailAction TF-3643 Thread Detail use getOwnEmailAddress in ThreadDetailAppBar TF-3643 Thread Detail add TextOverflow.ellipsis to EmailSubjectWidget TF-3643 Thread Detail fix round border threadDetailLoadingView
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:model/email/email_action_type.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/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/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_back_button.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class ThreadDetailAppBar extends StatelessWidget {
|
||||
const ThreadDetailAppBar({
|
||||
super.key,
|
||||
required this.responsiveUtils,
|
||||
required this.imagePaths,
|
||||
required this.isSearchRunning,
|
||||
required this.closeThreadDetailAction,
|
||||
required this.lastEmailOfThread,
|
||||
required this.ownUserName,
|
||||
this.mailboxContain,
|
||||
this.optionWidgets = const [],
|
||||
this.onEmailActionClick,
|
||||
this.onMoreActionClick,
|
||||
this.emailLoaded,
|
||||
});
|
||||
|
||||
final ResponsiveUtils responsiveUtils;
|
||||
final ImagePaths imagePaths;
|
||||
final bool isSearchRunning;
|
||||
final void Function(BuildContext context) closeThreadDetailAction;
|
||||
final PresentationEmail? lastEmailOfThread;
|
||||
final String ownUserName;
|
||||
final PresentationMailbox? mailboxContain;
|
||||
final List<Widget> optionWidgets;
|
||||
final OnEmailActionClick? onEmailActionClick;
|
||||
final OnMoreActionClick? onMoreActionClick;
|
||||
final EmailLoaded? emailLoaded;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(
|
||||
emailLoaded?.emailCurrent?.listPost ?? '',
|
||||
);
|
||||
|
||||
final child = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Container(
|
||||
height: PlatformInfo.isIOS
|
||||
? EmailViewAppBarWidgetStyles.heightIOS(context, responsiveUtils)
|
||||
: EmailViewAppBarWidgetStyles.height,
|
||||
padding: PlatformInfo.isIOS
|
||||
? EmailViewAppBarWidgetStyles.paddingIOS(context, responsiveUtils)
|
||||
: EmailViewAppBarWidgetStyles.padding,
|
||||
margin: !PlatformInfo.isMobile && responsiveUtils.isDesktop(context)
|
||||
? const EdgeInsetsDirectional.only(end: 16)
|
||||
: EdgeInsets.zero,
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: EmailViewAppBarWidgetStyles.bottomBorderColor,
|
||||
width: EmailViewAppBarWidgetStyles.bottomBorderWidth,
|
||||
),
|
||||
),
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(EmailViewAppBarWidgetStyles.radius),
|
||||
),
|
||||
color: EmailViewAppBarWidgetStyles.backgroundColor,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (_supportDisplayMailboxNameTitle(context))
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: EmailViewBackButton(
|
||||
imagePaths: imagePaths,
|
||||
onBackAction: () => closeThreadDetailAction(context),
|
||||
mailboxContain: mailboxContain,
|
||||
isSearchActivated: isSearchRunning,
|
||||
maxWidth: constraints.maxWidth,
|
||||
),
|
||||
),
|
||||
),
|
||||
...optionWidgets,
|
||||
if (lastEmailOfThread != null) ...[
|
||||
TMailButtonWidget.fromIcon(
|
||||
icon: imagePaths.icReply,
|
||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
||||
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
||||
tooltipMessage: AppLocalizations.of(context).reply,
|
||||
backgroundColor: Colors.transparent,
|
||||
onTapActionCallback: () => onEmailActionClick?.call(
|
||||
lastEmailOfThread!,
|
||||
EmailActionType.reply,
|
||||
),
|
||||
),
|
||||
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(
|
||||
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(
|
||||
icon: imagePaths.icMoreVertical,
|
||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
||||
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
||||
backgroundColor: Colors.transparent,
|
||||
tooltipMessage: AppLocalizations.of(context).more,
|
||||
onTapActionCallback: responsiveUtils.isScreenWithShortestSide(context)
|
||||
? () => onMoreActionClick?.call(lastEmailOfThread!, null)
|
||||
: null,
|
||||
onTapActionAtPositionCallback: !responsiveUtils.isScreenWithShortestSide(context)
|
||||
? (position) => onMoreActionClick?.call(lastEmailOfThread!, position)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (_, __) {
|
||||
closeThreadDetailAction(context);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
bool _supportDisplayMailboxNameTitle(BuildContext context) {
|
||||
final isSupportedDevice = PlatformInfo.isWeb
|
||||
? responsiveUtils.isDesktop(context)
|
||||
|| responsiveUtils.isMobile(context)
|
||||
|| responsiveUtils.isTablet(context)
|
||||
: responsiveUtils.isPortraitMobile(context)
|
||||
|| responsiveUtils.isLandscapeMobile(context)
|
||||
|| responsiveUtils.isTablet(context);
|
||||
return isSupportedDevice || isSearchRunning;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||
import 'package:core/presentation/views/text/text_overflow_builder.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:model/email/presentation_email.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/widgets/email_sender_builder.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_subject_widget.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/information_sender_and_receiver_builder.dart';
|
||||
|
||||
class ThreadDetailCollapsedEmail extends StatelessWidget {
|
||||
const ThreadDetailCollapsedEmail({
|
||||
super.key,
|
||||
required this.presentationEmail,
|
||||
required this.showSubject,
|
||||
required this.imagePaths,
|
||||
required this.responsiveUtils,
|
||||
this.openEmailAddressDetailAction,
|
||||
this.mailboxContain,
|
||||
this.emailLoaded,
|
||||
this.onEmailActionClick,
|
||||
this.onMoreActionClick,
|
||||
this.onToggleThreadDetailCollapseExpand,
|
||||
});
|
||||
|
||||
final PresentationEmail presentationEmail;
|
||||
final bool showSubject;
|
||||
final ImagePaths imagePaths;
|
||||
final ResponsiveUtils responsiveUtils;
|
||||
final OnOpenEmailAddressDetailAction? openEmailAddressDetailAction;
|
||||
final PresentationMailbox? mailboxContain;
|
||||
final EmailLoaded? emailLoaded;
|
||||
final OnEmailActionClick? onEmailActionClick;
|
||||
final OnMoreActionClick? onMoreActionClick;
|
||||
final VoidCallback? onToggleThreadDetailCollapseExpand;
|
||||
|
||||
String get preview => presentationEmail.getPartialContent();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: AppColor.colorDividerEmailView,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: onToggleThreadDetailCollapseExpand,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (showSubject)
|
||||
EmailSubjectWidget(presentationEmail: presentationEmail)
|
||||
else
|
||||
const SizedBox(height: 16),
|
||||
InformationSenderAndReceiverBuilder(
|
||||
emailSelected: presentationEmail,
|
||||
responsiveUtils: responsiveUtils,
|
||||
imagePaths: imagePaths,
|
||||
emailLoaded: emailLoaded,
|
||||
isInsideThreadDetailView: true,
|
||||
onEmailActionClick: onEmailActionClick,
|
||||
onMoreActionClick: onMoreActionClick,
|
||||
openEmailAddressDetailAction: openEmailAddressDetailAction,
|
||||
showRecipients: false,
|
||||
onTapAvatarActionClick: onToggleThreadDetailCollapseExpand,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextOverflowBuilder(
|
||||
preview,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/views/loading/cupertino_loading_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class ThreadDetailLoadMoreCircle extends StatefulWidget {
|
||||
const ThreadDetailLoadMoreCircle({
|
||||
super.key,
|
||||
required this.count,
|
||||
required this.onTap,
|
||||
required this.imagePaths,
|
||||
required this.isLoading,
|
||||
});
|
||||
|
||||
final int count;
|
||||
final VoidCallback onTap;
|
||||
final ImagePaths imagePaths;
|
||||
final bool isLoading;
|
||||
|
||||
@override
|
||||
State<ThreadDetailLoadMoreCircle> createState() => _ThreadDetailLoadMoreCircleState();
|
||||
}
|
||||
|
||||
class _ThreadDetailLoadMoreCircleState extends State<ThreadDetailLoadMoreCircle> {
|
||||
final _isHover = ValueNotifier(false);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_isHover.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
color: Colors.white,
|
||||
child: Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Container(
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
border: Border.symmetric(horizontal: BorderSide(
|
||||
color: AppColor.colorDividerEmailView,
|
||||
width: 0.5,
|
||||
)),
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: widget.onTap,
|
||||
onHover: (value) => _isHover.value = value,
|
||||
child: Container(
|
||||
margin: const EdgeInsetsDirectional.only(start: 16),
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: AppColor.colorDividerEmailView,
|
||||
width: 0.5,
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.white,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: ValueListenableBuilder(
|
||||
valueListenable: _isHover,
|
||||
builder: (context, isHover, child) {
|
||||
if (widget.isLoading) {
|
||||
return const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CupertinoLoadingWidget(),
|
||||
);
|
||||
}
|
||||
|
||||
if (isHover) {
|
||||
return child ?? const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Text(
|
||||
'${widget.count}',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.normal,
|
||||
height: 24 / 16,
|
||||
letterSpacing: -0.1,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: SvgPicture.asset(widget.imagePaths.icExpandArrows),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user