TF-4141 Add the AI needs-action option into the user settings.
This commit is contained in:
@@ -35,4 +35,8 @@ class OpenMailboxAction extends MailboxUIAction {
|
||||
|
||||
class SystemBackToInboxAction extends MailboxUIAction {}
|
||||
|
||||
class RefreshAllMailboxAction extends MailboxUIAction {}
|
||||
class RefreshAllMailboxAction extends MailboxUIAction {}
|
||||
|
||||
class AutoCreateActionRequiredFolderMailboxAction extends MailboxUIAction {}
|
||||
|
||||
class AutoRemoveActionRequiredFolderMailboxAction extends MailboxUIAction {}
|
||||
+20
@@ -42,4 +42,24 @@ extension HandleActionRequiredTabExtension on BaseMailboxController {
|
||||
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 ?? [])
|
||||
..removeWhere((node) => node.item.id == folderId);
|
||||
|
||||
defaultMailboxTree.value = MailboxTree(
|
||||
root.copyWith(children: children),
|
||||
);
|
||||
}
|
||||
|
||||
void _removeFromAllMailboxes(MailboxId folderId) {
|
||||
allMailboxes.removeWhere((mailbox) => mailbox.id == folderId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,6 +319,15 @@ class MailboxController extends BaseMailboxController
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1564,7 +1573,7 @@ class MailboxController extends BaseMailboxController
|
||||
|
||||
void autoCreateVirtualFolder() {
|
||||
addFavoriteFolderToMailboxList();
|
||||
if (mailboxDashBoardController.isAiCapabilitySupported) {
|
||||
if (mailboxDashBoardController.isAINeedsActionEnabled) {
|
||||
addActionRequiredFolder();
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -120,6 +120,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dow
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart' as search;
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_ai_needs_action_setting_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/ai_scribe/setup_cached_ai_scribe_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/cleanup_recent_search_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/delete_emails_in_mailbox_extension.dart';
|
||||
@@ -303,6 +304,7 @@ class MailboxDashBoardController extends ReloadableController
|
||||
final isRecoveringDeletedMessage = RxBool(false);
|
||||
final localFileDraggableAppState = Rxn<DraggableAppState>();
|
||||
final isSenderImportantFlagEnabled = RxBool(true);
|
||||
final isAINeedsActionSettingEnabled = RxBool(false);
|
||||
final isAppGridDialogDisplayed = RxBool(false);
|
||||
final isDrawerOpened = RxBool(false);
|
||||
final isContextMenuOpened = RxBool(false);
|
||||
@@ -512,6 +514,7 @@ class MailboxDashBoardController extends ReloadableController
|
||||
);
|
||||
} else if (success is GetServerSettingSuccess) {
|
||||
isSenderImportantFlagEnabled.value = success.settingOption.isDisplaySenderPriority;
|
||||
setupAINeedsActionSetting(options: success.settingOption);
|
||||
initializeAppLanguage(success);
|
||||
} else if (success is ClearMailboxSuccess) {
|
||||
clearMailboxSuccess(success);
|
||||
@@ -568,6 +571,7 @@ class MailboxDashBoardController extends ReloadableController
|
||||
_handleIdentityCache();
|
||||
} else if (failure is GetServerSettingFailure) {
|
||||
isSenderImportantFlagEnabled.value = true;
|
||||
setupAINeedsActionSetting();
|
||||
} else if (failure is GetAllIdentitiesFailure) {
|
||||
_handleGetAllIdentitiesFailure();
|
||||
} else if (failure is ClearMailboxFailure) {
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:server_settings/server_settings/tmail_server_settings.dart';
|
||||
import 'package:server_settings/server_settings/tmail_server_settings_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||
|
||||
extension SetupAiNeedsActionSettingExtension on MailboxDashBoardController {
|
||||
void setupAINeedsActionSetting({TMailServerSettingOptions? options}) {
|
||||
if (options != null) {
|
||||
isAINeedsActionSettingEnabled.value = options.isAINeedsActionEnabled;
|
||||
} else {
|
||||
isAINeedsActionSettingEnabled.value = false;
|
||||
}
|
||||
|
||||
if (isAINeedsActionSettingEnabled.isTrue) {
|
||||
dispatchMailboxUIAction(AutoCreateActionRequiredFolderMailboxAction());
|
||||
} else {
|
||||
dispatchMailboxUIAction(AutoRemoveActionRequiredFolderMailboxAction());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,7 @@ extension HandleAiActionExtension on MailboxDashBoardController {
|
||||
currentAccountId,
|
||||
);
|
||||
}
|
||||
|
||||
bool get isAINeedsActionEnabled =>
|
||||
isAINeedsActionSettingEnabled.value && isAiCapabilitySupported;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ enum PreferencesOptionType {
|
||||
senderPriority(isLocal: false),
|
||||
thread(isLocal: true),
|
||||
spamReport(isLocal: true),
|
||||
aiScribe(isLocal: true);
|
||||
aiScribe(isLocal: true),
|
||||
aiNeedsAction(isLocal: false);
|
||||
|
||||
final bool isLocal;
|
||||
|
||||
@@ -27,6 +28,8 @@ enum PreferencesOptionType {
|
||||
return appLocalizations.spamReports;
|
||||
case PreferencesOptionType.aiScribe:
|
||||
return appLocalizations.aiScribe;
|
||||
case PreferencesOptionType.aiNeedsAction:
|
||||
return appLocalizations.aiNeedsAction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +45,8 @@ enum PreferencesOptionType {
|
||||
return appLocalizations.spamReportsSettingExplanation;
|
||||
case PreferencesOptionType.aiScribe:
|
||||
return appLocalizations.aiScribeSettingExplanation;
|
||||
case PreferencesOptionType.aiNeedsAction:
|
||||
return appLocalizations.aiNeedsActionSettingExplanation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +62,8 @@ enum PreferencesOptionType {
|
||||
return appLocalizations.spamReportToggleDescription;
|
||||
case PreferencesOptionType.aiScribe:
|
||||
return appLocalizations.aiScribeToggleDescription;
|
||||
case PreferencesOptionType.aiNeedsAction:
|
||||
return appLocalizations.aiNeedsActionToggleDescription;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +82,8 @@ enum PreferencesOptionType {
|
||||
return preferencesSetting.spamReportConfig.isEnabled;
|
||||
case PreferencesOptionType.aiScribe:
|
||||
return preferencesSetting.aiScribeConfig.isEnabled;
|
||||
case PreferencesOptionType.aiNeedsAction:
|
||||
return settingOption?.isAINeedsActionEnabled ?? false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class PreferencesController extends BaseController {
|
||||
|
||||
final _manageAccountDashBoardController = Get.find<ManageAccountDashBoardController>();
|
||||
|
||||
bool get isAIScribeAvailable {
|
||||
bool get isAICapabilitySupported {
|
||||
return _manageAccountDashBoardController.isAICapabilitySupported;
|
||||
}
|
||||
|
||||
@@ -183,6 +183,11 @@ class PreferencesController extends BaseController {
|
||||
displaySenderPriority: !isEnabled,
|
||||
);
|
||||
break;
|
||||
case PreferencesOptionType.aiNeedsAction:
|
||||
newSettingOption = settingOption.value?.copyWith(
|
||||
aiNeedsActionEnabled: !isEnabled,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -68,17 +68,20 @@ class PreferencesView extends GetWidget<PreferencesController> with AppLoaderMix
|
||||
final availableSettingOptions = [
|
||||
if (settingOption != null)
|
||||
...PreferencesOptionType.values.where(
|
||||
(optionType) => !optionType.isLocal,
|
||||
(type) =>
|
||||
!type.isLocal &&
|
||||
type != PreferencesOptionType.aiNeedsAction,
|
||||
),
|
||||
if (localSettingOption.configs.isNotEmpty)
|
||||
...PreferencesOptionType.values.where(
|
||||
(optionType) => optionType.isLocal,
|
||||
).where((optionType) {
|
||||
if (optionType == PreferencesOptionType.aiScribe) {
|
||||
return controller.isAIScribeAvailable && !PlatformInfo.isMobile;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
(type) =>
|
||||
type.isLocal &&
|
||||
(type != PreferencesOptionType.aiScribe ||
|
||||
controller.isAICapabilitySupported),
|
||||
),
|
||||
if (settingOption != null &&
|
||||
controller.isAICapabilitySupported)
|
||||
PreferencesOptionType.aiNeedsAction,
|
||||
];
|
||||
|
||||
return Expanded(
|
||||
|
||||
@@ -724,8 +724,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
|
||||
final isSenderImportantFlagEnabled =
|
||||
dashboardController.isSenderImportantFlagEnabled.value;
|
||||
|
||||
final isAiCapabilitySupported =
|
||||
dashboardController.isAiCapabilitySupported;
|
||||
final isAINeedsActionEnabled = dashboardController.isAINeedsActionEnabled;
|
||||
|
||||
return EmailTileBuilder(
|
||||
presentationEmail: presentationEmail,
|
||||
@@ -734,7 +733,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
|
||||
isShowingEmailContent: isShowingEmailContent,
|
||||
isSenderImportantFlagEnabled: isSenderImportantFlagEnabled,
|
||||
isSearchEmailRunning: true,
|
||||
isAIEnabled: isAiCapabilitySupported,
|
||||
isAINeedsActionEnabled: isAINeedsActionEnabled,
|
||||
padding: SearchEmailViewStyle.getPaddingSearchResultList(
|
||||
context,
|
||||
controller.responsiveUtils,
|
||||
|
||||
@@ -902,7 +902,7 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
|
||||
|
||||
void autoCreateVirtualFolder() {
|
||||
addFavoriteFolderToMailboxList();
|
||||
if (dashboardController.isAiCapabilitySupported) {
|
||||
if (dashboardController.isAINeedsActionEnabled) {
|
||||
addActionRequiredFolder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ extension TmailServerSettingsExtension on TMailServerSettings {
|
||||
settings: TMailServerSettingOptions(
|
||||
alwaysReadReceipts: settings?.alwaysReadReceipts,
|
||||
displaySenderPriority: settings?.displaySenderPriority,
|
||||
aiNeedsActionEnabled: settings?.aiNeedsActionEnabled,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -510,8 +510,7 @@ class ThreadView extends GetWidget<ThreadController>
|
||||
final isSearchEmailRunning =
|
||||
controller.searchController.isSearchEmailRunning;
|
||||
|
||||
final isAiCapabilitySupported =
|
||||
dashboardController.isAiCapabilitySupported;
|
||||
final isAINeedsActionEnabled = dashboardController.isAINeedsActionEnabled;
|
||||
|
||||
return EmailTileBuilder(
|
||||
key: Key('email_tile_builder_${presentationEmail.id?.asString}'),
|
||||
@@ -523,7 +522,7 @@ class ThreadView extends GetWidget<ThreadController>
|
||||
isSearchEmailRunning: isSearchEmailRunning,
|
||||
isDrag: true,
|
||||
isSenderImportantFlagEnabled: isSenderImportantFlagEnabled,
|
||||
isAIEnabled: isAiCapabilitySupported,
|
||||
isAINeedsActionEnabled: isAINeedsActionEnabled,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -607,8 +606,7 @@ class ThreadView extends GetWidget<ThreadController>
|
||||
final isSearchEmailRunning =
|
||||
controller.searchController.isSearchEmailRunning;
|
||||
|
||||
final isAiCapabilitySupported =
|
||||
dashboardController.isAiCapabilitySupported;
|
||||
final isAINeedsActionEnabled = dashboardController.isAINeedsActionEnabled;
|
||||
|
||||
return Dismissible(
|
||||
key: ValueKey<EmailId?>(presentationEmail.id),
|
||||
@@ -632,7 +630,7 @@ class ThreadView extends GetWidget<ThreadController>
|
||||
searchQuery: controller.searchQuery,
|
||||
mailboxContain: presentationEmail.mailboxContain,
|
||||
isSearchEmailRunning: isSearchEmailRunning,
|
||||
isAIEnabled: isAiCapabilitySupported,
|
||||
isAINeedsActionEnabled: isAINeedsActionEnabled,
|
||||
emailActionClick: _handleEmailActionClicked,
|
||||
onMoreActionClick: (email, position) =>
|
||||
_handleEmailContextMenuAction(context, email, position),
|
||||
|
||||
@@ -20,7 +20,7 @@ class EmailTileBuilder extends StatelessWidget with BaseEmailItemTile {
|
||||
final bool isDrag;
|
||||
final bool isShowingEmailContent;
|
||||
final bool isSenderImportantFlagEnabled;
|
||||
final bool isAIEnabled;
|
||||
final bool isAINeedsActionEnabled;
|
||||
final OnPressEmailActionClick? emailActionClick;
|
||||
final OnMoreActionClick? onMoreActionClick;
|
||||
|
||||
@@ -32,7 +32,7 @@ class EmailTileBuilder extends StatelessWidget with BaseEmailItemTile {
|
||||
this.searchQuery,
|
||||
this.isSearchEmailRunning = false,
|
||||
this.isSenderImportantFlagEnabled = true,
|
||||
this.isAIEnabled = true,
|
||||
this.isAINeedsActionEnabled = true,
|
||||
this.mailboxContain,
|
||||
this.padding,
|
||||
this.isDrag = false,
|
||||
@@ -141,5 +141,5 @@ class EmailTileBuilder extends StatelessWidget with BaseEmailItemTile {
|
||||
}
|
||||
|
||||
bool get _shouldShowAIAction =>
|
||||
isAIEnabled && presentationEmail.hasNeedAction;
|
||||
isAINeedsActionEnabled && presentationEmail.hasNeedAction;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ class EmailTileBuilder extends StatefulWidget {
|
||||
final bool isDrag;
|
||||
final bool isShowingEmailContent;
|
||||
final bool isSenderImportantFlagEnabled;
|
||||
final bool isAIEnabled;
|
||||
final bool isAINeedsActionEnabled;
|
||||
final OnPressEmailActionClick? emailActionClick;
|
||||
final OnMoreActionClick? onMoreActionClick;
|
||||
|
||||
@@ -42,7 +42,7 @@ class EmailTileBuilder extends StatefulWidget {
|
||||
this.mailboxContain,
|
||||
this.padding,
|
||||
this.isDrag = false,
|
||||
this.isAIEnabled = false,
|
||||
this.isAINeedsActionEnabled = false,
|
||||
this.emailActionClick,
|
||||
this.onMoreActionClick,
|
||||
});
|
||||
@@ -423,7 +423,7 @@ class _EmailTileBuilderState extends State<EmailTileBuilder> with BaseEmailItem
|
||||
}
|
||||
|
||||
bool get _shouldShowAIAction =>
|
||||
widget.isAIEnabled && widget.presentationEmail.hasNeedAction;
|
||||
widget.isAINeedsActionEnabled && widget.presentationEmail.hasNeedAction;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2025-12-17T00:04:15.124514",
|
||||
"@@last_modified": "2025-12-22T16:54:22.593873",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -4862,6 +4862,24 @@
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"aiScribe": "AI Scribe",
|
||||
"@aiScribe": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"aiScribeSettingExplanation": "Use AI to help write and improve your emails",
|
||||
"@aiScribeSettingExplanation": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"aiScribeToggleDescription": "Enable AI Scribe",
|
||||
"@aiScribeToggleDescription": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"showMoreAttachmentButton": "Show +{count} more",
|
||||
"@showMoreAttachmentButton": {
|
||||
"type": "text",
|
||||
@@ -5130,12 +5148,6 @@
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"aiAssistant": "AI assistant",
|
||||
"@aiAssistant": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"actionRequired": "Action Required",
|
||||
"@actionRequired": {
|
||||
"type": "text",
|
||||
@@ -5153,5 +5165,23 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"aiNeedsAction": "AI needs-action",
|
||||
"@aiNeedsAction": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"aiNeedsActionToggleDescription": "Enable AI needs-action",
|
||||
"@aiNeedsActionToggleDescription": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"aiNeedsActionSettingExplanation": "Detect emails that need your attention using AI. When turned off, AI will not process any emails.",
|
||||
"@aiNeedsActionSettingExplanation": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -5478,4 +5478,25 @@ class AppLocalizations {
|
||||
name: 'youDoNotHaveAnyActionRequiredEmails',
|
||||
);
|
||||
}
|
||||
|
||||
String get aiNeedsAction {
|
||||
return Intl.message(
|
||||
'AI needs-action',
|
||||
name: 'aiNeedsAction',
|
||||
);
|
||||
}
|
||||
|
||||
String get aiNeedsActionToggleDescription {
|
||||
return Intl.message(
|
||||
'Enable AI needs-action',
|
||||
name: 'aiNeedsActionToggleDescription',
|
||||
);
|
||||
}
|
||||
|
||||
String get aiNeedsActionSettingExplanation {
|
||||
return Intl.message(
|
||||
'Detect emails that need your attention using AI. When turned off, AI will not process any emails.',
|
||||
name: 'aiNeedsActionSettingExplanation',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,14 @@ class TMailServerSettingOptions with EquatableMixin {
|
||||
@JsonKey(name: 'language')
|
||||
final String? language;
|
||||
|
||||
@JsonKey(name: 'ai.needs-action.enabled')
|
||||
final bool? aiNeedsActionEnabled;
|
||||
|
||||
TMailServerSettingOptions({
|
||||
this.alwaysReadReceipts,
|
||||
this.displaySenderPriority,
|
||||
this.language,
|
||||
this.aiNeedsActionEnabled,
|
||||
});
|
||||
|
||||
factory TMailServerSettingOptions.fromJson(Map<String, dynamic> json) =>
|
||||
@@ -55,11 +59,13 @@ class TMailServerSettingOptions with EquatableMixin {
|
||||
bool? alwaysReadReceipts,
|
||||
bool? displaySenderPriority,
|
||||
String? language,
|
||||
bool? aiNeedsActionEnabled,
|
||||
}) {
|
||||
return TMailServerSettingOptions(
|
||||
alwaysReadReceipts: alwaysReadReceipts ?? this.alwaysReadReceipts,
|
||||
displaySenderPriority: displaySenderPriority ?? this.displaySenderPriority,
|
||||
language: language ?? this.language,
|
||||
aiNeedsActionEnabled: aiNeedsActionEnabled ?? this.aiNeedsActionEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,5 +74,6 @@ class TMailServerSettingOptions with EquatableMixin {
|
||||
alwaysReadReceipts,
|
||||
displaySenderPriority,
|
||||
language,
|
||||
aiNeedsActionEnabled,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -5,4 +5,6 @@ extension TmailServerSettingsExtension on TMailServerSettingOptions {
|
||||
bool get isDisplaySenderPriority => displaySenderPriority ?? true;
|
||||
|
||||
bool get isAlwaysReadReceipts => alwaysReadReceipts ?? false;
|
||||
|
||||
bool get isAINeedsActionEnabled => aiNeedsActionEnabled ?? false;
|
||||
}
|
||||
Reference in New Issue
Block a user