diff --git a/lib/features/base/base_mailbox_controller.dart b/lib/features/base/base_mailbox_controller.dart index ee92dc783..cf1f30969 100644 --- a/lib/features/base/base_mailbox_controller.dart +++ b/lib/features/base/base_mailbox_controller.dart @@ -79,32 +79,36 @@ abstract class BaseMailboxController extends BaseController { List allMailbox, {MailboxId? mailboxIdSelected} ) async { - allMailboxes = allMailbox; - final tupleTree = await _treeBuilder.generateMailboxTreeInUI( - allMailbox, - mailboxIdSelected: mailboxIdSelected); + final recordTree = await _treeBuilder.generateMailboxTreeInUI( + allMailboxes: allMailbox, + currentDefaultTree: defaultMailboxTree.value, + currentPersonalTree: personalMailboxTree.value, + currentTeamMailboxTree: teamMailboxesTree.value, + mailboxIdSelected: mailboxIdSelected, + ); defaultMailboxTree.firstRebuild = true; personalMailboxTree.firstRebuild = true; teamMailboxesTree.firstRebuild = true; - defaultMailboxTree.value = tupleTree.value1; - personalMailboxTree.value = tupleTree.value2; - teamMailboxesTree.value = tupleTree.value3; - allMailboxes = tupleTree.value4; + defaultMailboxTree.value = recordTree.defaultTree; + personalMailboxTree.value = recordTree.personalTree; + teamMailboxesTree.value = recordTree.teamMailboxTree; + allMailboxes = recordTree.allMailboxes; } Future refreshTree(List allMailbox) async { - allMailboxes = allMailbox; - final tupleTree = await _treeBuilder.generateMailboxTreeInUIAfterRefreshChanges( - allMailbox, - defaultMailboxTree.value, - personalMailboxTree.value, - teamMailboxesTree.value); + final recordTree = await _treeBuilder.generateMailboxTreeInUIAfterRefreshChanges( + allMailboxes: allMailbox, + currentDefaultTree: defaultMailboxTree.value, + currentPersonalTree: personalMailboxTree.value, + currentTeamMailboxTree: teamMailboxesTree.value, + ); defaultMailboxTree.firstRebuild = true; personalMailboxTree.firstRebuild = true; teamMailboxesTree.firstRebuild = true; - defaultMailboxTree.value = tupleTree.value1; - personalMailboxTree.value = tupleTree.value2; - teamMailboxesTree.value = tupleTree.value3; + defaultMailboxTree.value = recordTree.defaultTree; + personalMailboxTree.value = recordTree.personalTree; + teamMailboxesTree.value = recordTree.teamMailboxTree; + allMailboxes = allMailbox; } void syncAllMailboxWithDisplayName(BuildContext context) { @@ -201,11 +205,11 @@ abstract class BaseMailboxController extends BaseController { 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; } - + + final mailboxPersonal = personalMailboxTree.value.findNode((node) => node.item.id == mailboxId); if (mailboxPersonal != null) { return mailboxPersonal; } diff --git a/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart b/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart index d0f83eede..74430b06a 100644 --- a/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart +++ b/lib/features/mailbox/presentation/model/mailbox_tree_builder.dart @@ -1,9 +1,13 @@ import 'dart:collection'; import 'package:collection/collection.dart'; -import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; -import 'package:model/model.dart'; +import 'package:model/extensions/mailbox_name_extension.dart'; +import 'package:model/extensions/presentation_mailbox_extension.dart'; +import 'package:model/mailbox/expand_mode.dart'; +import 'package:model/mailbox/mailbox_state.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:model/mailbox/select_mode.dart'; import 'mailbox_node.dart'; import 'mailbox_tree.dart'; @@ -17,154 +21,179 @@ class TreeBuilder { mailboxDictionary[mailbox.id] = MailboxNode(mailbox); } for (var mailbox in mailboxesList) { + final node = mailboxDictionary[mailbox.id]; + if (node == null) continue; + final parentId = mailbox.parentId; final parentNode = mailboxDictionary[parentId]; - final node = mailboxDictionary[mailbox.id]; - if (node != null) { - if (parentNode != null) { - parentNode.addChildNode(node); - parentNode.childrenItems?.sortByCompare( - (node) => node.item.name, - (name, other) => name?.compareAlphabetically(other) ?? -1 - ); - } else { - tree.root.addChildNode(node); - tree.root.childrenItems?.sortByCompare( - (node) => node.item.name, - (name, other) => name?.compareAlphabetically(other) ?? -1 - ); - } + if (parentNode != null) { + parentNode.addChildNode(node); + sortByMailboxNameNodeChildren(parentNode); + } else { + tree.root.addChildNode(node); + sortByMailboxNameNodeChildren(tree.root); } } return tree; } - Future>> generateMailboxTreeInUI( - List allMailboxes, - {MailboxId? mailboxIdSelected} - ) async { - final Map mailboxDictionary = HashMap(); - - final defaultTree = MailboxTree(MailboxNode.root()); - final personalTree = MailboxTree(MailboxNode.root()); - final teamMailboxes = MailboxTree(MailboxNode.root()); - - List listAllMailboxes = []; - - for (var mailbox in allMailboxes) { - if (mailbox.id == mailboxIdSelected) { - mailboxDictionary[mailbox.id] = MailboxNode( - mailbox.withMailboxSate(MailboxState.deactivated), - nodeState: MailboxState.deactivated); - } else { - mailboxDictionary[mailbox.id] = MailboxNode(mailbox); - } - } - - for (var mailbox in allMailboxes) { - final parentId = mailbox.parentId; - final parentNode = mailboxDictionary[parentId]; - final node = mailboxDictionary[mailbox.id]; - if (node != null) { - if (parentNode != null) { - if (parentNode.nodeState == MailboxState.deactivated) { - node.updateItem(mailbox.withMailboxSate(MailboxState.deactivated)); - node.updateNodeState(MailboxState.deactivated); - parentNode.addChildNode(node); - listAllMailboxes.add(node.item); - } else { - parentNode.addChildNode(node); - listAllMailboxes.add(node.item); - } - parentNode.childrenItems?.sortByCompare( - (node) => node.item.name, - (name, other) => name?.compareAlphabetically(other) ?? -1 - ); - } else if (parentId == null) { - listAllMailboxes.add(node.item); - - MailboxTree tree; - if (mailbox.hasRole()) { - tree = defaultTree; - } else if(mailbox.isPersonal) { - tree = personalTree; - } else { - tree = teamMailboxes; - } - - tree.root.addChildNode(node); - tree.root.childrenItems?.sortByCompare( - (node) => node.item.name, - (name, other) => name?.compareAlphabetically(other) ?? -1 - ); - } else { - listAllMailboxes.add(node.item); - } - } - } - - defaultTree.root.childrenItems?.sort((thisMailbox, thatMailbox) => thisMailbox.compareTo(thatMailbox)); - return Tuple4(defaultTree, personalTree, teamMailboxes, listAllMailboxes); - } - - Future> generateMailboxTreeInUIAfterRefreshChanges( - List allMailboxes, - MailboxTree defaultTreeBeforeChanges, - MailboxTree personalTreeBeforeChanges, - MailboxTree teamMailboxesTreeBeforeChanges - ) async { + Future<({ + List allMailboxes, + MailboxTree defaultTree, + MailboxTree personalTree, + MailboxTree teamMailboxTree + })> generateMailboxTreeInUI({ + required List allMailboxes, + required MailboxTree currentDefaultTree, + required MailboxTree currentPersonalTree, + required MailboxTree currentTeamMailboxTree, + MailboxId? mailboxIdSelected, + }) async { final Map mailboxDictionary = HashMap(); final newDefaultTree = MailboxTree(MailboxNode.root()); final newPersonalTree = MailboxTree(MailboxNode.root()); - final newTeamMailboxes = MailboxTree(MailboxNode.root()); + final newTeamMailboxTree = MailboxTree(MailboxNode.root()); + + final List newAllMailboxes = []; for (var mailbox in allMailboxes) { - 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, - expandMode: mailboxNodeBeforeChanges.expandMode, - selectMode: mailboxNodeBeforeChanges.selectMode); - } else { - mailboxDictionary[mailbox.id] = MailboxNode(mailbox); - } + final currentMailboxNode = findExistingNode( + id: mailbox.id, + currentDefaultTree: currentDefaultTree, + currentPersonalTree: currentPersonalTree, + currentTeamMailboxTree: currentTeamMailboxTree, + ); + + final isDeactivated = mailbox.id == mailboxIdSelected; + final newMailboxNode = MailboxNode( + isDeactivated ? mailbox.withMailboxSate(MailboxState.deactivated) : mailbox, + nodeState: isDeactivated ? MailboxState.deactivated : MailboxState.activated, + expandMode: currentMailboxNode?.expandMode ?? ExpandMode.COLLAPSE, + selectMode: currentMailboxNode?.selectMode ?? SelectMode.INACTIVE, + ); + + mailboxDictionary[mailbox.id] = newMailboxNode; } for (var mailbox in allMailboxes) { + final currentNode = mailboxDictionary[mailbox.id]; + if (currentNode == null) continue; + final parentId = mailbox.parentId; - final parentNode = mailboxDictionary[parentId]; - final node = mailboxDictionary[mailbox.id]; - if (node != null) { - if (parentNode != null) { - parentNode.addChildNode(node); - parentNode.childrenItems?.sortByCompare( - (node) => node.item.name, - (name, other) => name?.compareAlphabetically(other) ?? -1 - ); - } else if (parentId == null) { + final parentNode = parentId != null ? mailboxDictionary[parentId] : null; - MailboxTree tree; - if (mailbox.hasRole()) { - tree = newDefaultTree; - } else if(mailbox.isPersonal) { - tree = newPersonalTree; - } else { - tree = newTeamMailboxes; - } - - tree.root.addChildNode(node); - tree.root.childrenItems?.sortByCompare( - (node) => node.item.name, - (name, other) => name?.compareAlphabetically(other) ?? -1 - ); + if (parentNode != null) { + if (parentNode.nodeState == MailboxState.deactivated) { + currentNode.updateItem(mailbox.withMailboxSate(MailboxState.deactivated)); + currentNode.updateNodeState(MailboxState.deactivated); } + parentNode.addChildNode(currentNode); + + sortByMailboxNameNodeChildren(parentNode); + } else { + final targetTree = mailbox.hasRole() + ? newDefaultTree + : (mailbox.isPersonal ? newPersonalTree : newTeamMailboxTree); + targetTree.root.addChildNode(currentNode); + + sortByMailboxNameNodeChildren(targetTree.root); + } + + newAllMailboxes.add(currentNode.item); + } + + sortNodeChildren(newDefaultTree.root); + + return ( + allMailboxes: newAllMailboxes, + defaultTree: newDefaultTree, + personalTree: newPersonalTree, + teamMailboxTree: newTeamMailboxTree, + ); + } + + Future<({ + MailboxTree defaultTree, + MailboxTree personalTree, + MailboxTree teamMailboxTree + })> generateMailboxTreeInUIAfterRefreshChanges({ + required List allMailboxes, + required MailboxTree currentDefaultTree, + required MailboxTree currentPersonalTree, + required MailboxTree currentTeamMailboxTree, + }) async { + final Map mailboxDictionary = HashMap(); + + final newDefaultTree = MailboxTree(MailboxNode.root()); + final newPersonalTree = MailboxTree(MailboxNode.root()); + final newTeamMailboxTree = MailboxTree(MailboxNode.root()); + + for (var mailbox in allMailboxes) { + final currentMailboxNode = findExistingNode( + id: mailbox.id, + currentDefaultTree: currentDefaultTree, + currentPersonalTree: currentPersonalTree, + currentTeamMailboxTree: currentTeamMailboxTree, + ); + + final newMailboxNode = MailboxNode( + mailbox, + expandMode: currentMailboxNode?.expandMode ?? ExpandMode.COLLAPSE, + selectMode: currentMailboxNode?.selectMode ?? SelectMode.INACTIVE, + ); + + mailboxDictionary[mailbox.id] = newMailboxNode; + } + + for (var mailbox in allMailboxes) { + final currentNode = mailboxDictionary[mailbox.id]; + if (currentNode == null) continue; + + final parentId = mailbox.parentId; + final parentNode = parentId != null ? mailboxDictionary[parentId] : null; + + if (parentNode != null) { + parentNode.addChildNode(currentNode); + sortByMailboxNameNodeChildren(parentNode); + } else { + final targetTree = mailbox.hasRole() + ? newDefaultTree + : (mailbox.isPersonal ? newPersonalTree : newTeamMailboxTree); + targetTree.root.addChildNode(currentNode); + + sortByMailboxNameNodeChildren(targetTree.root); } } - newDefaultTree.root.childrenItems?.sort((thisMailbox, thatMailbox) => thisMailbox.compareTo(thatMailbox)); - return Tuple3(newDefaultTree, newPersonalTree, newTeamMailboxes); + sortNodeChildren(newDefaultTree.root); + + return ( + defaultTree: newDefaultTree, + personalTree: newPersonalTree, + teamMailboxTree: newTeamMailboxTree, + ); + } + + void sortNodeChildren(MailboxNode mailboxNode) { + mailboxNode.childrenItems?.sort((a, b) => a.compareTo(b)); + } + + void sortByMailboxNameNodeChildren(MailboxNode mailboxNode) { + mailboxNode.childrenItems?.sortByCompare( + (node) => node.item.name, + (name, other) => name?.compareAlphabetically(other) ?? -1, + ); + } + + MailboxNode? findExistingNode({ + required MailboxId id, + required MailboxTree currentDefaultTree, + required MailboxTree currentPersonalTree, + required MailboxTree currentTeamMailboxTree, + }) { + return currentDefaultTree.findNode((node) => node.item.id == id) ?? + currentPersonalTree.findNode((node) => node.item.id == id) ?? + currentTeamMailboxTree.findNode((node) => node.item.id == id); } } \ No newline at end of file diff --git a/test/features/mailbox/presentation/model/mailbox_tree_builder_test.dart b/test/features/mailbox/presentation/model/mailbox_tree_builder_test.dart index ec8df74a2..f1d9e4beb 100644 --- a/test/features/mailbox/presentation/model/mailbox_tree_builder_test.dart +++ b/test/features/mailbox/presentation/model/mailbox_tree_builder_test.dart @@ -248,10 +248,15 @@ void main() { PresentationMailbox(MailboxId(Id("1")), parentId: null, name: MailboxName('Inbox'), sortOrder: SortOrder(sortValue: 10), role: Role('inbox')), ]; - final generatedTree = await TreeBuilder().generateMailboxTreeInUI(testCase); + final generatedTree = await TreeBuilder().generateMailboxTreeInUI( + allMailboxes: testCase, + currentDefaultTree: MailboxTree(MailboxNode.root()), + currentPersonalTree: MailboxTree(MailboxNode.root()), + currentTeamMailboxTree: MailboxTree(MailboxNode.root()), + ); expect( - generatedTree.head.root.childrenItems, + generatedTree.defaultTree.root.childrenItems, equals(expectedTree.root.childrenItems) ); }); diff --git a/test/features/rule_filter_creator/presentation/rule_filter_creator_controller_test.dart b/test/features/rule_filter_creator/presentation/rule_filter_creator_controller_test.dart index fd4556812..3155bcebe 100644 --- a/test/features/rule_filter_creator/presentation/rule_filter_creator_controller_test.dart +++ b/test/features/rule_filter_creator/presentation/rule_filter_creator_controller_test.dart @@ -214,12 +214,17 @@ void main() { ]); }); - when(mockTreeBuilder.generateMailboxTreeInUI([spamMailbox])).thenAnswer((_) async { - return Tuple4>( - MailboxTree(MailboxNode(spamMailbox)), - MailboxTree(MailboxNode.root()), - MailboxTree(MailboxNode.root()), - [spamMailbox], + when(mockTreeBuilder.generateMailboxTreeInUI( + allMailboxes: [spamMailbox], + currentDefaultTree: MailboxTree(MailboxNode.root()), + currentPersonalTree: MailboxTree(MailboxNode.root()), + currentTeamMailboxTree: MailboxTree(MailboxNode.root()), + )).thenAnswer((_) async { + return ( + allMailboxes: [spamMailbox], + defaultTree: MailboxTree(MailboxNode(spamMailbox)), + personalTree: MailboxTree(MailboxNode.root()), + teamMailboxTree: MailboxTree(MailboxNode.root()), ); }); @@ -237,6 +242,10 @@ void main() { rulesFilterCreatorController.dispatchState(Right(UIClosedState())); rulesFilterCreatorController.listEmailRuleFilterActionSelected.clear(); + rulesFilterCreatorController.allMailboxes.clear(); + rulesFilterCreatorController.personalMailboxTree.value = MailboxTree(MailboxNode.root()); + rulesFilterCreatorController.defaultMailboxTree.value = MailboxTree(MailboxNode.root()); + rulesFilterCreatorController.teamMailboxesTree.value = MailboxTree(MailboxNode.root()); debugDefaultTargetPlatformOverride = null; tester.view.reset(); }); @@ -286,12 +295,17 @@ void main() { ]); }); - when(mockTreeBuilder.generateMailboxTreeInUI([mailboxA])).thenAnswer((_) async { - return Tuple4>( - MailboxTree(MailboxNode(mailboxA)), - MailboxTree(MailboxNode.root()), - MailboxTree(MailboxNode.root()), - [mailboxA], + when(mockTreeBuilder.generateMailboxTreeInUI( + allMailboxes: [mailboxA], + currentDefaultTree: MailboxTree(MailboxNode.root()), + currentPersonalTree: MailboxTree(MailboxNode.root()), + currentTeamMailboxTree: MailboxTree(MailboxNode.root()), + )).thenAnswer((_) async { + return ( + allMailboxes: [mailboxA], + defaultTree: MailboxTree(MailboxNode.root()), + personalTree: MailboxTree(MailboxNode(mailboxA)), + teamMailboxTree: MailboxTree(MailboxNode.root()), ); }); @@ -311,6 +325,10 @@ void main() { rulesFilterCreatorController.dispatchState(Right(UIClosedState())); rulesFilterCreatorController.listEmailRuleFilterActionSelected.clear(); + rulesFilterCreatorController.allMailboxes.clear(); + rulesFilterCreatorController.personalMailboxTree.value = MailboxTree(MailboxNode.root()); + rulesFilterCreatorController.defaultMailboxTree.value = MailboxTree(MailboxNode.root()); + rulesFilterCreatorController.teamMailboxesTree.value = MailboxTree(MailboxNode.root()); debugDefaultTargetPlatformOverride = null; tester.view.reset(); });