TF-4141 should not show inkwell effect when user drag email into virtual folder

This commit is contained in:
dab246
2025-12-29 13:00:06 +07:00
committed by Dat H. Pham
parent 3e86f53862
commit df5ed118b3
16 changed files with 106 additions and 58 deletions
@@ -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();
}
}
}
+10 -2
View File
@@ -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,
@@ -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<String> _getTextOnlyContentInEditor() async {
@@ -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<CapabilityIdentifier, CapabilityProperties Function(Map<String, dynamic>)> 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<AICapability>(
accountId,
AiScribeConstants.aiCapability,
@@ -197,6 +197,9 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
.mailboxDashBoardController
.selectedMailbox
.value,
isDraggingMailbox: controller
.mailboxDashBoardController
.isDraggingMailbox,
isHighlighted: isFolderHighlighted(mailboxNode),
onOpenMailboxFolderClick: (mailboxNode) =>
mailboxNode != null
@@ -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();
}
}
}
@@ -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<MailboxItemWidget> {
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 =>
@@ -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,
);
@@ -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,
@@ -54,6 +54,10 @@ class PreferencesController extends BaseController {
return _manageAccountDashBoardController.isAICapabilitySupported;
}
bool get isAIScribeCapabilityAvailable {
return _manageAccountDashBoardController.isAIScribeCapabilityAvailable;
}
@override
void onInit() {
super.onInit();
@@ -77,7 +77,7 @@ class PreferencesView extends GetWidget<PreferencesController> with AppLoaderMix
(type) =>
type.isLocal &&
(type != PreferencesOptionType.aiScribe ||
controller.isAICapabilitySupported),
controller.isAIScribeCapabilityAvailable),
),
if (settingOption != null &&
controller.isAICapabilitySupported)
@@ -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';
@@ -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();
@@ -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';
@@ -147,6 +147,11 @@ class MockMailboxDashBoardController extends Mock implements MailboxDashBoardCon
@override
Rx<AIScribeConfig> get cachedAIScribeConfig => AIScribeConfig.initial().obs;
@override
bool isAIScribeEndpointAvailable({Session? session, AccountId? accountId}) {
return false;
}
}
@GenerateNiceMocks([
@@ -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 = [