diff --git a/assets/images/ic_logout.svg b/assets/images/ic_logout.svg new file mode 100644 index 000000000..f166f3cc1 --- /dev/null +++ b/assets/images/ic_logout.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_setting.svg b/assets/images/ic_setting.svg new file mode 100644 index 000000000..c879a366f --- /dev/null +++ b/assets/images/ic_setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/lib/core.dart b/core/lib/core.dart index 4ebc370e7..432f9e855 100644 --- a/core/lib/core.dart +++ b/core/lib/core.dart @@ -61,6 +61,7 @@ export 'presentation/views/bottom_popup/cupertino_action_sheet_builder.dart'; export 'presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; export 'presentation/views/modal_sheets/edit_text_modal_sheet_builder.dart'; export 'presentation/views/search/search_bar_view.dart'; +export 'presentation/views/popup_menu/popup_menu_item_widget.dart'; // Resources export 'presentation/resources/assets_paths.dart'; diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 3840d4d77..7d2e6802c 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -92,6 +92,8 @@ class ImagePaths { String get icToastNotSpam => _getImagePath('ic_toast_not_spam.svg'); String get icNotSpam => _getImagePath('ic_not_spam.svg'); String get icAvatarSpam => _getImagePath('ic_avatar_spam.svg'); + String get icLogout => _getImagePath('ic_logout.svg'); + String get icSetting => _getImagePath('ic_setting.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/core/lib/presentation/views/image/avatar_builder.dart b/core/lib/presentation/views/image/avatar_builder.dart index c8e160145..93dfe9055 100644 --- a/core/lib/presentation/views/image/avatar_builder.dart +++ b/core/lib/presentation/views/image/avatar_builder.dart @@ -78,6 +78,7 @@ class AvatarBuilder { _onTapAvatarActionWithPositionClick?.call(position); } }, + borderRadius: BorderRadius.circular((_size ?? 40) / 2), child: Container( key: _key, width: _size ?? 40, diff --git a/core/lib/presentation/views/popup_menu/popup_menu_item_widget.dart b/core/lib/presentation/views/popup_menu/popup_menu_item_widget.dart new file mode 100644 index 000000000..a49832004 --- /dev/null +++ b/core/lib/presentation/views/popup_menu/popup_menu_item_widget.dart @@ -0,0 +1,37 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +@immutable +class PopupMenuItemWidget extends StatelessWidget { + + final Function onCallBack; + final String icon; + final String name; + final Color? iconColor; + final String? iconSelection; + + PopupMenuItemWidget(this.icon, this.name, this.onCallBack, {this.iconSelection, this.iconColor}); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => onCallBack.call(), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16), + child: SizedBox( + child: Row(children: [ + SvgPicture.asset(icon, width: 20, height: 20, fit: BoxFit.fill, color: iconColor), + SizedBox(width: 12), + Expanded(child: Text(name, + style: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500))), + if (iconSelection != null) + Padding( + padding: EdgeInsets.only(left: 12), + child: SvgPicture.asset(iconSelection!, width: 16, height: 16, fit: BoxFit.fill)), + ]) + ), + ) + ); + } +} \ No newline at end of file diff --git a/lib/features/base/action/ui_action.dart b/lib/features/base/action/ui_action.dart new file mode 100644 index 000000000..0552a70e6 --- /dev/null +++ b/lib/features/base/action/ui_action.dart @@ -0,0 +1,6 @@ + +import 'package:equatable/equatable.dart'; + +abstract class Action with EquatableMixin {} + +abstract class UIAction extends Action {} \ No newline at end of file diff --git a/lib/features/base/mixin/app_loader_mixin.dart b/lib/features/base/mixin/app_loader_mixin.dart new file mode 100644 index 000000000..f2b99fa36 --- /dev/null +++ b/lib/features/base/mixin/app_loader_mixin.dart @@ -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))); + } +} \ No newline at end of file diff --git a/lib/features/base/mixin/popup_context_menu_action_mixin.dart b/lib/features/base/mixin/popup_context_menu_action_mixin.dart index 0eb935bd7..b246a2bcc 100644 --- a/lib/features/base/mixin/popup_context_menu_action_mixin.dart +++ b/lib/features/base/mixin/popup_context_menu_action_mixin.dart @@ -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); } diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index b2d610284..e23d0bf13 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -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() { diff --git a/lib/features/email/presentation/email_bindings.dart b/lib/features/email/presentation/email_bindings.dart index af1cb70ca..9c031362a 100644 --- a/lib/features/email/presentation/email_bindings.dart +++ b/lib/features/email/presentation/email_bindings.dart @@ -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( diff --git a/lib/features/email/presentation/email_controller.dart b/lib/features/email/presentation/email_controller.dart index 6aa97b564..a08edb3ca 100644 --- a/lib/features/email/presentation/email_controller.dart +++ b/lib/features/email/presentation/email_controller.dart @@ -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(); diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index cdbad3e0e..76b23b36e 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -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(); final responsiveUtils = Get.find(); @@ -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 _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)), ]; } } \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart b/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart index 672ec239a..55641a53c 100644 --- a/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart +++ b/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart @@ -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, diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index de9542cbc..595b8d660 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -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!)) { diff --git a/lib/features/mailbox/presentation/mailbox_view_web.dart b/lib/features/mailbox/presentation/mailbox_view_web.dart index e8822ca58..66e05f6cb 100644 --- a/lib/features/mailbox/presentation/mailbox_view_web.dart +++ b/lib/features/mailbox/presentation/mailbox_view_web.dart @@ -25,11 +25,12 @@ class MailboxView extends GetWidget { @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 { 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)) diff --git a/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart b/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart index dba9e9c59..675d079ab 100644 --- a/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart +++ b/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart @@ -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), ), ) diff --git a/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart new file mode 100644 index 000000000..819e48edd --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart @@ -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 get props => []; +} + +class ComposeEmailAction extends DashBoardAction { + + RouterArguments? arguments; + + ComposeEmailAction({this.arguments}); + + @override + List get props => [arguments]; +} + +class CloseComposeEmailAction extends DashBoardAction { + + CloseComposeEmailAction(); + + @override + List get props => []; +} + +class RefreshAllEmailAction extends DashBoardAction { + + RefreshAllEmailAction(); + + @override + List get props => []; +} + +class SelectionAllEmailAction extends DashBoardAction { + + SelectionAllEmailAction(); + + @override + List get props => []; +} + +class CancelSelectionAllEmailAction extends DashBoardAction { + + CancelSelectionAllEmailAction(); + + @override + List get props => []; +} + +class MarkAsReadAllEmailAction extends DashBoardAction { + + MarkAsReadAllEmailAction(); + + @override + List get props => []; +} + +class FilterMessageAction extends DashBoardAction { + + BuildContext context; + FilterMessageOption option; + + FilterMessageAction(this.context, this.option); + + @override + List get props => [option]; +} + +class HandleEmailActionTypeAction extends DashBoardAction { + + BuildContext context; + EmailActionType emailAction; + List listEmailSelected; + + HandleEmailActionTypeAction(this.context, this.listEmailSelected, this.emailAction); + + @override + List get props => [listEmailSelected, emailAction]; +} + +class GoToSettingsAction extends DashBoardAction { + + GoToSettingsAction(); + + @override + List get props => []; +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/extensions/filter_message_option_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/filter_message_option_extension.dart new file mode 100644 index 000000000..cd5932287 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/extensions/filter_message_option_extension.dart @@ -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; + } + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart index 29aba4388..d75181e55 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart @@ -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(); final searchState = SearchState.initial().obs; final suggestionSearch = [].obs; - final dashBoardAction = DashBoardAction.none.obs; + final dashBoardAction = Rxn(); final routePath = AppRoutes.MAILBOX_DASHBOARD.obs; final appInformation = Rxn(); + final currentSelectMode = SelectMode.INACTIVE.obs; + final filterMessageOption = FilterMessageOption.all.obs; + final listEmailSelected = [].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(); - 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(); } 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(); diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart index 23e65b0db..61409c93b 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart @@ -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 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 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 with Ne crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthMobileTablet), - Expanded(child: _buildThreadAndEmailContainer(context)) + Expanded(child: _wrapContainerForThreadAndEmail(context)) ], ); } diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index 597da2c94..dc517e52f 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -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 with NetworkConnectionMixin { +class MailboxDashBoardView extends GetWidget with NetworkConnectionMixin, + UserSettingPopupMenuMixin, FilterEmailPopupMenuMixin { final _responsiveUtils = Get.find(); + final _imagePaths = Get.find(); 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 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 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(); } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/mixin/filter_email_popup_menu_mixin.dart b/lib/features/mailbox_dashboard/presentation/mixin/filter_email_popup_menu_mixin.dart new file mode 100644 index 000000000..d2f4a3644 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/mixin/filter_email_popup_menu_mixin.dart @@ -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(); + + List 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), + ]) + ), + ) + ); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart b/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart new file mode 100644 index 000000000..b66b602af --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart @@ -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(); + + List 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()); + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/model/dashboard_action.dart b/lib/features/mailbox_dashboard/presentation/model/dashboard_action.dart deleted file mode 100644 index 7af9da24b..000000000 --- a/lib/features/mailbox_dashboard/presentation/model/dashboard_action.dart +++ /dev/null @@ -1,5 +0,0 @@ - -enum DashBoardAction { - none, - compose -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart b/lib/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart deleted file mode 100644 index 6f16a9b8e..000000000 --- a/lib/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart +++ /dev/null @@ -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(); - - void openUserSettingAction(BuildContext context, RelativeRect? position, List 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 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(); - } -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/app_setting.dart b/lib/features/manage_account/presentation/model/app_setting.dart new file mode 100644 index 000000000..5de65ed1f --- /dev/null +++ b/lib/features/manage_account/presentation/model/app_setting.dart @@ -0,0 +1,6 @@ + +import 'package:tmail_ui_user/features/manage_account/presentation/model/reading_pane.dart'; + +class AppSetting { + static ReadingPane readingPane = ReadingPane.noSplit; +} \ No newline at end of file diff --git a/lib/features/setting/presentation/model/reading_pane.dart b/lib/features/manage_account/presentation/model/reading_pane.dart similarity index 100% rename from lib/features/setting/presentation/model/reading_pane.dart rename to lib/features/manage_account/presentation/model/reading_pane.dart diff --git a/lib/features/setting/presentation/model/app_setting.dart b/lib/features/setting/presentation/model/app_setting.dart deleted file mode 100644 index b2a67ec8f..000000000 --- a/lib/features/setting/presentation/model/app_setting.dart +++ /dev/null @@ -1,6 +0,0 @@ - -import 'package:tmail_ui_user/features/setting/presentation/model/reading_pane.dart'; - -class AppSetting { - static ReadingPane readingPane = ReadingPane.noSplit; -} \ No newline at end of file diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 02a83af81..7f4ce772e 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -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 = [].obs; final emailListSearch = [].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 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 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 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 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 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); } diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index e8edcb5b5..3a8d3e428 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -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 with UserSettingPopupMenuMixin { +class ThreadView extends GetWidget with AppLoaderMixin { final _responsiveUtils = Get.find(); final _imagePaths = Get.find(); @@ -44,11 +42,6 @@ class ThreadView extends GetWidget 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 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 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 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 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 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 with UserSettingPopupMenuMi } Widget _buildResultListEmail(BuildContext context, List 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 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)) diff --git a/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart b/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart index 6f87f25e7..00500b599 100644 --- a/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart +++ b/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart @@ -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, diff --git a/lib/features/thread/presentation/widgets/email_tile_builder.dart b/lib/features/thread/presentation/widgets/email_tile_builder.dart index bd273096f..2a9063c5d 100644 --- a/lib/features/thread/presentation/widgets/email_tile_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_builder.dart @@ -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, diff --git a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart index ddaeea5d4..bc5d9b68d 100644 --- a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart @@ -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, diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 095393a63..ddbed7081 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-04-15T16:53:02.138499", + "@@last_modified": "2022-04-25T09:26:28.013781", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -474,8 +474,8 @@ "placeholders_order": [], "placeholders": {} }, - "logout": "Logout", - "@logout": { + "sign_out": "Sign out", + "@sign_out": { "type": "text", "placeholders_order": [], "placeholders": {} @@ -1095,5 +1095,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "settings": "Settings", + "@settings": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "manage_account": "Manage account", + "@manage_account": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index ea2ca6f2a..642948a8a 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -506,9 +506,9 @@ class AppLocalizations { ); } - String get logout { - return Intl.message('Logout', - name: 'logout'); + String get sign_out { + return Intl.message('Sign out', + name: 'sign_out'); } String get hint_search_mailboxes { @@ -1153,4 +1153,14 @@ class AppLocalizations { name: 'un_spam', ); } + + String get settings { + return Intl.message('Settings', + name: 'settings'); + } + + String get manage_account { + return Intl.message('Manage account', + name: 'manage_account'); + } } \ No newline at end of file