TF-460 Separate the header of MailboxDashboard on the browser

This commit is contained in:
dab246
2022-04-25 15:56:36 +07:00
committed by Dat H. Pham
parent d0a54a2652
commit 52fd989272
36 changed files with 1033 additions and 643 deletions
+6
View File
@@ -0,0 +1,6 @@
import 'package:equatable/equatable.dart';
abstract class Action with EquatableMixin {}
abstract class UIAction extends Action {}
@@ -0,0 +1,13 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
mixin AppLoaderMixin {
Widget get loadingWidget {
return Center(child: SizedBox(
width: 24,
height: 24,
child: CupertinoActivityIndicator(color: AppColor.colorLoading)));
}
}
@@ -19,8 +19,8 @@ mixin PopupContextMenuActionMixin {
context: context,
position: position ?? RelativeRect.fromLTRB(16, 40, 16, 16),
color: Colors.white,
elevation: 5,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
items: popupMenuItems);
}
@@ -42,8 +42,8 @@ import 'package:tmail_ui_user/features/composer/presentation/model/screen_displa
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
import 'package:tmail_ui_user/features/upload/domain/state/local_file_picker_state.dart';
import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
@@ -782,7 +782,7 @@ class ComposerController extends BaseController {
void closeComposerWeb() {
FocusManager.instance.primaryFocus?.unfocus();
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.none);
mailboxDashBoardController.dispatchAction(CloseComposeEmailAction());
}
void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) {
@@ -798,7 +798,7 @@ class ComposerController extends BaseController {
void deleteComposer() {
FocusManager.instance.primaryFocus?.unfocus();
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.none);
mailboxDashBoardController.dispatchAction(CloseComposeEmailAction());
}
void toggleDisplayAttachments() {
@@ -23,11 +23,6 @@ import 'package:tmail_ui_user/features/login/domain/repository/credential_reposi
class EmailBindings extends BaseBindings {
@override
void dependencies() {
super.dependencies();
}
@override
void bindingsController() {
Get.put(EmailController(
@@ -35,9 +35,9 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_dialog_builder.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
@@ -86,7 +86,7 @@ class EmailController extends BaseController {
@override
void onInit() {
mailboxDashBoardController.selectedEmail.listen((presentationEmail) {
log('EmailController::onReady(): ${presentationEmail.toString()}');
log('EmailController::onReady(): selectedEmail: ${presentationEmail.toString()}');
if (_currentEmailId != presentationEmail?.id) {
_currentEmailId = presentationEmail?.id;
_resetToOriginalValue();
@@ -546,8 +546,8 @@ class EmailController extends BaseController {
emailAddress: emailAddress,
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
if (kIsWeb) {
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
if (mailboxDashBoardController.dashBoardAction.value is! ComposeEmailAction) {
mailboxDashBoardController.dispatchAction(ComposeEmailAction(arguments: arguments));
}
} else {
push(AppRoutes.COMPOSER, arguments: arguments);
@@ -565,8 +565,8 @@ class EmailController extends BaseController {
emailAddress: emailAddress,
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
if (kIsWeb) {
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
if (mailboxDashBoardController.dashBoardAction.value is! ComposeEmailAction) {
mailboxDashBoardController.dispatchAction(ComposeEmailAction(arguments: arguments));
}
if (Get.currentRoute == AppRoutes.EMAIL) {
popBack();
@@ -629,8 +629,8 @@ class EmailController extends BaseController {
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
if (kIsWeb) {
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
if (mailboxDashBoardController.dashBoardAction.value is! ComposeEmailAction) {
mailboxDashBoardController.dispatchAction(ComposeEmailAction(arguments: arguments));
}
if (Get.currentRoute == AppRoutes.EMAIL) {
popBack();
@@ -643,8 +643,8 @@ class EmailController extends BaseController {
void composeEmailAction() {
if (kIsWeb) {
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: ComposerArguments());
if (mailboxDashBoardController.dashBoardAction.value is! ComposeEmailAction) {
mailboxDashBoardController.dispatchAction(ComposeEmailAction(arguments: ComposerArguments()));
}
if (Get.currentRoute == AppRoutes.EMAIL) {
popBack();
+72 -107
View File
@@ -15,11 +15,10 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/app_bar_mail_w
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_file_tile_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/bottom_bar_mail_widget_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:filesize/filesize.dart';
class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectionMixin {
class EmailView extends GetView with NetworkConnectionMixin {
final emailController = Get.find<EmailController>();
final responsiveUtils = Get.find<ResponsiveUtils>();
@@ -27,6 +26,8 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
static const int LIMIT_ADDRESS_DISPLAY = 1;
EmailView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
@@ -37,58 +38,22 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
child: Scaffold(
backgroundColor: responsiveUtils.isDesktop(context) ? AppColor.colorBgDesktop : Colors.white,
body: Stack(children: [
Container(
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
decoration: responsiveUtils.isTabletLarge(context)
? BoxDecoration(border: Border(left: BorderSide(color: AppColor.colorLineLeftEmailView, width: 1.0)))
: null,
child: SafeArea(
right: responsiveUtils.isMobileDevice(context) && responsiveUtils.isLandscape(context),
left: responsiveUtils.isMobileDevice(context) && responsiveUtils.isLandscape(context),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (responsiveUtils.isDesktop(context))
Container(
color: Colors.white,
padding: EdgeInsets.only(right: 10, top: 16, bottom: 10),
child: _buildHeader(context)),
Expanded(child: _buildBody(context)),
]
)
),
),
Row(children: [
if ((!kIsWeb && !responsiveUtils.isMobile(context)) || (kIsWeb && responsiveUtils.isTabletLarge(context)))
const VerticalDivider(color: AppColor.lineItemListColor, width: 1, thickness: 0.2),
Expanded(child: SafeArea(
right: responsiveUtils.isLandscapeMobile(context),
left: responsiveUtils.isLandscapeMobile(context),
child: _buildBody(context)))
]),
Obx(() => !emailController.mailboxDashBoardController.isNetworkConnectionAvailable() && (responsiveUtils.isMobile(context) || responsiveUtils.isTablet(context))
? Align(alignment: Alignment.bottomCenter, child: buildNetworkConnectionWidget(context))
: SizedBox.shrink()),
: const SizedBox.shrink()),
])
)
);
}
Widget _buildHeader(BuildContext context) {
return Row(children: [
Spacer(),
Padding(
padding: EdgeInsets.only(right: 16),
child: (AvatarBuilder()
..text(emailController.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '')
..backgroundColor(Colors.white)
..textColor(Colors.black)
..context(context)
..addOnTapAvatarActionWithPositionClick((position) => openUserSettingAction(
context,
position,
popupMenuUserSettingActionTile(context, () => emailController.mailboxDashBoardController.logoutAction())))
..addBoxShadows([BoxShadow(
color: AppColor.colorShadowBgContentEmail,
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))])
..size(48))
.build()),
]);
}
Widget _buildBody(BuildContext context) {
return Container(
decoration: responsiveUtils.isDesktop(context)
@@ -97,17 +62,17 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
border: Border.all(color: AppColor.colorBorderBodyThread, width: 1),
color: Colors.white)
: null,
margin: responsiveUtils.isDesktop(context) ? EdgeInsets.all(16) : EdgeInsets.zero,
padding: responsiveUtils.isDesktop(context) ? EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 3) : EdgeInsets.zero,
margin: responsiveUtils.isDesktop(context) ? const EdgeInsets.all(16) : EdgeInsets.zero,
padding: responsiveUtils.isDesktop(context) ? const EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 3) : EdgeInsets.zero,
child: Column(children: [
_buildAppBar(context),
if (responsiveUtils.isDesktop(context)) SizedBox(height: 5),
if (responsiveUtils.isDesktop(context)) const SizedBox(height: 5),
Obx(() => emailController.currentEmail != null && !responsiveUtils.isDesktop(context)
? _buildDivider() : SizedBox.shrink()),
? _buildDivider() : const SizedBox.shrink()),
Expanded(child: _buildEmailBody(context)),
Obx(() => emailController.currentEmail != null
? Divider(color: AppColor.colorDividerEmailView, height: 1)
: SizedBox.shrink()),
? const Divider(color: AppColor.colorDividerEmailView, height: 1)
: const SizedBox.shrink()),
_buildBottomBar(context),
])
);
@@ -115,13 +80,13 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
Widget _buildDivider({EdgeInsets? edgeInsets}){
return Padding(
padding: edgeInsets ?? EdgeInsets.symmetric(horizontal: 16),
child: Divider(color: AppColor.colorDividerEmailView, height: 0.5));
padding: edgeInsets ?? const EdgeInsets.symmetric(horizontal: 16),
child: const Divider(color: AppColor.colorDividerEmailView, height: 0.5));
}
Widget _buildAppBar(BuildContext context) {
return Obx(() => Padding(
padding: EdgeInsets.only(top: 6),
padding: const EdgeInsets.only(top: 6),
child: (AppBarMailWidgetBuilder(context, imagePaths, responsiveUtils, emailController.currentEmail, emailController.currentMailbox)
..onBackActionClick(() => emailController.backToThreadView(context))
..addOnEmailActionClick((email, action) => emailController.handleEmailAction(context, email, action))
@@ -154,7 +119,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
return _buildEmailMessage(context);
} else {
return SingleChildScrollView(
physics : ClampingScrollPhysics(),
physics : const ClampingScrollPhysics(),
child: Container(
margin: EdgeInsets.zero,
width: double.infinity,
@@ -176,12 +141,12 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
return Text(
AppLocalizations.of(context).no_mail_selected,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, color: AppColor.mailboxTextColor, fontWeight: FontWeight.bold));
style: const TextStyle(fontSize: 25, color: AppColor.mailboxTextColor, fontWeight: FontWeight.bold));
}
Widget _buildEmailSubject(BuildContext context) {
return Padding(
padding: EdgeInsets.only(right: 16),
padding: const EdgeInsets.only(right: 16),
child: SelectableText(
'${emailController.mailboxDashBoardController.selectedEmail.value?.getEmailTitle()}',
maxLines: kIsWeb ? 3 : null,
@@ -196,7 +161,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
Widget _buildEmailMessage(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 16, right: 16, top: 10),
padding: const EdgeInsets.only(left: 16, right: 16, top: 10),
alignment: Alignment.center,
color: Colors.white,
child: LayoutBuilder(
@@ -209,22 +174,22 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
Expanded(child: _buildEmailSubject(context)),
_buildEmailTime(context),
]),
if (responsiveUtils.isDesktop(context)) SizedBox(height: 20),
if (!responsiveUtils.isDesktop(context)) _buildDivider(edgeInsets: EdgeInsets.only(top: 16)),
if (responsiveUtils.isDesktop(context)) const SizedBox(height: 20),
if (!responsiveUtils.isDesktop(context)) _buildDivider(edgeInsets: const EdgeInsets.only(top: 16)),
Obx(() => emailController.currentEmail != null
? _buildEmailAddress(
context,
emailController.currentEmail!,
emailController.emailAddressExpandMode.value,
emailController.isDisplayFullEmailAddress.value)
: SizedBox.shrink()),
_buildDivider(edgeInsets: EdgeInsets.only(top: 8)),
: const SizedBox.shrink()),
_buildDivider(edgeInsets: const EdgeInsets.only(top: 8)),
_buildAttachments(context),
if (kIsWeb)
Expanded(child: _buildEmailContent(context, constraints))
else
_buildEmailContent(context, constraints),
SizedBox(height: 16),
const SizedBox(height: 16),
],
);
})
@@ -240,7 +205,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
pattern: emailController.currentEmail?.receivedAt?.value.toLocal().toPatternForEmailView())}',
maxLines: 1,
overflow:TextOverflow.ellipsis,
style: TextStyle(fontSize: 13, color: AppColor.colorTime)));
style: const TextStyle(fontSize: 13, color: AppColor.colorTime)));
}
Widget _buildEmailAddress(BuildContext context, PresentationEmail email, ExpandMode expandMode, bool isDisplayFull) {
@@ -251,15 +216,15 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
if (email.from.numberEmailAddress() > 0)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.from, isDisplayFull),
if (email.to.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND)
_buildDivider(edgeInsets: EdgeInsets.only(top: kIsWeb ? 8 : 4, bottom: 4)),
_buildDivider(edgeInsets: const EdgeInsets.only(top: kIsWeb ? 8 : 4, bottom: 4)),
if (email.to.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.to, isDisplayFull),
if (email.cc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildDivider(edgeInsets: EdgeInsets.only(top: kIsWeb ? 8 : 4, bottom: 4)),
_buildDivider(edgeInsets: const EdgeInsets.only(top: kIsWeb ? 8 : 4, bottom: 4)),
if (email.cc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.cc, isDisplayFull),
if (email.bcc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildDivider(edgeInsets: EdgeInsets.only(top: kIsWeb ? 8 : 4, bottom: 4)),
_buildDivider(edgeInsets: const EdgeInsets.only(top: kIsWeb ? 8 : 4, bottom: 4)),
if (email.bcc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.bcc, isDisplayFull),
],
@@ -277,10 +242,10 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(top: kIsWeb ? 10: 20),
padding: const EdgeInsets.only(top: kIsWeb ? 10: 20),
child: Text(
'${prefixEmailAddress.asName(context)}:',
style: TextStyle(fontSize: 14, color: AppColor.colorEmailAddressPrefix))),
style: const TextStyle(fontSize: 14, color: AppColor.colorEmailAddressPrefix))),
Expanded(child: _buildEmailAddressWidget(
context,
presentationEmail,
@@ -302,26 +267,26 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
) {
final displayedEmailAddress = isDisplayFull ? listEmailAddress : listEmailAddress.sublist(0, LIMIT_ADDRESS_DISPLAY);
return Padding(
padding: EdgeInsets.only(top: 4),
padding: const EdgeInsets.only(top: 4),
child: Wrap(
children: [
...displayedEmailAddress.map((emailAddress) {
return Padding(
padding: EdgeInsets.only(left: 10),
padding: const EdgeInsets.only(left: 10),
child: GestureDetector(
onTap: () => emailController.openEmailAddressDialog(context, emailAddress),
child: Chip(
labelPadding: EdgeInsets.only(left: 8, right: 8, bottom: 2),
label: Text('${emailAddress.asString()}', maxLines: 1, overflow: TextOverflow.ellipsis),
labelStyle: TextStyle(color: AppColor.colorNameEmail, fontSize: 15, fontWeight: FontWeight.normal),
labelPadding: const EdgeInsets.only(left: 8, right: 8, bottom: 2),
label: Text(emailAddress.asString(), maxLines: 1, overflow: TextOverflow.ellipsis),
labelStyle: const TextStyle(color: AppColor.colorNameEmail, fontSize: 15, fontWeight: FontWeight.normal),
backgroundColor: AppColor.colorEmailAddressTag,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(width: 0, color: AppColor.colorEmailAddressTag),
side: const BorderSide(width: 0, color: AppColor.colorEmailAddressTag),
),
avatar: (AvatarBuilder()
..text('${emailAddress.asString().characters.first.toUpperCase()}')
..addTextStyle(TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.w600))
..text(emailAddress.asString().characters.first.toUpperCase())
..addTextStyle(const TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.w600))
..avatarColor(emailAddress.avatarColors))
.build(),
),
@@ -341,14 +306,14 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
borderRadius: BorderRadius.circular(12),
color: Colors.transparent,
child: Padding(
padding: EdgeInsets.only(top: 4, left: 16),
padding: const EdgeInsets.only(top: 4, left: 16),
child: TextButton(
onPressed: () => emailController.toggleDisplayEmailAddressAction(),
child: Text(
emailController.isExpandEmailAddress
? AppLocalizations.of(context).hide
: AppLocalizations.of(context).details,
style: TextStyle(fontSize: 15, color: AppColor.colorTextButton, fontWeight: FontWeight.normal),
style: const TextStyle(fontSize: 15, color: AppColor.colorTextButton, fontWeight: FontWeight.normal),
),
)
)
@@ -366,15 +331,15 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
return GestureDetector(
onTap: () => emailController.showFullEmailAddress(),
child: Padding(
padding: EdgeInsets.only(left: 8),
padding: const EdgeInsets.only(left: 8),
child: Chip(
labelPadding: EdgeInsets.symmetric(horizontal: 8),
labelPadding: const EdgeInsets.symmetric(horizontal: 8),
label: Text('+${_getRemainCountAddressReceiver(email)}', maxLines: 1, overflow: TextOverflow.ellipsis),
labelStyle: TextStyle(color: AppColor.colorTextButton, fontSize: 15, fontWeight: FontWeight.normal),
labelStyle: const TextStyle(color: AppColor.colorTextButton, fontSize: 15, fontWeight: FontWeight.normal),
backgroundColor: AppColor.colorEmailAddressTag,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(width: 0, color: AppColor.colorEmailAddressTag),
side: const BorderSide(width: 0, color: AppColor.colorEmailAddressTag),
),
),
),
@@ -383,15 +348,15 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
Widget _buildAttachments(BuildContext context) {
return Obx(() => emailController.viewState.value.fold(
(failure) => SizedBox.shrink(),
(failure) => const SizedBox.shrink(),
(success) {
if (success is LoadingState) {
return SizedBox.shrink();
return const SizedBox.shrink();
} else {
final attachments = emailController.attachments.listAttachmentsDisplayedOutSide;
return attachments.isNotEmpty
? _buildAttachmentsBody(context, attachments)
: SizedBox.shrink();
: const SizedBox.shrink();
}
}));
}
@@ -424,7 +389,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
padding: EdgeInsets.zero,
child: _buildAttachmentsHeader(context, attachments)),
GridView.builder(
key: Key('list_attachment'),
key: const Key('list_attachment'),
primary: false,
shrinkWrap: true,
padding: EdgeInsets.only(top: isExpand ? 0 : 16, bottom: 16),
@@ -483,18 +448,18 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${AppLocalizations.of(context).count_attachment(attachments.length)}',
style: TextStyle(fontSize: 12, color: AppColor.baseTextColor)),
AppLocalizations.of(context).count_attachment(attachments.length),
style: const TextStyle(fontSize: 12, color: AppColor.baseTextColor)),
Padding(
padding: EdgeInsets.only(left: 8),
padding: const EdgeInsets.only(left: 8),
child: Text(
'(${filesize(attachments.totalSize(), 1)})',
style: TextStyle(fontSize: 12, color: AppColor.nameUserColor, fontWeight: FontWeight.w500)))
style: const TextStyle(fontSize: 12, color: AppColor.nameUserColor, fontWeight: FontWeight.w500)))
],
),
if (attachments.length > 2)
Padding(
padding: EdgeInsets.only(left: 8),
padding: const EdgeInsets.only(left: 8),
child: IconButton(
icon: SvgPicture.asset(imagePaths.icExpandAttachment,
width: 20,
@@ -508,10 +473,10 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
Widget _buildEmailContent(BuildContext context, BoxConstraints constraints) {
return Obx(() => emailController.viewState.value.fold(
(failure) => SizedBox.shrink(),
(failure) => const SizedBox.shrink(),
(success) {
if (success is LoadingState) {
return Align(alignment: Alignment.topCenter, child: Padding(
return const Align(alignment: Alignment.topCenter, child: Padding(
padding: EdgeInsets.all(16),
child: SizedBox(
width: 30,
@@ -535,7 +500,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
mailtoDelegate: (uri) async => emailController.openMailToLink(uri));
}
} else {
return SizedBox.shrink();
return const SizedBox.shrink();
}
}
}));
@@ -550,15 +515,15 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
Widget _markAsEmailUnreadAction(BuildContext context, PresentationEmail email) {
return (EmailActionCupertinoActionSheetActionBuilder(
Key('mark_as_unread_action'),
const Key('mark_as_unread_action'),
SvgPicture.asset(imagePaths.icUnreadEmail, width: 28, height: 28, fit: BoxFit.fill, color: AppColor.colorTextButton),
AppLocalizations.of(context).mark_as_unread,
email,
iconLeftPadding: responsiveUtils.isMobile(context)
? EdgeInsets.only(left: 12, right: 16)
: EdgeInsets.only(right: 12),
? const EdgeInsets.only(left: 12, right: 16)
: const EdgeInsets.only(right: 12),
iconRightPadding: responsiveUtils.isMobile(context)
? EdgeInsets.only(right: 12)
? const EdgeInsets.only(right: 12)
: EdgeInsets.zero)
..onActionClick((email) => emailController.handleEmailAction(context, email, EmailActionType.markAsUnread)))
.build();
@@ -566,7 +531,7 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
Widget _markAsEmailSpamOrUnSpamAction(BuildContext context, PresentationEmail email) {
return (EmailActionCupertinoActionSheetActionBuilder(
Key('mark_as_spam_or_un_spam_action'),
const Key('mark_as_spam_or_un_spam_action'),
SvgPicture.asset(
emailController.currentMailbox?.isSpam == true ? imagePaths.icNotSpam : imagePaths.icSpam,
width: 28, height: 28, fit: BoxFit.fill, color: AppColor.colorTextButton),
@@ -575,10 +540,10 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
: AppLocalizations.of(context).mark_as_spam,
email,
iconLeftPadding: responsiveUtils.isMobile(context)
? EdgeInsets.only(left: 12, right: 16)
: EdgeInsets.only(right: 12),
? const EdgeInsets.only(left: 12, right: 16)
: const EdgeInsets.only(right: 12),
iconRightPadding: responsiveUtils.isMobile(context)
? EdgeInsets.only(right: 12)
? const EdgeInsets.only(right: 12)
: EdgeInsets.zero)
..onActionClick((email) => emailController.handleEmailAction(context, email,
emailController.currentMailbox?.isSpam == true ? EmailActionType.unSpam : EmailActionType.moveToSpam)))
@@ -587,8 +552,8 @@ class EmailView extends GetView with UserSettingPopupMenuMixin, NetworkConnectio
List<PopupMenuEntry> _popupMenuEmailActionTile(BuildContext context, PresentationEmail email) {
return [
PopupMenuItem(padding: EdgeInsets.symmetric(horizontal: 8), child: _markAsEmailUnreadAction(context, email)),
PopupMenuItem(padding: EdgeInsets.symmetric(horizontal: 8), child: _markAsEmailSpamOrUnSpamAction(context, email)),
PopupMenuItem(padding: const EdgeInsets.symmetric(horizontal: 8), child: _markAsEmailUnreadAction(context, email)),
PopupMenuItem(padding: const EdgeInsets.symmetric(horizontal: 8), child: _markAsEmailSpamOrUnSpamAction(context, email)),
];
}
}
@@ -3,8 +3,8 @@ import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/setting/presentation/model/app_setting.dart';
import 'package:tmail_ui_user/features/setting/presentation/model/reading_pane.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/app_setting.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/reading_pane.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnBackActionClick = void Function();
@@ -44,12 +44,12 @@ class AppBarMailWidgetBuilder {
Widget build() {
return Container(
key: Key('app_bar_messenger_widget'),
key: const Key('app_bar_messenger_widget'),
alignment: Alignment.center,
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
data: const MediaQueryData(padding: EdgeInsets.zero),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@@ -83,10 +83,10 @@ class AppBarMailWidgetBuilder {
return Transform(
transform: Matrix4.translationValues(-10.0, 0.0, 0.0),
child: Text(
'${_currentMailbox?.name?.name.capitalizeFirstEach ?? ''}',
_currentMailbox?.name?.name.capitalizeFirstEach ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 17, color: AppColor.colorTextButton))
style: const TextStyle(fontSize: 17, color: AppColor.colorTextButton))
);
}
@@ -115,7 +115,7 @@ class AppBarMailWidgetBuilder {
}
}),
Padding(
padding: EdgeInsets.only(left: 10, right: 16),
padding: const EdgeInsets.only(left: 10, right: 16),
child: buildIconWebHasPosition(
_context,
tooltip: AppLocalizations.of(_context).more,
@@ -106,64 +106,24 @@ class MailboxController extends BaseMailboxController {
@override
void onInit() {
mailboxDashBoardController.accountId.listen((accountId) {
if (accountId != null) {
getAllMailboxAction(accountId);
}
});
_onMailboxDashBoardListener();
super.onInit();
}
@override
void onReady() {
super.onReady();
mailboxDashBoardController.viewState.listen((state) {
state.fold(
(failure) {
if (failure is EmptyTrashFolderFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
}
},
(success) {
if (success is MarkAsMultipleEmailReadAllSuccess
|| success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is MoveMultipleEmailToMailboxAllSuccess
|| success is MoveMultipleEmailToMailboxHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is DeleteMultipleEmailsPermanentlyAllSuccess
|| success is DeleteMultipleEmailsPermanentlyHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is EmptyTrashFolderSuccess) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is MarkAsEmailReadSuccess
|| success is MoveToMailboxSuccess
|| success is DeleteEmailPermanentlySuccess
|| success is SaveEmailAsDraftsSuccess
|| success is RemoveEmailDraftsSuccess
|| success is SendEmailSuccess
|| success is UpdateEmailDraftsSuccess) {
refreshMailboxChanges();
}
}
);
});
_openMailboxEventController.stream.throttleTime(const Duration(milliseconds: 800)).listen((event) {
_openMailboxEventController.stream.throttleTime(Duration(milliseconds: 800)).listen((event) {
_handleOpenMailbox(event.buildContext, event.presentationMailbox);
});
_initCollapseMailboxCategories();
super.onReady();
}
@override
void onClose() {
mailboxDashBoardController.accountId.close();
mailboxDashBoardController.viewState.close();
searchInputController.dispose();
searchFocus.dispose();
super.onClose();
@@ -216,6 +176,50 @@ class MailboxController extends BaseMailboxController {
@override
void onError(error) {}
void _onMailboxDashBoardListener() {
mailboxDashBoardController.accountId.listen((accountId) {
log('MailboxController::_onMailboxDashBoardListener(): accountId: $accountId');
if (accountId != null) {
getAllMailboxAction(accountId);
}
});
mailboxDashBoardController.viewState.listen((state) {
log('MailboxController::_onMailboxDashBoardListener(): viewState: $viewState');
state.fold((failure) {
if (failure is EmptyTrashFolderFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
}
}, (success) {
if (success is MarkAsMultipleEmailReadAllSuccess ||
success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is MoveMultipleEmailToMailboxAllSuccess ||
success is MoveMultipleEmailToMailboxHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is DeleteMultipleEmailsPermanentlyAllSuccess ||
success is DeleteMultipleEmailsPermanentlyHasSomeEmailFailure) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is EmptyTrashFolderSuccess) {
mailboxDashBoardController.clearState();
refreshMailboxChanges();
} else if (success is MarkAsEmailReadSuccess ||
success is MoveToMailboxSuccess ||
success is DeleteEmailPermanentlySuccess ||
success is SaveEmailAsDraftsSuccess ||
success is RemoveEmailDraftsSuccess ||
success is SendEmailSuccess ||
success is UpdateEmailDraftsSuccess) {
refreshMailboxChanges();
}
});
});
}
void _initCollapseMailboxCategories() {
if (currentContext != null) {
if (kIsWeb && (_responsiveUtils.isMobile(currentContext!)) || _responsiveUtils.isTablet(currentContext!)) {
@@ -25,11 +25,12 @@ class MailboxView extends GetWidget<MailboxController> {
@override
Widget build(BuildContext context) {
return Drawer(
elevation: _responsiveUtils.isDesktop(context) ? 0 : 16.0,
child: Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
_buildLogoApp(context),
if (!_responsiveUtils.isDesktop(context)) _buildLogoApp(context),
if (!_responsiveUtils.isDesktop(context)) const Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2),
Expanded(child: Container(
padding: EdgeInsets.zero,
@@ -75,7 +76,7 @@ class MailboxView extends GetWidget<MailboxController> {
bottom: _responsiveUtils.isDesktop(context) ? 25 : 16,
left: _responsiveUtils.isDesktop(context) ? 32 : 16),
child: Row(children: [
(SloganBuilder(arrangedByHorizontal: true)
(SloganBuilder(arrangedByHorizontal: true)
..setSloganText(AppLocalizations.of(context).app_name)
..setSloganTextAlign(TextAlign.center)
..setSloganTextStyle(const TextStyle(color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold))
@@ -65,7 +65,7 @@ class UserInformationWidgetBuilder {
child: TextButton(
onPressed: () => _onLogoutActionClick?.call(),
child: Text(
AppLocalizations.of(_context).logout,
AppLocalizations.of(_context).manage_account,
style: const TextStyle(fontSize: 14, color: AppColor.colorTextButton),
),
)
@@ -0,0 +1,97 @@
import 'package:flutter/cupertino.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/filter_message_option.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
import 'package:tmail_ui_user/main/routes/router_arguments.dart';
class DashBoardAction extends UIAction {
static final idle = DashBoardAction();
DashBoardAction() : super();
@override
List<Object?> get props => [];
}
class ComposeEmailAction extends DashBoardAction {
RouterArguments? arguments;
ComposeEmailAction({this.arguments});
@override
List<Object?> get props => [arguments];
}
class CloseComposeEmailAction extends DashBoardAction {
CloseComposeEmailAction();
@override
List<Object?> get props => [];
}
class RefreshAllEmailAction extends DashBoardAction {
RefreshAllEmailAction();
@override
List<Object?> get props => [];
}
class SelectionAllEmailAction extends DashBoardAction {
SelectionAllEmailAction();
@override
List<Object?> get props => [];
}
class CancelSelectionAllEmailAction extends DashBoardAction {
CancelSelectionAllEmailAction();
@override
List<Object?> get props => [];
}
class MarkAsReadAllEmailAction extends DashBoardAction {
MarkAsReadAllEmailAction();
@override
List<Object?> get props => [];
}
class FilterMessageAction extends DashBoardAction {
BuildContext context;
FilterMessageOption option;
FilterMessageAction(this.context, this.option);
@override
List<Object?> get props => [option];
}
class HandleEmailActionTypeAction extends DashBoardAction {
BuildContext context;
EmailActionType emailAction;
List<PresentationEmail> listEmailSelected;
HandleEmailActionTypeAction(this.context, this.listEmailSelected, this.emailAction);
@override
List<Object> get props => [listEmailSelected, emailAction];
}
class GoToSettingsAction extends DashBoardAction {
GoToSettingsAction();
@override
List<Object?> get props => [];
}
@@ -0,0 +1,34 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension FilterMessageOptionExtension on FilterMessageOption {
String getName(BuildContext context) {
switch(this) {
case FilterMessageOption.all:
return '';
case FilterMessageOption.unread:
return AppLocalizations.of(context).unread;
case FilterMessageOption.attachments:
return AppLocalizations.of(context).with_attachments;
case FilterMessageOption.starred:
return AppLocalizations.of(context).starred;
}
}
String getIcon(ImagePaths imagePaths) {
switch(this) {
case FilterMessageOption.all:
return '';
case FilterMessageOption.unread:
return imagePaths.icUnread;
case FilterMessageOption.attachments:
return imagePaths.icAttachment;
case FilterMessageOption.starred:
return imagePaths.icStar;
}
}
}
@@ -15,6 +15,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart';
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart';
@@ -35,7 +36,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_user_p
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_user_profile_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart';
@@ -68,9 +69,12 @@ class MailboxDashBoardController extends ReloadableController {
final userProfile = Rxn<UserProfile>();
final searchState = SearchState.initial().obs;
final suggestionSearch = <String>[].obs;
final dashBoardAction = DashBoardAction.none.obs;
final dashBoardAction = Rxn<UIAction>();
final routePath = AppRoutes.MAILBOX_DASHBOARD.obs;
final appInformation = Rxn<PackageInfo>();
final currentSelectMode = SelectMode.INACTIVE.obs;
final filterMessageOption = FilterMessageOption.all.obs;
final listEmailSelected = <PresentationEmail>[].obs;
SearchQuery? searchQuery;
Session? sessionCurrent;
@@ -96,12 +100,12 @@ class MailboxDashBoardController extends ReloadableController {
@override
void onReady() {
super.onReady();
log('MailboxDashBoardController::onReady()');
dispatchRoute(AppRoutes.THREAD);
_setSessionCurrent();
_getUserProfile();
_initPackageInfo();
super.onReady();
}
@override
@@ -257,9 +261,9 @@ class MailboxDashBoardController extends ReloadableController {
bool get isDrawerOpen => scaffoldKey.currentState?.isDrawerOpen == true;
bool isSearchActive() {
return searchState.value.searchStatus == SearchStatus.ACTIVE;
}
bool isSearchActive() => searchState.value.searchStatus == SearchStatus.ACTIVE;
bool isSelectionEnabled() => currentSelectMode.value == SelectMode.ACTIVE;
void enableSearch() {
searchState.value = searchState.value.enableSearchState();
@@ -361,16 +365,14 @@ class MailboxDashBoardController extends ReloadableController {
}
}
void dispatchDashBoardAction(DashBoardAction action, {RouterArguments? arguments}) {
switch(action) {
case DashBoardAction.none:
routerArguments = null;
Get.delete<ComposerController>();
break;
case DashBoardAction.compose:
routerArguments = arguments;
ComposerBindings().dependencies();
break;
void dispatchAction(UIAction action) {
log('MailboxDashBoardController::dispatchAction(): ${action.runtimeType}');
if (action is ComposeEmailAction) {
routerArguments = action.arguments;
ComposerBindings().dependencies();
} else if (action is CloseComposeEmailAction) {
routerArguments = null;
Get.delete<ComposerController>();
}
dashBoardAction.value = action;
}
@@ -402,8 +404,8 @@ class MailboxDashBoardController extends ReloadableController {
void composeEmailAction() {
if (kIsWeb) {
if (dashBoardAction.value != DashBoardAction.compose) {
dispatchDashBoardAction(DashBoardAction.compose, arguments: ComposerArguments());
if (dashBoardAction.value is! ComposeEmailAction) {
dispatchAction(ComposeEmailAction(arguments: ComposerArguments()));
}
} else {
push(AppRoutes.COMPOSER, arguments: ComposerArguments());
@@ -412,8 +414,8 @@ class MailboxDashBoardController extends ReloadableController {
void goToComposer(ComposerArguments arguments) {
if (kIsWeb) {
if (dashBoardAction.value != DashBoardAction.compose) {
dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
if (dashBoardAction.value is! ComposeEmailAction) {
dispatchAction(ComposeEmailAction(arguments: arguments));
}
} else {
push(AppRoutes.COMPOSER, arguments: arguments);
@@ -434,6 +436,14 @@ class MailboxDashBoardController extends ReloadableController {
goToLogin();
}
void clearDashBoardAction() {
dashBoardAction.value = DashBoardAction.idle;
}
void goToSettings() {
dispatchAction(GoToSettingsAction());
}
@override
void onClose() {
_emailReceiveManager.closeEmailReceiveManagerStream();
@@ -5,10 +5,10 @@ import 'package:tmail_ui_user/features/base/mixin/network_connection_mixin.dart'
import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart';
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
import 'package:tmail_ui_user/features/setting/presentation/model/app_setting.dart';
import 'package:tmail_ui_user/features/setting/presentation/model/reading_pane.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/app_setting.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/reading_pane.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
@@ -28,19 +28,16 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> with Ne
? SizedBox(child: MailboxView(), width: double.infinity)
: SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthMobileTablet),
tablet: SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthMobileTablet),
tabletLarge: const SizedBox.shrink(),
desktop: const SizedBox.shrink()
tabletLarge: SizedBox.shrink(),
),
drawerEnableOpenDragGesture: _responsiveUtils.isMobile(context) || _responsiveUtils.isTablet(context),
body: Stack(children: [
ResponsiveWidget(
responsiveUtils: _responsiveUtils,
desktop: _buildLargeScreenView(context),
tabletLarge: _buildLargeScreenView(context),
tablet: ThreadView(),
mobile: ThreadView()
),
Obx(() => controller.dashBoardAction.value == DashBoardAction.compose
Obx(() => controller.dashBoardAction.value is ComposeEmailAction
? ComposerView()
: const SizedBox.shrink()),
Obx(() => controller.isNetworkConnectionAvailable()
@@ -50,7 +47,7 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> with Ne
);
}
Widget _buildThreadAndEmailContainer(BuildContext context) {
Widget _wrapContainerForThreadAndEmail(BuildContext context) {
switch(AppSetting.readingPane) {
case ReadingPane.noSplit:
return Obx(() {
@@ -97,7 +94,7 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> with Ne
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthMobileTablet),
Expanded(child: _buildThreadAndEmailContainer(context))
Expanded(child: _wrapContainerForThreadAndEmail(context))
],
);
}
@@ -1,44 +1,100 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/mixin/network_connection_mixin.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart';
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
import 'package:tmail_ui_user/features/setting/presentation/model/app_setting.dart';
import 'package:tmail_ui_user/features/setting/presentation/model/reading_pane.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mixin/filter_email_popup_menu_mixin.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/app_setting.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/reading_pane.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/filter_message_option_extension.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_bar_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> with NetworkConnectionMixin {
class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> with NetworkConnectionMixin,
UserSettingPopupMenuMixin, FilterEmailPopupMenuMixin {
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
MailboxDashBoardView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
if (controller.isDrawerOpen && (_responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context))) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
controller.closeDrawer();
});
}
return Scaffold(
key: controller.scaffoldKey,
backgroundColor: Colors.white,
drawer: ResponsiveWidget(
responsiveUtils: _responsiveUtils,
mobile: SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthWeb),
tablet: SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthWeb),
tabletLarge: const SizedBox.shrink(),
desktop: const SizedBox.shrink()
tabletLarge: const SizedBox.shrink()
),
drawerEnableOpenDragGesture: _responsiveUtils.isMobile(context) || _responsiveUtils.isTablet(context),
body: Stack(children: [
ResponsiveWidget(
responsiveUtils: _responsiveUtils,
desktop: _buildLargeScreenView(context),
tabletLarge: _buildLargeScreenView(context),
tablet: ThreadView(),
desktop: Column(children: [
Row(children: [
Container(width: 256, color: Colors.white,
padding: const EdgeInsets.only(top: 25, bottom: 25, left: 32),
child: Row(children: [
(SloganBuilder(arrangedByHorizontal: true)
..setSloganText(AppLocalizations.of(context).app_name)
..setSloganTextAlign(TextAlign.center)
..setSloganTextStyle(const TextStyle(color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold))
..setSizeLogo(24)
..setLogo(_imagePaths.icLogoTMail))
.build(),
Obx(() {
if (controller.appInformation.value != null) {
return Padding(padding: const EdgeInsets.only(top: 6),
child: Text(
'v.${controller.appInformation.value!.version}',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 13, color: AppColor.colorContentEmail, fontWeight: FontWeight.w500),
));
} else {
return const SizedBox.shrink();
}
}),
])
),
Expanded(child: Padding(
padding: const EdgeInsets.only(right: 10, top: 16, bottom: 10, left: 48),
child: _buildRightHeader(context)))
]),
Expanded(child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeMenuWidthWeb),
Expanded(child: _wrapContainerForThreadAndEmail(context))
],
))
]),
tabletLarge: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeMenuWidthWeb),
Expanded(child: _wrapContainerForThreadAndEmail(context))
],
),
mobile: ThreadView()
),
Obx(() => controller.dashBoardAction.value == DashBoardAction.compose
Obx(() => controller.dashBoardAction.value is ComposeEmailAction
? ComposerView()
: const SizedBox.shrink()),
Obx(() => controller.isNetworkConnectionAvailable()
@@ -48,7 +104,7 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> with Ne
);
}
Widget _buildThreadAndEmailContainer(BuildContext context) {
Widget _wrapContainerForThreadAndEmail(BuildContext context) {
switch(AppSetting.readingPane) {
case ReadingPane.noSplit:
return Obx(() {
@@ -84,19 +140,267 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> with Ne
}
}
Widget _buildLargeScreenView(BuildContext context) {
if (controller.isDrawerOpen && (_responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context))) {
WidgetsBinding.instance?.addPostFrameCallback((_) {
controller.closeDrawer();
});
}
Widget _buildRightHeader(BuildContext context) {
return Row(children: [
Obx(() {
if (controller.isSelectionEnabled()) {
return _buildListButtonTopBarSelection(context);
} else {
return controller.isSearchActive()
? _buildListButtonTopBarSearchActive(context)
: _buildListButtonTopBar(context);
}
}),
const SizedBox(width: 16),
Obx(() => !controller.isSearchActive() ? const Spacer() : const SizedBox.shrink()),
Obx(() => controller.isSearchActive() ? Expanded(child: _buildSearchForm(context)) : const SizedBox.shrink()),
Obx(() => !controller.isSearchActive()
? (SearchBarView(_imagePaths)
..hintTextSearch(AppLocalizations.of(context).search_emails)
..maxSizeWidth(240)
..addOnOpenSearchViewAction(() => controller.enableSearch()))
.build()
: const SizedBox.shrink()),
Obx(() => !controller.isSearchActive() ? const SizedBox(width: 16) : const SizedBox.shrink()),
(AvatarBuilder()
..text(controller.userProfile.value?.getAvatarText() ?? '')
..backgroundColor(Colors.white)
..textColor(Colors.black)
..context(context)
..addOnTapAvatarActionWithPositionClick((position) =>
controller.openPopupMenuAction(context, position, popupMenuUserSettingActionTile(context,
controller.userProfile.value,
onLogoutAction: () => controller.logoutAction(),
onSettingAction: () => controller.goToSettings())))
..addBoxShadows([const BoxShadow(
color: AppColor.colorShadowBgContentEmail,
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))])
..size(48))
.build(),
const SizedBox(width: 16)
]);
}
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeMenuWidthWeb),
Expanded(child: _buildThreadAndEmailContainer(context))
],
);
Widget _buildListButtonTopBar(BuildContext context) {
return Row(children: [
(ButtonBuilder(_imagePaths.icRefresh)
..key(const Key('button_reload_thread'))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppColor.colorButtonHeaderThread))
..paddingIcon(EdgeInsets.zero)
..size(16)
..radiusSplash(10)
..padding(const EdgeInsets.symmetric(horizontal: 8, vertical: 8))
..onPressActionClick(() => controller.dispatchAction(RefreshAllEmailAction())))
.build(),
const SizedBox(width: 16),
(ButtonBuilder(_imagePaths.icSelectAll)
..key(const Key('button_select_all'))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..radiusSplash(10)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread))
..onPressActionClick(() => controller.dispatchAction(SelectionAllEmailAction()))
..text(AppLocalizations.of(context).select_all, isVertical: false))
.build(),
const SizedBox(width: 16),
(ButtonBuilder(_imagePaths.icMarkAllAsRead)
..key(const Key('button_mark_all_as_read'))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..radiusSplash(10)
..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread))
..onPressActionClick(() => controller.dispatchAction(MarkAsReadAllEmailAction()))
..text(AppLocalizations.of(context).mark_all_as_read, isVertical: false))
.build(),
const SizedBox(width: 16),
Obx(() => (ButtonBuilder(_imagePaths.icFilterWeb)
..key(const Key('button_filter_messages'))
..context(context)
..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..radiusSplash(10)
..textStyle(TextStyle(
fontSize: 12,
color: controller.filterMessageOption.value == FilterMessageOption.all
? AppColor.colorTextButtonHeaderThread
: AppColor.colorNameEmail,
fontWeight: controller.filterMessageOption.value == FilterMessageOption.all
? FontWeight.normal
: FontWeight.w500))
..addIconAction(Padding(
padding: const EdgeInsets.only(left: 8),
child: SvgPicture.asset(_imagePaths.icArrowDown, fit: BoxFit.fill)))
..addOnPressActionWithPositionClick((position) => controller.openPopupMenuAction(context, position,
popupMenuFilterEmailActionTile(context,
controller.filterMessageOption.value,
(option) => controller.dispatchAction(FilterMessageAction(context, option)))))
..text(controller.filterMessageOption.value == FilterMessageOption.all
? AppLocalizations.of(context).filter_messages
: controller.filterMessageOption.value.getTitle(context), isVertical: false))
.build()),
]);
}
Widget _buildListButtonTopBarSearchActive(BuildContext context) {
return Row(children: [
(ButtonBuilder(_imagePaths.icSelectAll)
..key(const Key('button_select_all'))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..radiusSplash(10)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread))
..onPressActionClick(() => controller.dispatchAction(SelectionAllEmailAction()))
..text(AppLocalizations.of(context).select_all, isVertical: false))
.build(),
const SizedBox(width: 16),
(ButtonBuilder(_imagePaths.icMarkAllAsRead)
..key(const Key('button_mark_all_as_read'))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..radiusSplash(10)
..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread))
..onPressActionClick(() => controller.dispatchAction(MarkAsReadAllEmailAction()))
..text(AppLocalizations.of(context).mark_all_as_read, isVertical: false))
.build(),
]);
}
Widget _buildListButtonTopBarSelection(BuildContext context) {
return Row(children: [
buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icCloseComposer, color: AppColor.colorTextButton, fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).cancel,
onTap: () => controller.dispatchAction(CancelSelectionAllEmailAction())),
Obx(() => Text(
AppLocalizations.of(context).count_email_selected(controller.listEmailSelected.length),
style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorTextButton))),
const SizedBox(width: 30),
Obx(() => buildIconWeb(
icon: SvgPicture.asset(
controller.listEmailSelected.isAllEmailRead
? _imagePaths.icRead
: _imagePaths.icUnread,
fit: BoxFit.fill),
tooltip: controller.listEmailSelected.isAllEmailRead
? AppLocalizations.of(context).mark_as_unread
: AppLocalizations.of(context).mark_as_read,
onTap: () => controller.dispatchAction(
HandleEmailActionTypeAction(context,
controller.listEmailSelected,
controller.listEmailSelected.isAllEmailRead
? EmailActionType.markAsUnread
: EmailActionType.markAsRead)))),
Obx(() => buildIconWeb(
icon: SvgPicture.asset(
controller.listEmailSelected.isAllEmailStarred
? _imagePaths.icUnStar
: _imagePaths.icStar,
fit: BoxFit.fill),
tooltip: controller.listEmailSelected.isAllEmailStarred
? AppLocalizations.of(context).un_star
: AppLocalizations.of(context).star,
onTap: () => controller.dispatchAction(
HandleEmailActionTypeAction(context,
controller.listEmailSelected,
controller.listEmailSelected.isAllEmailStarred
? EmailActionType.markAsStarred
: EmailActionType.unMarkAsStarred)))),
Obx(() {
if (controller.selectedMailbox.value?.isDrafts == false) {
return buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icMove, fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).move,
onTap: () => controller.dispatchAction(
HandleEmailActionTypeAction(context,
controller.listEmailSelected,
EmailActionType.moveToMailbox)));
} else {
return const SizedBox.shrink();
}
}),
Obx(() {
if (controller.selectedMailbox.value?.isDrafts == false) {
return buildIconWeb(
icon: SvgPicture.asset(
controller.selectedMailbox.value?.isSpam == true
? _imagePaths.icNotSpam
: _imagePaths.icSpam,
fit: BoxFit.fill),
tooltip: controller.selectedMailbox.value?.isSpam == true
? AppLocalizations.of(context).un_spam
: AppLocalizations.of(context).mark_as_spam,
onTap: () {
if (controller.selectedMailbox.value?.isSpam == true) {
return controller.dispatchAction(
HandleEmailActionTypeAction(context,
controller.listEmailSelected,
EmailActionType.unSpam));
} else {
return controller.dispatchAction(
HandleEmailActionTypeAction(context,
controller.listEmailSelected,
EmailActionType.moveToSpam));
}
});
} else {
return const SizedBox.shrink();
}
}),
Obx(() => buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icDelete, fit: BoxFit.fill),
tooltip: controller.selectedMailbox.value?.isTrash == true
? AppLocalizations.of(context).delete_permanently
: AppLocalizations.of(context).move_to_trash,
onTap: () {
if (controller.selectedMailbox.value?.isTrash == true) {
return controller.dispatchAction(HandleEmailActionTypeAction(context,
controller.listEmailSelected,
EmailActionType.deletePermanently));
} else {
return controller.dispatchAction(HandleEmailActionTypeAction(context,
controller.listEmailSelected,
EmailActionType.moveToTrash));
}
})),
]);
}
Widget _buildSearchForm(BuildContext context) {
return (SearchAppBarWidget(context, _imagePaths, _responsiveUtils,
controller.searchQuery,
controller.searchFocus,
controller.searchInputController,
suggestionSearch: controller.suggestionSearch)
..addDecoration(const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: AppColor.colorBgSearchBar))
..setMargin(const EdgeInsets.only(right: 10))
..setHeightSearchBar(45)
..setHintText(AppLocalizations.of(context).search_mail)
..addOnCancelSearchPressed(() => controller.disableSearch())
..addOnClearTextSearchAction(() => controller.clearSearchText())
..addOnTextChangeSearchAction((query) => controller.addSuggestionSearch(query))
..addOnSearchTextAction((query) => controller.searchEmail(context, query)))
.build();
}
}
@@ -0,0 +1,55 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/filter_message_option_extension.dart';
mixin FilterEmailPopupMenuMixin {
final _imagePaths = Get.find<ImagePaths>();
List<PopupMenuEntry> popupMenuFilterEmailActionTile(BuildContext context,
FilterMessageOption optionSelected, Function(FilterMessageOption)? onCallBack) {
return [
PopupMenuItem(
padding: EdgeInsets.zero,
child: _filterEmailAction(context, optionSelected, FilterMessageOption.attachments, onCallBack)),
PopupMenuDivider(height: 0.5),
PopupMenuItem(
padding: EdgeInsets.zero,
child: _filterEmailAction(context, optionSelected, FilterMessageOption.unread, onCallBack)),
PopupMenuDivider(height: 0.5),
PopupMenuItem(
padding: EdgeInsets.zero,
child: _filterEmailAction(context, optionSelected, FilterMessageOption.starred, onCallBack)),
];
}
Widget _filterEmailAction(BuildContext context, FilterMessageOption optionSelected,
FilterMessageOption option, Function(FilterMessageOption)? onCallBack) {
return InkWell(
onTap: () => onCallBack?.call(option == optionSelected ? FilterMessageOption.all : option),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: SizedBox(
child: Row(children: [
SvgPicture.asset(option.getIcon(_imagePaths),
width: 20,
height: 20,
fit: BoxFit.fill,
color: option != FilterMessageOption.starred ? AppColor.colorTextButton : null),
SizedBox(width: 12),
Expanded(child: Text(
option.getName(context),
style: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500))),
if (optionSelected == option)
SizedBox(width: 12),
if (optionSelected == option)
SvgPicture.asset(_imagePaths.icFilterSelected, width: 16, height: 16, fit: BoxFit.fill),
])
),
)
);
}
}
@@ -0,0 +1,57 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
mixin UserSettingPopupMenuMixin {
final _imagePaths = Get.find<ImagePaths>();
List<PopupMenuEntry> popupMenuUserSettingActionTile(BuildContext context, UserProfile? userProfile,
{Function? onLogoutAction, Function? onSettingAction}) {
return [
PopupMenuItem(
enabled: false,
padding: EdgeInsets.zero,
child: _userInformation(context, userProfile)),
PopupMenuDivider(height: 0.5),
PopupMenuItem(
padding: EdgeInsets.zero,
child: _settingAction(context, onSettingAction)),
PopupMenuDivider(height: 0.5),
PopupMenuItem(
padding: EdgeInsets.zero,
child: _logoutAction(context, onLogoutAction)),
];
}
Widget _userInformation(BuildContext context, UserProfile? userProfile) {
if (userProfile != null) {
return SizedBox(
width: 300,
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20),
title: Text(userProfile.email, maxLines: 1, style: TextStyle(
fontSize: 15,
color: AppColor.colorHintSearchBar,
fontWeight: FontWeight.normal))),
);
}
return SizedBox.shrink();
}
Widget _settingAction(BuildContext context, Function? onCallBack) {
return PopupMenuItemWidget(
_imagePaths.icSetting,
AppLocalizations.of(context).settings,
() => onCallBack?.call());
}
Widget _logoutAction(BuildContext context, Function? onCallBack) {
return PopupMenuItemWidget(
_imagePaths.icLogout,
AppLocalizations.of(context).sign_out,
() => onCallBack?.call());
}
}
@@ -1,5 +0,0 @@
enum DashBoardAction {
none,
compose
}
@@ -1,37 +0,0 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/app_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
mixin UserSettingPopupMenuMixin {
final _imagePaths = Get.find<ImagePaths>();
void openUserSettingAction(BuildContext context, RelativeRect? position, List<PopupMenuEntry> popupMenuItems) async {
await showMenu(
context: context,
position: position ?? const RelativeRect.fromLTRB(16, 40, 16, 16),
color: Colors.white,
elevation: 5,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
items: popupMenuItems);
}
List<PopupMenuEntry> popupMenuUserSettingActionTile(BuildContext context, Function? onCallBack) {
return [
PopupMenuItem(padding: const EdgeInsets.symmetric(horizontal: 8), child: logoutAction(context, onCallBack)),
];
}
Widget logoutAction(BuildContext context, Function? onCallBack) {
return (AppActionSheetActionBuilder(
const Key('logout_action'),
SvgPicture.asset(_imagePaths.icCloseMailbox, color: AppColor.colorTextButton, fit: BoxFit.fill),
AppLocalizations.of(context).logout,
iconLeftPadding:const EdgeInsets.only(right: 12))
..onActionClick((option) => onCallBack?.call()))
.build();
}
}
@@ -0,0 +1,6 @@
import 'package:tmail_ui_user/features/manage_account/presentation/model/reading_pane.dart';
class AppSetting {
static ReadingPane readingPane = ReadingPane.noSplit;
}
@@ -1,6 +0,0 @@
import 'package:tmail_ui_user/features/setting/presentation/model/reading_pane.dart';
class AppSetting {
static ReadingPane readingPane = ReadingPane.noSplit;
}
@@ -36,8 +36,8 @@ import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_int
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
import 'package:tmail_ui_user/features/thread/domain/model/get_email_request.dart';
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
@@ -91,8 +91,6 @@ class ThreadController extends BaseController {
final emailList = <PresentationEmail>[].obs;
final emailListSearch = <PresentationEmail>[].obs;
final currentSelectMode = SelectMode.INACTIVE.obs;
final filterMessageOption = FilterMessageOption.all.obs;
bool canLoadMore = true;
bool canSearchMore = true;
@@ -131,50 +129,20 @@ class ThreadController extends BaseController {
@override
void onInit() {
_onMailboxDashBoardListener();
super.onInit();
mailboxDashBoardController.selectedMailbox.listen((selectedMailbox) {
if (_currentMailboxId != selectedMailbox?.id) {
log('ThreadController::onReady(): selectMailbox: ${selectedMailbox?.name?.name}(${selectedMailbox?.id})');
_currentMailboxId = selectedMailbox?.id;
_resetToOriginalValue();
_getAllEmail();
}
});
super.onInit();
dispatchState(Right(LoadingState()));
}
@override
void onReady() {
dispatchState(Right(LoadingState()));
super.onReady();
mailboxDashBoardController.viewState.listen((state) {
state.map((success) {
if (success is SearchEmailNewQuery){
mailboxDashBoardController.clearState();
_searchEmail();
} else if (success is MarkAsEmailReadSuccess
|| success is MoveToMailboxSuccess
|| success is MarkAsStarEmailSuccess
|| success is DeleteEmailPermanentlySuccess
|| success is SaveEmailAsDraftsSuccess
|| success is RemoveEmailDraftsSuccess
|| success is SendEmailSuccess
|| success is UpdateEmailDraftsSuccess) {
_refreshEmailChanges();
}
});
});
mailboxDashBoardController.searchState.listen((state) {
if (state.searchStatus == SearchStatus.INACTIVE) {
emailListSearch.clear();
}
});
}
@override
void onClose() {
mailboxDashBoardController.selectedMailbox.close();
mailboxDashBoardController.dashBoardAction.close();
mailboxDashBoardController.viewState.close();
mailboxDashBoardController.searchState.close();
listEmailController.dispose();
@@ -214,6 +182,7 @@ class ThreadController extends BaseController {
void onDone() {
viewState.value.fold(
(failure) {
log('ThreadController::onDone(): failure: $failure');
if (failure is MarkAsMultipleEmailReadAllFailure
|| failure is MarkAsMultipleEmailReadFailure) {
_markAsReadSelectedMultipleEmailFailure(failure);
@@ -229,6 +198,7 @@ class ThreadController extends BaseController {
(success) {
if (success is MarkAsMultipleEmailReadAllSuccess
|| success is MarkAsMultipleEmailReadHasSomeEmailFailure) {
log('ThreadController::onDone(): success: $success');
_markAsReadSelectedMultipleEmailSuccess(success);
} else if (success is MoveMultipleEmailToMailboxAllSuccess
|| success is MoveMultipleEmailToMailboxHasSomeEmailFailure) {
@@ -257,6 +227,69 @@ class ThreadController extends BaseController {
@override
void onError(error) {}
void _onMailboxDashBoardListener() {
mailboxDashBoardController.selectedMailbox.listen((selectedMailbox) {
log('ThreadController::_onMailboxDashBoardListener(): selectMailbox: ${selectedMailbox?.name?.name}(${selectedMailbox?.id})');
if (_currentMailboxId != selectedMailbox?.id) {
_currentMailboxId = selectedMailbox?.id;
_resetToOriginalValue();
_getAllEmail();
}
});
mailboxDashBoardController.searchState.listen((state) {
log('ThreadController::_onMailboxDashBoardListener(): searchState: $state');
if (state.searchStatus == SearchStatus.INACTIVE) {
emailListSearch.clear();
} else if (state.searchStatus == SearchStatus.ACTIVE) {
cancelSelectEmail();
}
});
mailboxDashBoardController.dashBoardAction.listen((action) {
log('ThreadController::_onMailboxDashBoardListener(): dashBoardAction: ${action.runtimeType}');
if (action is RefreshAllEmailAction) {
refreshAllEmail();
mailboxDashBoardController.clearDashBoardAction();
} else if (action is MarkAsReadAllEmailAction) {
markAsReadAllEmails();
mailboxDashBoardController.clearDashBoardAction();
} if (action is SelectionAllEmailAction) {
setSelectAllEmailAction();
mailboxDashBoardController.clearDashBoardAction();
} if (action is CancelSelectionAllEmailAction) {
cancelSelectEmail();
mailboxDashBoardController.clearDashBoardAction();
} if (action is FilterMessageAction) {
filterMessagesAction(action.context, action.option);
mailboxDashBoardController.clearDashBoardAction();
} if (action is HandleEmailActionTypeAction) {
log('ThreadController::_onMailboxDashBoardListener(): ${action.listEmailSelected.length}');
pressEmailSelectionAction(action.context, action.emailAction, action.listEmailSelected);
mailboxDashBoardController.clearDashBoardAction();
}
});
mailboxDashBoardController.viewState.listen((state) {
log('ThreadController::_onMailboxDashBoardListener(): viewState: $state');
state.map((success) {
if (success is SearchEmailNewQuery){
mailboxDashBoardController.clearState();
_searchEmail();
} else if (success is MarkAsEmailReadSuccess
|| success is MoveToMailboxSuccess
|| success is MarkAsStarEmailSuccess
|| success is DeleteEmailPermanentlySuccess
|| success is SaveEmailAsDraftsSuccess
|| success is RemoveEmailDraftsSuccess
|| success is SendEmailSuccess
|| success is UpdateEmailDraftsSuccess) {
_refreshEmailChanges();
}
});
});
}
void _getAllEmail() {
if (_accountId != null) {
_getAllEmailAction(_accountId!, mailboxId: _currentMailboxId);
@@ -303,7 +336,7 @@ class ThreadController extends BaseController {
sort: _sortOrder,
emailFilter: EmailFilter(
filter: _getFilterCondition(),
filterOption: filterMessageOption.value,
filterOption: mailboxDashBoardController.filterMessageOption.value,
mailboxId: mailboxId ?? _currentMailboxId),
propertiesCreated: ThreadConstants.propertiesDefault,
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
@@ -311,7 +344,7 @@ class ThreadController extends BaseController {
}
EmailFilterCondition _getFilterCondition({bool isLoadMore = false}) {
switch(filterMessageOption.value) {
switch(mailboxDashBoardController.filterMessageOption.value) {
case FilterMessageOption.all:
return EmailFilterCondition(
inMailbox: mailboxDashBoardController.selectedMailbox.value?.id,
@@ -350,7 +383,7 @@ class ThreadController extends BaseController {
sort: _sortOrder,
emailFilter: EmailFilter(
filter: _getFilterCondition(),
filterOption: filterMessageOption.value,
filterOption: mailboxDashBoardController.filterMessageOption.value,
mailboxId: _currentMailboxId),
propertiesCreated: ThreadConstants.propertiesDefault,
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
@@ -359,6 +392,7 @@ class ThreadController extends BaseController {
}
void _refreshEmailChanges() {
log('ThreadController::_refreshEmailChanges(): ');
if (isSearchActive()) {
if (_accountId != null && searchQuery != null) {
final limit = emailListSearch.isNotEmpty ? UnsignedInt(emailListSearch.length) : ThreadConstants.defaultLimit;
@@ -379,7 +413,7 @@ class ThreadController extends BaseController {
propertiesCreated: ThreadConstants.propertiesDefault,
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
inMailboxId: _currentMailboxId,
filterOption: filterMessageOption.value
filterOption: mailboxDashBoardController.filterMessageOption.value
));
}
}
@@ -439,16 +473,18 @@ class ThreadController extends BaseController {
}
if (_isUnSelectedAll()) {
currentSelectMode.value = SelectMode.INACTIVE;
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
mailboxDashBoardController.listEmailSelected.clear();
} else {
if (currentSelectMode.value == SelectMode.INACTIVE) {
currentSelectMode.value = SelectMode.ACTIVE;
if (mailboxDashBoardController.currentSelectMode.value == SelectMode.INACTIVE) {
mailboxDashBoardController.currentSelectMode.value = SelectMode.ACTIVE;
}
mailboxDashBoardController.listEmailSelected.value = listEmailSelected;
}
}
void enableSelectionEmail() {
currentSelectMode.value = SelectMode.ACTIVE;
mailboxDashBoardController.currentSelectMode.value = SelectMode.ACTIVE;
}
void setSelectAllEmailAction() {
@@ -457,7 +493,8 @@ class ThreadController extends BaseController {
} else {
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.ACTIVE)).toList();
}
currentSelectMode.value = SelectMode.ACTIVE;
mailboxDashBoardController.currentSelectMode.value = SelectMode.ACTIVE;
mailboxDashBoardController.listEmailSelected.value = listEmailSelected;
}
List<PresentationEmail> get listEmailSelected {
@@ -477,20 +514,28 @@ class ThreadController extends BaseController {
}
void cancelSelectEmail() {
if (isSearchActive()) {
emailListSearch.value = emailListSearch.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
} else {
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
emailListSearch.value = emailListSearch.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
mailboxDashBoardController.listEmailSelected.clear();
}
void markAsReadAllEmails() {
final listEmail = isSearchActive() ? emailListSearch.allEmailUnread : emailList.allEmailUnread;
log('ThreadController::markAsReadAllEmails(): ${listEmail.length}');
if (listEmail.isNotEmpty) {
markAsReadSelectedMultipleEmail(listEmail);
}
currentSelectMode.value = SelectMode.INACTIVE;
}
void markAsReadSelectedMultipleEmail(List<PresentationEmail> listPresentationEmail) {
final listEmail = listPresentationEmail.map((presentationEmail) => presentationEmail.toEmail()).toList();
log('ThreadController::markAsReadSelectedMultipleEmail(): listPresentationEmail: ${listPresentationEmail.length}');
final readAction = listPresentationEmail.isAllEmailRead ? ReadActions.markAsUnread : ReadActions.markAsRead;
final mailboxCurrent = mailboxDashBoardController.selectedMailbox.value;
if (_accountId != null && mailboxCurrent != null) {
cancelSelectEmail();
final listEmail = listPresentationEmail.map((presentationEmail) => presentationEmail.toEmail()).toList();
log('ThreadController::markAsReadSelectedMultipleEmail(): listEmail: ${listEmail.length}');
consumeState(_markAsMultipleEmailReadInteractor.execute(_accountId!, listEmail, readAction));
}
}
@@ -515,7 +560,7 @@ class ThreadController extends BaseController {
message: message,
icon: readActions == ReadActions.markAsUnread ? _imagePaths.icUnreadToast : _imagePaths.icReadToast);
}
log('ThreadController::_markAsReadSelectedMultipleEmailSuccess(): _refreshEmailChanges');
_refreshEmailChanges();
}
@@ -549,8 +594,15 @@ class ThreadController extends BaseController {
void filterMessagesAction(BuildContext context, FilterMessageOption filterOption) {
popBack();
final newFilterOption = filterMessageOption.value == filterOption ? FilterMessageOption.all : filterOption;
filterMessageOption.value = newFilterOption;
final newFilterOption = mailboxDashBoardController.filterMessageOption.value == filterOption
? FilterMessageOption.all
: filterOption;
log('ThreadController::filterMessagesAction(): newFilterOption: $newFilterOption');
mailboxDashBoardController.filterMessageOption.value = newFilterOption;
log('ThreadController::filterMessagesAction(): filterMessageOption: ${mailboxDashBoardController.filterMessageOption}');
_appToast.showToastWithIcon(
currentOverlayContext!,
@@ -737,10 +789,10 @@ class ThreadController extends BaseController {
}
void markAsStarSelectedMultipleEmail(List<PresentationEmail> listPresentationEmail) {
final listEmail = listPresentationEmail.map((presentationEmail) => presentationEmail.toEmail()).toList();
final starAction = listPresentationEmail.isAllEmailStarred ? MarkStarAction.unMarkStar : MarkStarAction.markStar;
if (_accountId != null) {
cancelSelectEmail();
final listEmail = listPresentationEmail.map((presentationEmail) => presentationEmail.toEmail()).toList();
consumeState(_markAsStarMultipleEmailInteractor.execute(_accountId!, listEmail, starAction));
}
}
@@ -840,9 +892,10 @@ class ThreadController extends BaseController {
_isLoadingMore = false;
}
bool isSelectionEnabled() => currentSelectMode.value == SelectMode.ACTIVE;
bool isSelectionEnabled() => mailboxDashBoardController.currentSelectMode.value == SelectMode.ACTIVE;
void pressEmailSelectionAction(BuildContext context, EmailActionType actionType, List<PresentationEmail> selectionEmail) {
log('ThreadController::pressEmailSelectionAction(): selectionEmail: ${selectionEmail.length}');
switch(actionType) {
case EmailActionType.markAsRead:
case EmailActionType.markAsUnread:
@@ -1115,9 +1168,8 @@ class ThreadController extends BaseController {
}
void _deleteMultipleEmailsPermanently(List<PresentationEmail> emailList) {
cancelSelectEmail();
final listEmailIds = emailList.map((email) => email.id).toList();
cancelSelectEmail();
if ( _accountId != null && listEmailIds.isNotEmpty) {
consumeState(_deleteMultipleEmailsPermanentlyInteractor.execute(_accountId!, listEmailIds));
}
@@ -1188,7 +1240,7 @@ class ThreadController extends BaseController {
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
if (kIsWeb) {
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
mailboxDashBoardController.dispatchAction(ComposeEmailAction(arguments: arguments));
} else {
push(AppRoutes.COMPOSER, arguments: arguments);
}
+13 -235
View File
@@ -1,15 +1,13 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/extensions/filter_message_option_extension.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart';
@@ -21,7 +19,7 @@ import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_ba
import 'package:tmail_ui_user/features/thread/presentation/widgets/suggestion_box_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMixin {
class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin {
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
@@ -44,11 +42,6 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_responsiveUtils.isDesktop(context))
Container(
color: Colors.white,
padding: const EdgeInsets.only(right: 10, top: 16, bottom: 10, left: 32),
child: _buildHeader(context)),
Obx(() => !controller.isSearchActive() && !_responsiveUtils.isDesktop(context)
? _buildAppBarNormal(context)
: const SizedBox.shrink()),
@@ -92,154 +85,6 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
);
}
Widget _buildHeader(BuildContext context) {
return Row(children: [
Obx(() => !controller.isSelectionEnabled() ? _buildListButtonTopBar(context) : const SizedBox.shrink()),
Obx(() => controller.isSelectionEnabled() ? _buildListButtonSelectionForDesktop(context) : const SizedBox.shrink()),
const SizedBox(width: 16),
Obx(() => !controller.isSearchActive() ? const Spacer() : const SizedBox.shrink()),
Expanded(child: _buildSearchInputFormForDesktop(context)),
_buildSearchButtonViewForDesktop(context),
Padding(
padding: const EdgeInsets.only(right: 16),
child: (AvatarBuilder()
..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '')
..backgroundColor(Colors.white)
..textColor(Colors.black)
..context(context)
..addOnTapAvatarActionWithPositionClick((position) => openUserSettingAction(
context,
position,
popupMenuUserSettingActionTile(context, () => controller.mailboxDashBoardController.logoutAction())))
..addBoxShadows([const BoxShadow(
color: AppColor.colorShadowBgContentEmail,
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))])
..size(48))
.build()),
]);
}
Widget _buildListButtonTopBar(BuildContext context) {
return Row(children: [
if (!controller.isSearchActive())
(ButtonBuilder(_imagePaths.icRefresh)
..key(const Key('button_reload_thread'))
..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread))
..paddingIcon(EdgeInsets.zero)
..size(16)
..radiusSplash(10)
..padding(const EdgeInsets.symmetric(horizontal: 8, vertical: 8))
..onPressActionClick(() => controller.refreshAllEmail()))
.build(),
if (!controller.isSearchActive()) const SizedBox(width: 16),
(ButtonBuilder(_imagePaths.icSelectAll)
..key(const Key('button_select_all'))
..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..radiusSplash(10)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread))
..onPressActionClick(() => controller.setSelectAllEmailAction())
..text(AppLocalizations.of(context).select_all, isVertical: false))
.build(),
const SizedBox(width: 16),
(ButtonBuilder(_imagePaths.icMarkAllAsRead)
..key(const Key('button_mark_all_as_read'))
..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..radiusSplash(10)
..textStyle(const TextStyle(fontSize: 12, color: AppColor.colorTextButtonHeaderThread))
..onPressActionClick(() {
final listEmail = controller.isSearchActive()
? controller.emailListSearch.allEmailUnread
: controller.emailList.allEmailUnread;
if (listEmail.isNotEmpty) {
controller.markAsReadSelectedMultipleEmail(listEmail);
}
})
..text(AppLocalizations.of(context).mark_all_as_read, isVertical: false))
.build(),
if (!controller.isSearchActive()) const SizedBox(width: 16),
if (!controller.isSearchActive())
(ButtonBuilder(_imagePaths.icFilterWeb)
..key(const Key('button_filter_messages'))
..context(context)
..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread))
..paddingIcon(const EdgeInsets.only(right: 8))
..size(16)
..padding(const EdgeInsets.symmetric(horizontal: 12, vertical: 8))
..radiusSplash(10)
..textStyle(TextStyle(
fontSize: 12,
color: controller.filterMessageOption.value == FilterMessageOption.all ? AppColor.colorTextButtonHeaderThread : AppColor.colorNameEmail,
fontWeight: controller.filterMessageOption.value == FilterMessageOption.all ? FontWeight.normal : FontWeight.w500))
..addIconAction(Padding(
padding: const EdgeInsets.only(left: 8),
child: SvgPicture.asset(_imagePaths.icArrowDown, fit: BoxFit.fill)))
..addOnPressActionWithPositionClick((position) =>
controller.openFilterMessagesForTablet(
context,
position,
_popupMenuEmailActionTile(context, controller.filterMessageOption.value)))
..text(controller.filterMessageOption.value == FilterMessageOption.all
? AppLocalizations.of(context).filter_messages
: controller.filterMessageOption.value.getTitle(context), isVertical: false))
.build(),
]);
}
Widget _buildListButtonSelectionForDesktop(BuildContext context) {
return Row(children: [
buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icCloseComposer, color: AppColor.colorTextButton, fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).cancel,
onTap: () => controller.cancelSelectEmail()),
Text(
AppLocalizations.of(context).count_email_selected(controller.listEmailSelected.length),
style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorTextButton),),
const SizedBox(width: 30),
buildIconWeb(
icon: SvgPicture.asset(controller.listEmailSelected.isAllEmailRead ? _imagePaths.icUnread : _imagePaths.icRead, fit: BoxFit.fill),
tooltip: controller.listEmailSelected.isAllEmailRead ? AppLocalizations.of(context).mark_as_unread : AppLocalizations.of(context).mark_as_read,
onTap: () => controller.pressEmailSelectionAction(
context,
controller.listEmailSelected.isAllEmailRead ? EmailActionType.markAsUnread : EmailActionType.markAsRead,
controller.listEmailSelected)),
buildIconWeb(
icon: SvgPicture.asset(controller.listEmailSelected.isAllEmailStarred ? _imagePaths.icUnStar : _imagePaths.icStar, fit: BoxFit.fill),
tooltip: controller.listEmailSelected.isAllEmailStarred ? AppLocalizations.of(context).un_star : AppLocalizations.of(context).star,
onTap: () => controller.pressEmailSelectionAction(
context,
controller.listEmailSelected.isAllEmailStarred ? EmailActionType.markAsStarred : EmailActionType.unMarkAsStarred,
controller.listEmailSelected)),
if (controller.currentMailbox?.isDrafts == false)
buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icMove, fit: BoxFit.fill),
tooltip: AppLocalizations.of(context).move,
onTap: () => controller.pressEmailSelectionAction(context, EmailActionType.moveToMailbox, controller.listEmailSelected)),
if (controller.currentMailbox?.isDrafts == false)
buildIconWeb(
icon: SvgPicture.asset(controller.currentMailbox?.isSpam == true ? _imagePaths.icNotSpam : _imagePaths.icSpam,
fit: BoxFit.fill),
tooltip: controller.currentMailbox?.isSpam == true ? AppLocalizations.of(context).un_spam : AppLocalizations.of(context).mark_as_spam,
onTap: () => controller.currentMailbox?.isSpam == true
? controller.pressEmailSelectionAction(context, EmailActionType.unSpam, controller.listEmailSelected)
: controller.pressEmailSelectionAction(context, EmailActionType.moveToSpam, controller.listEmailSelected)),
buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icDelete, fit: BoxFit.fill),
tooltip: controller.currentMailbox?.isTrash == true
? AppLocalizations.of(context).delete_permanently
: AppLocalizations.of(context).move_to_trash,
onTap: () => controller.currentMailbox?.isTrash == true
? controller.deleteSelectionEmailsPermanently(context, DeleteActionType.multiple, selectedEmails: controller.listEmailSelected)
: controller.pressEmailSelectionAction(context, EmailActionType.moveToTrash, controller.listEmailSelected)),
]);
}
Widget _buildListButtonSelectionForMobile(BuildContext context) {
return Obx(() {
if (controller.isSelectionEnabled() && !_responsiveUtils.isDesktop(context) && controller.listEmailSelected.isNotEmpty) {
@@ -292,54 +137,6 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
});
}
Widget _buildSearchButtonViewForDesktop(BuildContext context) {
return Obx(() {
if (!controller.isSearchActive() && _responsiveUtils.isDesktop(context)) {
return Padding(
padding: const EdgeInsets.only(right: 16),
child: (SearchBarView(_imagePaths)
..hintTextSearch(AppLocalizations.of(context).search_emails)
..maxSizeWidth(240)
..addOnOpenSearchViewAction(() => controller.enableSearch(context)))
.build());
} else {
return const SizedBox.shrink();
}
});
}
Widget _buildSearchInputFormForDesktop(BuildContext context) {
return Obx(() {
if (controller.isSearchActive() && _responsiveUtils.isDesktop(context)) {
return _buildSearchFormForDesktop(context);
} else {
return const SizedBox.shrink();
}
});
}
Widget _buildSearchFormForDesktop(BuildContext context) {
return (SearchAppBarWidget(
context,
_imagePaths,
_responsiveUtils,
controller.searchQuery,
controller.mailboxDashBoardController.searchFocus,
controller.mailboxDashBoardController.searchInputController,
suggestionSearch: controller.mailboxDashBoardController.suggestionSearch,)
..addDecoration(const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: AppColor.colorBgSearchBar))
..setMargin(const EdgeInsets.only(right: 10))
..setHeightSearchBar(45)
..setHintText(AppLocalizations.of(context).search_mail)
..addOnCancelSearchPressed(() => controller.disableSearch())
..addOnClearTextSearchAction(() => controller.mailboxDashBoardController.clearSearchText())
..addOnTextChangeSearchAction((query) => controller.mailboxDashBoardController.addSuggestionSearch(query))
..addOnSearchTextAction((query) => controller.mailboxDashBoardController.searchEmail(context, query)))
.build();
}
Widget _buildSearchForm(BuildContext context) {
return (SearchAppBarWidget(
context,
@@ -366,19 +163,18 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
_responsiveUtils,
controller.mailboxDashBoardController.selectedMailbox.value,
controller.listEmailSelected,
controller.currentSelectMode.value,
controller.filterMessageOption.value)
controller.mailboxDashBoardController.currentSelectMode.value,
controller.mailboxDashBoardController.filterMessageOption.value)
..addOpenMailboxMenuActionClick(() => controller.openMailboxLeftMenu())
..addOnEditThreadAction(() => controller.enableSelectionEmail())
..addOnEmailSelectionAction((actionType, selectionEmail) =>
controller.pressEmailSelectionAction(context, actionType, selectionEmail))
..addOnFilterEmailAction((filterMessageOption, position) =>
_responsiveUtils.isMobileDevice(context)
? controller.openFilterMessagesCupertinoActionSheet(
? controller.openContextMenuAction(
context,
_filterMessagesCupertinoActionTile(context, filterMessageOption),
cancelButton: _buildCupertinoActionCancelButton(context))
: controller.openFilterMessagesForTablet(
_filterMessagesCupertinoActionTile(context, filterMessageOption))
: controller.openPopupMenuAction(
context,
position,
_popupMenuEmailActionTile(context, filterMessageOption)))
@@ -423,15 +219,6 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
];
}
Widget _buildCupertinoActionCancelButton(BuildContext context) {
return CupertinoActionSheetAction(
child: Text(
AppLocalizations.of(context).cancel,
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 20, color: AppColor.colorTextButton)),
onPressed: () => controller.closeFilterMessageActionSheet(),
);
}
Widget _filterMessageWithAttachmentsAction(BuildContext context, FilterMessageOption optionCurrent) {
return (FilterMessageCupertinoActionSheetActionBuilder(
const Key('filter_attachment_action'),
@@ -502,36 +289,27 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
(success) {
if (controller.isSearchActive()) {
return success is SearchingState
? Padding(padding: const EdgeInsets.symmetric(vertical: 16), child: _loadingWidget)
? Padding(padding: const EdgeInsets.symmetric(vertical: 16), child: loadingWidget)
: const SizedBox.shrink();
} else {
return success is LoadingState
? Padding(padding: const EdgeInsets.symmetric(vertical: 16), child: _loadingWidget)
? Padding(padding: const EdgeInsets.symmetric(vertical: 16), child: loadingWidget)
: const SizedBox.shrink();
}
}));
}
Widget get _loadingWidget {
return const Center(child: Padding(
padding: EdgeInsets.zero,
child: SizedBox(
width: 24,
height: 24,
child: CupertinoActivityIndicator(color: AppColor.colorTextButton))));
}
Widget _buildLoadingViewLoadMore() {
return Obx(() => controller.viewState.value.fold(
(failure) => const SizedBox.shrink(),
(success) {
if (controller.isSearchActive()) {
return success is SearchingMoreState
? Padding(padding: const EdgeInsets.only(bottom: 16), child: _loadingWidget)
? Padding(padding: const EdgeInsets.only(bottom: 16), child: loadingWidget)
: const SizedBox.shrink();
} else {
return success is LoadingMoreState
? Padding(padding: const EdgeInsets.only(bottom: 16), child: _loadingWidget)
? Padding(padding: const EdgeInsets.only(bottom: 16), child: loadingWidget)
: const SizedBox.shrink();
}
}));
@@ -566,7 +344,7 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
}
Widget _buildResultListEmail(BuildContext context, List<PresentationEmail> listPresentationEmail) {
if (controller.currentSelectMode.value == SelectMode.INACTIVE) {
if (controller.mailboxDashBoardController.currentSelectMode.value == SelectMode.INACTIVE) {
return listPresentationEmail.isNotEmpty
? RefreshIndicator(
color: AppColor.colorTextButton,
@@ -608,7 +386,7 @@ class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMi
context,
listPresentationEmail[index],
controller.currentMailbox?.role,
controller.currentSelectMode.value,
controller.mailboxDashBoardController.currentSelectMode.value,
controller.mailboxDashBoardController.searchState.value.searchStatus,
controller.searchQuery)
..addOnPressEmailActionClick((action, email) => controller.pressEmailAction(context, action, email))
@@ -98,7 +98,7 @@ class AppBarThreadWidgetBuilder {
AppLocalizations.of(_context).count_email_selected(_listSelectionEmail.length),
style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorTextButton))),
buildIconWeb(
icon: SvgPicture.asset(_listSelectionEmail.isAllEmailRead ? _imagePaths.icUnread : _imagePaths.icRead, fit: BoxFit.fill),
icon: SvgPicture.asset(_listSelectionEmail.isAllEmailRead ? _imagePaths.icRead : _imagePaths.icUnread, fit: BoxFit.fill),
tooltip: _listSelectionEmail.isAllEmailRead ? AppLocalizations.of(_context).unread : AppLocalizations.of(_context).read,
onTap: () => _onEmailSelectionAction?.call(
_listSelectionEmail.isAllEmailRead ? EmailActionType.markAsUnread : EmailActionType.markAsRead,
@@ -52,21 +52,31 @@ class EmailTileBuilder {
data: ThemeData(splashColor: Colors.transparent, highlightColor: Colors.transparent),
child: ResponsiveWidget(
responsiveUtils: _responsiveUtils,
mobile: _buildListTile(),
desktop: Container(
margin: _selectModeAll == SelectMode.ACTIVE ? const EdgeInsets.only(top: 3, left: 8, right: 8) : EdgeInsets.zero,
padding: _selectModeAll == SelectMode.ACTIVE ? const EdgeInsets.symmetric(vertical: 8) : EdgeInsets.zero,
decoration: _selectModeAll == SelectMode.ACTIVE && _presentationEmail.selectMode == SelectMode.ACTIVE
? BoxDecoration(
borderRadius: BorderRadius.circular(14),
color: AppColor.colorItemEmailSelectedDesktop)
: null,
child: _buildListTileForDesktop(),
),
mobile: _wrapContainerForTile(_buildListTile()),
desktop: _wrapContainerForTile(_buildListTileForDesktop()),
)
);
}
Widget _wrapContainerForTile(Widget tile) {
if (_responsiveUtils.isDesktop(_context)) {
return Container(
margin: _selectModeAll == SelectMode.ACTIVE ? EdgeInsets.only(top: 3, left: 8, right: 8) : EdgeInsets.zero,
padding: _selectModeAll == SelectMode.ACTIVE ? EdgeInsets.symmetric(vertical: 8) : EdgeInsets.zero,
decoration: _selectModeAll == SelectMode.ACTIVE && _presentationEmail.selectMode == SelectMode.ACTIVE
? BoxDecoration(borderRadius: BorderRadius.circular(14), color: AppColor.colorItemEmailSelectedDesktop)
: null,
child: tile);
} else {
return Container(
margin: EdgeInsets.zero,
padding: EdgeInsets.only(bottom: 10, left: 16, right: 16),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(0), color: Colors.white),
alignment: Alignment.center,
child: tile);
}
}
Widget _buildListTile() {
return Container(
margin: EdgeInsets.zero,
@@ -51,54 +51,37 @@ class EmailTileBuilder {
data: ThemeData(splashColor: Colors.transparent, highlightColor: Colors.transparent),
child: ResponsiveWidget(
responsiveUtils: _responsiveUtils,
mobile: Container(
mobile: _wrapContainerForTile(_buildListTile()),
tablet: _wrapContainerForTile(_buildListTileTablet()),
desktop: _wrapContainerForTile(_buildListTileForDesktop()),
)
);
}
Widget _wrapContainerForTile(Widget tile) {
if (_responsiveUtils.isDesktop(_context)) {
return Container(
margin: _selectModeAll == SelectMode.ACTIVE ? EdgeInsets.only(top: 3, left: 8, right: 8) : EdgeInsets.zero,
padding: _selectModeAll == SelectMode.ACTIVE ? EdgeInsets.symmetric(vertical: 8) : EdgeInsets.zero,
decoration: _selectModeAll == SelectMode.ACTIVE && _presentationEmail.selectMode == SelectMode.ACTIVE
? BoxDecoration(borderRadius: BorderRadius.circular(14), color: AppColor.colorItemEmailSelectedDesktop)
: null,
child: tile,
);
} else {
return Container(
margin: _selectModeAll == SelectMode.ACTIVE
? const EdgeInsets.only(top: 3, left: 16, right: 16)
? EdgeInsets.only(top: 3, left: 16, right: 16)
: EdgeInsets.zero,
padding: _selectModeAll == SelectMode.ACTIVE
? const EdgeInsets.only(top: 8, bottom: 16, right: 8)
: const EdgeInsets.only(bottom: 10, left: 16, right: 16),
? EdgeInsets.only(top: 8, bottom: 16, right: 8)
: EdgeInsets.only(bottom: 10, left: 16, right: 16),
decoration: _selectModeAll == SelectMode.ACTIVE && _presentationEmail.selectMode == SelectMode.ACTIVE
? BoxDecoration(borderRadius: BorderRadius.circular(14), color: AppColor.colorItemEmailSelectedDesktop)
: BoxDecoration(borderRadius: BorderRadius.circular(0), color: Colors.white),
alignment: Alignment.center,
child: _buildListTile()),
tablet: Container(
margin: _selectModeAll == SelectMode.ACTIVE
? const EdgeInsets.only(top: 3, left: 16, right: 16)
: EdgeInsets.zero,
padding: _selectModeAll == SelectMode.ACTIVE
? const EdgeInsets.only(top: 8, bottom: 16, right: 8)
: const EdgeInsets.only(bottom: 10, left: 16, right: 16),
decoration: _selectModeAll == SelectMode.ACTIVE && _presentationEmail.selectMode == SelectMode.ACTIVE
? BoxDecoration(borderRadius: BorderRadius.circular(14), color: AppColor.colorItemEmailSelectedDesktop)
: BoxDecoration(borderRadius: BorderRadius.circular(0), color: Colors.white),
alignment: Alignment.center,
child: _buildListTileTabletLarge()),
tabletLarge: Container(
margin: _selectModeAll == SelectMode.ACTIVE
? const EdgeInsets.only(top: 3, left: 16, right: 16)
: EdgeInsets.zero,
padding: _selectModeAll == SelectMode.ACTIVE
? const EdgeInsets.only(top: 8, bottom: 16, right: 8)
: const EdgeInsets.only(bottom: 10, left: 16, right: 16),
decoration: _selectModeAll == SelectMode.ACTIVE && _presentationEmail.selectMode == SelectMode.ACTIVE
? BoxDecoration(borderRadius: BorderRadius.circular(14), color: AppColor.colorItemEmailSelectedDesktop)
: BoxDecoration(borderRadius: BorderRadius.circular(0), color: Colors.white),
alignment: Alignment.center,
child: _buildListTileTabletLarge()),
desktop: Container(
margin: _selectModeAll == SelectMode.ACTIVE ? const EdgeInsets.only(top: 3, left: 8, right: 8) : EdgeInsets.zero,
padding: _selectModeAll == SelectMode.ACTIVE ? const EdgeInsets.symmetric(vertical: 8) : EdgeInsets.zero,
decoration: _selectModeAll == SelectMode.ACTIVE && _presentationEmail.selectMode == SelectMode.ACTIVE
? BoxDecoration(
borderRadius: BorderRadius.circular(14),
color: AppColor.colorItemEmailSelectedDesktop)
: null,
child: _buildListTileForDesktop(),
),
)
);
child: tile);
}
}
Widget _buildListTile() {
@@ -208,7 +191,7 @@ class EmailTileBuilder {
]);
}
Widget _buildListTileTabletLarge() {
Widget _buildListTileTablet() {
return StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
return InkWell(
onTap: () => _emailActionClick?.call(EmailActionType.preview, _presentationEmail),
@@ -523,11 +506,13 @@ class EmailTileBuilder {
TextStyle? textStyle
}) {
if (_selectModeAll == SelectMode.ACTIVE) {
return Tooltip(
child: Padding(
padding: const EdgeInsets.all(12),
child: SvgPicture.asset(_presentationEmail.selectMode == SelectMode.ACTIVE ? _imagePaths.icSelected : _imagePaths.icUnSelected, fit: BoxFit.fill)),
message: AppLocalizations.of(_context).select);
return Padding(
padding: EdgeInsets.all(12),
child: SvgPicture.asset(
_presentationEmail.selectMode == SelectMode.ACTIVE
? _imagePaths.icSelected
: _imagePaths.icUnSelected,
fit: BoxFit.fill));
} else {
return Container(
width: iconSize ?? 48,