TF-3466 Fix refresh folds folder

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-02-06 14:21:32 +07:00
committed by Dat H. Pham
parent 005790ae5f
commit d51f06f6f0
4 changed files with 218 additions and 162 deletions
+23 -19
View File
@@ -79,32 +79,36 @@ abstract class BaseMailboxController extends BaseController {
List<PresentationMailbox> allMailbox, List<PresentationMailbox> allMailbox,
{MailboxId? mailboxIdSelected} {MailboxId? mailboxIdSelected}
) async { ) async {
allMailboxes = allMailbox; final recordTree = await _treeBuilder.generateMailboxTreeInUI(
final tupleTree = await _treeBuilder.generateMailboxTreeInUI( allMailboxes: allMailbox,
allMailbox, currentDefaultTree: defaultMailboxTree.value,
mailboxIdSelected: mailboxIdSelected); currentPersonalTree: personalMailboxTree.value,
currentTeamMailboxTree: teamMailboxesTree.value,
mailboxIdSelected: mailboxIdSelected,
);
defaultMailboxTree.firstRebuild = true; defaultMailboxTree.firstRebuild = true;
personalMailboxTree.firstRebuild = true; personalMailboxTree.firstRebuild = true;
teamMailboxesTree.firstRebuild = true; teamMailboxesTree.firstRebuild = true;
defaultMailboxTree.value = tupleTree.value1; defaultMailboxTree.value = recordTree.defaultTree;
personalMailboxTree.value = tupleTree.value2; personalMailboxTree.value = recordTree.personalTree;
teamMailboxesTree.value = tupleTree.value3; teamMailboxesTree.value = recordTree.teamMailboxTree;
allMailboxes = tupleTree.value4; allMailboxes = recordTree.allMailboxes;
} }
Future<void> refreshTree(List<PresentationMailbox> allMailbox) async { Future<void> refreshTree(List<PresentationMailbox> allMailbox) async {
allMailboxes = allMailbox; final recordTree = await _treeBuilder.generateMailboxTreeInUIAfterRefreshChanges(
final tupleTree = await _treeBuilder.generateMailboxTreeInUIAfterRefreshChanges( allMailboxes: allMailbox,
allMailbox, currentDefaultTree: defaultMailboxTree.value,
defaultMailboxTree.value, currentPersonalTree: personalMailboxTree.value,
personalMailboxTree.value, currentTeamMailboxTree: teamMailboxesTree.value,
teamMailboxesTree.value); );
defaultMailboxTree.firstRebuild = true; defaultMailboxTree.firstRebuild = true;
personalMailboxTree.firstRebuild = true; personalMailboxTree.firstRebuild = true;
teamMailboxesTree.firstRebuild = true; teamMailboxesTree.firstRebuild = true;
defaultMailboxTree.value = tupleTree.value1; defaultMailboxTree.value = recordTree.defaultTree;
personalMailboxTree.value = tupleTree.value2; personalMailboxTree.value = recordTree.personalTree;
teamMailboxesTree.value = tupleTree.value3; teamMailboxesTree.value = recordTree.teamMailboxTree;
allMailboxes = allMailbox;
} }
void syncAllMailboxWithDisplayName(BuildContext context) { void syncAllMailboxWithDisplayName(BuildContext context) {
@@ -201,11 +205,11 @@ abstract class BaseMailboxController extends BaseController {
MailboxNode? findMailboxNodeById(MailboxId mailboxId) { MailboxNode? findMailboxNodeById(MailboxId mailboxId) {
final mailboxNode = defaultMailboxTree.value.findNode((node) => node.item.id == mailboxId); final mailboxNode = defaultMailboxTree.value.findNode((node) => node.item.id == mailboxId);
final mailboxPersonal = personalMailboxTree.value.findNode((node) => node.item.id == mailboxId);
if (mailboxNode != null) { if (mailboxNode != null) {
return mailboxNode; return mailboxNode;
} }
final mailboxPersonal = personalMailboxTree.value.findNode((node) => node.item.id == mailboxId);
if (mailboxPersonal != null) { if (mailboxPersonal != null) {
return mailboxPersonal; return mailboxPersonal;
} }
@@ -1,9 +1,13 @@
import 'dart:collection'; import 'dart:collection';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.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_node.dart';
import 'mailbox_tree.dart'; import 'mailbox_tree.dart';
@@ -17,154 +21,179 @@ class TreeBuilder {
mailboxDictionary[mailbox.id] = MailboxNode(mailbox); mailboxDictionary[mailbox.id] = MailboxNode(mailbox);
} }
for (var mailbox in mailboxesList) { for (var mailbox in mailboxesList) {
final node = mailboxDictionary[mailbox.id];
if (node == null) continue;
final parentId = mailbox.parentId; final parentId = mailbox.parentId;
final parentNode = mailboxDictionary[parentId]; final parentNode = mailboxDictionary[parentId];
final node = mailboxDictionary[mailbox.id]; if (parentNode != null) {
if (node != null) { parentNode.addChildNode(node);
if (parentNode != null) { sortByMailboxNameNodeChildren(parentNode);
parentNode.addChildNode(node); } else {
parentNode.childrenItems?.sortByCompare<MailboxName?>( tree.root.addChildNode(node);
(node) => node.item.name, sortByMailboxNameNodeChildren(tree.root);
(name, other) => name?.compareAlphabetically(other) ?? -1
);
} else {
tree.root.addChildNode(node);
tree.root.childrenItems?.sortByCompare<MailboxName?>(
(node) => node.item.name,
(name, other) => name?.compareAlphabetically(other) ?? -1
);
}
} }
} }
return tree; return tree;
} }
Future<Tuple4<MailboxTree, MailboxTree, MailboxTree, List<PresentationMailbox>>> generateMailboxTreeInUI( Future<({
List<PresentationMailbox> allMailboxes, List<PresentationMailbox> allMailboxes,
{MailboxId? mailboxIdSelected} MailboxTree defaultTree,
) async { MailboxTree personalTree,
final Map<MailboxId, MailboxNode> mailboxDictionary = HashMap(); MailboxTree teamMailboxTree
})> generateMailboxTreeInUI({
final defaultTree = MailboxTree(MailboxNode.root()); required List<PresentationMailbox> allMailboxes,
final personalTree = MailboxTree(MailboxNode.root()); required MailboxTree currentDefaultTree,
final teamMailboxes = MailboxTree(MailboxNode.root()); required MailboxTree currentPersonalTree,
required MailboxTree currentTeamMailboxTree,
List<PresentationMailbox> listAllMailboxes = <PresentationMailbox>[]; MailboxId? mailboxIdSelected,
}) async {
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<MailboxName?>(
(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<MailboxName?>(
(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<Tuple3<MailboxTree, MailboxTree, MailboxTree>> generateMailboxTreeInUIAfterRefreshChanges(
List<PresentationMailbox> allMailboxes,
MailboxTree defaultTreeBeforeChanges,
MailboxTree personalTreeBeforeChanges,
MailboxTree teamMailboxesTreeBeforeChanges
) async {
final Map<MailboxId, MailboxNode> mailboxDictionary = HashMap(); final Map<MailboxId, MailboxNode> mailboxDictionary = HashMap();
final newDefaultTree = MailboxTree(MailboxNode.root()); final newDefaultTree = MailboxTree(MailboxNode.root());
final newPersonalTree = MailboxTree(MailboxNode.root()); final newPersonalTree = MailboxTree(MailboxNode.root());
final newTeamMailboxes = MailboxTree(MailboxNode.root()); final newTeamMailboxTree = MailboxTree(MailboxNode.root());
final List<PresentationMailbox> newAllMailboxes = <PresentationMailbox>[];
for (var mailbox in allMailboxes) { for (var mailbox in allMailboxes) {
final mailboxNodeBeforeChanges = defaultTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id) final currentMailboxNode = findExistingNode(
?? personalTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id) id: mailbox.id,
?? teamMailboxesTreeBeforeChanges.findNode((node) => node.item.id == mailbox.id); currentDefaultTree: currentDefaultTree,
if (mailboxNodeBeforeChanges != null) { currentPersonalTree: currentPersonalTree,
mailboxDictionary[mailbox.id] = MailboxNode( currentTeamMailboxTree: currentTeamMailboxTree,
mailbox, );
expandMode: mailboxNodeBeforeChanges.expandMode,
selectMode: mailboxNodeBeforeChanges.selectMode); final isDeactivated = mailbox.id == mailboxIdSelected;
} else { final newMailboxNode = MailboxNode(
mailboxDictionary[mailbox.id] = MailboxNode(mailbox); 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) { for (var mailbox in allMailboxes) {
final currentNode = mailboxDictionary[mailbox.id];
if (currentNode == null) continue;
final parentId = mailbox.parentId; final parentId = mailbox.parentId;
final parentNode = mailboxDictionary[parentId]; final parentNode = parentId != null ? mailboxDictionary[parentId] : null;
final node = mailboxDictionary[mailbox.id];
if (node != null) {
if (parentNode != null) {
parentNode.addChildNode(node);
parentNode.childrenItems?.sortByCompare<MailboxName?>(
(node) => node.item.name,
(name, other) => name?.compareAlphabetically(other) ?? -1
);
} else if (parentId == null) {
MailboxTree tree; if (parentNode != null) {
if (mailbox.hasRole()) { if (parentNode.nodeState == MailboxState.deactivated) {
tree = newDefaultTree; currentNode.updateItem(mailbox.withMailboxSate(MailboxState.deactivated));
} else if(mailbox.isPersonal) { currentNode.updateNodeState(MailboxState.deactivated);
tree = newPersonalTree;
} else {
tree = newTeamMailboxes;
}
tree.root.addChildNode(node);
tree.root.childrenItems?.sortByCompare<MailboxName?>(
(node) => node.item.name,
(name, other) => name?.compareAlphabetically(other) ?? -1
);
} }
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<PresentationMailbox> allMailboxes,
required MailboxTree currentDefaultTree,
required MailboxTree currentPersonalTree,
required MailboxTree currentTeamMailboxTree,
}) async {
final Map<MailboxId, MailboxNode> 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)); sortNodeChildren(newDefaultTree.root);
return Tuple3(newDefaultTree, newPersonalTree, newTeamMailboxes);
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<MailboxName?>(
(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);
} }
} }
@@ -248,10 +248,15 @@ void main() {
PresentationMailbox(MailboxId(Id("1")), parentId: null, name: MailboxName('Inbox'), sortOrder: SortOrder(sortValue: 10), role: Role('inbox')), 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( expect(
generatedTree.head.root.childrenItems, generatedTree.defaultTree.root.childrenItems,
equals(expectedTree.root.childrenItems) equals(expectedTree.root.childrenItems)
); );
}); });
@@ -214,12 +214,17 @@ void main() {
]); ]);
}); });
when(mockTreeBuilder.generateMailboxTreeInUI([spamMailbox])).thenAnswer((_) async { when(mockTreeBuilder.generateMailboxTreeInUI(
return Tuple4<MailboxTree, MailboxTree, MailboxTree, List<PresentationMailbox>>( allMailboxes: [spamMailbox],
MailboxTree(MailboxNode(spamMailbox)), currentDefaultTree: MailboxTree(MailboxNode.root()),
MailboxTree(MailboxNode.root()), currentPersonalTree: MailboxTree(MailboxNode.root()),
MailboxTree(MailboxNode.root()), currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
[spamMailbox], )).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.dispatchState(Right(UIClosedState()));
rulesFilterCreatorController.listEmailRuleFilterActionSelected.clear(); 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; debugDefaultTargetPlatformOverride = null;
tester.view.reset(); tester.view.reset();
}); });
@@ -286,12 +295,17 @@ void main() {
]); ]);
}); });
when(mockTreeBuilder.generateMailboxTreeInUI([mailboxA])).thenAnswer((_) async { when(mockTreeBuilder.generateMailboxTreeInUI(
return Tuple4<MailboxTree, MailboxTree, MailboxTree, List<PresentationMailbox>>( allMailboxes: [mailboxA],
MailboxTree(MailboxNode(mailboxA)), currentDefaultTree: MailboxTree(MailboxNode.root()),
MailboxTree(MailboxNode.root()), currentPersonalTree: MailboxTree(MailboxNode.root()),
MailboxTree(MailboxNode.root()), currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
[mailboxA], )).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.dispatchState(Right(UIClosedState()));
rulesFilterCreatorController.listEmailRuleFilterActionSelected.clear(); 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; debugDefaultTargetPlatformOverride = null;
tester.view.reset(); tester.view.reset();
}); });