feat(hotkey): add global reactivate_profiles shortcut (#5527)

* feat(hotkey): add global reactivate_profiles shortcut

* feat(profile): expose validation state for reactivation shortcuts
This commit is contained in:
Sline
2025-11-19 17:06:23 +08:00
committed by GitHub
parent 94b07b51d6
commit f439e93a2b
34 changed files with 134 additions and 22 deletions

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -15,6 +15,9 @@ notifications:
lightweightModeEntered:
title: 경량 모드
body: 경량 모드에 진입했습니다.
profilesReactivated:
title: Profiles
body: Profile Reactivated.
appQuit:
title: 곧 종료
body: Clash Verge가 곧 종료됩니다.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -15,6 +15,9 @@ notifications:
lightweightModeEntered:
title: 轻量模式
body: 已进入轻量模式。
profilesReactivated:
title: 订阅
body: 订阅已激活。
appQuit:
title: 即将退出
body: Clash Verge 即将退出。

View File

@@ -15,6 +15,9 @@ notifications:
lightweightModeEntered:
title: 輕量模式
body: 已進入輕量模式。
profilesReactivated:
title: 訂閱
body: 訂閱已啟用。
appQuit:
title: 即將退出
body: Clash Verge 即將退出。

View File

@@ -36,14 +36,29 @@ pub async fn get_profiles() -> CmdResult<IProfiles> {
#[tauri::command]
pub async fn enhance_profiles() -> CmdResult {
match feat::enhance_profiles().await {
Ok(_) => {}
Err(e) => {
logging!(error, Type::Cmd, "{}", e);
return Err(e.to_string().into());
}
}
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);
Err(e.to_string().into())
}
}
}
/// 导入配置文件

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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();

View File

@@ -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<DialogRef>((props, ref) => {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "تفعيل/تعطيل وكيل النظام",
"toggleTunMode": "تفعيل/تعطيل وضع TUN",
"entryLightweightMode": "Entry Lightweight Mode",
"direct": "الوضع المباشر"
"direct": "الوضع المباشر",
"reactivateProfiles": "إعادة تنشيط الملفات الشخصية"
}
},
"password": {

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "فعال/غیرفعال کردن پراکسی سیستم",
"toggleTunMode": "فعال/غیرفعال کردن حالت Tun",
"entryLightweightMode": "Entry Lightweight Mode",
"direct": "حالت مستقیم"
"direct": "حالت مستقیم",
"reactivateProfiles": "فعال‌سازی مجدد پروفایل‌ها"
}
},
"password": {

View File

@@ -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": {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "システムプロキシを開く/閉じる",
"toggleTunMode": "TUNモードを開く/閉じる",
"entryLightweightMode": "軽量モードに入る",
"direct": "直接接続モード"
"direct": "直接接続モード",
"reactivateProfiles": "プロファイルを再アクティブ化"
}
},
"password": {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "시스템 프록시 켜기/끄기",
"toggleTunMode": "TUN 모드 켜기/끄기",
"entryLightweightMode": "경량 모드 진입",
"direct": "직접 모드"
"direct": "직접 모드",
"reactivateProfiles": "프로필 재활성화"
}
},
"password": {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "Включить/Отключить системный прокси",
"toggleTunMode": "Включить/Отключить режим TUN",
"entryLightweightMode": "Вход в LightWeight Mode",
"direct": "Прямой режим"
"direct": "Прямой режим",
"reactivateProfiles": "Перезапустить профиль"
}
},
"password": {

View File

@@ -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": {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "Системалы проксины кабызу/сүндерү",
"toggleTunMode": "Tun режимын кабызу/сүндерү",
"entryLightweightMode": "Entry Lightweight Mode",
"direct": "Туры режим"
"direct": "Туры режим",
"reactivateProfiles": "Профильләрне янәдән активлаштыру"
}
},
"password": {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "打开/关闭系统代理",
"toggleTunMode": "打开/关闭 TUN 模式",
"entryLightweightMode": "进入轻量模式",
"direct": "直连模式"
"direct": "直连模式",
"reactivateProfiles": "重新激活订阅"
}
},
"password": {

View File

@@ -553,7 +553,8 @@
"toggleSystemProxy": "開啟/關閉系統代理",
"toggleTunMode": "開啟/關閉 虛擬網路介面卡模式",
"entryLightweightMode": "進入輕量模式",
"direct": "直連模式"
"direct": "直連模式",
"reactivateProfiles": "重新啟用訂閱"
}
},
"password": {

View File

@@ -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),

View File

@@ -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",

View File

@@ -885,6 +885,7 @@ export interface TranslationResources {
entryLightweightMode: string;
global: string;
openOrCloseDashboard: string;
reactivateProfiles: string;
rule: string;
toggleSystemProxy: string;
toggleTunMode: string;