diff --git a/assets/images/ic_show_mailbox.svg b/assets/images/ic_show_mailbox.svg new file mode 100644 index 000000000..4211ac007 --- /dev/null +++ b/assets/images/ic_show_mailbox.svg @@ -0,0 +1,5 @@ + + + diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 66ed9ae5d..8e1b00117 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -173,6 +173,7 @@ class ImagePaths { String get icMarkAsRead => _getImagePath('ic_mark_as_read.svg'); String get icDeleteMailbox => _getImagePath('ic_delete_mailbox.svg'); String get icHideMailbox => _getImagePath('ic_hide_mailbox.svg'); + String get icShowMailbox => _getImagePath('ic_show_mailbox.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/base/base_mailbox_controller.dart b/lib/features/base/base_mailbox_controller.dart index cb4455f6a..10d4299a0 100644 --- a/lib/features/base/base_mailbox_controller.dart +++ b/lib/features/base/base_mailbox_controller.dart @@ -17,6 +17,12 @@ import 'package:model/mailbox/select_mode.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_action_state.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_state.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_multiple_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_request.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; @@ -392,4 +398,22 @@ abstract class BaseMailboxController extends BaseController { ); } } + + SubscribeRequest? generateSubscribeRequest( + MailboxId mailboxId, + MailboxSubscribeState subscribeState, + MailboxSubscribeAction subscribeAction + ) { + final mailboxNode = findMailboxNodeById(mailboxId); + + if (mailboxNode != null) { + if (mailboxNode.hasChildren()) { + final listDescendantMailboxIds = mailboxNode.descendantsAsList().mailboxIds; + return SubscribeMultipleMailboxRequest(mailboxId, listDescendantMailboxIds, subscribeState, subscribeAction); + } else { + return SubscribeMailboxRequest(mailboxId, subscribeState, subscribeAction); + } + } + return null; + } } \ No newline at end of file diff --git a/lib/features/base/widget/popup_item_widget.dart b/lib/features/base/widget/popup_item_widget.dart new file mode 100644 index 000000000..47a402a8f --- /dev/null +++ b/lib/features/base/widget/popup_item_widget.dart @@ -0,0 +1,57 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class PopupItemWidget extends StatelessWidget { + + final String _iconAction; + final String _nameAction; + final Color? colorIcon; + final double? iconSize; + final TextStyle? styleName; + final EdgeInsets? padding; + final VoidCallback? onCallbackAction; + + const PopupItemWidget( + this._iconAction, + this._nameAction, + { + Key? key, + this.colorIcon, + this.iconSize, + this.styleName, + this.padding, + this.onCallbackAction + } + ) : super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onCallbackAction, + child: Padding( + padding: padding ?? const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + child: SizedBox( + child: Row(children: [ + SvgPicture.asset( + _iconAction, + width: iconSize ?? 20, + height: iconSize ?? 20, + fit: BoxFit.fill, + color: colorIcon + ), + const SizedBox(width: 12), + Expanded(child: Text( + _nameAction, + style: styleName ?? const TextStyle( + fontSize: 17, + fontWeight: FontWeight.normal, + color: Colors.black + ) + )), + ]) + ), + ) + ); + } +} \ No newline at end of file diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 3f8e0b527..90769534e 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -21,7 +21,7 @@ import 'package:model/extensions/list_attachment_extension.dart'; import 'package:model/extensions/list_email_content_extension.dart'; import 'package:model/extensions/presentation_email_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; -import 'package:tmail_ui_user/features/base/mixin/popup_menu_widget_mixin.dart'; +import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/app_bar_mail_widget_builder.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_file_tile_builder.dart'; @@ -32,8 +32,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/extensions/va import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -class EmailView extends GetWidget - with PopupMenuWidgetMixin { +class EmailView extends GetWidget { final responsiveUtils = Get.find(); final imagePaths = Get.find(); @@ -554,7 +553,7 @@ class EmailView extends GetWidget PopupMenuEntry _markAsEmailUnreadPopupItemAction(BuildContext context, PresentationEmail email) { return PopupMenuItem( padding: EdgeInsets.zero, - child: popupItem( + child: PopupItemWidget( imagePaths.icUnreadEmail, AppLocalizations.of(context).mark_as_unread, colorIcon: AppColor.colorTextButton, @@ -579,7 +578,7 @@ class EmailView extends GetWidget ) { return PopupMenuItem( padding: EdgeInsets.zero, - child: popupItem( + child: PopupItemWidget( mailboxContain?.isSpam == true ? imagePaths.icNotSpam : imagePaths.icSpam, mailboxContain?.isSpam == true ? AppLocalizations.of(context).remove_from_spam @@ -602,7 +601,7 @@ class EmailView extends GetWidget PopupMenuEntry _quickCreatingRulePopupItemAction(BuildContext context, PresentationEmail email) { return PopupMenuItem( padding: EdgeInsets.zero, - child: popupItem( + child: PopupItemWidget( imagePaths.icQuickCreatingRule, AppLocalizations.of(context).quickCreatingRule, colorIcon: AppColor.colorTextButton, diff --git a/lib/features/mailbox/domain/model/mailbox_subscribe_action_state.dart b/lib/features/mailbox/domain/model/mailbox_subscribe_action_state.dart index 106655294..92a9eca18 100644 --- a/lib/features/mailbox/domain/model/mailbox_subscribe_action_state.dart +++ b/lib/features/mailbox/domain/model/mailbox_subscribe_action_state.dart @@ -1,5 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + enum MailboxSubscribeAction { subscribe, unSubscribe, - undo + undo; + + String getToastMessageSuccess(BuildContext context) { + switch(this) { + case MailboxSubscribeAction.subscribe: + return AppLocalizations.of(context).toastMessageShowMailboxSuccess; + case MailboxSubscribeAction.unSubscribe: + return AppLocalizations.of(context).toastMsgHideMailboxSuccess; + case MailboxSubscribeAction.undo: + return ''; + } + } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 41e60d348..a6caabc73 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -52,7 +52,6 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/rename_mailbox_in import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart'; @@ -993,29 +992,11 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM await refreshTree(_mailboxList); } - SubscribeRequest? _generateSubscribeRequest( - MailboxId mailboxId, - MailboxSubscribeState subscribeState, - MailboxSubscribeAction subscribeAction - ) { - final mailboxNode = findMailboxNodeById(mailboxId); - - if (mailboxNode != null) { - if (mailboxNode.hasChildren()) { - final listDescendantMailboxIds = mailboxNode.descendantsAsList().mailboxIds; - return SubscribeMultipleMailboxRequest(mailboxId, listDescendantMailboxIds, subscribeState, subscribeAction); - } else { - return SubscribeMailboxRequest(mailboxId, subscribeState, subscribeAction); - } - } - return null; - } - void _unsubscribeMailboxAction(MailboxId mailboxId) { final _accountId = mailboxDashBoardController.accountId.value; if (_accountId != null) { - final subscribeRequest = _generateSubscribeRequest( + final subscribeRequest = generateSubscribeRequest( mailboxId, MailboxSubscribeState.disabled, MailboxSubscribeAction.unSubscribe @@ -1146,25 +1127,4 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM } } } - - MailboxActions _mailboxActionForSpam() { - return mailboxDashBoardController.enableSpamReport - ? MailboxActions.disableSpamReport - : MailboxActions.enableSpamReport; - } - - List listActionForMailbox(PresentationMailbox mailbox) { - return [ - if (BuildUtils.isWeb) - MailboxActions.openInNewTab, - if (mailbox.isSpam) - _mailboxActionForSpam(), - MailboxActions.markAsRead, - MailboxActions.move, - MailboxActions.rename, - MailboxActions.delete, - if (mailbox.isSupportedDisableMailbox) - MailboxActions.disableMailbox - ]; - } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_view.dart b/lib/features/mailbox/presentation/mailbox_view.dart index 3bd31373d..6ea660b46 100644 --- a/lib/features/mailbox/presentation/mailbox_view.dart +++ b/lib/features/mailbox/presentation/mailbox_view.dart @@ -6,18 +6,16 @@ import 'package:get/get.dart'; import 'package:model/model.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/model/context_item_mailbox_action.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/bottom_bar_selection_mailbox_widget.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_bottom_sheet_action_tile_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/user_information_widget_builder.dart'; import 'package:tmail_ui_user/features/quotas/presentation/widget/quotas_footer_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -class MailboxView extends GetWidget { +class MailboxView extends GetWidget with MailboxWidgetMixin { final _imagePaths = Get.find(); final _responsiveUtils = Get.find(); @@ -328,95 +326,54 @@ class MailboxView extends GetWidget { ]); } - MailboxActions _mailboxActionForSpam() { - return controller.mailboxDashBoardController.enableSpamReport - ? MailboxActions.disableSpamReport - : MailboxActions.enableSpamReport; - } - - List _listActionForMailbox(PresentationMailbox mailbox) { - return [ - if (BuildUtils.isWeb) - MailboxActions.openInNewTab, - if (mailbox.isSpam) - _mailboxActionForSpam(), - MailboxActions.markAsRead, - MailboxActions.move, - MailboxActions.rename, - MailboxActions.delete, - if (mailbox.isSupportedDisableMailbox) - MailboxActions.disableMailbox - ]; - } - - void _openBottomSheetMailboxMenuAction(BuildContext context, PresentationMailbox mailbox) { - final mailboxActionsSupported = _listActionForMailbox(mailbox); - - final listContextMailboxPopupMenuItemAction = mailboxActionsSupported - .map((action) => ContextMenuItemMailboxAction(action, action.getContextMenuItemState(mailbox))) - .toList(); - - controller.openContextMenuAction( - context, - _bottomSheetMailboxActionTiles( - context, - mailbox, - listContextMailboxPopupMenuItemAction - ) - ); - } - - List _bottomSheetMailboxActionTiles( - BuildContext context, - PresentationMailbox mailbox, - List contextMenuActions - ) { - return contextMenuActions - .map((action) => _openBottomSheetMailboxMenuActionTile(context, action, mailbox)) - .toList(); - } - - Widget _openBottomSheetMailboxMenuActionTile( - BuildContext context, - ContextMenuItemMailboxAction contextMenuItem, - PresentationMailbox mailbox - ) { - return (MailboxBottomSheetActionTileBuilder( - Key('${contextMenuItem.action.name}_action'), - SvgPicture.asset( - contextMenuItem.action.getContextMenuIcon(_imagePaths), - color: AppColor.primaryColor), - contextMenuItem.action.getTitleContextMenu(context), - mailbox, - absorbing: !contextMenuItem.isActivated, - opacity: !contextMenuItem.isActivated) - ..onActionClick((mailbox) => controller.handleMailboxAction(context, contextMenuItem.action, mailbox))) - .build(); - } - List _buildListChildTileWidget(BuildContext context, MailboxNode parentNode, {MailboxNode? lastNode}) { return parentNode.childrenItems - ?.map((mailboxNode) => mailboxNode.hasChildren() - ? TreeViewChild( + ?.map((mailboxNode) { + if (mailboxNode.hasChildren()) { + return TreeViewChild( + context, + key: const Key('children_tree_mailbox_child'), + isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND, + parent: Obx(() => (MailBoxFolderTileBuilder( + context, + _imagePaths, + mailboxNode, + lastNode: lastNode, + allSelectMode: controller.currentSelectMode.value) + ..addOnLongPressMailboxNodeAction((mailboxNode) { + openMailboxMenuActionOnMobile( + context, + _imagePaths, + mailboxNode.item, + controller + ); + }) + ..addOnClickOpenMailboxNodeAction((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) + ..addOnClickExpandMailboxNodeAction((mailboxNode) => controller.toggleMailboxFolder(mailboxNode)) + ..addOnSelectMailboxNodeAction((mailboxNode) => controller.selectMailboxNode(mailboxNode)) + ).build()), + children: _buildListChildTileWidget(context, mailboxNode) + ).build(); + } else { + return Obx(() => (MailBoxFolderTileBuilder( context, - key: const Key('children_tree_mailbox_child'), - isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND, - parent: Obx(() => (MailBoxFolderTileBuilder(context, _imagePaths, mailboxNode, lastNode: lastNode, - allSelectMode: controller.currentSelectMode.value) - ..addOnLongPressMailboxNodeAction((mailboxNode) => _openBottomSheetMailboxMenuAction(context, mailboxNode.item)) - ..addOnClickOpenMailboxNodeAction((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) - ..addOnClickExpandMailboxNodeAction((mailboxNode) => controller.toggleMailboxFolder(mailboxNode)) - ..addOnSelectMailboxNodeAction((mailboxNode) => controller.selectMailboxNode(mailboxNode))) - .build()), - children: _buildListChildTileWidget(context, mailboxNode) - ).build() - : Obx(() => (MailBoxFolderTileBuilder(context, _imagePaths, mailboxNode, lastNode: lastNode, + _imagePaths, + mailboxNode, + lastNode: lastNode, allSelectMode: controller.currentSelectMode.value) - ..addOnLongPressMailboxNodeAction((mailboxNode) => _openBottomSheetMailboxMenuAction(context, mailboxNode.item)) + ..addOnLongPressMailboxNodeAction((mailboxNode) { + openMailboxMenuActionOnMobile( + context, + _imagePaths, + mailboxNode.item, + controller + ); + }) ..addOnClickOpenMailboxNodeAction((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) - ..addOnSelectMailboxNodeAction((mailboxNode) => controller.selectMailboxNode(mailboxNode))) - .build()) - ).toList() ?? []; + ..addOnSelectMailboxNodeAction((mailboxNode) => controller.selectMailboxNode(mailboxNode)) + ).build()); + } + }).toList() ?? []; } Widget _buildOptionSelectionMailbox(BuildContext context) { diff --git a/lib/features/mailbox/presentation/mailbox_view_web.dart b/lib/features/mailbox/presentation/mailbox_view_web.dart index 196f72e46..227dc30e5 100644 --- a/lib/features/mailbox/presentation/mailbox_view_web.dart +++ b/lib/features/mailbox/presentation/mailbox_view_web.dart @@ -5,13 +5,10 @@ import 'package:get/get.dart'; import 'package:model/model.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; -import 'package:tmail_ui_user/features/base/mixin/popup_menu_widget_mixin.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/model/context_item_mailbox_action.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_bottom_sheet_action_tile_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/user_information_widget_builder.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/app_dashboard/app_list_dashboard_item.dart'; @@ -19,7 +16,9 @@ import 'package:tmail_ui_user/features/quotas/presentation/widget/quotas_footer_ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; -class MailboxView extends GetWidget with AppLoaderMixin, PopupMenuWidgetMixin { +class MailboxView extends GetWidget + with AppLoaderMixin, + MailboxWidgetMixin { final _imagePaths = Get.find(); final _responsiveUtils = Get.find(); @@ -135,7 +134,10 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu const Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), const SizedBox(height: 13), Padding( - padding: EdgeInsets.only(left: _responsiveUtils.isDesktop(context) ? 0 : 12), + padding: EdgeInsets.only( + left: _responsiveUtils.isDesktop(context) ? 0 : 12, + bottom: 8 + ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -170,24 +172,50 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu )), ]), ), - const SizedBox(height: 8), - Obx(() => controller.personalMailboxIsNotEmpty - ? Column( - children: [ - _buildHeaderMailboxCategory(context, MailboxCategories.personalMailboxes), - _buildMailboxCategory(context, MailboxCategories.personalMailboxes, controller.personalRootNode), - ], - ) - : const SizedBox.shrink()), - const SizedBox(height: 8), - Obx(() => controller.teamMailboxesIsNotEmpty - ? Column( - children: [ - _buildHeaderMailboxCategory(context, MailboxCategories.teamMailboxes), - _buildMailboxCategory(context, MailboxCategories.teamMailboxes, controller.teamMailboxesRootNode), - ], - ) - : const SizedBox.shrink()), + Obx(() { + if (controller.personalMailboxIsNotEmpty) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Column( + children: [ + _buildHeaderMailboxCategory( + context, + MailboxCategories.personalMailboxes + ), + _buildMailboxCategory( + context, + MailboxCategories.personalMailboxes, + controller.personalRootNode + ), + ], + ), + ); + } else { + return const SizedBox.shrink(); + } + }), + Obx(() { + if (controller.teamMailboxesIsNotEmpty) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Column( + children: [ + _buildHeaderMailboxCategory( + context, + MailboxCategories.teamMailboxes + ), + _buildMailboxCategory( + context, + MailboxCategories.teamMailboxes, + controller.teamMailboxesRootNode + ), + ] + ) + ); + } else { + return const SizedBox.shrink(); + } + }) ]) ), Obx(() => controller.mailboxDashBoardController.isDraggingMailbox @@ -284,39 +312,63 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu : const Offstage()); } - List _buildListChildTileWidget(BuildContext context, - MailboxNode parentNode, {MailboxNode? lastNode}) { - return parentNode.childrenItems - ?.map((mailboxNode) => mailboxNode.hasChildren() - ? TreeViewChild( + List _buildListChildTileWidget( + BuildContext context, + MailboxNode parentNode, + {MailboxNode? lastNode} + ) { + return parentNode.childrenItems?.map((mailboxNode) { + if (mailboxNode.hasChildren()) { + return TreeViewChild( + context, + key: const Key('children_tree_mailbox_child'), + isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND, + parent: Obx(() => (MailBoxFolderTileBuilder( context, - key: const Key('children_tree_mailbox_child'), - isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND, - parent: Obx(() => (MailBoxFolderTileBuilder(context, _imagePaths, mailboxNode, lastNode: lastNode, - mailboxNodeSelected: controller.mailboxDashBoardController.selectedMailbox.value) - ..addOnClickOpenMailboxNodeAction((mailboxNode) => - controller.openMailbox(context, mailboxNode.item)) - ..addOnClickExpandMailboxNodeAction((mailboxNode) => - controller.toggleMailboxFolder(mailboxNode)) - ..addOnClickOpenMenuMailboxNodeAction((position, mailboxNode) => - _openMailboxMenuAction(context, position, mailboxNode.item)) - ..addOnSelectMailboxNodeAction((mailboxNode) => - controller.selectMailboxNode(mailboxNode)) - ..addOnDragEmailToMailboxAccepted(_handleDragItemAccepted)) - .build()), - children: _buildListChildTileWidget(context, mailboxNode) - ).build() - : Obx(() => (MailBoxFolderTileBuilder(context, _imagePaths, mailboxNode, lastNode: lastNode, - mailboxNodeSelected: controller.mailboxDashBoardController.selectedMailbox.value) - ..addOnClickOpenMailboxNodeAction((mailboxNode) => - controller.openMailbox(context, mailboxNode.item)) - ..addOnClickOpenMenuMailboxNodeAction((position, mailboxNode) => - _openMailboxMenuAction(context, position, mailboxNode.item)) - ..addOnSelectMailboxNodeAction((mailboxNode) => - controller.selectMailboxNode(mailboxNode)) - ..addOnDragEmailToMailboxAccepted(_handleDragItemAccepted)) - .build()) - ).toList() ?? []; + _imagePaths, + mailboxNode, + lastNode: lastNode, + mailboxNodeSelected: controller.mailboxDashBoardController.selectedMailbox.value) + ..addOnClickOpenMailboxNodeAction((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) + ..addOnClickExpandMailboxNodeAction((mailboxNode) => controller.toggleMailboxFolder(mailboxNode)) + ..addOnClickOpenMenuMailboxNodeAction((position, mailboxNode) { + openMailboxMenuActionOnWeb( + context, + _imagePaths, + _responsiveUtils, + position, + mailboxNode.item, + controller + ); + }) + ..addOnSelectMailboxNodeAction((mailboxNode) => controller.selectMailboxNode(mailboxNode)) + ..addOnDragEmailToMailboxAccepted(_handleDragItemAccepted) + ).build()), + children: _buildListChildTileWidget(context, mailboxNode) + ).build(); + } else { + return Obx(() => (MailBoxFolderTileBuilder( + context, + _imagePaths, + mailboxNode, + lastNode: lastNode, + mailboxNodeSelected: controller.mailboxDashBoardController.selectedMailbox.value) + ..addOnClickOpenMailboxNodeAction((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) + ..addOnClickOpenMenuMailboxNodeAction((position, mailboxNode) { + openMailboxMenuActionOnWeb( + context, + _imagePaths, + _responsiveUtils, + position, + mailboxNode.item, + controller + ); + }) + ..addOnSelectMailboxNodeAction((mailboxNode) => controller.selectMailboxNode(mailboxNode)) + ..addOnDragEmailToMailboxAccepted(_handleDragItemAccepted) + ).build()); + } + }).toList() ?? []; } void _handleDragItemAccepted(List listEmails, PresentationMailbox presentationMailbox) { @@ -342,109 +394,6 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu ); } - void _openMailboxMenuAction( - BuildContext context, - RelativeRect position, - PresentationMailbox mailbox - ) { - final mailboxActionsSupported = controller.listActionForMailbox(mailbox); - - final listContextMenuItemAction = mailboxActionsSupported - .map((action) => ContextMenuItemMailboxAction( - action, - action.getContextMenuItemState(mailbox))) - .toList(); - - if (_responsiveUtils.isScreenWithShortestSide(context)) { - controller.openContextMenuAction( - context, - _bottomSheetMailboxActionTiles( - context, - mailbox, - listContextMenuItemAction)); - } else { - controller.openPopupMenuAction( - context, - position, - _popupMenuMailboxActionTiles( - context, - mailbox, - listContextMenuItemAction)); - } - } - - List _bottomSheetMailboxActionTiles( - BuildContext context, - PresentationMailbox mailbox, - List contextMenuActions - ) { - return contextMenuActions - .map((action) => _mailboxContextMenuActionTile(context, action, mailbox)) - .toList(); - } - - Widget _mailboxContextMenuActionTile( - BuildContext context, - ContextMenuItemMailboxAction contextMenuItem, - PresentationMailbox mailbox - ) { - return (MailboxBottomSheetActionTileBuilder( - Key('${contextMenuItem.action.name}_action'), - SvgPicture.asset( - contextMenuItem.action.getContextMenuIcon(_imagePaths), - color: contextMenuItem.action.getColorContextMenuIcon(), - width: 24, - height: 24 - ), - contextMenuItem.action.getTitleContextMenu(context), - mailbox, - absorbing: !contextMenuItem.isActivated, - opacity: !contextMenuItem.isActivated) - ..actionTextStyle(textStyle: const TextStyle( - fontSize: 16, - color: Colors.black, - fontWeight: FontWeight.w500 - )) - ..onActionClick((mailbox) => controller.handleMailboxAction(context, contextMenuItem.action, mailbox))) - .build(); - } - - List _popupMenuMailboxActionTiles( - BuildContext context, - PresentationMailbox mailbox, - List contextMenuActions - ) { - return contextMenuActions - .map((action) => _mailboxPopupMenuActionTile(context, action, mailbox)) - .toList(); - } - - PopupMenuItem _mailboxPopupMenuActionTile( - BuildContext context, - ContextMenuItemMailboxAction contextMenuItem, - PresentationMailbox mailbox - ) { - return PopupMenuItem( - padding: EdgeInsets.zero, - child: AbsorbPointer( - absorbing: !contextMenuItem.isActivated, - child: Opacity( - opacity: contextMenuItem.isActivated ? 1.0 : 0.3, - child: popupItem( - contextMenuItem.action.getContextMenuIcon(_imagePaths), - contextMenuItem.action.getTitleContextMenu(context), - colorIcon: contextMenuItem.action.getColorContextMenuIcon(), - styleName: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 16, - color: contextMenuItem.action.getColorContextMenuTitle() - ), - onCallbackAction: () => controller.handleMailboxAction(context, contextMenuItem.action, mailbox) - ), - ), - )); - } - Widget _buildAppGridDashboard(BuildContext context) { return Column( children: [ @@ -452,9 +401,12 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu AnimatedContainer( padding: const EdgeInsets.only(top: 8), duration: const Duration(milliseconds: 400), - child: controller.mailboxDashBoardController.appGridDashboardController.appDashboardExpandMode.value == ExpandMode.EXPAND - ? _buildAppGridInMailboxView(context) - : const Offstage()) + child: Obx(() { + return controller.mailboxDashBoardController.appGridDashboardController.appDashboardExpandMode.value == ExpandMode.EXPAND + ? _buildAppGridInMailboxView(context) + : const Offstage(); + }) + ) ]); } diff --git a/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart b/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart new file mode 100644 index 000000000..c4f75deb5 --- /dev/null +++ b/lib/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart @@ -0,0 +1,217 @@ + +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/utils/build_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/context_item_mailbox_action.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_bottom_sheet_action_tile_builder.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; + +mixin MailboxWidgetMixin { + + MailboxActions _mailboxActionForSpam(MailboxDashBoardController dashBoardController) { + return dashBoardController.enableSpamReport + ? MailboxActions.disableSpamReport + : MailboxActions.enableSpamReport; + } + + List listActionForMailbox( + PresentationMailbox mailbox, + MailboxDashBoardController dashBoardController + ) { + return [ + if (BuildUtils.isWeb) + MailboxActions.openInNewTab, + if (mailbox.isSpam) + _mailboxActionForSpam(dashBoardController), + MailboxActions.markAsRead, + MailboxActions.move, + MailboxActions.rename, + MailboxActions.delete, + if (mailbox.isSupportedDisableMailbox) + MailboxActions.disableMailbox + ]; + } + + void openMailboxMenuActionOnMobile( + BuildContext context, + ImagePaths imagePaths, + PresentationMailbox mailbox, + MailboxController controller + ) { + final contextMenuActions = listContextMenuItemAction(mailbox, controller.mailboxDashBoardController); + + controller.openContextMenuAction( + context, + contextMenuMailboxActionTiles( + context, + imagePaths, + mailbox, + contextMenuActions, + handleMailboxAction: controller.handleMailboxAction + ) + ); + } + + List contextMenuMailboxActionTiles( + BuildContext context, + ImagePaths imagePaths, + PresentationMailbox mailbox, + List contextMenuActions, + { + required Function(BuildContext, MailboxActions, PresentationMailbox) handleMailboxAction + } + ) { + return contextMenuActions + .map((action) => _buildContextMenuActionTile( + context, + imagePaths, + action, + mailbox, + handleMailboxAction: handleMailboxAction + )) + .toList(); + } + + Widget _buildContextMenuActionTile( + BuildContext context, + ImagePaths imagePaths, + ContextMenuItemMailboxAction contextMenuItem, + PresentationMailbox mailbox, + { + required Function(BuildContext, MailboxActions, PresentationMailbox) handleMailboxAction + } + ) { + return (MailboxBottomSheetActionTileBuilder( + Key('${contextMenuItem.action.name}_action'), + SvgPicture.asset( + contextMenuItem.action.getContextMenuIcon(imagePaths), + color: contextMenuItem.action.getColorContextMenuIcon(), + width: 24, + height: 24 + ), + contextMenuItem.action.getTitleContextMenu(context), + mailbox, + absorbing: !contextMenuItem.isActivated, + opacity: !contextMenuItem.isActivated) + ..actionTextStyle(textStyle: TextStyle( + fontSize: 16, + color: contextMenuItem.action.getColorContextMenuTitle(), + fontWeight: FontWeight.w500 + )) + ..onActionClick((mailbox) => handleMailboxAction(context, contextMenuItem.action, mailbox)) + ).build(); + } + + List listContextMenuItemAction( + PresentationMailbox mailbox, + MailboxDashBoardController dashBoardController, + { + List? mailboxActions + } + ) { + final mailboxActionsSupported = mailboxActions ?? listActionForMailbox( + mailbox, + dashBoardController + ); + + final listContextMenuItemAction = mailboxActionsSupported + .map((action) => ContextMenuItemMailboxAction(action, action.getContextMenuItemState(mailbox))) + .toList(); + + return listContextMenuItemAction; + } + + void openMailboxMenuActionOnWeb( + BuildContext context, + ImagePaths imagePaths, + ResponsiveUtils responsiveUtils, + RelativeRect position, + PresentationMailbox mailbox, + MailboxController controller + ) { + final contextMenuActions = listContextMenuItemAction(mailbox, controller.mailboxDashBoardController); + + if (responsiveUtils.isScreenWithShortestSide(context)) { + controller.openContextMenuAction( + context, + contextMenuMailboxActionTiles( + context, + imagePaths, + mailbox, + contextMenuActions, + handleMailboxAction: controller.handleMailboxAction + ) + ); + } else { + controller.openPopupMenuAction( + context, + position, + popupMenuMailboxActionTiles( + context, + imagePaths, + mailbox, + contextMenuActions, + handleMailboxAction: controller.handleMailboxAction + ) + ); + } + } + + List popupMenuMailboxActionTiles( + BuildContext context, + ImagePaths imagePaths, + PresentationMailbox mailbox, + List contextMenuActions, + { + required Function(BuildContext, MailboxActions, PresentationMailbox) handleMailboxAction + } + ) { + return contextMenuActions + .map((action) => _buildPopupMenuItem( + context, + imagePaths, + action, + mailbox, + handleMailboxAction: handleMailboxAction + )) + .toList(); + } + + PopupMenuItem _buildPopupMenuItem( + BuildContext context, + ImagePaths imagePaths, + ContextMenuItemMailboxAction contextMenuItem, + PresentationMailbox mailbox, + { + required Function(BuildContext, MailboxActions, PresentationMailbox) handleMailboxAction + } + ) { + return PopupMenuItem( + padding: EdgeInsets.zero, + child: AbsorbPointer( + absorbing: !contextMenuItem.isActivated, + child: Opacity( + opacity: contextMenuItem.isActivated ? 1.0 : 0.3, + child: PopupItemWidget( + contextMenuItem.action.getContextMenuIcon(imagePaths), + contextMenuItem.action.getTitleContextMenu(context), + colorIcon: contextMenuItem.action.getColorContextMenuIcon(), + iconSize: 24, + styleName: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16, + color: contextMenuItem.action.getColorContextMenuTitle() + ), + onCallbackAction: () => handleMailboxAction(context, contextMenuItem.action, mailbox) + ), + ), + ) + ); + } +} \ No newline at end of file diff --git a/lib/features/mailbox/presentation/model/mailbox_actions.dart b/lib/features/mailbox/presentation/model/mailbox_actions.dart index c5b1c14fc..0ca833461 100644 --- a/lib/features/mailbox/presentation/model/mailbox_actions.dart +++ b/lib/features/mailbox/presentation/model/mailbox_actions.dart @@ -17,7 +17,8 @@ enum MailboxActions { openInNewTab, disableSpamReport, enableSpamReport, - disableMailbox + disableMailbox, + enableMailbox } extension MailboxActionsExtension on MailboxActions { @@ -55,6 +56,8 @@ extension MailboxActionsExtension on MailboxActions { return AppLocalizations.of(context).deleteMailbox; case MailboxActions.disableMailbox: return AppLocalizations.of(context).hideMailBoxes; + case MailboxActions.enableMailbox: + return AppLocalizations.of(context).showMailbox; default: return ''; } @@ -78,6 +81,8 @@ extension MailboxActionsExtension on MailboxActions { return imagePaths.icDeleteMailbox; case MailboxActions.disableMailbox: return imagePaths.icHideMailbox; + case MailboxActions.enableMailbox: + return imagePaths.icShowMailbox; default: return ''; } @@ -142,9 +147,10 @@ extension MailboxActionsExtension on MailboxActions { case MailboxActions.openInNewTab: case MailboxActions.disableSpamReport: case MailboxActions.enableSpamReport: - return mailbox.isPersonal - ? ContextMenuItemState.activated - : ContextMenuItemState.deactivated; + return mailbox.isPersonal + ? ContextMenuItemState.activated + : ContextMenuItemState.deactivated; + case MailboxActions.enableMailbox: case MailboxActions.disableMailbox: return mailbox.hasRole() ? ContextMenuItemState.deactivated @@ -156,7 +162,7 @@ extension MailboxActionsExtension on MailboxActions { case MailboxActions.move: case MailboxActions.rename: case MailboxActions.delete: - return !mailbox.hasRole() && mailbox.isPersonal + return !mailbox.hasRole() && mailbox.isPersonal ? ContextMenuItemState.activated : ContextMenuItemState.deactivated; default: diff --git a/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart b/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart index 8df7a0faa..6828c8050 100644 --- a/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart +++ b/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart @@ -133,7 +133,7 @@ class MailBoxFolderTileBuilder { child: Material( color: Colors.transparent, child: InkWell( - onLongPress: () => _onLongPressMailboxFolderClick?.call(_mailboxNode), + onLongPress: () => _onLongPressMailboxNodeAction?.call(_mailboxNode), onTap: () => allSelectMode == SelectMode.ACTIVE ? _onSelectMailboxFolderClick?.call(_mailboxNode) : _onOpenMailboxFolderClick?.call(_mailboxNode), 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 5c50d7497..cfb5ea8bc 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -191,7 +191,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { : const SizedBox.shrink() ), Obx(() => controller.searchMailboxActivated.value == true && !responsiveUtils.isWebDesktop(context) - ? const PointerInterceptor(child: SearchMailboxView()) + ? const SearchMailboxView() : const SizedBox.shrink() ), _buildDownloadTaskStateWidget(), diff --git a/lib/features/search/mailbox/presentation/search_mailbox_bindings.dart b/lib/features/search/mailbox/presentation/search_mailbox_bindings.dart index 1348b36bc..92f47338e 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_bindings.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_bindings.dart @@ -20,6 +20,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailb import 'package:tmail_ui_user/features/mailbox/domain/usecases/rename_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/search_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/search/mailbox/presentation/search_mailbox_controller.dart'; @@ -38,6 +39,7 @@ class SearchMailboxBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), Get.find(), Get.find() )); @@ -76,6 +78,7 @@ class SearchMailboxBindings extends BaseBindings { Get.lazyPut(() => VerifyNameInteractor()); Get.lazyPut(() => SearchMailboxInteractor()); Get.lazyPut(() => SubscribeMailboxInteractor(Get.find())); + Get.lazyPut(() => SubscribeMultipleMailboxInteractor(Get.find())); } @override diff --git a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart index 0186cfc6c..5a63ced6e 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart @@ -13,6 +13,8 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:model/email/presentation_email.dart'; +import 'package:model/extensions/presentation_email_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:debounce_throttle/debounce_throttle.dart'; @@ -23,6 +25,8 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_st import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_multiple_mailbox_request.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/delete_multiple_mailbox_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart'; @@ -31,6 +35,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/state/refresh_changes_all_ import 'package:tmail_ui_user/features/mailbox/domain/state/rename_mailbox_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/search_mailbox_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/subscribe_mailbox_state.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/state/subscribe_multiple_mailbox_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/delete_multiple_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/move_mailbox_interactor.dart'; @@ -38,12 +43,14 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailb import 'package:tmail_ui_user/features/mailbox/domain/usecases/rename_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/search_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/utils/mailbox_utils.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; import 'package:tmail_ui_user/features/search/mailbox/presentation/search_mailbox_bindings.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -59,6 +66,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa final MoveMailboxInteractor _moveMailboxInteractor; final DeleteMultipleMailboxInteractor _deleteMultipleMailboxInteractor; final SubscribeMailboxInteractor _subscribeMailboxInteractor; + final SubscribeMultipleMailboxInteractor _subscribeMultipleMailboxInteractor; final dashboardController = Get.find(); final responsiveUtils = Get.find(); @@ -70,6 +78,10 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa final textInputSearchController = TextEditingController(); late Debouncer _deBouncerTime; + PresentationMailbox? get selectedMailbox => dashboardController.selectedMailbox.value; + + PresentationEmail? get selectedEmail => dashboardController.selectedEmail.value; + SearchMailboxController( this._getAllMailboxInteractor, this._refreshAllMailboxInteractor, @@ -78,6 +90,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa this._moveMailboxInteractor, this._deleteMultipleMailboxInteractor, this._subscribeMailboxInteractor, + this._subscribeMultipleMailboxInteractor, TreeBuilder treeBuilder, VerifyNameInteractor verifyNameInteractor ) : super(treeBuilder, verifyNameInteractor); @@ -126,12 +139,16 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa refreshMailboxChanges(mailboxState: success.currentMailboxState); } else if (success is MoveMailboxSuccess) { _moveMailboxSuccess(success); - }else if (success is DeleteMultipleMailboxAllSuccess) { + } else if (success is DeleteMultipleMailboxAllSuccess) { _deleteMultipleMailboxSuccess(success.listMailboxIdDeleted, success.currentMailboxState); } else if (success is DeleteMultipleMailboxHasSomeSuccess) { _deleteMultipleMailboxSuccess(success.listMailboxIdDeleted, success.currentMailboxState); } else if (success is SubscribeMailboxSuccess) { _handleSubscribeMailboxSuccess(success); + } else if (success is SubscribeMultipleMailboxAllSuccess) { + _handleSubscribeMultipleMailboxAllSuccess(success); + } else if (success is SubscribeMultipleMailboxHasSomeSuccess) { + _handleSubscribeMultipleMailboxHasSomeSuccess(success); } } @@ -222,7 +239,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa case MailboxActions.disableSpamReport: case MailboxActions.enableSpamReport: dashboardController.storeSpamReportStateAction(); - return; + break; case MailboxActions.markAsRead: markAsReadMailboxAction(context, mailbox, dashboardController); break; @@ -252,11 +269,18 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa ); break; case MailboxActions.disableMailbox: - _subscribeMailboxAction(SubscribeMailboxRequest( + _updateSubscribeStateOfMailboxAction( mailbox.id, MailboxSubscribeState.disabled, MailboxSubscribeAction.unSubscribe - )); + ); + break; + case MailboxActions.enableMailbox: + _updateSubscribeStateOfMailboxAction( + mailbox.id, + MailboxSubscribeState.enabled, + MailboxSubscribeAction.subscribe + ); break; default: break; @@ -394,26 +418,105 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa } } - void _subscribeMailboxAction(SubscribeMailboxRequest subscribeMailboxRequest) { + void _updateSubscribeStateOfMailboxAction( + MailboxId mailboxId, + MailboxSubscribeState subscribeState, + MailboxSubscribeAction subscribeAction + ) { final _accountId = dashboardController.accountId.value; if (_accountId != null) { - consumeState(_subscribeMailboxInteractor.execute( - _accountId, - subscribeMailboxRequest - )); + final subscribeRequest = generateSubscribeRequest(mailboxId, subscribeState, subscribeAction); + + if (subscribeRequest is SubscribeMultipleMailboxRequest) { + consumeState(_subscribeMultipleMailboxInteractor.execute(_accountId, subscribeRequest)); + } else if (subscribeRequest is SubscribeMailboxRequest) { + consumeState(_subscribeMailboxInteractor.execute(_accountId, subscribeRequest)); + } + } + } + + void openMailboxAction(BuildContext context, PresentationMailbox mailbox) { + FocusScope.of(context).unfocus(); + dashboardController.openMailboxAction(context, mailbox); + + if (!responsiveUtils.isWebDesktop(context)) { + closeSearchView(context); } } void _handleSubscribeMailboxSuccess(SubscribeMailboxSuccess success) { - if(success.mailboxSubscribeStateAction == MailboxSubscribeAction.unSubscribe - && currentOverlayContext != null - && currentContext != null - ) { + if (success.subscribeAction != MailboxSubscribeAction.undo) { + _showToastSubscribeMailboxSuccess(success.mailboxId, success.subscribeAction); + + if (success.mailboxId == selectedMailbox?.id) { + dashboardController.selectedMailbox.value = null; + dashboardController.dispatchMailboxUIAction(SelectMailboxDefaultAction()); + _closeEmailViewIfMailboxDisabledOrNotExist([success.mailboxId]); + } + } + + refreshMailboxChanges(mailboxState: success.currentMailboxState); + } + + void _handleSubscribeMultipleMailboxAllSuccess(SubscribeMultipleMailboxAllSuccess success) { + if(success.subscribeAction != MailboxSubscribeAction.undo) { + _showToastSubscribeMailboxSuccess( + success.parentMailboxId, + success.subscribeAction, + listDescendantMailboxIds: success.mailboxIdsSubscribe + ); + + if (success.mailboxIdsSubscribe.contains(selectedMailbox?.id)) { + dashboardController.selectedMailbox.value = null; + dashboardController.dispatchMailboxUIAction(SelectMailboxDefaultAction()); + _closeEmailViewIfMailboxDisabledOrNotExist(success.mailboxIdsSubscribe); + } + } + + refreshMailboxChanges(mailboxState: success.currentMailboxState); + } + + void _handleSubscribeMultipleMailboxHasSomeSuccess(SubscribeMultipleMailboxHasSomeSuccess success) { + if(success.subscribeAction != MailboxSubscribeAction.undo) { + _showToastSubscribeMailboxSuccess( + success.parentMailboxId, + success.subscribeAction, + listDescendantMailboxIds: success.mailboxIdsSubscribe + ); + + if (success.mailboxIdsSubscribe.contains(selectedMailbox?.id)) { + dashboardController.selectedMailbox.value = null; + dashboardController.dispatchMailboxUIAction(SelectMailboxDefaultAction()); + _closeEmailViewIfMailboxDisabledOrNotExist(success.mailboxIdsSubscribe); + } + } + + refreshMailboxChanges(mailboxState: success.currentMailboxState); + } + + void _showToastSubscribeMailboxSuccess( + MailboxId mailboxIdSubscribed, + MailboxSubscribeAction subscribeAction, + {List? listDescendantMailboxIds} + ) { + if (currentOverlayContext != null && currentContext != null) { _appToast.showBottomToast( currentOverlayContext!, - AppLocalizations.of(currentContext!).toastMsgHideMailboxSuccess, + subscribeAction.getToastMessageSuccess(currentContext!), actionName: AppLocalizations.of(currentContext!).undo, - onActionClick: () => _invokeUndoUnsubscribeMailboxAction(success.mailboxId), + onActionClick: () { + if (subscribeAction == MailboxSubscribeAction.unSubscribe) { + _undoUnsubscribeMailboxAction( + mailboxIdSubscribed, + listDescendantMailboxIds: listDescendantMailboxIds + ); + } else { + _undoSubscribeMailboxAction( + mailboxIdSubscribed, + listDescendantMailboxIds: listDescendantMailboxIds + ); + } + }, leadingIcon: SvgPicture.asset( imagePaths.icFolderMailbox, width: 24, @@ -428,24 +531,79 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa maxWidth: responsiveUtils.getMaxWidthToast(currentContext!) ); } - - refreshMailboxChanges(mailboxState: success.currentMailboxState); } - void _invokeUndoUnsubscribeMailboxAction(MailboxId mailboxId) { - _subscribeMailboxAction(SubscribeMailboxRequest( - mailboxId, - MailboxSubscribeState.enabled, - MailboxSubscribeAction.undo - )); + void _undoUnsubscribeMailboxAction( + MailboxId mailboxIdSubscribed, + {List? listDescendantMailboxIds} + ) { + final _accountId = dashboardController.accountId.value; + if (_accountId != null) { + SubscribeRequest? subscribeRequest; + + if (listDescendantMailboxIds != null) { + subscribeRequest = SubscribeMultipleMailboxRequest( + mailboxIdSubscribed, + listDescendantMailboxIds, + MailboxSubscribeState.enabled, + MailboxSubscribeAction.undo + ); + } else { + subscribeRequest = SubscribeMailboxRequest( + mailboxIdSubscribed, + MailboxSubscribeState.enabled, + MailboxSubscribeAction.undo + ); + } + + if (subscribeRequest is SubscribeMultipleMailboxRequest) { + consumeState(_subscribeMultipleMailboxInteractor.execute(_accountId, subscribeRequest)); + } else if (subscribeRequest is SubscribeMailboxRequest) { + consumeState(_subscribeMailboxInteractor.execute(_accountId, subscribeRequest)); + } + } } - void openMailboxAction(BuildContext context, PresentationMailbox mailbox) { - FocusScope.of(context).unfocus(); - dashboardController.openMailboxAction(context, mailbox); + void _undoSubscribeMailboxAction( + MailboxId mailboxIdSubscribed, + {List? listDescendantMailboxIds} + ) { + final _accountId = dashboardController.accountId.value; + if (_accountId != null) { + SubscribeRequest? subscribeRequest; - if (!responsiveUtils.isWebDesktop(context)) { - closeSearchView(context); + if (listDescendantMailboxIds != null) { + subscribeRequest = SubscribeMultipleMailboxRequest( + mailboxIdSubscribed, + listDescendantMailboxIds, + MailboxSubscribeState.disabled, + MailboxSubscribeAction.undo + ); + } else { + subscribeRequest = SubscribeMailboxRequest( + mailboxIdSubscribed, + MailboxSubscribeState.disabled, + MailboxSubscribeAction.undo + ); + } + + if (subscribeRequest is SubscribeMultipleMailboxRequest) { + consumeState(_subscribeMultipleMailboxInteractor.execute(_accountId, subscribeRequest)); + } else if (subscribeRequest is SubscribeMailboxRequest) { + consumeState(_subscribeMailboxInteractor.execute(_accountId, subscribeRequest)); + } + } + } + + void _closeEmailViewIfMailboxDisabledOrNotExist(List mailboxIdsDisabled) { + if (selectedEmail == null) { + return; + } + + final mailboxContain = selectedEmail!.findMailboxContain(dashboardController.mapMailboxById); + if (mailboxContain != null && mailboxIdsDisabled.contains(mailboxContain.id)) { + dashboardController.clearSelectedEmail(); + dashboardController.dispatchRoute(DashboardRoutes.thread); } } diff --git a/lib/features/search/mailbox/presentation/search_mailbox_view.dart b/lib/features/search/mailbox/presentation/search_mailbox_view.dart index 29d50eb1b..492bb5be8 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_view.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_view.dart @@ -8,19 +8,20 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:focused_menu_custom/modals.dart'; import 'package:get/get.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; -import 'package:tmail_ui_user/features/base/mixin/popup_menu_widget_mixin.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/search_mailbox_state.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/context_item_mailbox_action.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_bottom_sheet_action_tile_builder.dart'; import 'package:tmail_ui_user/features/search/mailbox/presentation/search_mailbox_controller.dart'; import 'package:tmail_ui_user/features/search/mailbox/presentation/utils/search_mailbox_utils.dart'; import 'package:tmail_ui_user/features/search/mailbox/presentation/widgets/mailbox_searched_item_builder.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class SearchMailboxView extends GetWidget - with AppLoaderMixin, PopupMenuWidgetMixin { + with AppLoaderMixin, + MailboxWidgetMixin { final Color? backgroundColor; @@ -35,7 +36,7 @@ class SearchMailboxView extends GetWidget body: GestureDetector( onTap: () => FocusScope.of(context).unfocus(), child: BuildUtils.isWeb - ? _buildSearchBody(context) + ? PointerInterceptor(child: _buildSearchBody(context)) : SafeArea(child: _buildSearchBody(context)), ), ); @@ -250,30 +251,14 @@ class SearchMailboxView extends GetWidget ); } - MailboxActions _mailboxActionForSpam() { - return controller.dashboardController.enableSpamReport - ? MailboxActions.disableSpamReport - : MailboxActions.enableSpamReport; - } - List _listActionForMailboxUnsubscribed() { return [ - MailboxActions.markAsRead + MailboxActions.enableMailbox ]; } List _listActionForMailboxSubscribed(PresentationMailbox mailbox) { - return [ - if (BuildUtils.isWeb) - MailboxActions.openInNewTab, - if (mailbox.isSpam) - _mailboxActionForSpam(), - MailboxActions.markAsRead, - MailboxActions.move, - MailboxActions.rename, - MailboxActions.delete, - MailboxActions.disableMailbox - ]; + return listActionForMailbox(mailbox, controller.dashboardController); } void _openMailboxMenuAction( @@ -281,106 +266,39 @@ class SearchMailboxView extends GetWidget PresentationMailbox mailbox, {RelativeRect? position} ) { - final mailboxActionsSupported = mailbox.isSubscribed?.value == true + final mailboxActionsSupported = mailbox.supportedSubscribe ? _listActionForMailboxSubscribed(mailbox) : _listActionForMailboxUnsubscribed(); - final listContextMenuItemAction = mailboxActionsSupported - .map((action) => ContextMenuItemMailboxAction(action, action.getContextMenuItemState(mailbox))) - .toList(); + final contextMenuActions = listContextMenuItemAction( + mailbox, + controller.dashboardController, + mailboxActions: mailboxActionsSupported + ); if (controller.responsiveUtils.isScreenWithShortestSide(context) || position == null) { controller.openContextMenuAction( context, - _bottomSheetMailboxActionTiles( + contextMenuMailboxActionTiles( context, + controller.imagePaths, mailbox, - listContextMenuItemAction + contextMenuActions, + handleMailboxAction: controller.handleMailboxAction ) ); } else { controller.openPopupMenuAction( context, position, - _popupMenuMailboxActionTiles( + popupMenuMailboxActionTiles( context, + controller.imagePaths, mailbox, - listContextMenuItemAction + contextMenuActions, + handleMailboxAction: controller.handleMailboxAction ) ); } } - - List _bottomSheetMailboxActionTiles( - BuildContext context, - PresentationMailbox mailbox, - List contextMenuActions - ) { - return contextMenuActions - .map((action) => _mailboxContextMenuActionTile(context, action, mailbox)) - .toList(); - } - - Widget _mailboxContextMenuActionTile( - BuildContext context, - ContextMenuItemMailboxAction contextMenuItem, - PresentationMailbox mailbox - ) { - return (MailboxBottomSheetActionTileBuilder( - Key('${contextMenuItem.action.name}_action'), - SvgPicture.asset( - contextMenuItem.action.getContextMenuIcon(controller.imagePaths), - width: 24, - height: 24, - color: contextMenuItem.action.getColorContextMenuIcon() - ), - contextMenuItem.action.getTitleContextMenu(context), - mailbox, - absorbing: !contextMenuItem.isActivated, - opacity: !contextMenuItem.isActivated) - ..actionTextStyle(textStyle: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.black)) - ..onActionClick((mailbox) => controller.handleMailboxAction(context, contextMenuItem.action, mailbox)) - ).build(); - } - - List _popupMenuMailboxActionTiles( - BuildContext context, - PresentationMailbox mailbox, - List contextMenuActions - ) { - return contextMenuActions - .map((action) => _mailboxPopupMenuActionTile(context, action, mailbox)) - .toList(); - } - - PopupMenuItem _mailboxPopupMenuActionTile( - BuildContext context, - ContextMenuItemMailboxAction contextMenuItem, - PresentationMailbox mailbox - ) { - return PopupMenuItem( - padding: EdgeInsets.zero, - child: AbsorbPointer( - absorbing: !contextMenuItem.isActivated, - child: Opacity( - opacity: contextMenuItem.isActivated ? 1.0 : 0.3, - child: popupItem( - contextMenuItem.action.getContextMenuIcon(controller.imagePaths), - contextMenuItem.action.getTitleContextMenu(context), - colorIcon: contextMenuItem.action.getColorContextMenuIcon(), - iconSize: 24, - styleName: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 16, - color: contextMenuItem.action.getColorContextMenuTitle() - ), - onCallbackAction: () => controller.handleMailboxAction(context, contextMenuItem.action, mailbox)) - , - ) - ) - ); - } } \ No newline at end of file diff --git a/lib/features/search/mailbox/presentation/widgets/mailbox_searched_item_builder.dart b/lib/features/search/mailbox/presentation/widgets/mailbox_searched_item_builder.dart index 84f432b08..57f56eb22 100644 --- a/lib/features/search/mailbox/presentation/widgets/mailbox_searched_item_builder.dart +++ b/lib/features/search/mailbox/presentation/widgets/mailbox_searched_item_builder.dart @@ -89,8 +89,7 @@ class _MailboxSearchedItemBuilderState extends State ] ) )), - if (widget._presentationMailbox.isSubscribed?.value == true) - _buildMenuIcon(context) + _buildMenuIcon(context) ] ), ) diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 1d5490a56..572dd097d 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-02-03T16:28:53.514637", + "@@last_modified": "2023-02-10T03:40:25.843946", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -120,8 +120,8 @@ "placeholders_order": [], "placeholders": {} }, - "myFolders": "My Folders", - "@myFolders": { + "personalMailboxes": "Personal mailboxes", + "@personalMailboxes": { "type": "text", "placeholders_order": [], "placeholders": {} @@ -2680,10 +2680,52 @@ "placeholders_order": [], "placeholders": {} }, + "mailBoxes": "Mailboxes", + "@mailBoxes": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "teamMailBoxes": "Team-mailboxes", + "@teamMailBoxes": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "hideMailBoxes": "Hide mailbox", + "@hideMailBoxes": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, "thisImageCannotBeAdded": "This image cannot be added.", "@thisImageCannotBeAdded": { "type": "text", "placeholders_order": [], "placeholders": {} + }, + "toastMsgHideMailboxSuccess": "This mailbox has been hidden from your primary mailbox", + "@toastMsgHideMailboxSuccess": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "searchForMailboxes": "Search for mailboxes", + "@searchForMailboxes": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "showMailbox": "Show mailbox", + "@showMailbox": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "toastMessageShowMailboxSuccess": "This mailbox is already displayed in your primary mailbox", + "@toastMessageShowMailboxSuccess": { + "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 ffb91421f..e8b7dff44 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2792,4 +2792,17 @@ class AppLocalizations { name: 'searchForMailboxes' ); } + + String get showMailbox { + return Intl.message( + 'Show mailbox', + name: 'showMailbox' + ); + } + + String get toastMessageShowMailboxSuccess { + return Intl.message( + 'This mailbox is already displayed in your primary mailbox', + name: 'toastMessageShowMailboxSuccess'); + } } \ No newline at end of file