Compare commits
2 Commits
chore/i18n
...
dev
@@ -211,28 +211,18 @@ impl Hotkey {
|
|||||||
let is_quit = matches!(function, HotkeyFunction::Quit);
|
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;
|
if event.state == ShortcutState::Pressed {
|
||||||
let event_owned = event;
|
logging!(debug, Type::Hotkey, "Hotkey pressed: {:?}", hotkey_event);
|
||||||
let function_owned = function;
|
let hotkey = hotkey_event.key;
|
||||||
let is_quit_owned = is_quit;
|
if hotkey == Code::KeyQ && is_quit {
|
||||||
|
if let Some(window) = handle::Handle::get_window()
|
||||||
AsyncHandler::spawn(move || async move {
|
&& window.is_focused().unwrap_or(false)
|
||||||
if event_owned.state == ShortcutState::Pressed {
|
{
|
||||||
logging!(
|
logging!(debug, Type::Hotkey, "Executing quit function");
|
||||||
debug,
|
Self::execute_function(function);
|
||||||
Type::Hotkey,
|
}
|
||||||
"Hotkey pressed: {:?}",
|
} else {
|
||||||
hotkey_event_owned
|
AsyncHandler::spawn(move || async move {
|
||||||
);
|
|
||||||
|
|
||||||
if hotkey_event_owned.key == Code::KeyQ && is_quit_owned {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logging!(debug, Type::Hotkey, "Executing function directly");
|
logging!(debug, Type::Hotkey, "Executing function directly");
|
||||||
|
|
||||||
let is_enable_global_hotkey = Config::verge()
|
let is_enable_global_hotkey = Config::verge()
|
||||||
@@ -242,19 +232,19 @@ impl Hotkey {
|
|||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
|
|
||||||
if is_enable_global_hotkey {
|
if is_enable_global_hotkey {
|
||||||
Self::execute_function(function_owned);
|
Self::execute_function(function);
|
||||||
} else {
|
} else {
|
||||||
use crate::utils::window_manager::WindowManager;
|
use crate::utils::window_manager::WindowManager;
|
||||||
let is_visible = WindowManager::is_main_window_visible();
|
let is_visible = WindowManager::is_main_window_visible();
|
||||||
let is_focused = WindowManager::is_main_window_focused();
|
let is_focused = WindowManager::is_main_window_focused();
|
||||||
|
|
||||||
if is_focused && is_visible {
|
if is_focused && is_visible {
|
||||||
Self::execute_function(function_owned);
|
Self::execute_function(function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use std::{
|
|||||||
mpsc,
|
mpsc,
|
||||||
},
|
},
|
||||||
thread,
|
thread,
|
||||||
time::Instant,
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use tauri::{Emitter, WebviewWindow};
|
use tauri::{Emitter, WebviewWindow};
|
||||||
|
|
||||||
@@ -92,12 +92,15 @@ impl NotificationSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn worker_loop(rx: mpsc::Receiver<FrontendEvent>) {
|
fn worker_loop(rx: mpsc::Receiver<FrontendEvent>) {
|
||||||
let handle = Handle::global();
|
loop {
|
||||||
while !handle.is_exiting() {
|
let handle = Handle::global();
|
||||||
match rx.try_recv() {
|
if handle.is_exiting() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
match rx.recv_timeout(Duration::from_millis(1_000)) {
|
||||||
Ok(event) => Self::process_event(handle, event),
|
Ok(event) => Self::process_event(handle, event),
|
||||||
Err(mpsc::TryRecvError::Disconnected) => break,
|
Err(mpsc::RecvTimeoutError::Timeout) => (),
|
||||||
Err(mpsc::TryRecvError::Empty) => break,
|
Err(mpsc::RecvTimeoutError::Disconnected) => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ use futures::future::join_all;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::future::Future;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{
|
use std::{
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
@@ -550,49 +548,34 @@ impl Tray {
|
|||||||
let tray = builder.build(app_handle)?;
|
let tray = builder.build(app_handle)?;
|
||||||
|
|
||||||
tray.on_tray_icon_event(|_app_handle, event| {
|
tray.on_tray_icon_event(|_app_handle, event| {
|
||||||
// 忽略移动、进入和离开等无需处理的事件,避免不必要的刷新
|
if let TrayIconEvent::Click {
|
||||||
match event {
|
button: MouseButton::Left,
|
||||||
TrayIconEvent::Move { .. }
|
button_state: MouseButtonState::Down,
|
||||||
| TrayIconEvent::Enter { .. }
|
..
|
||||||
| TrayIconEvent::Leave { .. } => {
|
} = event
|
||||||
return;
|
{
|
||||||
}
|
AsyncHandler::spawn(|| async move {
|
||||||
_ => {}
|
let tray_event = { Config::verge().await.latest_arc().tray_event.clone() };
|
||||||
}
|
let tray_event: String = tray_event.unwrap_or_else(|| "main_window".into());
|
||||||
|
logging!(debug, Type::Tray, "tray event: {tray_event:?}");
|
||||||
|
|
||||||
AsyncHandler::spawn(|| async move {
|
|
||||||
let tray_event = { Config::verge().await.latest_arc().tray_event.clone() };
|
|
||||||
let tray_event: String = tray_event.unwrap_or_else(|| "main_window".into());
|
|
||||||
logging!(debug, Type::Tray, "tray event: {tray_event:?}");
|
|
||||||
|
|
||||||
if let TrayIconEvent::Click {
|
|
||||||
button: MouseButton::Left,
|
|
||||||
button_state: MouseButtonState::Down,
|
|
||||||
..
|
|
||||||
} = event
|
|
||||||
{
|
|
||||||
// 添加防抖检查,防止快速连击
|
// 添加防抖检查,防止快速连击
|
||||||
if !should_handle_tray_click() {
|
if !should_handle_tray_click() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fut: Pin<Box<dyn Future<Output = ()> + Send>> = match tray_event.as_str() {
|
match tray_event.as_str() {
|
||||||
"system_proxy" => Box::pin(async move {
|
"system_proxy" => feat::toggle_system_proxy().await,
|
||||||
feat::toggle_system_proxy().await;
|
"tun_mode" => feat::toggle_tun_mode(None).await,
|
||||||
}),
|
"main_window" => {
|
||||||
"tun_mode" => Box::pin(async move {
|
|
||||||
feat::toggle_tun_mode(None).await;
|
|
||||||
}),
|
|
||||||
"main_window" => Box::pin(async move {
|
|
||||||
if !lightweight::exit_lightweight_mode().await {
|
if !lightweight::exit_lightweight_mode().await {
|
||||||
WindowManager::show_main_window().await;
|
WindowManager::show_main_window().await;
|
||||||
};
|
};
|
||||||
}),
|
}
|
||||||
_ => Box::pin(async move {}),
|
_ => {}
|
||||||
};
|
};
|
||||||
fut.await;
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
tray.on_menu_event(on_menu_event);
|
tray.on_menu_event(on_menu_event);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use percent_encoding::percent_decode_str;
|
use percent_encoding::percent_decode_str;
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
@@ -73,24 +75,23 @@ pub(super) async fn resolve_scheme(param: &str) -> Result<()> {
|
|||||||
"failed to parse profile from url: {:?}",
|
"failed to parse profile from url: {:?}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
// TODO 通知系统疑似损坏,前端无法显示通知事件
|
|
||||||
handle::Handle::notice_message("import_sub_url::error", e.to_string());
|
handle::Handle::notice_message("import_sub_url::error", e.to_string());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let uid = item.uid.clone().unwrap_or_default();
|
let uid = item.uid.clone().unwrap_or_default();
|
||||||
// TODO 通过 deep link 导入后需要正确调用前端刷新订阅页面,以及通知结果
|
|
||||||
match profiles::profiles_append_item_safe(&mut item).await {
|
match profiles::profiles_append_item_safe(&mut item).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
Config::profiles().await.apply();
|
Config::profiles().await.apply();
|
||||||
let _ = Config::profiles().await.data_arc().save_file().await;
|
let _ = Config::profiles().await.data_arc().save_file().await;
|
||||||
// TODO 通知系统疑似损坏,前端无法显示通知事件
|
|
||||||
handle::Handle::notice_message(
|
handle::Handle::notice_message(
|
||||||
"import_sub_url::ok",
|
"import_sub_url::ok",
|
||||||
item.uid.clone().unwrap_or_default(),
|
"", // 空 msg 传入,我们不希望导致 后端-前端-后端 死循环,这里只做提醒。
|
||||||
);
|
);
|
||||||
// TODO fuck me this shit is fucking broken as fucked
|
handle::Handle::refresh_verge();
|
||||||
|
handle::Handle::notify_profile_changed(uid.clone());
|
||||||
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||||
handle::Handle::notify_profile_changed(uid);
|
handle::Handle::notify_profile_changed(uid);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -101,14 +102,10 @@ pub(super) async fn resolve_scheme(param: &str) -> Result<()> {
|
|||||||
e
|
e
|
||||||
);
|
);
|
||||||
Config::profiles().await.discard();
|
Config::profiles().await.discard();
|
||||||
// TODO 通知系统疑似损坏,前端无法显示通知事件
|
|
||||||
handle::Handle::notice_message("import_sub_url::error", e.to_string());
|
handle::Handle::notice_message("import_sub_url::error", e.to_string());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handle::Handle::refresh_verge();
|
|
||||||
handle::Handle::refresh_clash();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ export const handleNoticeMessage = (
|
|||||||
) => {
|
) => {
|
||||||
const handlers: Record<string, () => void> = {
|
const handlers: Record<string, () => void> = {
|
||||||
"import_sub_url::ok": () => {
|
"import_sub_url::ok": () => {
|
||||||
navigate("/profile", { state: { current: msg } });
|
// 空 msg 传入,我们不希望导致 后端-前端-后端 死循环,这里只做提醒。
|
||||||
|
// 未来细分事件通知时,可以考虑传入订阅 ID 或其他标识符
|
||||||
|
// navigate("/profile", { state: { current: msg } });
|
||||||
|
navigate("/profile");
|
||||||
showNotice("success", t("Import Subscription Successful"));
|
showNotice("success", t("Import Subscription Successful"));
|
||||||
},
|
},
|
||||||
"import_sub_url::error": () => {
|
"import_sub_url::error": () => {
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import {
|
|||||||
sortableKeyboardCoordinates,
|
sortableKeyboardCoordinates,
|
||||||
} from "@dnd-kit/sortable";
|
} from "@dnd-kit/sortable";
|
||||||
import {
|
import {
|
||||||
|
CheckBoxOutlineBlankRounded,
|
||||||
|
CheckBoxRounded,
|
||||||
ClearRounded,
|
ClearRounded,
|
||||||
ContentPasteRounded,
|
ContentPasteRounded,
|
||||||
|
DeleteRounded,
|
||||||
|
IndeterminateCheckBoxRounded,
|
||||||
LocalFireDepartmentRounded,
|
LocalFireDepartmentRounded,
|
||||||
RefreshRounded,
|
RefreshRounded,
|
||||||
TextSnippetOutlined,
|
TextSnippetOutlined,
|
||||||
CheckBoxOutlineBlankRounded,
|
|
||||||
CheckBoxRounded,
|
|
||||||
IndeterminateCheckBoxRounded,
|
|
||||||
DeleteRounded,
|
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { LoadingButton } from "@mui/lab";
|
import { LoadingButton } from "@mui/lab";
|
||||||
import { Box, Button, Divider, Grid, IconButton, Stack } from "@mui/material";
|
import { Box, Button, Divider, Grid, IconButton, Stack } from "@mui/material";
|
||||||
|
|||||||
Reference in New Issue
Block a user