mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 08:45:41 +08:00
fix: disable tun mode menu on tray when tun mode is unavailable (#4975)
* fix: check if service installed when toggle tun mode on tray * chore: cargo fmt * fix: auto disable tun mode * docs: update UPDATELOG.md * fix: init Tun mode status * chore: update * feat: disable tun mode tray menu when tun mode is unavailable * fix: restart core when uninstall service is canceled * chore: remove check notification when toggle tun mode * chore: fix updatelog --------- Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
use super::{IClashTemp, IProfiles, IRuntime, IVerge};
|
||||
use crate::{
|
||||
cmd,
|
||||
config::{PrfItem, profiles_append_item_safe},
|
||||
constants::{files, timing},
|
||||
core::{CoreManager, handle, validate::CoreConfigValidator},
|
||||
enhance, logging,
|
||||
core::{CoreManager, handle, service, tray, validate::CoreConfigValidator},
|
||||
enhance, logging, logging_error,
|
||||
utils::{Draft, dirs, help, logging::Type},
|
||||
};
|
||||
use anyhow::{Result, anyhow};
|
||||
@@ -55,6 +56,20 @@ impl Config {
|
||||
pub async fn init_config() -> Result<()> {
|
||||
Self::ensure_default_profile_items().await?;
|
||||
|
||||
// init Tun mode
|
||||
if !cmd::system::is_admin().unwrap_or_default()
|
||||
&& service::is_service_available().await.is_err()
|
||||
{
|
||||
let verge = Config::verge().await;
|
||||
verge.draft_mut().enable_tun_mode = Some(false);
|
||||
verge.apply();
|
||||
let _ = tray::Tray::global().update_tray_display().await;
|
||||
|
||||
// 分离数据获取和异步调用避免Send问题
|
||||
let verge_data = Config::verge().await.latest_ref().clone();
|
||||
logging_error!(Type::Core, verge_data.save_file().await);
|
||||
}
|
||||
|
||||
let validation_result = Self::generate_and_validate().await?;
|
||||
|
||||
if let Some((msg_type, msg_content)) = validation_result {
|
||||
|
||||
@@ -8,7 +8,6 @@ use anyhow::{Result, bail};
|
||||
use parking_lot::Mutex;
|
||||
use smartstring::alias::String;
|
||||
use std::{collections::HashMap, fmt, str::FromStr, sync::Arc};
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, ShortcutState};
|
||||
|
||||
/// Enum representing all available hotkey functions
|
||||
@@ -105,66 +104,53 @@ impl Hotkey {
|
||||
}
|
||||
|
||||
/// Execute the function associated with a hotkey function enum
|
||||
fn execute_function(function: HotkeyFunction, app_handle: &AppHandle) {
|
||||
let app_handle = app_handle.clone();
|
||||
fn execute_function(function: HotkeyFunction) {
|
||||
match function {
|
||||
HotkeyFunction::OpenOrCloseDashboard => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
crate::feat::open_or_close_dashboard().await;
|
||||
notify_event(app_handle, NotificationEvent::DashboardToggled).await;
|
||||
notify_event(NotificationEvent::DashboardToggled).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::ClashModeRule => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::change_clash_mode("rule".into()).await;
|
||||
notify_event(
|
||||
app_handle,
|
||||
NotificationEvent::ClashModeChanged { mode: "Rule" },
|
||||
)
|
||||
.await;
|
||||
notify_event(NotificationEvent::ClashModeChanged { mode: "Rule" }).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::ClashModeGlobal => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::change_clash_mode("global".into()).await;
|
||||
notify_event(
|
||||
app_handle,
|
||||
NotificationEvent::ClashModeChanged { mode: "Global" },
|
||||
)
|
||||
.await;
|
||||
notify_event(NotificationEvent::ClashModeChanged { mode: "Global" }).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::ClashModeDirect => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::change_clash_mode("direct".into()).await;
|
||||
notify_event(
|
||||
app_handle,
|
||||
NotificationEvent::ClashModeChanged { mode: "Direct" },
|
||||
)
|
||||
.await;
|
||||
notify_event(NotificationEvent::ClashModeChanged { mode: "Direct" }).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::ToggleSystemProxy => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::toggle_system_proxy().await;
|
||||
notify_event(app_handle, NotificationEvent::SystemProxyToggled).await;
|
||||
notify_event(NotificationEvent::SystemProxyToggled).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::ToggleTunMode => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::toggle_tun_mode(None).await;
|
||||
notify_event(app_handle, NotificationEvent::TunModeToggled).await;
|
||||
notify_event(NotificationEvent::TunModeToggled).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::EntryLightweightMode => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
entry_lightweight_mode().await;
|
||||
notify_event(app_handle, NotificationEvent::LightweightModeEntered).await;
|
||||
notify_event(NotificationEvent::LightweightModeEntered).await;
|
||||
});
|
||||
}
|
||||
HotkeyFunction::Quit => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
notify_event(app_handle, NotificationEvent::AppQuit).await;
|
||||
notify_event(NotificationEvent::AppQuit).await;
|
||||
feat::quit().await;
|
||||
});
|
||||
}
|
||||
@@ -172,7 +158,7 @@ impl Hotkey {
|
||||
HotkeyFunction::Hide => {
|
||||
AsyncHandler::spawn(async move || {
|
||||
feat::hide().await;
|
||||
notify_event(app_handle, NotificationEvent::AppHidden).await;
|
||||
notify_event(NotificationEvent::AppHidden).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -224,14 +210,12 @@ impl Hotkey {
|
||||
|
||||
let is_quit = matches!(function, HotkeyFunction::Quit);
|
||||
|
||||
manager.on_shortcut(hotkey, move |app_handle, hotkey_event, event| {
|
||||
manager.on_shortcut(hotkey, move |_app_handle, hotkey_event, event| {
|
||||
let hotkey_event_owned = *hotkey_event;
|
||||
let event_owned = event;
|
||||
let function_owned = function;
|
||||
let is_quit_owned = is_quit;
|
||||
|
||||
let app_handle_cloned = app_handle.clone();
|
||||
|
||||
AsyncHandler::spawn(move || async move {
|
||||
if event_owned.state == ShortcutState::Pressed {
|
||||
logging!(
|
||||
@@ -242,11 +226,11 @@ impl Hotkey {
|
||||
);
|
||||
|
||||
if hotkey_event_owned.key == Code::KeyQ && is_quit_owned {
|
||||
if let Some(window) = app_handle_cloned.get_webview_window("main")
|
||||
if let Some(window) = handle::Handle::get_window()
|
||||
&& window.is_focused().unwrap_or(false)
|
||||
{
|
||||
logging!(debug, Type::Hotkey, "Executing quit function");
|
||||
Self::execute_function(function_owned, &app_handle_cloned);
|
||||
Self::execute_function(function_owned);
|
||||
}
|
||||
} else {
|
||||
logging!(debug, Type::Hotkey, "Executing function directly");
|
||||
@@ -258,14 +242,14 @@ impl Hotkey {
|
||||
.unwrap_or(true);
|
||||
|
||||
if is_enable_global_hotkey {
|
||||
Self::execute_function(function_owned, &app_handle_cloned);
|
||||
Self::execute_function(function_owned);
|
||||
} else {
|
||||
use crate::utils::window_manager::WindowManager;
|
||||
let is_visible = WindowManager::is_main_window_visible();
|
||||
let is_focused = WindowManager::is_main_window_focused();
|
||||
|
||||
if is_focused && is_visible {
|
||||
Self::execute_function(function_owned, &app_handle_cloned);
|
||||
Self::execute_function(function_owned);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::tray,
|
||||
logging, logging_error,
|
||||
utils::{dirs, init::service_writer_config, logging::Type},
|
||||
};
|
||||
@@ -531,6 +532,7 @@ impl ServiceManager {
|
||||
return Err(anyhow::anyhow!("服务不可用: {}", reason));
|
||||
}
|
||||
}
|
||||
let _ = tray::Tray::global().update_tray_display().await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use tauri_plugin_mihomo::models::Proxies;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod speed_rate;
|
||||
use crate::config::PrfSelected;
|
||||
use crate::core::service;
|
||||
use crate::module::lightweight;
|
||||
use crate::process::AsyncHandler;
|
||||
use crate::utils::window_manager::WindowManager;
|
||||
@@ -297,6 +298,9 @@ impl Tray {
|
||||
let verge = Config::verge().await.latest_ref().clone();
|
||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||
let tun_mode_available = cmd::system::is_admin().unwrap_or_default()
|
||||
|| service::is_service_available().await.is_ok();
|
||||
println!("tun_mode_available: {}", tun_mode_available);
|
||||
let mode = {
|
||||
Config::clash()
|
||||
.await
|
||||
@@ -322,6 +326,7 @@ impl Tray {
|
||||
Some(mode.as_str()),
|
||||
*system_proxy,
|
||||
*tun_mode,
|
||||
tun_mode_available,
|
||||
profile_uid_and_name,
|
||||
is_lightweight_mode,
|
||||
)
|
||||
@@ -837,6 +842,7 @@ async fn create_tray_menu(
|
||||
mode: Option<&str>,
|
||||
system_proxy_enabled: bool,
|
||||
tun_mode_enabled: bool,
|
||||
tun_mode_available: bool,
|
||||
profile_uid_and_name: Vec<(String, String)>,
|
||||
is_lightweight_mode: bool,
|
||||
) -> Result<tauri::menu::Menu<Wry>> {
|
||||
@@ -980,7 +986,7 @@ async fn create_tray_menu(
|
||||
app_handle,
|
||||
MenuIds::TUN_MODE,
|
||||
&texts.tun_mode,
|
||||
true,
|
||||
tun_mode_available,
|
||||
tun_mode_enabled,
|
||||
hotkeys.get("toggle_tun_mode").map(|s| s.as_str()),
|
||||
)?;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::utils::i18n::t;
|
||||
use crate::{core::handle, utils::i18n::t};
|
||||
|
||||
use tauri::AppHandle;
|
||||
use tauri_plugin_notification::NotificationExt;
|
||||
|
||||
pub enum NotificationEvent<'a> {
|
||||
@@ -16,8 +15,10 @@ pub enum NotificationEvent<'a> {
|
||||
AppHidden,
|
||||
}
|
||||
|
||||
fn notify(app: &AppHandle, title: &str, body: &str) {
|
||||
app.notification()
|
||||
fn notify(title: &str, body: &str) {
|
||||
let app_handle = handle::Handle::app_handle();
|
||||
app_handle
|
||||
.notification()
|
||||
.builder()
|
||||
.title(title)
|
||||
.body(body)
|
||||
@@ -25,49 +26,44 @@ fn notify(app: &AppHandle, title: &str, body: &str) {
|
||||
.ok();
|
||||
}
|
||||
|
||||
pub async fn notify_event<'a>(app: AppHandle, event: NotificationEvent<'a>) {
|
||||
pub async fn notify_event<'a>(event: NotificationEvent<'a>) {
|
||||
match event {
|
||||
NotificationEvent::DashboardToggled => {
|
||||
notify(
|
||||
&app,
|
||||
&t("DashboardToggledTitle").await,
|
||||
&t("DashboardToggledBody").await,
|
||||
);
|
||||
}
|
||||
NotificationEvent::ClashModeChanged { mode } => {
|
||||
notify(
|
||||
&app,
|
||||
&t("ClashModeChangedTitle").await,
|
||||
&t_with_args("ClashModeChangedBody", mode).await,
|
||||
);
|
||||
}
|
||||
NotificationEvent::SystemProxyToggled => {
|
||||
notify(
|
||||
&app,
|
||||
&t("SystemProxyToggledTitle").await,
|
||||
&t("SystemProxyToggledBody").await,
|
||||
);
|
||||
}
|
||||
NotificationEvent::TunModeToggled => {
|
||||
notify(
|
||||
&app,
|
||||
&t("TunModeToggledTitle").await,
|
||||
&t("TunModeToggledBody").await,
|
||||
);
|
||||
}
|
||||
NotificationEvent::LightweightModeEntered => {
|
||||
notify(
|
||||
&app,
|
||||
&t("LightweightModeEnteredTitle").await,
|
||||
&t("LightweightModeEnteredBody").await,
|
||||
);
|
||||
}
|
||||
NotificationEvent::AppQuit => {
|
||||
notify(&app, &t("AppQuitTitle").await, &t("AppQuitBody").await);
|
||||
notify(&t("AppQuitTitle").await, &t("AppQuitBody").await);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
NotificationEvent::AppHidden => {
|
||||
notify(&app, &t("AppHiddenTitle").await, &t("AppHiddenBody").await);
|
||||
notify(&t("AppHiddenTitle").await, &t("AppHiddenBody").await);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user