From 10ba3867d8320c1acee19832035c39b0d830b647 Mon Sep 17 00:00:00 2001 From: HuyNguyen Date: Thu, 2 Feb 2023 22:19:43 +0700 Subject: [PATCH] TF-1310: [Presentation] Refactor buildTree logic in TreeBuilder + BaseMailboxController --- .../base/base_mailbox_controller.dart | 67 ++++-- .../destination_picker_controller.dart | 9 +- .../presentation/destination_picker_view.dart | 6 +- .../model/destination_picker_arguments.dart | 14 +- .../controller/single_email_controller.dart | 3 +- .../extensions/mailbox_cache_extension.dart | 4 +- .../data/extensions/mailbox_extension.dart | 3 +- .../mailbox/data/model/mailbox_cache.dart | 12 +- .../mailbox/data/network/mailbox_api.dart | 10 +- .../repository/mailbox_repository_impl.dart | 2 +- .../presentation_mailbox_extension.dart | 21 +- .../presentation/mailbox_controller.dart | 47 +++- .../mailbox/presentation/mailbox_view.dart | 81 +++++-- .../presentation/mailbox_view_web.dart | 67 ++++-- .../model/mailbox_categories.dart | 21 +- .../model/mailbox_categories_expand_mode.dart | 15 +- .../model/mailbox_tree_builder.dart | 42 +++- .../widgets/mailbox_folder_tile_builder.dart | 226 +++++++++++------- .../mailbox_creator_controller.dart | 18 +- .../model/mailbox_creator_arguments.dart | 19 +- .../advanced_filter_controller.dart | 2 + .../mailbox_dashboard_controller.dart | 5 +- .../rules_filter_creator_controller.dart | 3 +- .../presentation/search_email_controller.dart | 1 + .../mixin/email_action_controller.dart | 3 +- lib/main/localizations/app_localizations.dart | 24 +- model/lib/extensions/mailbox_extension.dart | 3 + .../presentation_mailbox_extension.dart | 15 +- model/lib/mailbox/mailbox_property.dart | 1 + model/lib/mailbox/presentation_mailbox.dart | 16 +- 30 files changed, 523 insertions(+), 237 deletions(-) diff --git a/lib/features/base/base_mailbox_controller.dart b/lib/features/base/base_mailbox_controller.dart index 3745a716c..61e9cd63c 100644 --- a/lib/features/base/base_mailbox_controller.dart +++ b/lib/features/base/base_mailbox_controller.dart @@ -12,8 +12,9 @@ abstract class BaseMailboxController extends BaseController { BaseMailboxController(this._treeBuilder); - final folderMailboxTree = MailboxTree(MailboxNode.root()).obs; + final personalMailboxTree = MailboxTree(MailboxNode.root()).obs; final defaultMailboxTree = MailboxTree(MailboxNode.root()).obs; + final teamMailboxesTree = MailboxTree(MailboxNode.root()).obs; List allMailboxes = []; @@ -26,20 +27,27 @@ abstract class BaseMailboxController extends BaseController { allMailbox, mailboxIdSelected: mailboxIdSelected); defaultMailboxTree.firstRebuild = true; - folderMailboxTree.firstRebuild = true; + personalMailboxTree.firstRebuild = true; + teamMailboxesTree.firstRebuild = true; defaultMailboxTree.value = tupleTree.value1; - folderMailboxTree.value = tupleTree.value2; - allMailboxes = tupleTree.value3; + personalMailboxTree.value = tupleTree.value2; + teamMailboxesTree.value = tupleTree.value3; + allMailboxes = tupleTree.value4; } Future refreshTree(List allMailbox) async { allMailboxes = allMailbox; final tupleTree = await _treeBuilder.generateMailboxTreeInUIAfterRefreshChanges( - allMailbox, defaultMailboxTree.value, folderMailboxTree.value); + allMailbox, + defaultMailboxTree.value, + personalMailboxTree.value, + teamMailboxesTree.value); defaultMailboxTree.firstRebuild = true; - folderMailboxTree.firstRebuild = true; + personalMailboxTree.firstRebuild = true; + teamMailboxesTree.firstRebuild = true; defaultMailboxTree.value = tupleTree.value1; - folderMailboxTree.value = tupleTree.value2; + personalMailboxTree.value = tupleTree.value2; + teamMailboxesTree.value = tupleTree.value3; } void toggleMailboxFolder(MailboxNode selectedMailboxNode) { @@ -52,9 +60,14 @@ abstract class BaseMailboxController extends BaseController { defaultMailboxTree.refresh(); } - if (folderMailboxTree.value.updateExpandedNode(selectedMailboxNode, newExpandMode) != null) { + if (personalMailboxTree.value.updateExpandedNode(selectedMailboxNode, newExpandMode) != null) { log('toggleMailboxFolder() refresh folderMailboxTree'); - folderMailboxTree.refresh(); + personalMailboxTree.refresh(); + } + + if (teamMailboxesTree.value.updateExpandedNode(selectedMailboxNode, newExpandMode) != null) { + log('toggleMailboxFolder() refresh teamMailboxesTree'); + teamMailboxesTree.refresh(); } } @@ -68,31 +81,43 @@ abstract class BaseMailboxController extends BaseController { defaultMailboxTree.refresh(); } - if (folderMailboxTree.value.updateSelectedNode(mailboxNodeSelected, newSelectMode) != null) { + if (personalMailboxTree.value.updateSelectedNode(mailboxNodeSelected, newSelectMode) != null) { log('selectMailboxNode() refresh folderMailboxTree'); - folderMailboxTree.refresh(); + personalMailboxTree.refresh(); + } + + if (teamMailboxesTree.value.updateSelectedNode(mailboxNodeSelected, newSelectMode) != null) { + log('selectMailboxNode() refresh folderMailboxTree'); + teamMailboxesTree.refresh(); } } void unAllSelectedMailboxNode() { defaultMailboxTree.value.updateNodesUIMode(selectMode: SelectMode.INACTIVE); - folderMailboxTree.value.updateNodesUIMode(selectMode: SelectMode.INACTIVE); + personalMailboxTree.value.updateNodesUIMode(selectMode: SelectMode.INACTIVE); + teamMailboxesTree.value.updateNodesUIMode(selectMode: SelectMode.INACTIVE); defaultMailboxTree.refresh(); - folderMailboxTree.refresh(); + personalMailboxTree.refresh(); + teamMailboxesTree.refresh(); } MailboxNode? findMailboxNodeById(MailboxId mailboxId) { final mailboxNode = defaultMailboxTree.value.findNode((node) => node.item.id == mailboxId); + final mailboxPersonal = personalMailboxTree.value.findNode((node) => node.item.id == mailboxId); if (mailboxNode != null) { return mailboxNode; } - return folderMailboxTree.value.findNode((node) => node.item.id == mailboxId); + + if (mailboxPersonal != null) { + return mailboxPersonal; + } + return teamMailboxesTree.value.findNode((node) => node.item.id == mailboxId); } String? findNodePath(MailboxId mailboxId) { var mailboxNodePath = defaultMailboxTree.value.getNodePath(mailboxId); if (mailboxNodePath == null) { - return folderMailboxTree.value.getNodePath(mailboxId); + return personalMailboxTree.value.getNodePath(mailboxId); } return mailboxNodePath; } @@ -120,10 +145,16 @@ abstract class BaseMailboxController extends BaseController { bool get defaultMailboxHasChild => defaultMailboxTree.value.root.childrenItems?.isNotEmpty ?? false; - bool get folderMailboxHasChild => - folderMailboxTree.value.root.childrenItems?.isNotEmpty ?? false; + bool get personalMailboxHasChild => + personalMailboxTree.value.root.childrenItems?.isNotEmpty ?? false; + + bool get teamMailboxesHasChild => + teamMailboxesTree.value.root.childrenItems?.isNotEmpty ?? false; MailboxNode get defaultRootNode => defaultMailboxTree.value.root; - MailboxNode get folderRootNode => folderMailboxTree.value.root; + MailboxNode get personalRootNode => personalMailboxTree.value.root; + + MailboxNode get teamMailboxesRootNode => teamMailboxesTree.value.root; + } diff --git a/lib/features/destination_picker/presentation/destination_picker_controller.dart b/lib/features/destination_picker/presentation/destination_picker_controller.dart index c41465a41..c745b789a 100644 --- a/lib/features/destination_picker/presentation/destination_picker_controller.dart +++ b/lib/features/destination_picker/presentation/destination_picker_controller.dart @@ -110,6 +110,7 @@ class DestinationPickerController extends BaseMailboxController { mailboxAction.value = arguments!.mailboxAction; mailboxIdSelected = arguments!.mailboxIdSelected; accountId = arguments!.accountId; + _session = arguments!.session; getAllMailboxAction(); } } @@ -175,9 +176,9 @@ class DestinationPickerController extends BaseMailboxController { mailboxCategoriesExpandMode.value.defaultMailbox = newExpandMode; mailboxCategoriesExpandMode.refresh(); break; - case MailboxCategories.folders: - final newExpandMode = mailboxCategoriesExpandMode.value.folderMailbox == ExpandMode.EXPAND ? ExpandMode.COLLAPSE : ExpandMode.EXPAND; - mailboxCategoriesExpandMode.value.folderMailbox = newExpandMode; + case MailboxCategories.personalMailboxes: + final newExpandMode = mailboxCategoriesExpandMode.value.personalMailboxes == ExpandMode.EXPAND ? ExpandMode.COLLAPSE : ExpandMode.EXPAND; + mailboxCategoriesExpandMode.value.personalMailboxes = newExpandMode; mailboxCategoriesExpandMode.refresh(); break; default: @@ -235,7 +236,7 @@ class DestinationPickerController extends BaseMailboxController { if (mailboxDestination.value == null || mailboxDestination.value == PresentationMailbox.unifiedMailbox) { final allChildrenAtMailboxLocation = (defaultMailboxTree.value.root.childrenItems ?? []) + - (folderMailboxTree.value.root.childrenItems ?? []); + (personalMailboxTree.value.root.childrenItems ?? []); if (allChildrenAtMailboxLocation.isNotEmpty) { listMailboxNameAsStringExist = allChildrenAtMailboxLocation .where((mailboxNode) => mailboxNode.nameNotEmpty) diff --git a/lib/features/destination_picker/presentation/destination_picker_view.dart b/lib/features/destination_picker/presentation/destination_picker_view.dart index ffe74b79a..c2f13b409 100644 --- a/lib/features/destination_picker/presentation/destination_picker_view.dart +++ b/lib/features/destination_picker/presentation/destination_picker_view.dart @@ -224,11 +224,11 @@ class DestinationPickerView extends GetWidget actions, mailboxIdSelected) : const SizedBox.shrink()), - Obx(() => controller.folderMailboxHasChild + Obx(() => controller.personalMailboxHasChild ? _buildMailboxCategory( context, - MailboxCategories.folders, - controller.folderRootNode, + MailboxCategories.personalMailboxes, + controller.personalRootNode, actions, mailboxIdSelected) : const SizedBox.shrink()), diff --git a/lib/features/destination_picker/presentation/model/destination_picker_arguments.dart b/lib/features/destination_picker/presentation/model/destination_picker_arguments.dart index 846b60de7..16ed5ba22 100644 --- a/lib/features/destination_picker/presentation/model/destination_picker_arguments.dart +++ b/lib/features/destination_picker/presentation/model/destination_picker_arguments.dart @@ -1,6 +1,7 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; @@ -8,9 +9,18 @@ class DestinationPickerArguments with EquatableMixin { final AccountId accountId; final MailboxActions mailboxAction; final MailboxId? mailboxIdSelected; + final Session? session; - DestinationPickerArguments(this.accountId, this.mailboxAction, {this.mailboxIdSelected}); + DestinationPickerArguments( + this.accountId, + this.mailboxAction, + this.session, + {this.mailboxIdSelected}); @override - List get props => [accountId, mailboxAction, mailboxIdSelected]; + List get props => [ + accountId, + mailboxAction, + mailboxIdSelected, + session]; } \ No newline at end of file diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 8646f0309..dbb73257d 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -576,9 +576,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void moveToMailbox(BuildContext context, PresentationEmail email) async { final currentMailbox = getMailboxContain(email); final accountId = mailboxDashBoardController.accountId.value; + final _session = mailboxDashBoardController.sessionCurrent; if (currentMailbox != null && accountId != null) { - final arguments = DestinationPickerArguments(accountId, MailboxActions.moveEmail); + final arguments = DestinationPickerArguments(accountId, MailboxActions.moveEmail, _session); if (BuildUtils.isWeb) { showDialogDestinationPicker( context: context, diff --git a/lib/features/mailbox/data/extensions/mailbox_cache_extension.dart b/lib/features/mailbox/data/extensions/mailbox_cache_extension.dart index a0bf40109..e68331cd2 100644 --- a/lib/features/mailbox/data/extensions/mailbox_cache_extension.dart +++ b/lib/features/mailbox/data/extensions/mailbox_cache_extension.dart @@ -2,6 +2,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/namespace.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_cache.dart'; import 'package:tmail_ui_user/features/mailbox/data/extensions/mailbox_rights_cache_extension.dart'; @@ -18,7 +19,8 @@ extension MailboxCacheExtension on MailboxCache { totalThreads: totalThreads != null ? TotalThreads(UnsignedInt(totalThreads!)) : null, unreadThreads: unreadThreads != null ? UnreadThreads(UnsignedInt(unreadThreads!)) : null, myRights: myRights != null ? myRights!.toMailboxRights() : null, - isSubscribed: isSubscribed != null ? IsSubscribed(isSubscribed!) : null + isSubscribed: isSubscribed != null ? IsSubscribed(isSubscribed!) : null, + namespace: namespace != null ? Namespace(namespace!) : null ); } } \ No newline at end of file diff --git a/lib/features/mailbox/data/extensions/mailbox_extension.dart b/lib/features/mailbox/data/extensions/mailbox_extension.dart index 16f65a642..ecbfa169f 100644 --- a/lib/features/mailbox/data/extensions/mailbox_extension.dart +++ b/lib/features/mailbox/data/extensions/mailbox_extension.dart @@ -16,7 +16,8 @@ extension MailboxExtension on Mailbox { totalThreads: totalThreads?.value.value.round(), unreadThreads: unreadThreads?.value.value.round(), myRights: myRights != null ? myRights!.toMailboxRightsCache() : null, - isSubscribed: isSubscribed?.value + isSubscribed: isSubscribed?.value, + namespace: namespace?.value ); } } \ No newline at end of file diff --git a/lib/features/mailbox/data/model/mailbox_cache.dart b/lib/features/mailbox/data/model/mailbox_cache.dart index a85f5d4df..05fe3e005 100644 --- a/lib/features/mailbox/data/model/mailbox_cache.dart +++ b/lib/features/mailbox/data/model/mailbox_cache.dart @@ -45,6 +45,9 @@ class MailboxCache extends HiveObject with EquatableMixin { @HiveField(11) final DateTime? lastOpened; + @HiveField(12) + final String? namespace; + MailboxCache( this.id, { @@ -58,7 +61,8 @@ class MailboxCache extends HiveObject with EquatableMixin { this.unreadThreads, this.myRights, this.isSubscribed, - this.lastOpened + this.lastOpened, + this.namespace, } ); @@ -68,7 +72,13 @@ class MailboxCache extends HiveObject with EquatableMixin { name, parentId, role, + totalEmails, unreadEmails, + totalThreads, + unreadThreads, lastOpened, + myRights, + isSubscribed, + namespace, ]; } \ No newline at end of file diff --git a/lib/features/mailbox/data/network/mailbox_api.dart b/lib/features/mailbox/data/network/mailbox_api.dart index 553fe50fe..3b4c550bd 100644 --- a/lib/features/mailbox/data/network/mailbox_api.dart +++ b/lib/features/mailbox/data/network/mailbox_api.dart @@ -47,7 +47,7 @@ class MailboxAPI with HandleSetErrorMixin { final queryInvocation = jmapRequestBuilder.invocation(getMailboxCreated); - final capabilities = checkCapabilities(session, accountId); + final capabilities = capabilitiesSupportedMailboxes(session, accountId); final result = await (jmapRequestBuilder ..usings(capabilities)) @@ -61,17 +61,13 @@ class MailboxAPI with HandleSetErrorMixin { return MailboxResponse(mailboxes: resultCreated?.list, state: resultCreated?.state); } - Set checkCapabilities(Session session, AccountId accountId) { + Set capabilitiesSupportedMailboxes(Session session, AccountId accountId) { final getMailboxCreated = GetMailboxMethod(accountId); try { requireCapability( session, accountId, - [ - CapabilityIdentifier.jmapCore, - CapabilityIdentifier.jmapMail, - CapabilityIdentifier.jmapTeamMailboxes - ]); + [CapabilityIdentifier.jmapTeamMailboxes]); return getMailboxCreated.requiredCapabilitiesSupportTeamMailboxes; } catch (_) { return getMailboxCreated.requiredCapabilities; diff --git a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart index 61e20a267..6b1b4f0dc 100644 --- a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart +++ b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart @@ -70,7 +70,7 @@ class MailboxRepositoryImpl extends MailboxRepository { ]); } } else { - final mailboxResponse = await mapDataSource[DataSourceType.network]!.getAllMailbox(session, accountId,); + final mailboxResponse = await mapDataSource[DataSourceType.network]!.getAllMailbox(session, accountId); await Future.wait([ mapDataSource[DataSourceType.local]!.update(created: mailboxResponse.mailboxes), diff --git a/lib/features/mailbox/domain/extensions/presentation_mailbox_extension.dart b/lib/features/mailbox/domain/extensions/presentation_mailbox_extension.dart index 2c2e85790..2d80ed044 100644 --- a/lib/features/mailbox/domain/extensions/presentation_mailbox_extension.dart +++ b/lib/features/mailbox/domain/extensions/presentation_mailbox_extension.dart @@ -25,8 +25,27 @@ extension PresentationMailboxExtension on PresentationMailbox { default: return imagePaths.icFolderMailbox; } + } else if (isChildOfTeamMailboxes) { + switch(name!.name.toLowerCase()) { + case 'inbox': + return imagePaths.icMailboxInbox; + case 'drafts': + return imagePaths.icMailboxDrafts; + case 'archive': + return imagePaths.icMailboxArchived; + case 'sent': + return imagePaths.icMailboxSent; + case 'trash': + return imagePaths.icMailboxTrash; + case 'spam': + return imagePaths.icMailboxSpam; + case 'templates': + return imagePaths.icMailboxTemplate; + default: + return imagePaths.icFolderMailbox; + } } else { - return imagePaths.icFolderMailbox; + return imagePaths.icFolderMailbox; } } } \ 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 14bf684a4..467f46063 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -153,7 +153,7 @@ class MailboxController extends BaseMailboxController { newState.map((success) async { if (success is GetAllMailboxSuccess) { _currentMailboxState = success.currentMailboxState; - await buildTree(success.mailboxList); + _buildMailboxTreeHasSubscribed(success.mailboxList); } else if (success is RefreshChangesAllMailboxSuccess) { _currentMailboxState = success.currentMailboxState; await refreshTree(success.mailboxList); @@ -292,7 +292,8 @@ class MailboxController extends BaseMailboxController { && (_responsiveUtils.isMobile(currentContext!) || _responsiveUtils.isTablet(currentContext!))) { mailboxCategoriesExpandMode.value = MailboxCategoriesExpandMode( defaultMailbox: ExpandMode.COLLAPSE, - folderMailbox: ExpandMode.COLLAPSE); + personalMailboxes: ExpandMode.COLLAPSE, + teamMailboxes: ExpandMode.COLLAPSE); } else { mailboxCategoriesExpandMode.value = MailboxCategoriesExpandMode.initial(); } @@ -496,9 +497,11 @@ class MailboxController extends BaseMailboxController { final accountId = mailboxDashBoardController.accountId.value; if (accountId != null) { final arguments = MailboxCreatorArguments( - accountId, - defaultMailboxTree.value, - folderMailboxTree.value); + accountId, + defaultMailboxTree.value, + personalMailboxTree.value, + teamMailboxesTree.value, + mailboxDashBoardController.sessionCurrent!); if (BuildUtils.isWeb) { showDialogMailboxCreator( @@ -656,10 +659,13 @@ class MailboxController extends BaseMailboxController { final defaultMailboxSelected = defaultMailboxTree.value .findNodes((node) => node.selectMode == SelectMode.ACTIVE); - final folderMailboxSelected = folderMailboxTree.value + final folderMailboxSelected = personalMailboxTree.value .findNodes((node) => node.selectMode == SelectMode.ACTIVE); - return [defaultMailboxSelected, folderMailboxSelected] + final teamMailboxesSelected = teamMailboxesTree.value + .findNodes((node) => node.selectMode == SelectMode.ACTIVE); + + return [defaultMailboxSelected, folderMailboxSelected, teamMailboxesSelected] .expand((node) => node) .map((node) => node.item) .toList(); @@ -736,7 +742,7 @@ class MailboxController extends BaseMailboxController { final tupleMap = MailboxUtils.generateMapDescendantIdsAndMailboxIdList( [presentationMailbox], defaultMailboxTree.value, - folderMailboxTree.value); + personalMailboxTree.value); final mapDescendantIds = tupleMap.value1; final listMailboxId = tupleMap.value2; @@ -816,7 +822,7 @@ class MailboxController extends BaseMailboxController { final tupleMap = MailboxUtils.generateMapDescendantIdsAndMailboxIdList( selectedMailboxList, defaultMailboxTree.value, - folderMailboxTree.value); + personalMailboxTree.value); final mapDescendantIds = tupleMap.value1; final listMailboxId = tupleMap.value2; consumeState(_deleteMultipleMailboxInteractor.execute( @@ -947,10 +953,12 @@ class MailboxController extends BaseMailboxController { void _moveMailboxAction(BuildContext context, PresentationMailbox mailboxSelected) async { final accountId = mailboxDashBoardController.accountId.value; + final _session = mailboxDashBoardController.sessionCurrent; if (accountId != null) { final arguments = DestinationPickerArguments( accountId, MailboxActions.move, + _session, mailboxIdSelected: mailboxSelected.id); if (BuildUtils.isWeb) { @@ -1039,7 +1047,10 @@ class MailboxController extends BaseMailboxController { void _createListMailboxNameAsStringInMailboxParent(PresentationMailbox mailboxRenamed) { if (mailboxRenamed.parentId == null) { - final allChildrenAtMailboxLocation = (defaultMailboxTree.value.root.childrenItems ?? []) + (folderMailboxTree.value.root.childrenItems ?? []); + final allChildrenAtMailboxLocation = ( + defaultMailboxTree.value.root.childrenItems ?? []) + + (personalMailboxTree.value.root.childrenItems ?? []) + + (teamMailboxesTree.value.root.childrenItems ?? []); if (allChildrenAtMailboxLocation.isNotEmpty) { listMailboxNameAsStringExist = allChildrenAtMailboxLocation .where((mailboxNode) => mailboxNode.nameNotEmpty) @@ -1071,9 +1082,14 @@ class MailboxController extends BaseMailboxController { mailboxCategoriesExpandMode.value.defaultMailbox = newExpandMode; mailboxCategoriesExpandMode.refresh(); break; - case MailboxCategories.folders: - final newExpandMode = mailboxCategoriesExpandMode.value.folderMailbox == ExpandMode.EXPAND ? ExpandMode.COLLAPSE : ExpandMode.EXPAND; - mailboxCategoriesExpandMode.value.folderMailbox = newExpandMode; + case MailboxCategories.personalMailboxes: + final newExpandMode = mailboxCategoriesExpandMode.value.personalMailboxes == ExpandMode.EXPAND ? ExpandMode.COLLAPSE : ExpandMode.EXPAND; + mailboxCategoriesExpandMode.value.personalMailboxes = newExpandMode; + mailboxCategoriesExpandMode.refresh(); + break; + case MailboxCategories.teamMailboxes: + final newExpandMode = mailboxCategoriesExpandMode.value.teamMailboxes == ExpandMode.EXPAND ? ExpandMode.COLLAPSE : ExpandMode.EXPAND; + mailboxCategoriesExpandMode.value.teamMailboxes = newExpandMode; mailboxCategoriesExpandMode.refresh(); break; case MailboxCategories.appGrid: @@ -1185,4 +1201,9 @@ class MailboxController extends BaseMailboxController { duration: const Duration(milliseconds: 300), curve: Curves.fastOutSlowIn); } + + void _buildMailboxTreeHasSubscribed(List mailboxList) async { + final _mailboxList = mailboxList.where((mailbox) => mailbox.isSubscribed?.value == true).toList(); + await buildTree(_mailboxList); + } } \ 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 1ee77eb7c..3036f4955 100644 --- a/lib/features/mailbox/presentation/mailbox_view.dart +++ b/lib/features/mailbox/presentation/mailbox_view.dart @@ -187,19 +187,6 @@ class MailboxView extends GetWidget { ]); } - Widget _buildSearchBarWidget(BuildContext context) { - return Padding( - padding: EdgeInsets.only( - top: _responsiveUtils.isDesktop(context) ? 16 : 12, - bottom: 16, - left: _responsiveUtils.isLandscapeMobile(context) ? 0 : 16, - right: 16), - child: SearchBarView( - _imagePaths, - hintTextSearch: AppLocalizations.of(context).hint_search_mailboxes, - onOpenSearchViewAction: controller.enableSearch)); - } - Widget _buildLoadingView() { return Obx(() => controller.viewState.value.fold( (failure) => const SizedBox.shrink(), @@ -231,15 +218,54 @@ class MailboxView extends GetWidget { } return _buildUserInformation(context); }), - _buildSearchBarWidget(context), _buildLoadingView(), Obx(() => controller.defaultMailboxTree.value.root.childrenItems?.isNotEmpty ?? false ? _buildMailboxCategory(context, MailboxCategories.exchange, controller.defaultMailboxTree.value.root) : const SizedBox.shrink()), + const Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), const SizedBox(height: 12), - Obx(() => controller.folderMailboxTree.value.root.childrenItems?.isNotEmpty ?? false - ? _buildMailboxCategory(context, MailboxCategories.folders, controller.folderMailboxTree.value.root) - : const SizedBox.shrink()), + Container( + margin: EdgeInsets.only( + left: _responsiveUtils.isLandscapeMobile(context) ? 0 : 8, + right: 16), + padding: const EdgeInsets.only(left: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(AppLocalizations.of(context).mailBoxes, + style: const TextStyle( + fontSize: 20, + color: Colors.black, + fontWeight: FontWeight.bold)), + Row( + children: [ + buildIconWeb( + iconSize: 20, + minSize: 40, + iconPadding: EdgeInsets.zero, + splashRadius: 15, + icon: SvgPicture.asset(_imagePaths.icSearchBar, color: AppColor.colorTextButton, fit: BoxFit.fill), + onTap: () => controller.enableSearch()), + buildIconWeb( + minSize: 40, + iconSize: 20, + iconPadding: EdgeInsets.zero, + splashRadius: 15, + icon: SvgPicture.asset(_imagePaths.icAddNewFolder, color: AppColor.colorTextButton, fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).new_mailbox, + onTap: () => controller.goToCreateNewMailboxView(context)), + ], + ), + ]), + ), + const SizedBox(height: 8), + Obx(() => controller.personalMailboxTree.value.root.childrenItems?.isNotEmpty ?? false + ? _buildMailboxCategory(context, MailboxCategories.personalMailboxes, controller.personalMailboxTree.value.root) + : const SizedBox.shrink()), + const SizedBox(height: 8), + Obx(() => controller.teamMailboxesTree.value.root.childrenItems?.isNotEmpty ?? false + ? _buildMailboxCategory(context, MailboxCategories.teamMailboxes, controller.teamMailboxesTree.value.root) + : const SizedBox.shrink()), Obx(() => controller.isMailboxListScrollable.isFalse && !controller.isSearchActive() && !controller.isSelectionEnabled() @@ -254,21 +280,25 @@ class MailboxView extends GetWidget { Widget _buildHeaderMailboxCategory(BuildContext context, MailboxCategories categories) { return Padding( padding: EdgeInsets.only( - left: _responsiveUtils.isLandscapeMobile(context) ? 8 : 28, - right: 16), + right: _responsiveUtils.isLandscapeMobile(context) ? 8 : 28, + left: 16), child: Row(children: [ - Expanded(child: Text(categories.getTitle(context), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 20, color: Colors.black, fontWeight: FontWeight.bold))), - buildIconWeb( + buildIconWeb( + minSize: 40, + iconSize: 20, + iconPadding: EdgeInsets.zero, + splashRadius: 15, icon: SvgPicture.asset( categories.getExpandMode(controller.mailboxCategoriesExpandMode.value) == ExpandMode.EXPAND ? _imagePaths.icExpandFolder : _imagePaths.icCollapseFolder, color: AppColor.primaryColor, fit: BoxFit.fill), tooltip: AppLocalizations.of(context).collapse, - onTap: () => controller.toggleMailboxCategories(categories)) + onTap: () => controller.toggleMailboxCategories(categories)), + Expanded(child: Text(categories.getTitle(context), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 20, color: Colors.black, fontWeight: FontWeight.bold))), ])); } @@ -276,7 +306,6 @@ class MailboxView extends GetWidget { final lastNode = mailboxNode.childrenItems?.last; return Container( - decoration: BoxDecoration(borderRadius: BorderRadius.circular(14), color: Colors.white), margin: EdgeInsets.only( left: _responsiveUtils.isLandscapeMobile(context) ? 0 : 16, right: 16), diff --git a/lib/features/mailbox/presentation/mailbox_view_web.dart b/lib/features/mailbox/presentation/mailbox_view_web.dart index 7942573cd..ef3a34992 100644 --- a/lib/features/mailbox/presentation/mailbox_view_web.dart +++ b/lib/features/mailbox/presentation/mailbox_view_web.dart @@ -132,14 +132,6 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu .build()); } - Widget _buildSearchBarWidget(BuildContext context) { - return Padding( - padding: EdgeInsets.only(top: 16, bottom: 16, right: 4, left: _responsiveUtils.isDesktop(context) ? 0 : 12), - child: SearchBarView( - _imagePaths, - hintTextSearch: AppLocalizations.of(context).hint_search_mailboxes, - onOpenSearchViewAction: controller.enableSearch)); - } Widget _buildLoadingView() { return Obx(() => controller.viewState.value.fold( @@ -147,7 +139,7 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu (success) => success is LoadingState ? Padding(padding: const EdgeInsets.only(top: 16), child: loadingWidget) : const SizedBox.shrink())); - } + } Widget _buildListMailbox(BuildContext context) { return Stack( @@ -178,22 +170,49 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu : const SizedBox.shrink()), const SizedBox(height: 8), 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), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(AppLocalizations.of(context).mailBoxes, + style: const TextStyle( + fontSize: 17, + color: Colors.black, + fontWeight: FontWeight.bold)), + Padding( + padding: EdgeInsets.only(right: _responsiveUtils.isDesktop(context) ? 0 : 12), + child: Row( + children: [ + buildIconWeb( + minSize: 40, + iconSize: 20, + iconPadding: EdgeInsets.zero, + splashRadius: 15, + icon: SvgPicture.asset(_imagePaths.icSearchBar, color: AppColor.colorTextButton, fit: BoxFit.fill), + onTap: () => controller.enableSearch()), + buildIconWeb( + minSize: 40, + iconSize: 20, + iconPadding: EdgeInsets.zero, + splashRadius: 15, + icon: SvgPicture.asset(_imagePaths.icAddNewFolder, color: AppColor.colorTextButton, fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).new_mailbox, + onTap: () => controller.goToCreateNewMailboxView(context)), + ], + )), + ]), + ), const SizedBox(height: 8), - _buildHeaderMailboxCategory(context, MailboxCategories.folders), - Row(children: [ - Expanded(child: _buildSearchBarWidget(context)), - Padding( - padding: EdgeInsets.only(right: _responsiveUtils.isDesktop(context) ? 0 : 12), - child: buildIconWeb( - minSize: 40, - iconPadding: EdgeInsets.zero, - splashRadius: 15, - icon: SvgPicture.asset(_imagePaths.icAddNewFolder, color: AppColor.colorTextButton, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).new_mailbox, - onTap: () => controller.goToCreateNewMailboxView(context))), - ]), - Obx(() => controller.folderMailboxHasChild - ? _buildMailboxCategory(context, MailboxCategories.folders, controller.folderRootNode) + _buildHeaderMailboxCategory(context, MailboxCategories.personalMailboxes), + Obx(() => controller.personalMailboxHasChild + ? _buildMailboxCategory(context, MailboxCategories.personalMailboxes, controller.personalRootNode) + : const SizedBox.shrink()), + const SizedBox(height: 8), + _buildHeaderMailboxCategory(context, MailboxCategories.teamMailboxes), + Obx(() => controller.teamMailboxesHasChild + ? _buildMailboxCategory(context, MailboxCategories.teamMailboxes, controller.teamMailboxesRootNode) : const SizedBox.shrink()), ]) ), diff --git a/lib/features/mailbox/presentation/model/mailbox_categories.dart b/lib/features/mailbox/presentation/model/mailbox_categories.dart index 2fe65434e..a4b2f1bbb 100644 --- a/lib/features/mailbox/presentation/model/mailbox_categories.dart +++ b/lib/features/mailbox/presentation/model/mailbox_categories.dart @@ -6,8 +6,9 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; enum MailboxCategories { exchange, - folders, + personalMailboxes, appGrid, + teamMailboxes } extension MailboxCategoriessExtension on MailboxCategories { @@ -16,10 +17,12 @@ extension MailboxCategoriessExtension on MailboxCategories { switch(this) { case MailboxCategories.exchange: return 'exchange'; - case MailboxCategories.folders: - return 'folders'; + case MailboxCategories.personalMailboxes: + return 'personalMailboxes'; case MailboxCategories.appGrid: return 'appGrid'; + case MailboxCategories.teamMailboxes: + return 'teamMailboxes'; } } @@ -27,10 +30,12 @@ extension MailboxCategoriessExtension on MailboxCategories { switch(this) { case MailboxCategories.exchange: return AppLocalizations.of(context).exchange; - case MailboxCategories.folders: - return AppLocalizations.of(context).myFolders; + case MailboxCategories.personalMailboxes: + return AppLocalizations.of(context).personalMailboxes; case MailboxCategories.appGrid: return AppLocalizations.of(context).appGridTittle; + case MailboxCategories.teamMailboxes: + return AppLocalizations.of(context).teamMailBoxes; } } @@ -38,8 +43,10 @@ extension MailboxCategoriessExtension on MailboxCategories { switch(this) { case MailboxCategories.exchange: return categoriesExpandMode.defaultMailbox; - case MailboxCategories.folders: - return categoriesExpandMode.folderMailbox; + case MailboxCategories.personalMailboxes: + return categoriesExpandMode.personalMailboxes; + case MailboxCategories.teamMailboxes: + return categoriesExpandMode.teamMailboxes; default: return ExpandMode.COLLAPSE; } diff --git a/lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart b/lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart index b38c013b1..6f46d64c4 100644 --- a/lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart +++ b/lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart @@ -4,14 +4,21 @@ import 'package:model/mailbox/expand_mode.dart'; class MailboxCategoriesExpandMode with EquatableMixin { ExpandMode defaultMailbox; - ExpandMode folderMailbox; + ExpandMode personalMailboxes; + ExpandMode teamMailboxes; - MailboxCategoriesExpandMode({required this.defaultMailbox, required this.folderMailbox}); + MailboxCategoriesExpandMode({ + required this.defaultMailbox, + required this.personalMailboxes, + required this.teamMailboxes}); factory MailboxCategoriesExpandMode.initial() { - return MailboxCategoriesExpandMode(defaultMailbox: ExpandMode.EXPAND, folderMailbox: ExpandMode.EXPAND); + return MailboxCategoriesExpandMode( + defaultMailbox: ExpandMode.EXPAND, + personalMailboxes: ExpandMode.EXPAND, + teamMailboxes: ExpandMode.EXPAND); } @override - List get props => [defaultMailbox, folderMailbox]; + List get props => [defaultMailbox, personalMailboxes, teamMailboxes]; } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart b/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart index 568a8647a..e79242a73 100644 --- a/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart +++ b/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart @@ -39,14 +39,16 @@ class TreeBuilder { return tree; } - Future>> generateMailboxTreeInUI( + Future>> generateMailboxTreeInUI( List allMailboxes, {MailboxId? mailboxIdSelected} ) async { final Map mailboxDictionary = HashMap(); final defaultTree = MailboxTree(MailboxNode.root()); - final folderTree = MailboxTree(MailboxNode.root()); + final personalTree = MailboxTree(MailboxNode.root()); + final teamMailboxes = MailboxTree(MailboxNode.root()); + List listAllMailboxes = []; for (var mailbox in allMailboxes) { @@ -81,7 +83,14 @@ class TreeBuilder { } else { listAllMailboxes.add(node.item); - var tree = mailbox.hasRole() ? defaultTree : folderTree; + MailboxTree tree; + if (mailbox.hasRole()) { + tree = defaultTree; + } else if(mailbox.isPersonal) { + tree = personalTree; + } else { + tree = teamMailboxes; + } tree.root.addChildNode(node); tree.root.childrenItems?.sortByCompare( @@ -93,22 +102,25 @@ class TreeBuilder { } defaultTree.root.childrenItems?.sort((thisMailbox, thatMailbox) => thisMailbox.compareTo(thatMailbox)); - return Tuple3(defaultTree, folderTree, listAllMailboxes); + return Tuple4(defaultTree, personalTree, teamMailboxes, listAllMailboxes); } - Future> generateMailboxTreeInUIAfterRefreshChanges( + Future> generateMailboxTreeInUIAfterRefreshChanges( List allMailboxes, MailboxTree defaultTreeBeforeChanges, - MailboxTree folderTreeBeforeChanges, + MailboxTree personalTreeBeforeChanges, + MailboxTree teamMailboxesTreeBeforeChanges ) async { final Map mailboxDictionary = HashMap(); final newDefaultTree = MailboxTree(MailboxNode.root()); - final newFolderTree = MailboxTree(MailboxNode.root()); + final newPersonalTree = MailboxTree(MailboxNode.root()); + final newTeamMailboxes = MailboxTree(MailboxNode.root()); for (var mailbox in allMailboxes) { - final mailboxNodeBeforeChanges = defaultTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id) ?? - folderTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id); + final mailboxNodeBeforeChanges = defaultTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id) + ?? personalTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id) + ?? teamMailboxesTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id); if (mailboxNodeBeforeChanges != null) { mailboxDictionary[mailbox.id] = MailboxNode( mailbox, @@ -131,7 +143,15 @@ class TreeBuilder { (name, other) => name?.compareAlphabetically(other) ?? -1 ); } else { - var tree = mailbox.hasRole() ? newDefaultTree : newFolderTree; + + MailboxTree tree; + if (mailbox.hasRole()) { + tree = newDefaultTree; + } else if(mailbox.isPersonal) { + tree = newPersonalTree; + } else { + tree = newTeamMailboxes; + } tree.root.addChildNode(node); tree.root.childrenItems?.sortByCompare( @@ -143,6 +163,6 @@ class TreeBuilder { } newDefaultTree.root.childrenItems?.sort((thisMailbox, thatMailbox) => thisMailbox.compareTo(thatMailbox)); - return Tuple2(newDefaultTree, newFolderTree); + return Tuple3(newDefaultTree, newPersonalTree, newTeamMailboxes); } } \ No newline at end of file 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 3cabf4cfb..a24d3bf24 100644 --- a/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart +++ b/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart @@ -105,12 +105,16 @@ class MailBoxFolderTileBuilder { color: backgroundColorItem), padding: const EdgeInsets.only(left: 4, right: 4, top: 8, bottom: 8), margin: const EdgeInsets.only(bottom: 4), - child: Row(children: [ - _buildLeadingMailboxItem(), - const SizedBox(width: 4), - Expanded(child: _buildTitleFolderItem()), - const SizedBox(width: 8), - _buildTrailingMailboxItem() + child: Row( + crossAxisAlignment: _mailboxNode.item.isTeamMailboxes + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, + children: [ + _buildLeadingMailboxItem(), + const SizedBox(width: 4), + Expanded(child: _buildTitleFolderItem()), + const SizedBox(width: 8), + _buildTrailingMailboxItem() ]) ), ); @@ -131,27 +135,27 @@ class MailBoxFolderTileBuilder { : _onOpenMailboxFolderClick?.call(_mailboxNode), child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(14)), - child: Container( - color: Colors.white, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.symmetric( - vertical: _mailboxNode.hasChildren() ? 8 : 15), - child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - _buildLeadingMailboxItem(), - const SizedBox(width: 8), - Expanded(child: _buildTitleFolderItem()), - _buildSelectedIcon(), - const SizedBox(width: 8), - _buildTrailingMailboxItem() - ]), - ), - _buildDivider(), - ] - ) + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric( + vertical: _mailboxNode.hasChildren() ? 8 : 15), + child: Row( + crossAxisAlignment: _mailboxNode.item.isTeamMailboxes + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, + children: [ + _buildLeadingMailboxItem(), + const SizedBox(width: 8), + Expanded(child: _buildTitleFolderItem()), + _buildSelectedIcon(), + const SizedBox(width: 8), + _buildTrailingMailboxItem() + ]), + ), + ] ) ), ), @@ -193,33 +197,69 @@ class MailBoxFolderTileBuilder { if (mailboxDisplayed == MailboxDisplayed.mailbox) { return Row(mainAxisSize: MainAxisSize.min, children: [ if (_mailboxNode.hasChildren()) - buildIconWeb( - icon: SvgPicture.asset( - _mailboxNode.expandMode == ExpandMode.EXPAND - ? _imagePaths.icExpandFolder - : _imagePaths.icCollapseFolder, - color: _mailboxNode.expandMode == ExpandMode.EXPAND - ? AppColor.colorExpandMailbox - : AppColor.colorCollapseMailbox, - fit: BoxFit.fill), - minSize: 12, - splashRadius: 10, - iconPadding: EdgeInsets.zero, - tooltip: _mailboxNode.expandMode == ExpandMode.EXPAND - ? AppLocalizations.of(_context).collapse - : AppLocalizations.of(_context).expand, - onTap: () => _onExpandFolderActionClick?.call(_mailboxNode)) + Row( + children: [ + const SizedBox(width: 8), + buildIconWeb( + icon: SvgPicture.asset( + _mailboxNode.expandMode == ExpandMode.EXPAND + ? _imagePaths.icExpandFolder + : _imagePaths.icCollapseFolder, + color: _mailboxNode.expandMode == ExpandMode.EXPAND + ? AppColor.colorExpandMailbox + : AppColor.colorCollapseMailbox, + fit: BoxFit.fill), + minSize: 12, + splashRadius: 10, + iconPadding: EdgeInsets.zero, + tooltip: _mailboxNode.expandMode == ExpandMode.EXPAND + ? AppLocalizations.of(_context).collapse + : AppLocalizations.of(_context).expand, + onTap: () => _onExpandFolderActionClick?.call(_mailboxNode)), + const SizedBox(width: 4), + ], + ) else - const SizedBox(width: 24), + SizedBox(width:_mailboxNode.item.hasRole() ? 0 : 24), Transform( transform: Matrix4.translationValues(-4.0, 0.0, 0.0), - child: _buildLeadingIcon()) + child: _buildLeadingIcon()), ]); } else { return _buildLeadingIcon(); } } else { - return _buildLeadingIcon(); + if (mailboxDisplayed == MailboxDisplayed.mailbox) { + return Row(mainAxisSize: MainAxisSize.min, children: [ + if (_mailboxNode.hasChildren()) + Row( + children: [ + const SizedBox(width: 12), + buildIconWeb( + icon: SvgPicture.asset( + _mailboxNode.expandMode == ExpandMode.EXPAND + ? _imagePaths.icExpandFolder + : _imagePaths.icCollapseFolder, + color: _mailboxNode.expandMode == ExpandMode.EXPAND + ? AppColor.colorExpandMailbox + : AppColor.colorCollapseMailbox, + fit: BoxFit.fill), + minSize: 12, + splashRadius: 10, + iconPadding: EdgeInsets.zero, + tooltip: _mailboxNode.expandMode == ExpandMode.EXPAND + ? AppLocalizations.of(_context).collapse + : AppLocalizations.of(_context).expand, + onTap: () => _onExpandFolderActionClick?.call(_mailboxNode)), + ], + ) + else + SizedBox(width: _mailboxNode.item.hasRole() ? 0 : 36), + _buildLeadingIcon(), + ]); + } else { + return _buildLeadingIcon(); + } } } @@ -259,30 +299,13 @@ class MailBoxFolderTileBuilder { } else { if (_mailboxNode.hasChildren()) { return Padding( - padding: const EdgeInsets.only(right: 4), + padding: const EdgeInsets.only(right: 12), child: Row( children: [ if (_mailboxNode.item.getCountUnReadEmails().isNotEmpty && _mailboxNode.item.matchCountingRules() && mailboxDisplayed == MailboxDisplayed.mailbox) _buildCounter(), - buildIconWeb( - icon: SvgPicture.asset( - _mailboxNode.expandMode == ExpandMode.EXPAND - ? _imagePaths.icExpandFolder - : _imagePaths.icCollapseFolder, - color: _mailboxNode.expandMode == ExpandMode.EXPAND - ? AppColor.colorExpandMailbox - : AppColor.colorCollapseMailbox, - fit: BoxFit.fill), - splashRadius: mailboxDisplayed == MailboxDisplayed.mailbox ? 20 : 20, - iconPadding: EdgeInsets.zero, - minSize: mailboxDisplayed == MailboxDisplayed.mailbox ? 40 : 24, - tooltip: _mailboxNode.expandMode == ExpandMode.EXPAND - ? AppLocalizations.of(_context).collapse - : AppLocalizations.of(_context).expand, - onTap: () => _onExpandFolderActionClick?.call(_mailboxNode) - ), ], ), ); @@ -290,35 +313,67 @@ class MailBoxFolderTileBuilder { && _mailboxNode.item.matchCountingRules() && mailboxDisplayed == MailboxDisplayed.mailbox) { return Padding( - padding: const EdgeInsets.only(right: 20), + padding: const EdgeInsets.only(right: 12), child: _buildCounter(), ); } else { - return const SizedBox(width: 20); + return const SizedBox(); } } } Widget _buildLeadingIcon() { if (BuildUtils.isWeb) { - return _buildMailboxIcon(); + return _buildLeadingIconTeamMailboxes(); } else { return allSelectMode == SelectMode.ACTIVE ? _buildSelectModeIcon() - : _buildMailboxIcon(); + : _buildLeadingIconTeamMailboxes(); + } + } + + Widget _buildLeadingIconTeamMailboxes() { + if(!_mailboxNode.item.isPersonal) { + return _buildLeadingIconForChildOfTeamMailboxes(); + } else { + return _buildMailboxIcon(); + } + } + + Widget _buildLeadingIconForChildOfTeamMailboxes() { + if(_mailboxNode.item.hasParentId()) { + return _buildMailboxIcon(); + } else { + return const SizedBox(); } } Widget _buildTitleFolderItem() { - return Text( - _mailboxNode.item.name?.name ?? '', - maxLines: 1, - softWrap: CommonTextStyle.defaultSoftWrap, - overflow: CommonTextStyle.defaultTextOverFlow, - style: const TextStyle( - fontSize: 15, - color: AppColor.colorNameEmail, - fontWeight: FontWeight.normal), + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _mailboxNode.item.name?.name ?? '', + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + style: TextStyle( + fontSize: _mailboxNode.item.isTeamMailboxes ? 16 : 15, + color: _mailboxNode.item.isTeamMailboxes ? Colors.black : AppColor.colorNameEmail, + fontWeight: _mailboxNode.item.isTeamMailboxes ? FontWeight.bold : FontWeight.normal), + ), + if(_mailboxNode.item.isTeamMailboxes) + Text( + _mailboxNode.item.nameTeamMailBoxes ?? '', + maxLines: 1, + softWrap: CommonTextStyle.defaultSoftWrap, + overflow: CommonTextStyle.defaultTextOverFlow, + style: const TextStyle( + fontSize: 13, + color: AppColor.colorEmailAddressFull, + fontWeight: FontWeight.w400), + ), + ], ); } @@ -335,8 +390,7 @@ class MailBoxFolderTileBuilder { } Widget _buildMailboxIcon() { - return SvgPicture.asset( - _mailboxNode.item.getMailboxIcon(_imagePaths), + return SvgPicture.asset(_mailboxNode.item.getMailboxIcon(_imagePaths), width: BuildUtils.isWeb ? 20 : 24, height: BuildUtils.isWeb ? 20 : 24, fit: BoxFit.fill); @@ -395,20 +449,6 @@ class MailBoxFolderTileBuilder { } } - Widget _buildDivider() { - if (lastNode?.item.id != _mailboxNode.item.id) { - return const Padding( - padding: EdgeInsets.only(left: 30), - child: Divider( - color: AppColor.lineItemListColor, - height: 0.5, - thickness: 0.2 - ) - ); - } - return const SizedBox.shrink(); - } - Widget _buildSelectedIcon() { if (_mailboxNode.item.id == mailboxIdAlreadySelected && mailboxDisplayed == MailboxDisplayed.destinationPicker && diff --git a/lib/features/mailbox_creator/presentation/mailbox_creator_controller.dart b/lib/features/mailbox_creator/presentation/mailbox_creator_controller.dart index 776e515b7..b5f76fffb 100644 --- a/lib/features/mailbox_creator/presentation/mailbox_creator_controller.dart +++ b/lib/features/mailbox_creator/presentation/mailbox_creator_controller.dart @@ -3,6 +3,7 @@ import 'package:core/core.dart'; import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; @@ -34,8 +35,10 @@ class MailboxCreatorController extends BaseController { MailboxCreatorArguments? arguments; AccountId? accountId; - MailboxTree? folderMailboxTree; + Session? _session; MailboxTree? defaultMailboxTree; + MailboxTree? personalMailboxTree; + MailboxTree? teamMailboxesTre; OnCreatedMailboxCallback? onCreatedMailboxCallback; VoidCallback? onDismissMailboxCreator; @@ -56,9 +59,11 @@ class MailboxCreatorController extends BaseController { void onReady() { super.onReady(); if (arguments != null) { - folderMailboxTree = arguments!.folderMailboxTree; + personalMailboxTree = arguments!.personalMailboxTree; defaultMailboxTree = arguments!.defaultMailboxTree; + teamMailboxesTre = arguments!.teamMailboxesTree; accountId = arguments!.accountId; + _session = arguments!.session; _createListMailboxNameAsStringInMailboxLocation(); } } @@ -89,13 +94,17 @@ class MailboxCreatorController extends BaseController { final mailboxNode = defaultMailboxTree?.findNode((node) => node.item.id == mailboxId); if (mailboxNode != null) { return mailboxNode; + } else if(mailboxNode!.item.isTeamMailboxes) { + return teamMailboxesTre?.findNode((node) => node.item.id == mailboxId); } - return folderMailboxTree?.findNode((node) => node.item.id == mailboxId); + return personalMailboxTree?.findNode((node) => node.item.id == mailboxId); } void _createListMailboxNameAsStringInMailboxLocation() { if (selectedMailbox.value == null) { - final allChildrenAtMailboxLocation = (defaultMailboxTree?.root.childrenItems ?? []) + (folderMailboxTree?.root.childrenItems ?? []); + final allChildrenAtMailboxLocation = (defaultMailboxTree?.root.childrenItems ?? []) + + (personalMailboxTree?.root.childrenItems ?? []) + + (teamMailboxesTre?.root.childrenItems ?? []); if (allChildrenAtMailboxLocation.isNotEmpty) { listMailboxNameAsStringExist = allChildrenAtMailboxLocation .where((mailboxNode) => mailboxNode.nameNotEmpty) @@ -150,6 +159,7 @@ class MailboxCreatorController extends BaseController { final arguments = DestinationPickerArguments( accountId!, MailboxActions.create, + _session, mailboxIdSelected: selectedMailbox.value?.id); if (BuildUtils.isWeb) { diff --git a/lib/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart b/lib/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart index cac239475..63ed9d466 100644 --- a/lib/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart +++ b/lib/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart @@ -1,15 +1,28 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; class MailboxCreatorArguments with EquatableMixin{ final AccountId accountId; - final MailboxTree folderMailboxTree; + final MailboxTree personalMailboxTree; final MailboxTree defaultMailboxTree; + final MailboxTree teamMailboxesTree; + final Session session; - MailboxCreatorArguments(this.accountId, this.defaultMailboxTree, this.folderMailboxTree); + MailboxCreatorArguments( + this.accountId, + this.defaultMailboxTree, + this.personalMailboxTree, + this.teamMailboxesTree, + this.session); @override - List get props => [accountId, defaultMailboxTree, folderMailboxTree]; + List get props => [ + accountId, + defaultMailboxTree, + personalMailboxTree, + teamMailboxesTree, + session]; } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart index c2d54bc71..7da60bd92 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart @@ -137,10 +137,12 @@ class AdvancedFilterController extends BaseController { void selectedMailBox(BuildContext context) async { final accountId = _mailboxDashBoardController.accountId.value; + final _session = _mailboxDashBoardController.sessionCurrent; if (accountId != null) { final arguments = DestinationPickerArguments( accountId, MailboxActions.select, + _session, mailboxIdSelected: searchController.searchEmailFilter.value.mailbox?.id); if (BuildUtils.isWeb) { diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index f07ac0e37..d9e92e4a9 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -733,7 +733,10 @@ class MailboxDashBoardController extends ReloadableController { PresentationMailbox currentMailbox ) async { if (accountId.value != null) { - final arguments = DestinationPickerArguments(accountId.value!, MailboxActions.moveEmail); + final arguments = DestinationPickerArguments( + accountId.value!, + MailboxActions.moveEmail, + sessionCurrent); if (BuildUtils.isWeb) { showDialogDestinationPicker( diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart index 89a781217..f29609616 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart @@ -234,7 +234,8 @@ class RulesFilterCreatorController extends BaseMailboxController { if (_accountId != null) { final arguments = DestinationPickerArguments( _accountId!, - MailboxActions.selectForRuleAction); + MailboxActions.selectForRuleAction, + _session); if (BuildUtils.isWeb) { showDialogDestinationPicker( diff --git a/lib/features/search/presentation/search_email_controller.dart b/lib/features/search/presentation/search_email_controller.dart index 8aad31675..58bfa08ca 100644 --- a/lib/features/search/presentation/search_email_controller.dart +++ b/lib/features/search/presentation/search_email_controller.dart @@ -462,6 +462,7 @@ class SearchEmailController extends BaseController final arguments = DestinationPickerArguments( mailboxDashBoardController.accountId.value!, MailboxActions.select, + mailboxDashBoardController.sessionCurrent, mailboxIdSelected: mailbox?.id); if (BuildUtils.isWeb) { diff --git a/lib/features/thread/presentation/mixin/email_action_controller.dart b/lib/features/thread/presentation/mixin/email_action_controller.dart index af584f5fd..cae986fd0 100644 --- a/lib/features/thread/presentation/mixin/email_action_controller.dart +++ b/lib/features/thread/presentation/mixin/email_action_controller.dart @@ -110,9 +110,10 @@ mixin EmailActionController on ViewAsDialogActionMixin { {PresentationMailbox? mailboxContain} ) async { final accountId = mailboxDashBoardController.accountId.value; + final _session = mailboxDashBoardController.sessionCurrent; if (mailboxContain != null && accountId != null) { - final arguments = DestinationPickerArguments(accountId, MailboxActions.moveEmail); + final arguments = DestinationPickerArguments(accountId, MailboxActions.moveEmail, _session); if (BuildUtils.isWeb) { showDialogDestinationPicker( diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 95ffdd4bf..3d91407be 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -117,10 +117,10 @@ class AppLocalizations { ); } - String get myFolders { + String get personalMailboxes { return Intl.message( - 'My Folders', - name: 'myFolders', + 'Personal mailboxes', + name: 'personalMailboxes', ); } @@ -2754,4 +2754,22 @@ class AppLocalizations { name: 'saveEmailAsDraftFailureWithSetErrorTypeOverQuota', ); } + + String get mailBoxes { + return Intl.message( + 'Mailboxes', + name: 'mailBoxes'); + } + + String get teamMailBoxes { + return Intl.message( + 'Team-mailboxes', + name: 'teamMailBoxes'); + } + + String get hideMailBoxes { + return Intl.message( + 'Hide mailbox', + name: 'hideMailBoxes'); + } } \ No newline at end of file diff --git a/model/lib/extensions/mailbox_extension.dart b/model/lib/extensions/mailbox_extension.dart index 1da03bf49..9331a7a59 100644 --- a/model/lib/extensions/mailbox_extension.dart +++ b/model/lib/extensions/mailbox_extension.dart @@ -19,6 +19,7 @@ extension MailboxExtension on Mailbox { unreadThreads: unreadThreads, myRights: myRights, isSubscribed: isSubscribed, + namespace: namespace, ); } @@ -35,6 +36,7 @@ extension MailboxExtension on Mailbox { unreadThreads: updatedProperties.contain(MailboxProperty.unreadThreads) ? newMailbox.unreadThreads : unreadThreads, myRights: updatedProperties.contain(MailboxProperty.myRights) ? newMailbox.myRights : myRights, isSubscribed: updatedProperties.contain(MailboxProperty.isSubscribed) ? newMailbox.isSubscribed : isSubscribed, + namespace: updatedProperties.contain(MailboxProperty.namespace) ? newMailbox.namespace : namespace, ); } @@ -51,6 +53,7 @@ extension MailboxExtension on Mailbox { unreadThreads: unreadThreads, myRights: myRights, isSubscribed: isSubscribed, + namespace: namespace, ); } } \ No newline at end of file diff --git a/model/lib/extensions/presentation_mailbox_extension.dart b/model/lib/extensions/presentation_mailbox_extension.dart index 8b9c768a1..4b2e6cbb1 100644 --- a/model/lib/extensions/presentation_mailbox_extension.dart +++ b/model/lib/extensions/presentation_mailbox_extension.dart @@ -18,7 +18,8 @@ extension PresentationMailboxExtension on PresentationMailbox { isSubscribed: isSubscribed, selectMode: selectMode, mailboxPath: mailboxPath, - state: state + state: state, + namespace: namespace, ); } @@ -37,7 +38,8 @@ extension PresentationMailboxExtension on PresentationMailbox { isSubscribed: isSubscribed, selectMode: selectMode, mailboxPath: mailboxPath, - state: newMailboxState + state: newMailboxState, + namespace: namespace, ); } @@ -53,7 +55,8 @@ extension PresentationMailboxExtension on PresentationMailbox { totalThreads: totalThreads, unreadThreads: unreadThreads, myRights: myRights, - isSubscribed: isSubscribed + isSubscribed: isSubscribed, + namespace: namespace, ); } @@ -72,7 +75,8 @@ extension PresentationMailboxExtension on PresentationMailbox { isSubscribed: isSubscribed, mailboxPath: mailboxPath, selectMode: selectMode == SelectMode.INACTIVE ? SelectMode.ACTIVE : SelectMode.INACTIVE, - state: state + state: state, + namespace: namespace, ); } @@ -91,7 +95,8 @@ extension PresentationMailboxExtension on PresentationMailbox { isSubscribed: isSubscribed, mailboxPath: mailboxPath, selectMode: selectMode, - state: state + state: state, + namespace: namespace, ); } } \ No newline at end of file diff --git a/model/lib/mailbox/mailbox_property.dart b/model/lib/mailbox/mailbox_property.dart index a410c5dec..6fc134627 100644 --- a/model/lib/mailbox/mailbox_property.dart +++ b/model/lib/mailbox/mailbox_property.dart @@ -11,4 +11,5 @@ class MailboxProperty { static const String unreadThreads = 'unreadThreads'; static const String myRights = 'myRights'; static const String isSubscribed = 'isSubscribed'; + static const String namespace = 'namespace'; } \ No newline at end of file diff --git a/model/lib/mailbox/presentation_mailbox.dart b/model/lib/mailbox/presentation_mailbox.dart index 5bb8de676..a40e35805 100644 --- a/model/lib/mailbox/presentation_mailbox.dart +++ b/model/lib/mailbox/presentation_mailbox.dart @@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_rights.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/namespace.dart'; import 'package:model/mailbox/mailbox_state.dart'; import 'package:model/mailbox/select_mode.dart'; @@ -34,6 +35,7 @@ class PresentationMailbox with EquatableMixin { final SelectMode selectMode; final String? mailboxPath; final MailboxState? state; + final Namespace? namespace; PresentationMailbox( this.id, @@ -51,6 +53,7 @@ class PresentationMailbox with EquatableMixin { this.selectMode = SelectMode.INACTIVE, this.mailboxPath, this.state = MailboxState.activated, + this.namespace, } ); @@ -60,6 +63,12 @@ class PresentationMailbox with EquatableMixin { bool hasRole() => role != null && role!.value.isNotEmpty; + bool get isPersonal => namespace == Namespace('Personal'); + + bool get isTeamMailboxes => !isPersonal && !hasParentId(); + + bool get isChildOfTeamMailboxes => !isPersonal && hasParentId(); + String getCountUnReadEmails() { if (unreadEmails == null || unreadEmails!.value.value <= 0) { return ''; @@ -69,7 +78,7 @@ class PresentationMailbox with EquatableMixin { } bool get isSpam => role == roleSpam; - + bool get isTrash => role == roleTrash; bool get isDrafts => role == roleDrafts; @@ -88,6 +97,10 @@ class PresentationMailbox with EquatableMixin { } } + String? get nameTeamMailBoxes => namespace?.value.substring( + (namespace?.value.indexOf('[') ?? 0) + 1, + namespace?.value.indexOf(']')); + @override List get props => [ id, @@ -104,5 +117,6 @@ class PresentationMailbox with EquatableMixin { selectMode, mailboxPath, state, + namespace, ]; } \ No newline at end of file