diff --git a/lib/features/base/base_mailbox_controller.dart b/lib/features/base/base_mailbox_controller.dart index 6b108457c..b970a2e7b 100644 --- a/lib/features/base/base_mailbox_controller.dart +++ b/lib/features/base/base_mailbox_controller.dart @@ -30,6 +30,8 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_request.da import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/expand_mode_extension.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_action_required_tab_extension.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_favorite_tab_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/model/mailbox_actions.dart'; @@ -672,4 +674,11 @@ abstract class BaseMailboxController extends BaseController ); } } + + void autoCreateVirtualFolder(bool isAINeedsActionEnabled) { + addFavoriteFolderToMailboxList(); + if (isAINeedsActionEnabled) { + addActionRequiredFolder(); + } + } } \ No newline at end of file diff --git a/lib/features/base/mixin/ai_scribe_mixin.dart b/lib/features/base/mixin/ai_scribe_mixin.dart index 293267b5a..bd39b24e7 100644 --- a/lib/features/base/mixin/ai_scribe_mixin.dart +++ b/lib/features/base/mixin/ai_scribe_mixin.dart @@ -8,8 +8,6 @@ import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions mixin AiScribeMixin { AICapability? getAICapability({Session? session, AccountId? accountId}) { - if (PlatformInfo.isMobile) return null; - if (accountId == null || session == null) { return null; } @@ -17,8 +15,18 @@ mixin AiScribeMixin { return session.getAICapability(accountId); } + bool isAIScribeEndpointAvailable({Session? session, AccountId? accountId}) { + final aiCapability = getAICapability( + session: session, + accountId: accountId, + ); + return aiCapability?.isScribeEndpointAvailable == true; + } + void injectAIScribeBindings(Session? session, AccountId? accountId) { try { + if (PlatformInfo.isMobile) return; + final aiCapability = getAICapability( session: session, accountId: accountId, diff --git a/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart b/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart index b63a94425..3a8b86804 100644 --- a/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart +++ b/lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart @@ -9,17 +9,18 @@ import 'package:tmail_ui_user/features/composer/presentation/mixin/text_selectio extension HandleAiScribeInComposerExtension on ComposerController { bool get isAIScribeAvailable { - final aiCapability = getAICapability( + final isAIScribeEndpointAvailable = + mailboxDashBoardController.isAIScribeEndpointAvailable( session: mailboxDashBoardController.sessionCurrent, accountId: mailboxDashBoardController.accountId.value, ); - final isScribeEndpointAvailable = - aiCapability?.isScribeEndpointAvailable == true; final isAIScribeConfigEnabled = mailboxDashBoardController.cachedAIScribeConfig.value.isEnabled; - return isAIScribeConfigEnabled && isScribeEndpointAvailable; + return isAIScribeConfigEnabled && + isAIScribeEndpointAvailable && + !PlatformInfo.isMobile; } Future _getTextOnlyContentInEditor() async { diff --git a/lib/features/home/domain/extensions/session_extensions.dart b/lib/features/home/domain/extensions/session_extensions.dart index 7190dd19b..8b4e4edf5 100644 --- a/lib/features/home/domain/extensions/session_extensions.dart +++ b/lib/features/home/domain/extensions/session_extensions.dart @@ -28,7 +28,6 @@ extension SessionExtensions on Session { static final CapabilityIdentifier linagoraContactSupportCapability = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:contact:support')); static final CapabilityIdentifier linagoraDownloadAllCapability = CapabilityIdentifier(Uri.parse('com:linagora:params:downloadAll')); static final CapabilityIdentifier linagoraSaaSCapability = CapabilityIdentifier(Uri.parse('com:linagora:params:saas')); - static final CapabilityIdentifier linagoraAICapability = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:aibot')); static final Map)> customMapCapabilitiesConverter = { linagoraContactSupportCapability: ContactSupportCapability.deserialize, @@ -172,6 +171,10 @@ extension SessionExtensions on Session { AICapability? getAICapability(AccountId accountId) { try { + if (!AiScribeConstants.aiCapability.isSupported(this, accountId)) { + return null; + } + final aiCapability = getCapabilityProperties( accountId, AiScribeConstants.aiCapability, diff --git a/lib/features/mailbox/presentation/base_mailbox_view.dart b/lib/features/mailbox/presentation/base_mailbox_view.dart index d3427c569..6ad8d5e28 100644 --- a/lib/features/mailbox/presentation/base_mailbox_view.dart +++ b/lib/features/mailbox/presentation/base_mailbox_view.dart @@ -197,6 +197,9 @@ abstract class BaseMailboxView extends GetWidget .mailboxDashBoardController .selectedMailbox .value, + isDraggingMailbox: controller + .mailboxDashBoardController + .isDraggingMailbox, isHighlighted: isFolderHighlighted(mailboxNode), onOpenMailboxFolderClick: (mailboxNode) => mailboxNode != null diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 387971d07..9144828e3 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -70,7 +70,6 @@ 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/presentation/action/mailbox_ui_action.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_action_required_tab_extension.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_favorite_tab_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; @@ -86,7 +85,7 @@ import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_ma import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; @@ -265,14 +264,18 @@ class MailboxController extends BaseMailboxController viewState.value.fold( (failure) { if (failure is GetAllMailboxFailure) { - autoCreateVirtualFolder(); + autoCreateVirtualFolder( + mailboxDashBoardController.isAINeedsActionEnabled, + ); mailboxDashBoardController.updateRefreshAllMailboxState(Left(RefreshAllMailboxFailure())); showRetryToast(failure); } }, (success) { if (success is GetAllMailboxSuccess) { - autoCreateVirtualFolder(); + autoCreateVirtualFolder( + mailboxDashBoardController.isAINeedsActionEnabled, + ); mailboxDashBoardController.updateRefreshAllMailboxState(Right(RefreshAllMailboxSuccess())); _handleCreateDefaultFolderIfMissing(mailboxDashBoardController.mapDefaultMailboxIdByRole); _handleDataFromNavigationRouter(); @@ -281,7 +284,9 @@ class MailboxController extends BaseMailboxController _updateMailboxIdsBlockNotificationToKeychain(success.mailboxList); } } else if (success is CreateDefaultMailboxAllSuccess) { - autoCreateVirtualFolder(); + autoCreateVirtualFolder( + mailboxDashBoardController.isAINeedsActionEnabled, + ); } }); } @@ -612,7 +617,9 @@ class MailboxController extends BaseMailboxController if (currentContext != null) { syncAllMailboxWithDisplayName(currentContext!); } - autoCreateVirtualFolder(); + autoCreateVirtualFolder( + mailboxDashBoardController.isAINeedsActionEnabled, + ); _setMapMailbox(); _setOutboxMailbox(); _selectSelectedMailboxDefault(); @@ -1570,11 +1577,4 @@ class MailboxController extends BaseMailboxController ); } } - - void autoCreateVirtualFolder() { - addFavoriteFolderToMailboxList(); - if (mailboxDashBoardController.isAINeedsActionEnabled) { - addActionRequiredFolder(); - } - } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/widgets/mailbox_item_widget.dart b/lib/features/mailbox/presentation/widgets/mailbox_item_widget.dart index 61352a41a..c92f33099 100644 --- a/lib/features/mailbox/presentation/widgets/mailbox_item_widget.dart +++ b/lib/features/mailbox/presentation/widgets/mailbox_item_widget.dart @@ -31,6 +31,7 @@ class MailboxItemWidget extends StatefulWidget { final double? itemHeight; final String? iconSelected; final bool isHighlighted; + final bool isDraggingMailbox; final OnClickExpandMailboxNodeAction? onExpandFolderActionClick; final OnClickOpenMailboxNodeAction? onOpenMailboxFolderClick; @@ -45,6 +46,7 @@ class MailboxItemWidget extends StatefulWidget { required this.mailboxNode, this.mailboxDisplayed = MailboxDisplayed.mailbox, this.isHighlighted = false, + this.isDraggingMailbox = false, this.mailboxNodeSelected, this.mailboxActions, this.mailboxIdAlreadySelected, @@ -322,12 +324,19 @@ class _MailboxItemWidgetState extends State { widget.mailboxNodeSelected?.id == widget.mailboxNode.item.id; Color get backgroundColorItem { - if (widget.mailboxDisplayed == MailboxDisplayed.mailbox) { - return _isSelected || widget.isHighlighted - ? AppColor.blue100 - : Colors.transparent; + // Non-mailbox views are always white + if (widget.mailboxDisplayed != MailboxDisplayed.mailbox) { + return Colors.white; } - return Colors.white; + + // Dragging action-required mailboxes must not show highlight + if (widget.isDraggingMailbox && widget.mailboxNode.item.isActionRequired) { + return AppColor.colorBgDesktop; + } + + return (_isSelected || widget.isHighlighted) + ? AppColor.blue100 + : Colors.transparent; } bool get isFolderModalActive => diff --git a/lib/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart b/lib/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart similarity index 72% rename from lib/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart rename to lib/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart index bada1a4e6..58a7e74b6 100644 --- a/lib/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart +++ b/lib/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart @@ -1,8 +1,8 @@ -import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; +import 'package:scribe/scribe/ai/presentation/utils/ai_scribe_constants.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/main/error/capability_validator.dart'; -extension HandleAiActionExtension on MailboxDashBoardController { +extension HandleAiNeedsActionExtension on MailboxDashBoardController { bool get isAiCapabilitySupported { final currentAccountId = accountId.value; final currentSession = sessionCurrent; @@ -11,7 +11,7 @@ extension HandleAiActionExtension on MailboxDashBoardController { return false; } - return SessionExtensions.linagoraAICapability.isSupported( + return AiScribeConstants.aiCapability.isSupported( currentSession, currentAccountId, ); diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart index 32e063f06..763877225 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart @@ -341,6 +341,17 @@ class ManageAccountDashBoardController extends ReloadableController } } + bool get isAIScribeCapabilityAvailable { + if (accountId.value != null && sessionCurrent != null) { + return isAIScribeEndpointAvailable( + session: sessionCurrent!, + accountId: accountId.value!, + ); + } else { + return false; + } + } + void disableVacationResponder( VacationResponse vacation, { bool isAuto = false, diff --git a/lib/features/manage_account/presentation/preferences/preferences_controller.dart b/lib/features/manage_account/presentation/preferences/preferences_controller.dart index ae870fe62..45de856eb 100644 --- a/lib/features/manage_account/presentation/preferences/preferences_controller.dart +++ b/lib/features/manage_account/presentation/preferences/preferences_controller.dart @@ -54,6 +54,10 @@ class PreferencesController extends BaseController { return _manageAccountDashBoardController.isAICapabilitySupported; } + bool get isAIScribeCapabilityAvailable { + return _manageAccountDashBoardController.isAIScribeCapabilityAvailable; + } + @override void onInit() { super.onInit(); diff --git a/lib/features/manage_account/presentation/preferences/preferences_view.dart b/lib/features/manage_account/presentation/preferences/preferences_view.dart index be0fa5567..3cc7bdca3 100644 --- a/lib/features/manage_account/presentation/preferences/preferences_view.dart +++ b/lib/features/manage_account/presentation/preferences/preferences_view.dart @@ -77,7 +77,7 @@ class PreferencesView extends GetWidget with AppLoaderMix (type) => type.isLocal && (type != PreferencesOptionType.aiScribe || - controller.isAICapabilitySupported), + controller.isAIScribeCapabilityAvailable), ), if (settingOption != null && controller.isAICapabilitySupported) diff --git a/lib/features/search/email/presentation/search_email_view.dart b/lib/features/search/email/presentation/search_email_view.dart index 6fe7aefbd..102ec9f8b 100644 --- a/lib/features/search/email/presentation/search_email_view.dart +++ b/lib/features/search/email/presentation/search_email_view.dart @@ -18,7 +18,7 @@ import 'package:tmail_ui_user/features/base/widget/keyboard/keyboard_handler_wra import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart'; import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart'; diff --git a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart index 38c4c933c..9959aff14 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart @@ -58,8 +58,6 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/subaddressing_int import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_action_required_tab_extension.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_favorite_tab_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_actions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; @@ -69,7 +67,7 @@ import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_na import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_mailbox_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_reactive_obx_variable_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; @@ -215,11 +213,15 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa super.onDone(); viewState.value.fold((failure) { if (failure is GetAllMailboxFailure) { - autoCreateVirtualFolder(); + autoCreateVirtualFolder( + dashboardController.isAINeedsActionEnabled, + ); } }, (success) { if (success is GetAllMailboxSuccess) { - autoCreateVirtualFolder(); + autoCreateVirtualFolder( + dashboardController.isAINeedsActionEnabled, + ); } }); } @@ -900,13 +902,6 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa FocusManager.instance.primaryFocus?.unfocus(); } - void autoCreateVirtualFolder() { - addFavoriteFolderToMailboxList(); - if (dashboardController.isAINeedsActionEnabled) { - addActionRequiredFolder(); - } - } - @override void onClose() { textInputSearchController.dispose(); diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 804286768..a731e9ce7 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -20,7 +20,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state. import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/move_folder_content_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_open_context_menu_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart'; diff --git a/test/features/composer/presentation/composer_controller_test.dart b/test/features/composer/presentation/composer_controller_test.dart index 1bb31c6b8..1620520f0 100644 --- a/test/features/composer/presentation/composer_controller_test.dart +++ b/test/features/composer/presentation/composer_controller_test.dart @@ -147,6 +147,11 @@ class MockMailboxDashBoardController extends Mock implements MailboxDashBoardCon @override Rx get cachedAIScribeConfig => AIScribeConfig.initial().obs; + + @override + bool isAIScribeEndpointAvailable({Session? session, AccountId? accountId}) { + return false; + } } @GenerateNiceMocks([ diff --git a/test/features/mailbox/presentation/extensions/list_mailbox_node_extension_test.dart b/test/features/mailbox/presentation/extensions/list_mailbox_node_extension_test.dart index 6175a989a..c7db72764 100644 --- a/test/features/mailbox/presentation/extensions/list_mailbox_node_extension_test.dart +++ b/test/features/mailbox/presentation/extensions/list_mailbox_node_extension_test.dart @@ -114,19 +114,19 @@ void main() { test( 'should insert after Starred when role missing but name matches (case-insensitive)', - () { - nodes = [ - buildNode('1', name: 'Inbox'), - buildNode('2', name: 'STARRED'), // no role - buildNode('3', name: 'Trash'), - ]; + () { + nodes = [ + buildNode('1', name: 'Inbox'), + buildNode('2', name: 'STARRED'), // no role + buildNode('3', name: 'Trash'), + ]; - final newNode = buildNode('4', name: 'Draft'); - nodes.insertAfterStarredOrInbox(newNode); + final newNode = buildNode('4', name: 'Draft'); + nodes.insertAfterStarredOrInbox(newNode); - final ids = nodes.mailboxIds.map((id) => id.id.value).toList(); - expect(ids, ['1', '2', '4', '3']); - }); + final ids = nodes.mailboxIds.map((id) => id.id.value).toList(); + expect(ids, ['1', '2', '4', '3']); + }); test('should insert after Inbox when Starred not found', () { nodes = [ @@ -162,7 +162,7 @@ void main() { ]; final newNode = - buildNode('2', name: 'Starred', role: 'favorite'); // duplicate id + buildNode('2', name: 'Starred', role: 'favorite'); // duplicate id nodes.insertAfterStarredOrInbox(newNode); final ids = nodes.mailboxIds.map((id) => id.id.value).toList(); @@ -184,15 +184,15 @@ void main() { bool isInbox(MailboxNode node) => node.item.role?.value == PresentationMailbox.inboxRole || - node.item.name?.name.toLowerCase() == 'inbox'; + node.item.name?.name.toLowerCase() == 'inbox'; bool isStarred(MailboxNode node) => node.item.role?.value == PresentationMailbox.favoriteRole || - node.item.name?.name.toLowerCase() == 'starred'; + node.item.name?.name.toLowerCase() == 'starred'; bool isSent(MailboxNode node) => node.item.role?.value == PresentationMailbox.sentRole || - node.item.name?.name.toLowerCase() == 'sent'; + node.item.name?.name.toLowerCase() == 'sent'; test('should insert after first matched priority', () { nodes = [