From f439e93a2bc6aab2bca54bf647572a83fd672c9a Mon Sep 17 00:00:00 2001 From: Sline Date: Wed, 19 Nov 2025 17:06:23 +0800 Subject: [PATCH] feat(hotkey): add global reactivate_profiles shortcut (#5527) * feat(hotkey): add global reactivate_profiles shortcut * feat(profile): expose validation state for reactivation shortcuts --- src-tauri/locales/ar.yml | 3 ++ src-tauri/locales/de.yml | 3 ++ src-tauri/locales/en.yml | 3 ++ src-tauri/locales/es.yml | 3 ++ src-tauri/locales/fa.yml | 3 ++ src-tauri/locales/id.yml | 3 ++ src-tauri/locales/jp.yml | 3 ++ src-tauri/locales/ko.yml | 3 ++ src-tauri/locales/ru.yml | 3 ++ src-tauri/locales/tr.yml | 3 ++ src-tauri/locales/tt.yml | 3 ++ src-tauri/locales/zh.yml | 3 ++ src-tauri/locales/zhtw.yml | 3 ++ src-tauri/src/cmd/profile.rs | 23 ++++++++++-- src-tauri/src/core/hotkey.rs | 37 +++++++++++++++++++ src-tauri/src/feat/profile.rs | 7 +--- src-tauri/src/utils/notification.rs | 6 +++ src/components/setting/mods/hotkey-viewer.tsx | 2 + src/locales/ar/settings.json | 3 +- src/locales/de/settings.json | 3 +- src/locales/en/settings.json | 3 +- src/locales/es/settings.json | 3 +- src/locales/fa/settings.json | 3 +- src/locales/id/settings.json | 3 +- src/locales/jp/settings.json | 3 +- src/locales/ko/settings.json | 3 +- src/locales/ru/settings.json | 3 +- src/locales/tr/settings.json | 3 +- src/locales/tt/settings.json | 3 +- src/locales/zh/settings.json | 3 +- src/locales/zhtw/settings.json | 3 +- src/pages/_layout/notificationHandlers.ts | 1 + src/types/generated/i18n-keys.ts | 1 + src/types/generated/i18n-resources.ts | 1 + 34 files changed, 134 insertions(+), 22 deletions(-) diff --git a/src-tauri/locales/ar.yml b/src-tauri/locales/ar.yml index a054627f7..bd2ef91fd 100644 --- a/src-tauri/locales/ar.yml +++ b/src-tauri/locales/ar.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/de.yml b/src-tauri/locales/de.yml index 2cda8afe8..4bef5d8bd 100644 --- a/src-tauri/locales/de.yml +++ b/src-tauri/locales/de.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/en.yml b/src-tauri/locales/en.yml index a054627f7..bd2ef91fd 100644 --- a/src-tauri/locales/en.yml +++ b/src-tauri/locales/en.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/es.yml b/src-tauri/locales/es.yml index 974899b15..6616029e5 100644 --- a/src-tauri/locales/es.yml +++ b/src-tauri/locales/es.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/fa.yml b/src-tauri/locales/fa.yml index a054627f7..bd2ef91fd 100644 --- a/src-tauri/locales/fa.yml +++ b/src-tauri/locales/fa.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/id.yml b/src-tauri/locales/id.yml index 587534e9c..1a095afc9 100644 --- a/src-tauri/locales/id.yml +++ b/src-tauri/locales/id.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/jp.yml b/src-tauri/locales/jp.yml index 4ed031a4a..c8bb59412 100644 --- a/src-tauri/locales/jp.yml +++ b/src-tauri/locales/jp.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/ko.yml b/src-tauri/locales/ko.yml index 51dccf885..ce4a45117 100644 --- a/src-tauri/locales/ko.yml +++ b/src-tauri/locales/ko.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: 경량 모드 body: 경량 모드에 진입했습니다. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: 곧 종료 body: Clash Verge가 곧 종료됩니다. diff --git a/src-tauri/locales/ru.yml b/src-tauri/locales/ru.yml index cff8fe27c..24cf7689b 100644 --- a/src-tauri/locales/ru.yml +++ b/src-tauri/locales/ru.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/tr.yml b/src-tauri/locales/tr.yml index f6ffb6895..3b1df8408 100644 --- a/src-tauri/locales/tr.yml +++ b/src-tauri/locales/tr.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/tt.yml b/src-tauri/locales/tt.yml index a054627f7..bd2ef91fd 100644 --- a/src-tauri/locales/tt.yml +++ b/src-tauri/locales/tt.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: Lightweight Mode body: Entered lightweight mode. + profilesReactivated: + title: Profiles + body: Profile Reactivated. appQuit: title: About to Exit body: Clash Verge is about to exit. diff --git a/src-tauri/locales/zh.yml b/src-tauri/locales/zh.yml index 6b137faeb..dd1fa4b53 100644 --- a/src-tauri/locales/zh.yml +++ b/src-tauri/locales/zh.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: 轻量模式 body: 已进入轻量模式。 + profilesReactivated: + title: 订阅 + body: 订阅已激活。 appQuit: title: 即将退出 body: Clash Verge 即将退出。 diff --git a/src-tauri/locales/zhtw.yml b/src-tauri/locales/zhtw.yml index 9e07ca714..aaeec6c91 100644 --- a/src-tauri/locales/zhtw.yml +++ b/src-tauri/locales/zhtw.yml @@ -15,6 +15,9 @@ notifications: lightweightModeEntered: title: 輕量模式 body: 已進入輕量模式。 + profilesReactivated: + title: 訂閱 + body: 訂閱已啟用。 appQuit: title: 即將退出 body: Clash Verge 即將退出。 diff --git a/src-tauri/src/cmd/profile.rs b/src-tauri/src/cmd/profile.rs index efb1095d3..37db0f3de 100644 --- a/src-tauri/src/cmd/profile.rs +++ b/src-tauri/src/cmd/profile.rs @@ -36,14 +36,29 @@ pub async fn get_profiles() -> CmdResult { #[tauri::command] pub async fn enhance_profiles() -> CmdResult { match feat::enhance_profiles().await { - Ok(_) => {} + Ok((true, _)) => { + handle::Handle::refresh_clash(); + Ok(()) + } + Ok((false, msg)) => { + let message: String = if msg.is_empty() { + "Failed to reactivate profiles".into() + } else { + msg + }; + logging!( + warn, + Type::Cmd, + "Reactivate profiles command failed validation: {}", + message.as_str() + ); + Err(message) + } Err(e) => { logging!(error, Type::Cmd, "{}", e); - return Err(e.to_string().into()); + Err(e.to_string().into()) } } - handle::Handle::refresh_clash(); - Ok(()) } /// 导入配置文件 diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index 6f7a52b3a..7423affa1 100755 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -21,6 +21,7 @@ pub enum HotkeyFunction { ToggleSystemProxy, ToggleTunMode, EntryLightweightMode, + ReactivateProfiles, Quit, #[cfg(target_os = "macos")] Hide, @@ -36,6 +37,7 @@ impl fmt::Display for HotkeyFunction { Self::ToggleSystemProxy => "toggle_system_proxy", Self::ToggleTunMode => "toggle_tun_mode", Self::EntryLightweightMode => "entry_lightweight_mode", + Self::ReactivateProfiles => "reactivate_profiles", Self::Quit => "quit", #[cfg(target_os = "macos")] Self::Hide => "hide", @@ -56,6 +58,7 @@ impl FromStr for HotkeyFunction { "toggle_system_proxy" => Ok(Self::ToggleSystemProxy), "toggle_tun_mode" => Ok(Self::ToggleTunMode), "entry_lightweight_mode" => Ok(Self::EntryLightweightMode), + "reactivate_profiles" => Ok(Self::ReactivateProfiles), "quit" => Ok(Self::Quit), #[cfg(target_os = "macos")] "hide" => Ok(Self::Hide), @@ -149,6 +152,40 @@ impl Hotkey { notify_event(NotificationEvent::LightweightModeEntered).await; }); } + HotkeyFunction::ReactivateProfiles => { + AsyncHandler::spawn(async move || match feat::enhance_profiles().await { + Ok((true, _)) => { + handle::Handle::refresh_clash(); + notify_event(NotificationEvent::ProfilesReactivated).await; + } + Ok((false, msg)) => { + let message = if msg.is_empty() { + "Failed to reactivate profiles.".to_string() + } else { + msg.to_string() + }; + logging!( + warn, + Type::Hotkey, + "Hotkey profile reactivation failed validation: {}", + message.as_str() + ); + handle::Handle::notice_message("reactivate_profiles::error", message); + } + Err(err) => { + logging!( + error, + Type::Hotkey, + "Failed to reactivate subscriptions via hotkey: {}", + err + ); + handle::Handle::notice_message( + "reactivate_profiles::error", + err.to_string(), + ); + } + }); + } HotkeyFunction::Quit => { AsyncHandler::spawn(async move || { notify_event(NotificationEvent::AppQuit).await; diff --git a/src-tauri/src/feat/profile.rs b/src-tauri/src/feat/profile.rs index c32e7cf22..6fc78ca6e 100644 --- a/src-tauri/src/feat/profile.rs +++ b/src-tauri/src/feat/profile.rs @@ -259,9 +259,6 @@ pub async fn update_profile( } /// 增强配置 -pub async fn enhance_profiles() -> Result<()> { - crate::core::CoreManager::global() - .update_config() - .await - .map(|_| ()) +pub async fn enhance_profiles() -> Result<(bool, String)> { + crate::core::CoreManager::global().update_config().await } diff --git a/src-tauri/src/utils/notification.rs b/src-tauri/src/utils/notification.rs index d7ff371a5..1308be6b6 100644 --- a/src-tauri/src/utils/notification.rs +++ b/src-tauri/src/utils/notification.rs @@ -9,6 +9,7 @@ pub enum NotificationEvent<'a> { SystemProxyToggled, TunModeToggled, LightweightModeEntered, + ProfilesReactivated, AppQuit, #[cfg(target_os = "macos")] AppHidden, @@ -54,6 +55,11 @@ pub async fn notify_event<'a>(event: NotificationEvent<'a>) { let body = rust_i18n::t!("notifications.lightweightModeEntered.body").to_string(); notify(&title, &body); } + NotificationEvent::ProfilesReactivated => { + let title = rust_i18n::t!("notifications.profilesReactivated.title").to_string(); + let body = rust_i18n::t!("notifications.profilesReactivated.body").to_string(); + notify(&title, &body); + } NotificationEvent::AppQuit => { let title = rust_i18n::t!("notifications.appQuit.title").to_string(); let body = rust_i18n::t!("notifications.appQuit.body").to_string(); diff --git a/src/components/setting/mods/hotkey-viewer.tsx b/src/components/setting/mods/hotkey-viewer.tsx index 574abea4b..8052bba1c 100644 --- a/src/components/setting/mods/hotkey-viewer.tsx +++ b/src/components/setting/mods/hotkey-viewer.tsx @@ -24,6 +24,7 @@ const HOTKEY_FUNC = [ "toggle_system_proxy", "toggle_tun_mode", "entry_lightweight_mode", + "reactivate_profiles", ] as const; const HOTKEY_FUNC_LABELS: Record<(typeof HOTKEY_FUNC)[number], string> = { @@ -36,6 +37,7 @@ const HOTKEY_FUNC_LABELS: Record<(typeof HOTKEY_FUNC)[number], string> = { toggle_tun_mode: "settings.modals.hotkey.functions.toggleTunMode", entry_lightweight_mode: "settings.modals.hotkey.functions.entryLightweightMode", + reactivate_profiles: "settings.modals.hotkey.functions.reactivateProfiles", }; export const HotkeyViewer = forwardRef((props, ref) => { diff --git a/src/locales/ar/settings.json b/src/locales/ar/settings.json index 6a9ffcac3..b59682e8c 100644 --- a/src/locales/ar/settings.json +++ b/src/locales/ar/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "تفعيل/تعطيل وكيل النظام", "toggleTunMode": "تفعيل/تعطيل وضع TUN", "entryLightweightMode": "Entry Lightweight Mode", - "direct": "الوضع المباشر" + "direct": "الوضع المباشر", + "reactivateProfiles": "إعادة تنشيط الملفات الشخصية" } }, "password": { diff --git a/src/locales/de/settings.json b/src/locales/de/settings.json index 1cfa4c01f..b50761ca1 100644 --- a/src/locales/de/settings.json +++ b/src/locales/de/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "Systemproxy ein/ausschalten", "toggleTunMode": "TUN-Modus ein/ausschalten", "entryLightweightMode": "Leichtgewichtigen Modus betreten", - "direct": "Direktverbindungs-Modus" + "direct": "Direktverbindungs-Modus", + "reactivateProfiles": "Abonnement erneut aktivieren" } }, "password": { diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json index 08cce1d21..5d9ea7155 100644 --- a/src/locales/en/settings.json +++ b/src/locales/en/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "Enable/Disable System Proxy", "toggleTunMode": "Enable/Disable Tun Mode", "entryLightweightMode": "Entry Lightweight Mode", - "direct": "Direct Mode" + "direct": "Direct Mode", + "reactivateProfiles": "Reactivate Profiles" } }, "password": { diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json index a687ed588..70ad7c282 100644 --- a/src/locales/es/settings.json +++ b/src/locales/es/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "Activar/desactivar el proxy del sistema", "toggleTunMode": "Activar/desactivar el modo TUN", "entryLightweightMode": "Entrar en modo ligero", - "direct": "Modo de conexión directa" + "direct": "Modo de conexión directa", + "reactivateProfiles": "Reactivar suscripciones" } }, "password": { diff --git a/src/locales/fa/settings.json b/src/locales/fa/settings.json index b99ec661e..7304ca881 100644 --- a/src/locales/fa/settings.json +++ b/src/locales/fa/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "فعال/غیرفعال کردن پراکسی سیستم", "toggleTunMode": "فعال/غیرفعال کردن حالت Tun", "entryLightweightMode": "Entry Lightweight Mode", - "direct": "حالت مستقیم" + "direct": "حالت مستقیم", + "reactivateProfiles": "فعال‌سازی مجدد پروفایل‌ها" } }, "password": { diff --git a/src/locales/id/settings.json b/src/locales/id/settings.json index abdf1bea5..53f7ca0f9 100644 --- a/src/locales/id/settings.json +++ b/src/locales/id/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "Aktifkan/Nonaktifkan Proksi Sistem", "toggleTunMode": "Aktifkan/Nonaktifkan Mode Tun", "entryLightweightMode": "Entry Lightweight Mode", - "direct": "Mode Langsung" + "direct": "Mode Langsung", + "reactivateProfiles": "Reaktivasi Profil" } }, "password": { diff --git a/src/locales/jp/settings.json b/src/locales/jp/settings.json index f02ec9b55..e7353fba0 100644 --- a/src/locales/jp/settings.json +++ b/src/locales/jp/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "システムプロキシを開く/閉じる", "toggleTunMode": "TUNモードを開く/閉じる", "entryLightweightMode": "軽量モードに入る", - "direct": "直接接続モード" + "direct": "直接接続モード", + "reactivateProfiles": "プロファイルを再アクティブ化" } }, "password": { diff --git a/src/locales/ko/settings.json b/src/locales/ko/settings.json index faa61a57c..8fb1f6945 100644 --- a/src/locales/ko/settings.json +++ b/src/locales/ko/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "시스템 프록시 켜기/끄기", "toggleTunMode": "TUN 모드 켜기/끄기", "entryLightweightMode": "경량 모드 진입", - "direct": "직접 모드" + "direct": "직접 모드", + "reactivateProfiles": "프로필 재활성화" } }, "password": { diff --git a/src/locales/ru/settings.json b/src/locales/ru/settings.json index 2a73cbf61..c0894de76 100644 --- a/src/locales/ru/settings.json +++ b/src/locales/ru/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "Включить/Отключить системный прокси", "toggleTunMode": "Включить/Отключить режим TUN", "entryLightweightMode": "Вход в LightWeight Mode", - "direct": "Прямой режим" + "direct": "Прямой режим", + "reactivateProfiles": "Перезапустить профиль" } }, "password": { diff --git a/src/locales/tr/settings.json b/src/locales/tr/settings.json index 2dee69253..f34d01ff4 100644 --- a/src/locales/tr/settings.json +++ b/src/locales/tr/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "Sistem Vekil'ini Etkinleştir/Devre Dışı Bırak", "toggleTunMode": "Tun Modunu Etkinleştir/Devre Dışı Bırak", "entryLightweightMode": "Hafif Moda Gir", - "direct": "Doğrudan Mod" + "direct": "Doğrudan Mod", + "reactivateProfiles": "Profilleri Yeniden Etkinleştir" } }, "password": { diff --git a/src/locales/tt/settings.json b/src/locales/tt/settings.json index 231779998..6a4d19904 100644 --- a/src/locales/tt/settings.json +++ b/src/locales/tt/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "Системалы проксины кабызу/сүндерү", "toggleTunMode": "Tun режимын кабызу/сүндерү", "entryLightweightMode": "Entry Lightweight Mode", - "direct": "Туры режим" + "direct": "Туры режим", + "reactivateProfiles": "Профильләрне янәдән активлаштыру" } }, "password": { diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json index 3677fe1cf..d14902e7d 100644 --- a/src/locales/zh/settings.json +++ b/src/locales/zh/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "打开/关闭系统代理", "toggleTunMode": "打开/关闭 TUN 模式", "entryLightweightMode": "进入轻量模式", - "direct": "直连模式" + "direct": "直连模式", + "reactivateProfiles": "重新激活订阅" } }, "password": { diff --git a/src/locales/zhtw/settings.json b/src/locales/zhtw/settings.json index d78440f29..4287abaad 100644 --- a/src/locales/zhtw/settings.json +++ b/src/locales/zhtw/settings.json @@ -553,7 +553,8 @@ "toggleSystemProxy": "開啟/關閉系統代理", "toggleTunMode": "開啟/關閉 虛擬網路介面卡模式", "entryLightweightMode": "進入輕量模式", - "direct": "直連模式" + "direct": "直連模式", + "reactivateProfiles": "重新啟用訂閱" } }, "password": { diff --git a/src/pages/_layout/notificationHandlers.ts b/src/pages/_layout/notificationHandlers.ts index 58631b8f3..29cda855b 100644 --- a/src/pages/_layout/notificationHandlers.ts +++ b/src/pages/_layout/notificationHandlers.ts @@ -34,6 +34,7 @@ export const handleNoticeMessage = ( "settings.feedback.notifications.updater.withClashProxyFailed", msg, ), + "reactivate_profiles::error": () => showNotice.error(msg), update_failed: () => showNotice.error(msg), "config_validate::boot_error": () => showNotice.error("shared.feedback.validation.config.bootFailed", msg), diff --git a/src/types/generated/i18n-keys.ts b/src/types/generated/i18n-keys.ts index 39722fe83..c100a1ae0 100644 --- a/src/types/generated/i18n-keys.ts +++ b/src/types/generated/i18n-keys.ts @@ -622,6 +622,7 @@ export const translationKeys = [ "settings.modals.hotkey.functions.toggleTunMode", "settings.modals.hotkey.functions.entryLightweightMode", "settings.modals.hotkey.functions.direct", + "settings.modals.hotkey.functions.reactivateProfiles", "settings.modals.password.prompts.enterRoot", "settings.modals.networkInterface.title", "settings.modals.networkInterface.fields.ipAddress", diff --git a/src/types/generated/i18n-resources.ts b/src/types/generated/i18n-resources.ts index d3d6b34c2..a9536452e 100644 --- a/src/types/generated/i18n-resources.ts +++ b/src/types/generated/i18n-resources.ts @@ -885,6 +885,7 @@ export interface TranslationResources { entryLightweightMode: string; global: string; openOrCloseDashboard: string; + reactivateProfiles: string; rule: string; toggleSystemProxy: string; toggleTunMode: string;