TF-4284 Fix refreshing causes "virtual mailboxes" to be hidden (#4290)

This commit is contained in:
Dat Vu
2026-04-10 15:29:04 +07:00
committed by GitHub
parent c9e2e5db80
commit cb5d43630a
11 changed files with 493 additions and 225 deletions
+58 -29
View File
@@ -37,6 +37,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentat
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
@@ -62,6 +63,7 @@ typedef OnMoveFolderContentActionCallback = void Function(
); );
typedef DeleteMailboxActionCallback = void Function(PresentationMailbox mailbox); typedef DeleteMailboxActionCallback = void Function(PresentationMailbox mailbox);
typedef AllowSubaddressingActionCallback = void Function(MailboxId, Map<String, List<String>?>?, MailboxActions); typedef AllowSubaddressingActionCallback = void Function(MailboxId, Map<String, List<String>?>?, MailboxActions);
typedef OnUpdateMailboxCollectionCallback = MailboxCollection Function(MailboxCollection);
abstract class BaseMailboxController extends BaseController abstract class BaseMailboxController extends BaseController
with ExpandFolderTriggerScrollableMixin { with ExpandFolderTriggerScrollableMixin {
@@ -87,40 +89,62 @@ abstract class BaseMailboxController extends BaseController
List<PresentationMailbox> allMailboxes = <PresentationMailbox>[]; List<PresentationMailbox> allMailboxes = <PresentationMailbox>[];
MailboxCollection get currentMailboxCollection => MailboxCollection(
allMailboxes: allMailboxes,
defaultTree: defaultMailboxTree.value,
personalTree: personalMailboxTree.value,
teamMailboxTree: teamMailboxesTree.value,
);
Future<void> buildTree( Future<void> buildTree(
List<PresentationMailbox> allMailbox, List<PresentationMailbox> allMailbox, {
{MailboxId? mailboxIdSelected} MailboxId? mailboxIdSelected,
) async { OnUpdateMailboxCollectionCallback? onUpdateMailboxCollectionCallback,
final recordTree = await _treeBuilder.generateMailboxTreeInUI( }) async {
MailboxCollection mailboxCollection =
await _treeBuilder.generateMailboxTreeInUI(
allMailboxes: allMailbox, allMailboxes: allMailbox,
currentDefaultTree: defaultMailboxTree.value, currentCollection: currentMailboxCollection,
currentPersonalTree: personalMailboxTree.value,
currentTeamMailboxTree: teamMailboxesTree.value,
mailboxIdSelected: mailboxIdSelected, mailboxIdSelected: mailboxIdSelected,
); );
defaultMailboxTree.firstRebuild = true;
personalMailboxTree.firstRebuild = true; if (onUpdateMailboxCollectionCallback != null) {
teamMailboxesTree.firstRebuild = true; mailboxCollection = onUpdateMailboxCollectionCallback(mailboxCollection);
defaultMailboxTree.value = recordTree.defaultTree; }
personalMailboxTree.value = recordTree.personalTree;
teamMailboxesTree.value = recordTree.teamMailboxTree; updateMailboxTree(mailboxCollection: mailboxCollection);
allMailboxes = recordTree.allMailboxes;
} }
Future<void> refreshTree(List<PresentationMailbox> allMailbox) async { Future<void> refreshTree(
final recordTree = await _treeBuilder.generateMailboxTreeInUIAfterRefreshChanges( List<PresentationMailbox> allMailbox, {
OnUpdateMailboxCollectionCallback? onUpdateMailboxCollectionCallback,
}) async {
MailboxCollection mailboxCollection =
await _treeBuilder.generateMailboxTreeInUIAfterRefreshChanges(
allMailboxes: allMailbox, allMailboxes: allMailbox,
currentDefaultTree: defaultMailboxTree.value, currentCollection: currentMailboxCollection,
currentPersonalTree: personalMailboxTree.value,
currentTeamMailboxTree: teamMailboxesTree.value,
); );
defaultMailboxTree.firstRebuild = true;
personalMailboxTree.firstRebuild = true; if (onUpdateMailboxCollectionCallback != null) {
teamMailboxesTree.firstRebuild = true; mailboxCollection = onUpdateMailboxCollectionCallback(mailboxCollection);
defaultMailboxTree.value = recordTree.defaultTree; }
personalMailboxTree.value = recordTree.personalTree;
teamMailboxesTree.value = recordTree.teamMailboxTree; updateMailboxTree(mailboxCollection: mailboxCollection);
allMailboxes = allMailbox; }
void updateMailboxTree({
required MailboxCollection mailboxCollection,
bool isRefreshTrigger = true,
}) {
if (isRefreshTrigger) {
defaultMailboxTree.firstRebuild = true;
personalMailboxTree.firstRebuild = true;
teamMailboxesTree.firstRebuild = true;
}
defaultMailboxTree.value = mailboxCollection.defaultTree;
personalMailboxTree.value = mailboxCollection.personalTree;
teamMailboxesTree.value = mailboxCollection.teamMailboxTree;
allMailboxes = mailboxCollection.allMailboxes;
} }
void syncAllMailboxWithDisplayName(BuildContext context) { void syncAllMailboxWithDisplayName(BuildContext context) {
@@ -675,10 +699,15 @@ abstract class BaseMailboxController extends BaseController
} }
} }
void autoCreateVirtualFolder(bool isAINeedsActionEnabled) { bool get isAINeedsActionEnabled => false;
addFavoriteFolderToMailboxList();
MailboxCollection updateMailboxCollection(MailboxCollection mailboxCollection) {
MailboxCollection updated = addFavoriteFolderToMailboxList(
mailboxCollection: mailboxCollection,
);
if (isAINeedsActionEnabled) { if (isAINeedsActionEnabled) {
addActionRequiredFolder(); updated = addActionRequiredFolder(mailboxCollection: updated);
} }
return updated;
} }
} }
@@ -3,15 +3,26 @@ import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension HandleActionRequiredTabExtension on BaseMailboxController { extension HandleActionRequiredTabExtension on BaseMailboxController {
void addActionRequiredFolder() { MailboxCollection addActionRequiredFolder({
required MailboxCollection mailboxCollection,
}) {
final folder = _buildActionRequiredFolder(); final folder = _buildActionRequiredFolder();
_addToDefaultMailboxTree(folder); return mailboxCollection.copyWith(
_addToAllMailboxes(folder); defaultTree: _addToDefaultMailboxTree(
folder: folder,
currentDefaultTree: mailboxCollection.defaultTree,
),
allMailboxes: _addToAllMailboxes(
folder: folder,
currentAllMailboxes: mailboxCollection.allMailboxes,
),
);
} }
PresentationMailbox _buildActionRequiredFolder() { PresentationMailbox _buildActionRequiredFolder() {
@@ -23,43 +34,72 @@ extension HandleActionRequiredTabExtension on BaseMailboxController {
); );
} }
void _addToDefaultMailboxTree(PresentationMailbox folder) { MailboxTree _addToDefaultMailboxTree({
final root = defaultMailboxTree.value.root; required PresentationMailbox folder,
required MailboxTree currentDefaultTree,
}) {
final root = currentDefaultTree.root;
final children = List<MailboxNode>.from(root.childrenItems ?? []); final children = List<MailboxNode>.from(root.childrenItems ?? []);
if (children.any((node) => node.item.id == folder.id)) {
return currentDefaultTree;
}
children.insertAfterStarredOrInbox(MailboxNode(folder)); children.insertAfterStarredOrInbox(MailboxNode(folder));
defaultMailboxTree.value = MailboxTree( return MailboxTree(root.copyWith(children: children));
root.copyWith(children: children), }
List<PresentationMailbox> _addToAllMailboxes({
required PresentationMailbox folder,
required List<PresentationMailbox> currentAllMailboxes,
}) {
if (_allMailboxesContains(
id: folder.id,
currentAllMailboxes: currentAllMailboxes,
)) {
return currentAllMailboxes;
}
return [...currentAllMailboxes, folder];
}
bool _allMailboxesContains({
required MailboxId id,
required List<PresentationMailbox> currentAllMailboxes,
}) {
return currentAllMailboxes.any((mailbox) => mailbox.id == id);
}
MailboxCollection removeActionRequiredFolder({
required MailboxCollection mailboxCollection,
}) {
return mailboxCollection.copyWith(
defaultTree: _removeFromDefaultMailboxTree(
folderId: PresentationMailbox.actionRequiredFolder.id,
currentDefaultTree: mailboxCollection.defaultTree,
),
allMailboxes: _removeFromAllMailboxes(
folderId: PresentationMailbox.actionRequiredFolder.id,
currentAllMailboxes: mailboxCollection.allMailboxes,
),
); );
} }
void _addToAllMailboxes(PresentationMailbox folder) { MailboxTree _removeFromDefaultMailboxTree({
if (_allMailboxesContains(folder.id)) return; required MailboxId folderId,
allMailboxes.add(folder); required MailboxTree currentDefaultTree,
} }) {
final root = currentDefaultTree.root;
bool _allMailboxesContains(MailboxId id) {
return allMailboxes.any((mailbox) => mailbox.id == id);
}
void removeActionRequiredFolder() {
final folder = PresentationMailbox.actionRequiredFolder;
_removeFromDefaultMailboxTree(folder.id);
_removeFromAllMailboxes(folder.id);
}
void _removeFromDefaultMailboxTree(MailboxId folderId) {
final root = defaultMailboxTree.value.root;
final children = List<MailboxNode>.from(root.childrenItems ?? []) final children = List<MailboxNode>.from(root.childrenItems ?? [])
..removeWhere((node) => node.item.id == folderId); ..removeWhere((node) => node.item.id == folderId);
return MailboxTree(root.copyWith(children: children));
defaultMailboxTree.value = MailboxTree(
root.copyWith(children: children),
);
} }
void _removeFromAllMailboxes(MailboxId folderId) { List<PresentationMailbox> _removeFromAllMailboxes({
allMailboxes.removeWhere((mailbox) => mailbox.id == folderId); required MailboxId folderId,
required List<PresentationMailbox> currentAllMailboxes,
}) {
return currentAllMailboxes
.where((mailbox) => mailbox.id != folderId)
.toList();
} }
} }
@@ -2,12 +2,15 @@ import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension HandleFavoriteTabExtension on BaseMailboxController { extension HandleFavoriteTabExtension on BaseMailboxController {
void addFavoriteFolderToMailboxList() { MailboxCollection addFavoriteFolderToMailboxList({
required MailboxCollection mailboxCollection,
}) {
PresentationMailbox favoriteFolder = PresentationMailbox.favoriteFolder; PresentationMailbox favoriteFolder = PresentationMailbox.favoriteFolder;
if (currentContext != null) { if (currentContext != null) {
favoriteFolder = favoriteFolder.copyWith( favoriteFolder = favoriteFolder.copyWith(
@@ -15,16 +18,28 @@ extension HandleFavoriteTabExtension on BaseMailboxController {
); );
} }
_addFavoriteFolderToDefaultMailboxTree(favoriteFolder); final newDefaultTree = _addFavoriteFolderToDefaultMailboxTree(
_addFavoriteFolderToAllMailboxes(favoriteFolder); favoriteFolder: favoriteFolder,
defaultTree: mailboxCollection.defaultTree,
);
final newAllMailboxes = _addFavoriteFolderToAllMailboxes(
favoriteFolder: favoriteFolder,
allMailboxes: mailboxCollection.allMailboxes,
);
return mailboxCollection.copyWith(
defaultTree: newDefaultTree,
allMailboxes: newAllMailboxes,
);
} }
void _addFavoriteFolderToDefaultMailboxTree( MailboxTree _addFavoriteFolderToDefaultMailboxTree({
PresentationMailbox favoriteFolder, required PresentationMailbox favoriteFolder,
) { required MailboxTree defaultTree,
final defaultMailboxNode = defaultMailboxTree.value.root; }) {
List<MailboxNode> currentDefaultFolders = final defaultMailboxNode = defaultTree.root;
defaultMailboxNode.childrenItems ?? []; final currentDefaultFolders =
List<MailboxNode>.from(defaultMailboxNode.childrenItems ?? []);
if (currentDefaultFolders.isEmpty) { if (currentDefaultFolders.isEmpty) {
currentDefaultFolders.add(MailboxNode(favoriteFolder)); currentDefaultFolders.add(MailboxNode(favoriteFolder));
@@ -32,17 +47,20 @@ extension HandleFavoriteTabExtension on BaseMailboxController {
currentDefaultFolders.insertAfterInbox(MailboxNode(favoriteFolder)); currentDefaultFolders.insertAfterInbox(MailboxNode(favoriteFolder));
} }
defaultMailboxTree.value = MailboxTree( return MailboxTree(
defaultMailboxNode.copyWith(children: currentDefaultFolders), defaultMailboxNode.copyWith(children: currentDefaultFolders),
); );
} }
void _addFavoriteFolderToAllMailboxes(PresentationMailbox favoriteFolder) { List<PresentationMailbox> _addFavoriteFolderToAllMailboxes({
required PresentationMailbox favoriteFolder,
required List<PresentationMailbox> allMailboxes,
}) {
final alreadyExists = allMailboxes.any( final alreadyExists = allMailboxes.any(
(mailbox) => mailbox.id == favoriteFolder.id, (mailbox) => mailbox.id == favoriteFolder.id,
); );
if (alreadyExists) return; if (alreadyExists) return allMailboxes;
allMailboxes.add(favoriteFolder); return [...allMailboxes, favoriteFolder];
} }
} }
@@ -257,8 +257,9 @@ class MailboxController extends BaseMailboxController
toastManager: toastManager, toastManager: toastManager,
); );
} else if (failure is CreateDefaultMailboxFailure) { } else if (failure is CreateDefaultMailboxFailure) {
autoCreateVirtualFolder( updateMailboxTree(
mailboxDashBoardController.isAINeedsActionEnabled, mailboxCollection: updateMailboxCollection(currentMailboxCollection),
isRefreshTrigger: false,
); );
} else { } else {
super.handleFailureViewState(failure); super.handleFailureViewState(failure);
@@ -271,8 +272,9 @@ class MailboxController extends BaseMailboxController
viewState.value.fold( viewState.value.fold(
(failure) { (failure) {
if (failure is GetAllMailboxFailure) { if (failure is GetAllMailboxFailure) {
autoCreateVirtualFolder( updateMailboxTree(
mailboxDashBoardController.isAINeedsActionEnabled, mailboxCollection: updateMailboxCollection(currentMailboxCollection),
isRefreshTrigger: false,
); );
mailboxDashBoardController.updateRefreshAllMailboxState(Left(RefreshAllMailboxFailure())); mailboxDashBoardController.updateRefreshAllMailboxState(Left(RefreshAllMailboxFailure()));
showRetryToast(failure); showRetryToast(failure);
@@ -303,38 +305,7 @@ class MailboxController extends BaseMailboxController
_handleNavigationRouteParameters _handleNavigationRouteParameters
); );
ever(mailboxDashBoardController.mailboxUIAction, (action) { ever(mailboxDashBoardController.mailboxUIAction, _handleMailboxUIAction);
if (action is SelectMailboxDefaultAction) {
_switchBackToMailboxDefault();
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is RefreshChangeMailboxAction) {
_refreshMailboxChanges(newState: action.newState);
} else if (action is OpenMailboxAction) {
if (currentContext != null) {
_handleOpenMailbox(currentContext!, action.presentationMailbox);
if (action.presentationMailbox.role == PresentationMailbox.roleInbox) {
_autoScrollToTopMailboxList();
}
}
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is SystemBackToInboxAction) {
_disableAllSearchEmail();
_switchBackToMailboxDefault();
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is RefreshAllMailboxAction) {
refreshAllMailbox();
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is AutoCreateActionRequiredFolderMailboxAction) {
addActionRequiredFolder();
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is AutoRemoveActionRequiredFolderMailboxAction) {
removeActionRequiredFolder();
mailboxDashBoardController.clearMailboxUIAction();
if (selectedMailbox?.isActionRequired == true) {
_switchBackToMailboxDefault();
}
}
});
ever(mailboxDashBoardController.viewState, (viewState) { ever(mailboxDashBoardController.viewState, (viewState) {
final reactionState = viewState.getOrElse(() => UIState.idle); final reactionState = viewState.getOrElse(() => UIState.idle);
@@ -452,6 +423,57 @@ class MailboxController extends BaseMailboxController
}); });
} }
void _handleMailboxUIAction(MailboxUIAction? action) {
if (action is SelectMailboxDefaultAction) {
_switchBackToMailboxDefault();
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is RefreshChangeMailboxAction) {
_refreshMailboxChanges(newState: action.newState);
} else if (action is OpenMailboxAction) {
_onOpenMailboxAction(action);
} else if (action is SystemBackToInboxAction) {
_disableAllSearchEmail();
_switchBackToMailboxDefault();
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is RefreshAllMailboxAction) {
refreshAllMailbox();
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is AutoCreateActionRequiredFolderMailboxAction) {
updateMailboxTree(
mailboxCollection: addActionRequiredFolder(
mailboxCollection: currentMailboxCollection,
),
isRefreshTrigger: false,
);
mailboxDashBoardController.clearMailboxUIAction();
} else if (action is AutoRemoveActionRequiredFolderMailboxAction) {
_onAutoRemoveActionRequiredFolderMailboxAction();
}
}
void _onOpenMailboxAction(OpenMailboxAction action) {
if (currentContext != null) {
_handleOpenMailbox(currentContext!, action.presentationMailbox);
if (action.presentationMailbox.role == PresentationMailbox.roleInbox) {
_autoScrollToTopMailboxList();
}
}
mailboxDashBoardController.clearMailboxUIAction();
}
void _onAutoRemoveActionRequiredFolderMailboxAction() {
updateMailboxTree(
mailboxCollection: removeActionRequiredFolder(
mailboxCollection: currentMailboxCollection,
),
isRefreshTrigger: false,
);
mailboxDashBoardController.clearMailboxUIAction();
if (selectedMailbox?.isActionRequired == true) {
_switchBackToMailboxDefault();
}
}
void _handleMarkEmailsAsReadOrUnread({ void _handleMarkEmailsAsReadOrUnread({
required MailboxId? affectedMailboxId, required MailboxId? affectedMailboxId,
int? readCount, int? readCount,
@@ -614,14 +636,14 @@ class MailboxController extends BaseMailboxController
.mailboxList .mailboxList
.listSubscribedMailboxesAndDefaultMailboxes; .listSubscribedMailboxesAndDefaultMailboxes;
await refreshTree(listMailboxDisplayed.withoutVirtualMailbox); await refreshTree(
listMailboxDisplayed.withoutVirtualMailbox,
onUpdateMailboxCollectionCallback: updateMailboxCollection,
);
if (currentContext != null) { if (currentContext != null) {
syncAllMailboxWithDisplayName(currentContext!); syncAllMailboxWithDisplayName(currentContext!);
} }
autoCreateVirtualFolder(
mailboxDashBoardController.isAINeedsActionEnabled,
);
_setMapMailbox(); _setMapMailbox();
_setOutboxMailbox(); _setOutboxMailbox();
_selectSelectedMailboxDefault(); _selectSelectedMailboxDefault();
@@ -632,6 +654,10 @@ class MailboxController extends BaseMailboxController
} }
} }
@override
bool get isAINeedsActionEnabled =>
mailboxDashBoardController.isAINeedsActionEnabled;
void _setMapMailbox() { void _setMapMailbox() {
final mapDefaultMailboxIdByRole = { final mapDefaultMailboxIdByRole = {
for (var mailboxNode in defaultMailboxTree.value.root.childrenItems ?? List<MailboxNode>.empty()) for (var mailboxNode in defaultMailboxTree.value.root.childrenItems ?? List<MailboxNode>.empty())
@@ -706,8 +732,9 @@ class MailboxController extends BaseMailboxController
.toList(); .toList();
if (listRoleMissing.isEmpty || accountId == null || session == null) { if (listRoleMissing.isEmpty || accountId == null || session == null) {
autoCreateVirtualFolder( updateMailboxTree(
mailboxDashBoardController.isAINeedsActionEnabled, mailboxCollection: updateMailboxCollection(currentMailboxCollection),
isRefreshTrigger: false,
); );
return; return;
} }
@@ -726,8 +753,9 @@ class MailboxController extends BaseMailboxController
Future<void> _handleCreateDefaultFolderIfMissingSuccess(CreateDefaultMailboxAllSuccess success) async { Future<void> _handleCreateDefaultFolderIfMissingSuccess(CreateDefaultMailboxAllSuccess success) async {
if (success.listMailbox.isEmpty) { if (success.listMailbox.isEmpty) {
autoCreateVirtualFolder( updateMailboxTree(
mailboxDashBoardController.isAINeedsActionEnabled, mailboxCollection: updateMailboxCollection(currentMailboxCollection),
isRefreshTrigger: false,
); );
return; return;
} }
@@ -743,13 +771,13 @@ class MailboxController extends BaseMailboxController
allMailboxes.add(mailbox.toPresentationMailbox()); allMailboxes.add(mailbox.toPresentationMailbox());
} }
await buildTree(allMailboxes.withoutVirtualMailbox); await buildTree(
allMailboxes.withoutVirtualMailbox,
onUpdateMailboxCollectionCallback: updateMailboxCollection,
);
if (currentContext != null) { if (currentContext != null) {
syncAllMailboxWithDisplayName(currentContext!); syncAllMailboxWithDisplayName(currentContext!);
} }
autoCreateVirtualFolder(
mailboxDashBoardController.isAINeedsActionEnabled,
);
_setMapMailbox(); _setMapMailbox();
_setOutboxMailbox(); _setOutboxMailbox();
} }
@@ -1339,7 +1367,10 @@ class MailboxController extends BaseMailboxController
currentMailboxState = success.currentMailboxState; currentMailboxState = success.currentMailboxState;
log('MailboxController::_handleGetAllMailboxSuccess:currentMailboxState: $currentMailboxState'); log('MailboxController::_handleGetAllMailboxSuccess:currentMailboxState: $currentMailboxState');
final listMailboxDisplayed = success.mailboxList.listSubscribedMailboxesAndDefaultMailboxes; final listMailboxDisplayed = success.mailboxList.listSubscribedMailboxesAndDefaultMailboxes;
await buildTree(listMailboxDisplayed.withoutVirtualMailbox); await buildTree(
listMailboxDisplayed.withoutVirtualMailbox,
onUpdateMailboxCollectionCallback: updateMailboxCollection,
);
if (currentContext != null) { if (currentContext != null) {
syncAllMailboxWithDisplayName(currentContext!); syncAllMailboxWithDisplayName(currentContext!);
} }
@@ -0,0 +1,47 @@
import 'package:equatable/equatable.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
class MailboxCollection with EquatableMixin {
final List<PresentationMailbox> allMailboxes;
final MailboxTree defaultTree;
final MailboxTree personalTree;
final MailboxTree teamMailboxTree;
const MailboxCollection({
required this.allMailboxes,
required this.defaultTree,
required this.personalTree,
required this.teamMailboxTree,
});
factory MailboxCollection.empty() => MailboxCollection(
allMailboxes: const [],
defaultTree: MailboxTree(MailboxNode.root()),
personalTree: MailboxTree(MailboxNode.root()),
teamMailboxTree: MailboxTree(MailboxNode.root()),
);
MailboxCollection copyWith({
List<PresentationMailbox>? allMailboxes,
MailboxTree? defaultTree,
MailboxTree? personalTree,
MailboxTree? teamMailboxTree,
}) {
return MailboxCollection(
allMailboxes: allMailboxes ?? this.allMailboxes,
defaultTree: defaultTree ?? this.defaultTree,
personalTree: personalTree ?? this.personalTree,
teamMailboxTree: teamMailboxTree ?? this.teamMailboxTree,
);
}
@override
List<Object?> get props => [
allMailboxes,
defaultTree,
personalTree,
teamMailboxTree,
];
}
@@ -8,6 +8,7 @@ import 'package:model/mailbox/expand_mode.dart';
import 'package:model/mailbox/mailbox_state.dart'; import 'package:model/mailbox/mailbox_state.dart';
import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:model/mailbox/select_mode.dart'; import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'mailbox_node.dart'; import 'mailbox_node.dart';
import 'mailbox_tree.dart'; import 'mailbox_tree.dart';
@@ -37,16 +38,9 @@ class TreeBuilder {
return tree; return tree;
} }
Future<({ Future<MailboxCollection> generateMailboxTreeInUI({
List<PresentationMailbox> allMailboxes,
MailboxTree defaultTree,
MailboxTree personalTree,
MailboxTree teamMailboxTree
})> generateMailboxTreeInUI({
required List<PresentationMailbox> allMailboxes, required List<PresentationMailbox> allMailboxes,
required MailboxTree currentDefaultTree, required MailboxCollection currentCollection,
required MailboxTree currentPersonalTree,
required MailboxTree currentTeamMailboxTree,
MailboxId? mailboxIdSelected, MailboxId? mailboxIdSelected,
MailboxId? mailboxIdExpanded, MailboxId? mailboxIdExpanded,
}) async { }) async {
@@ -61,9 +55,7 @@ class TreeBuilder {
for (var mailbox in allMailboxes) { for (var mailbox in allMailboxes) {
final currentMailboxNode = findExistingNode( final currentMailboxNode = findExistingNode(
id: mailbox.id, id: mailbox.id,
currentDefaultTree: currentDefaultTree, currentCollection: currentCollection,
currentPersonalTree: currentPersonalTree,
currentTeamMailboxTree: currentTeamMailboxTree,
); );
final isDeactivated = mailbox.id == mailboxIdSelected; final isDeactivated = mailbox.id == mailboxIdSelected;
@@ -85,19 +77,12 @@ class TreeBuilder {
final parentNode = parentId != null ? mailboxDictionary[parentId] : null; final parentNode = parentId != null ? mailboxDictionary[parentId] : null;
if (parentNode != null) { if (parentNode != null) {
if (parentNode.nodeState == MailboxState.deactivated) { _propagateDeactivationIfNeeded(parentNode, currentNode, mailbox);
currentNode.updateItem(mailbox.withMailboxSate(MailboxState.deactivated));
currentNode.updateNodeState(MailboxState.deactivated);
}
parentNode.addChildNode(currentNode); parentNode.addChildNode(currentNode);
sortByMailboxNameNodeChildren(parentNode); sortByMailboxNameNodeChildren(parentNode);
} else { } else {
final targetTree = mailbox.hasRole() final targetTree = _resolveTargetTree(mailbox, newDefaultTree, newPersonalTree, newTeamMailboxTree);
? newDefaultTree
: (mailbox.isPersonal ? newPersonalTree : newTeamMailboxTree);
targetTree.root.addChildNode(currentNode); targetTree.root.addChildNode(currentNode);
sortByMailboxNameNodeChildren(targetTree.root); sortByMailboxNameNodeChildren(targetTree.root);
} }
@@ -106,7 +91,7 @@ class TreeBuilder {
sortNodeChildren(newDefaultTree.root); sortNodeChildren(newDefaultTree.root);
return ( return MailboxCollection(
allMailboxes: newAllMailboxes, allMailboxes: newAllMailboxes,
defaultTree: newDefaultTree, defaultTree: newDefaultTree,
personalTree: newPersonalTree, personalTree: newPersonalTree,
@@ -114,15 +99,9 @@ class TreeBuilder {
); );
} }
Future<({ Future<MailboxCollection> generateMailboxTreeInUIAfterRefreshChanges({
MailboxTree defaultTree,
MailboxTree personalTree,
MailboxTree teamMailboxTree
})> generateMailboxTreeInUIAfterRefreshChanges({
required List<PresentationMailbox> allMailboxes, required List<PresentationMailbox> allMailboxes,
required MailboxTree currentDefaultTree, required MailboxCollection currentCollection,
required MailboxTree currentPersonalTree,
required MailboxTree currentTeamMailboxTree,
}) async { }) async {
final Map<MailboxId, MailboxNode> mailboxDictionary = HashMap(); final Map<MailboxId, MailboxNode> mailboxDictionary = HashMap();
@@ -133,9 +112,7 @@ class TreeBuilder {
for (var mailbox in allMailboxes) { for (var mailbox in allMailboxes) {
final currentMailboxNode = findExistingNode( final currentMailboxNode = findExistingNode(
id: mailbox.id, id: mailbox.id,
currentDefaultTree: currentDefaultTree, currentCollection: currentCollection,
currentPersonalTree: currentPersonalTree,
currentTeamMailboxTree: currentTeamMailboxTree,
); );
final newMailboxNode = MailboxNode( final newMailboxNode = MailboxNode(
@@ -158,18 +135,16 @@ class TreeBuilder {
parentNode.addChildNode(currentNode); parentNode.addChildNode(currentNode);
sortByMailboxNameNodeChildren(parentNode); sortByMailboxNameNodeChildren(parentNode);
} else { } else {
final targetTree = mailbox.hasRole() final targetTree = _resolveTargetTree(mailbox, newDefaultTree, newPersonalTree, newTeamMailboxTree);
? newDefaultTree
: (mailbox.isPersonal ? newPersonalTree : newTeamMailboxTree);
targetTree.root.addChildNode(currentNode); targetTree.root.addChildNode(currentNode);
sortByMailboxNameNodeChildren(targetTree.root); sortByMailboxNameNodeChildren(targetTree.root);
} }
} }
sortNodeChildren(newDefaultTree.root); sortNodeChildren(newDefaultTree.root);
return ( return MailboxCollection(
allMailboxes: allMailboxes,
defaultTree: newDefaultTree, defaultTree: newDefaultTree,
personalTree: newPersonalTree, personalTree: newPersonalTree,
teamMailboxTree: newTeamMailboxTree, teamMailboxTree: newTeamMailboxTree,
@@ -189,12 +164,30 @@ class TreeBuilder {
MailboxNode? findExistingNode({ MailboxNode? findExistingNode({
required MailboxId id, required MailboxId id,
required MailboxTree currentDefaultTree, required MailboxCollection currentCollection,
required MailboxTree currentPersonalTree,
required MailboxTree currentTeamMailboxTree,
}) { }) {
return currentDefaultTree.findNode((node) => node.item.id == id) ?? return currentCollection.defaultTree.findNode((node) => node.item.id == id) ??
currentPersonalTree.findNode((node) => node.item.id == id) ?? currentCollection.personalTree.findNode((node) => node.item.id == id) ??
currentTeamMailboxTree.findNode((node) => node.item.id == id); currentCollection.teamMailboxTree.findNode((node) => node.item.id == id);
}
MailboxTree _resolveTargetTree(
PresentationMailbox mailbox,
MailboxTree defaultTree,
MailboxTree personalTree,
MailboxTree teamMailboxTree,
) {
if (mailbox.hasRole()) return defaultTree;
return mailbox.isPersonal ? personalTree : teamMailboxTree;
}
void _propagateDeactivationIfNeeded(
MailboxNode parentNode,
MailboxNode currentNode,
PresentationMailbox mailbox,
) {
if (parentNode.nodeState != MailboxState.deactivated) return;
currentNode.updateItem(mailbox.withMailboxSate(MailboxState.deactivated));
currentNode.updateNodeState(MailboxState.deactivated);
} }
} }
@@ -6,6 +6,7 @@ import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/base/mixin/expand_folder_trigger_scrollable_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/expand_folder_trigger_scrollable_mixin.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/expand_mode_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/expand_mode_extension.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
@@ -77,9 +78,12 @@ class MailboxCreatorController extends BaseController
Future<void> _buildMailboxTree(MailboxCreatorArguments arguments) async { Future<void> _buildMailboxTree(MailboxCreatorArguments arguments) async {
final recordTree = await _treeBuilder.generateMailboxTreeInUI( final recordTree = await _treeBuilder.generateMailboxTreeInUI(
allMailboxes: arguments.listMailboxes, allMailboxes: arguments.listMailboxes,
currentDefaultTree: defaultMailboxTree.value, currentCollection: MailboxCollection(
currentPersonalTree: personalMailboxTree.value, allMailboxes: const [],
currentTeamMailboxTree: MailboxTree(MailboxNode.root()), defaultTree: defaultMailboxTree.value,
personalTree: personalMailboxTree.value,
teamMailboxTree: MailboxTree(MailboxNode.root()),
),
); );
personalMailboxTree.value = recordTree.personalTree; personalMailboxTree.value = recordTree.personalTree;
defaultMailboxTree.value = recordTree.defaultTree; defaultMailboxTree.value = recordTree.defaultTree;
@@ -165,13 +165,19 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
void handleSuccessViewState(Success success) async { void handleSuccessViewState(Success success) async {
if (success is GetAllMailboxSuccess) { if (success is GetAllMailboxSuccess) {
currentMailboxState = success.currentMailboxState; currentMailboxState = success.currentMailboxState;
await buildTree(success.mailboxList); await buildTree(
success.mailboxList,
onUpdateMailboxCollectionCallback: updateMailboxCollection,
);
if (currentContext != null) { if (currentContext != null) {
syncAllMailboxWithDisplayName(currentContext!); syncAllMailboxWithDisplayName(currentContext!);
} }
} else if (success is RefreshChangesAllMailboxSuccess) { } else if (success is RefreshChangesAllMailboxSuccess) {
currentMailboxState = success.currentMailboxState; currentMailboxState = success.currentMailboxState;
await refreshTree(success.mailboxList); await refreshTree(
success.mailboxList,
onUpdateMailboxCollectionCallback: updateMailboxCollection,
);
if (currentContext != null) { if (currentContext != null) {
syncAllMailboxWithDisplayName(currentContext!); syncAllMailboxWithDisplayName(currentContext!);
} }
@@ -213,19 +219,17 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
super.onDone(); super.onDone();
viewState.value.fold((failure) { viewState.value.fold((failure) {
if (failure is GetAllMailboxFailure) { if (failure is GetAllMailboxFailure) {
autoCreateVirtualFolder( updateMailboxTree(
dashboardController.isAINeedsActionEnabled, mailboxCollection: updateMailboxCollection(currentMailboxCollection),
isRefreshTrigger: false,
); );
} }
}, (success) { }, (success) {});
if (success is GetAllMailboxSuccess) {
autoCreateVirtualFolder(
dashboardController.isAINeedsActionEnabled,
);
}
});
} }
@override
bool get isAINeedsActionEnabled => dashboardController.isAINeedsActionEnabled;
void _initializeDebounceTimeTextSearchChange() { void _initializeDebounceTimeTextSearchChange() {
_deBouncerTime = Debouncer<String>( _deBouncerTime = Debouncer<String>(
const Duration(milliseconds: 300), const Duration(milliseconds: 300),
@@ -8,6 +8,7 @@ import 'package:model/mailbox/expand_mode.dart';
import 'package:model/mailbox/mailbox_state.dart'; import 'package:model/mailbox/mailbox_state.dart';
import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:model/mailbox/select_mode.dart'; import 'package:model/mailbox/select_mode.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
@@ -256,9 +257,7 @@ void main() {
final generatedTree = await TreeBuilder().generateMailboxTreeInUI( final generatedTree = await TreeBuilder().generateMailboxTreeInUI(
allMailboxes: testCase, allMailboxes: testCase,
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
); );
expect( expect(
@@ -323,9 +322,7 @@ void main() {
() async { () async {
final generatedTrees = await TreeBuilder().generateMailboxTreeInUI( final generatedTrees = await TreeBuilder().generateMailboxTreeInUI(
allMailboxes: filteredMailboxes, allMailboxes: filteredMailboxes,
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
); );
expectNoVirtualFoldersRecursively( expectNoVirtualFoldersRecursively(
@@ -350,9 +347,7 @@ void main() {
final generatedTrees = final generatedTrees =
await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges( await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges(
allMailboxes: filteredMailboxes, allMailboxes: filteredMailboxes,
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
); );
expectNoVirtualFoldersRecursively( expectNoVirtualFoldersRecursively(
@@ -392,9 +387,7 @@ void main() {
final generatedTree = await TreeBuilder().generateMailboxTreeInUI( final generatedTree = await TreeBuilder().generateMailboxTreeInUI(
allMailboxes: filtered, allMailboxes: filtered,
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
); );
final children = generatedTree.defaultTree.root.childrenItems ?? []; final children = generatedTree.defaultTree.root.childrenItems ?? [];
@@ -437,9 +430,7 @@ void main() {
final generatedTree = await TreeBuilder().generateMailboxTreeInUI( final generatedTree = await TreeBuilder().generateMailboxTreeInUI(
allMailboxes: testCaseWithVirtualFolders, allMailboxes: testCaseWithVirtualFolders,
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
); );
final children = generatedTree.defaultTree.root.childrenItems ?? []; final children = generatedTree.defaultTree.root.childrenItems ?? [];
@@ -484,9 +475,7 @@ void main() {
final result = final result =
await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges( await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges(
allMailboxes: mailboxes, allMailboxes: mailboxes,
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
); );
expect(result.defaultTree.root.childrenItems?.length, equals(1)); expect(result.defaultTree.root.childrenItems?.length, equals(1));
@@ -542,9 +531,12 @@ void main() {
final result = final result =
await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges( await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges(
allMailboxes: [mailbox], allMailboxes: [mailbox],
currentDefaultTree: currentDefaultTree, currentCollection: MailboxCollection(
currentPersonalTree: MailboxTree(MailboxNode.root()), allMailboxes: const [],
currentTeamMailboxTree: MailboxTree(MailboxNode.root()), defaultTree: currentDefaultTree,
personalTree: MailboxTree(MailboxNode.root()),
teamMailboxTree: MailboxTree(MailboxNode.root()),
),
); );
final newNode = result.defaultTree.root.childrenItems?.first; final newNode = result.defaultTree.root.childrenItems?.first;
@@ -561,6 +553,128 @@ void main() {
}); });
}); });
group('MailboxCollection allMailboxes field', () {
final inbox = PresentationMailbox(
MailboxId(Id('inbox')),
name: MailboxName('Inbox'),
role: Role('inbox'),
);
final sent = PresentationMailbox(
MailboxId(Id('sent')),
name: MailboxName('Sent'),
role: Role('sent'),
);
test(
'generateMailboxTreeInUIAfterRefreshChanges: allMailboxes excludes virtual folders from previous collection',
() async {
final virtualFavorite = PresentationMailbox.favoriteFolder;
final previousDefaultTree = MailboxTree(MailboxNode.root())
..root.addChildNode(MailboxNode(virtualFavorite));
final previousCollection = MailboxCollection(
allMailboxes: [inbox, virtualFavorite],
defaultTree: previousDefaultTree,
personalTree: MailboxTree(MailboxNode.root()),
teamMailboxTree: MailboxTree(MailboxNode.root()),
);
final result = await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges(
allMailboxes: [inbox, sent],
currentCollection: previousCollection,
);
expect(
result.allMailboxes.every((m) => !m.isVirtualFolder),
isTrue,
reason: 'Virtual folders from previousCollection must not bleed into result.allMailboxes',
);
expect(result.allMailboxes.length, equals(2));
},
);
test(
'generateMailboxTreeInUIAfterRefreshChanges: deleted server mailboxes are excluded from result',
() async {
final deleted = PresentationMailbox(
MailboxId(Id('deleted')),
name: MailboxName('Old Folder'),
);
final previousDefaultTree = MailboxTree(MailboxNode.root())
..root.addChildNode(MailboxNode(deleted));
final previousCollection = MailboxCollection(
allMailboxes: [inbox, deleted],
defaultTree: previousDefaultTree,
personalTree: MailboxTree(MailboxNode.root()),
teamMailboxTree: MailboxTree(MailboxNode.root()),
);
final result = await TreeBuilder().generateMailboxTreeInUIAfterRefreshChanges(
allMailboxes: [inbox],
currentCollection: previousCollection,
);
expect(result.allMailboxes.length, equals(1));
expect(
result.allMailboxes.any((m) => m.id == deleted.id),
isFalse,
reason: 'Mailbox removed from server must not appear in result',
);
},
);
test(
'generateMailboxTreeInUI: deleted server mailboxes are excluded from result',
() async {
final deleted = PresentationMailbox(
MailboxId(Id('deleted')),
name: MailboxName('Old Folder'),
);
final previousDefaultTree = MailboxTree(MailboxNode.root())
..root.addChildNode(MailboxNode(deleted));
final previousCollection = MailboxCollection(
allMailboxes: [inbox, deleted],
defaultTree: previousDefaultTree,
personalTree: MailboxTree(MailboxNode.root()),
teamMailboxTree: MailboxTree(MailboxNode.root()),
);
final result = await TreeBuilder().generateMailboxTreeInUI(
allMailboxes: [inbox],
currentCollection: previousCollection,
);
expect(result.allMailboxes.length, equals(1));
expect(
result.allMailboxes.any((m) => m.id == deleted.id),
isFalse,
reason: 'Mailbox removed from server must not appear in result',
);
},
);
test(
'generateMailboxTreeInUI: selected mailbox in allMailboxes has state deactivated',
() async {
final result = await TreeBuilder().generateMailboxTreeInUI(
allMailboxes: [inbox, sent],
currentCollection: MailboxCollection.empty(),
mailboxIdSelected: inbox.id,
);
final selectedInResult = result.allMailboxes.firstWhere((m) => m.id == inbox.id);
expect(
selectedInResult.state,
equals(MailboxState.deactivated),
reason: 'Selected mailbox must be deactivated in allMailboxes',
);
expect(result.allMailboxes.length, equals(2));
},
);
});
group('Cascading Deactivation (generateMailboxTreeInUI only)', () { group('Cascading Deactivation (generateMailboxTreeInUI only)', () {
test('Selecting a parent deactivates it and cascades to its children', test('Selecting a parent deactivates it and cascades to its children',
() async { () async {
@@ -589,9 +703,7 @@ void main() {
final result = await TreeBuilder().generateMailboxTreeInUI( final result = await TreeBuilder().generateMailboxTreeInUI(
allMailboxes: mailboxes, allMailboxes: mailboxes,
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
mailboxIdSelected: parentId, mailboxIdSelected: parentId,
); );
@@ -60,6 +60,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox
import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
@@ -816,14 +817,12 @@ void main() {
when( when(
treeBuilder.generateMailboxTreeInUI( treeBuilder.generateMailboxTreeInUI(
allMailboxes: anyNamed('allMailboxes'), allMailboxes: anyNamed('allMailboxes'),
currentDefaultTree: anyNamed('currentDefaultTree'), currentCollection: anyNamed('currentCollection'),
currentPersonalTree: anyNamed('currentPersonalTree'),
currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'),
mailboxIdSelected: anyNamed('mailboxIdSelected'), mailboxIdSelected: anyNamed('mailboxIdSelected'),
mailboxIdExpanded: anyNamed('mailboxIdExpanded'), mailboxIdExpanded: anyNamed('mailboxIdExpanded'),
), ),
).thenAnswer( ).thenAnswer(
(_) async => ( (_) async => MailboxCollection(
allMailboxes: currentMailboxList, allMailboxes: currentMailboxList,
defaultTree: defaultTree, defaultTree: defaultTree,
personalTree: personalTree, personalTree: personalTree,
@@ -865,9 +864,7 @@ void main() {
verify( verify(
treeBuilder.generateMailboxTreeInUI( treeBuilder.generateMailboxTreeInUI(
allMailboxes: anyNamed('allMailboxes'), allMailboxes: anyNamed('allMailboxes'),
currentDefaultTree: anyNamed('currentDefaultTree'), currentCollection: anyNamed('currentCollection'),
currentPersonalTree: anyNamed('currentPersonalTree'),
currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'),
mailboxIdSelected: anyNamed('mailboxIdSelected'), mailboxIdSelected: anyNamed('mailboxIdSelected'),
mailboxIdExpanded: anyNamed('mailboxIdExpanded'), mailboxIdExpanded: anyNamed('mailboxIdExpanded'),
), ),
@@ -958,14 +955,12 @@ void main() {
when( when(
treeBuilder.generateMailboxTreeInUI( treeBuilder.generateMailboxTreeInUI(
allMailboxes: anyNamed('allMailboxes'), allMailboxes: anyNamed('allMailboxes'),
currentDefaultTree: anyNamed('currentDefaultTree'), currentCollection: anyNamed('currentCollection'),
currentPersonalTree: anyNamed('currentPersonalTree'),
currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'),
mailboxIdSelected: anyNamed('mailboxIdSelected'), mailboxIdSelected: anyNamed('mailboxIdSelected'),
mailboxIdExpanded: anyNamed('mailboxIdExpanded'), mailboxIdExpanded: anyNamed('mailboxIdExpanded'),
), ),
).thenAnswer( ).thenAnswer(
(_) async => ( (_) async => MailboxCollection(
allMailboxes: currentMailboxList, allMailboxes: currentMailboxList,
defaultTree: defaultTree, defaultTree: defaultTree,
personalTree: personalTree, personalTree: personalTree,
@@ -1008,9 +1003,7 @@ void main() {
verify( verify(
treeBuilder.generateMailboxTreeInUI( treeBuilder.generateMailboxTreeInUI(
allMailboxes: anyNamed('allMailboxes'), allMailboxes: anyNamed('allMailboxes'),
currentDefaultTree: anyNamed('currentDefaultTree'), currentCollection: anyNamed('currentCollection'),
currentPersonalTree: anyNamed('currentPersonalTree'),
currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'),
mailboxIdSelected: anyNamed('mailboxIdSelected'), mailboxIdSelected: anyNamed('mailboxIdSelected'),
mailboxIdExpanded: anyNamed('mailboxIdExpanded'), mailboxIdExpanded: anyNamed('mailboxIdExpanded'),
), ),
@@ -32,6 +32,7 @@ import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oi
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_collection.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
@@ -211,11 +212,9 @@ void main() {
when(mockTreeBuilder.generateMailboxTreeInUI( when(mockTreeBuilder.generateMailboxTreeInUI(
allMailboxes: [spamMailbox], allMailboxes: [spamMailbox],
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
)).thenAnswer((_) async { )).thenAnswer((_) async {
return ( return MailboxCollection(
allMailboxes: [spamMailbox], allMailboxes: [spamMailbox],
defaultTree: MailboxTree(MailboxNode(spamMailbox)), defaultTree: MailboxTree(MailboxNode(spamMailbox)),
personalTree: MailboxTree(MailboxNode.root()), personalTree: MailboxTree(MailboxNode.root()),
@@ -292,11 +291,9 @@ void main() {
when(mockTreeBuilder.generateMailboxTreeInUI( when(mockTreeBuilder.generateMailboxTreeInUI(
allMailboxes: [mailboxA], allMailboxes: [mailboxA],
currentDefaultTree: MailboxTree(MailboxNode.root()), currentCollection: MailboxCollection.empty(),
currentPersonalTree: MailboxTree(MailboxNode.root()),
currentTeamMailboxTree: MailboxTree(MailboxNode.root()),
)).thenAnswer((_) async { )).thenAnswer((_) async {
return ( return MailboxCollection(
allMailboxes: [mailboxA], allMailboxes: [mailboxA],
defaultTree: MailboxTree(MailboxNode.root()), defaultTree: MailboxTree(MailboxNode.root()),
personalTree: MailboxTree(MailboxNode(mailboxA)), personalTree: MailboxTree(MailboxNode(mailboxA)),