From c2852c8a824968de0321212b51ed919fb523fbd9 Mon Sep 17 00:00:00 2001 From: MystiPanda Date: Sat, 24 Feb 2024 11:25:22 +0800 Subject: [PATCH] refactor: Optimize implementation of Custom tray icon --- src-tauri/Cargo.toml | 2 +- src-tauri/src/cmds.rs | 27 +++++++ src-tauri/src/config/verge.rs | 8 +- src-tauri/src/core/tray.rs | 25 ++++--- src-tauri/src/main.rs | 2 + src-tauri/tauri.conf.json | 3 + src/components/setting/mods/layout-viewer.tsx | 73 +++++++++++-------- src/services/cmds.ts | 11 +++ src/services/types.d.ts | 6 +- 9 files changed, 111 insertions(+), 46 deletions(-) diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3eab4967..4df54ac1 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -39,7 +39,7 @@ serde = { version = "1.0", features = ["derive"] } reqwest = { version = "0.11", features = ["json", "rustls-tls"] } sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" } auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" } -tauri = { version = "1.5", features = [ "protocol-asset", "dialog-open", "notification-all", "icon-png", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] } +tauri = { version = "1.5", features = [ "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] } [target.'cfg(windows)'.dependencies] runas = "=1.0.0" # 高版本会返回错误 Status diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 91e3a26e..e7b106ad 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -267,6 +267,33 @@ pub async fn test_delay(url: String) -> CmdResult { Ok(feat::test_delay(url).await.unwrap_or(10000u32)) } +#[tauri::command] +pub fn get_app_dir() -> CmdResult { + let app_home_dir = wrap_err!(dirs::app_home_dir())? + .to_string_lossy() + .to_string(); + Ok(app_home_dir) +} + +#[tauri::command] +pub fn copy_icon_file(path: String, name: String) -> CmdResult { + let file_path = std::path::Path::new(&path); + let icon_dir = wrap_err!(dirs::app_home_dir())?.join("icons"); + if !icon_dir.exists() { + let _ = std::fs::create_dir_all(&icon_dir); + } + let dest_path = icon_dir.join(name); + + if file_path.exists() { + match std::fs::copy(file_path, &dest_path) { + Ok(_) => Ok(dest_path.to_string_lossy().to_string()), + Err(err) => Err(err.to_string()), + } + } else { + return Err("file not found".to_string()); + } +} + #[tauri::command] pub fn exit_app(app_handle: tauri::AppHandle) { let _ = resolve::save_window_size_position(&app_handle, true); diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index 88995529..7c1a32dc 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -37,11 +37,13 @@ pub struct IVerge { pub enable_memory_usage: Option, /// common tray icon - pub common_tray_icon: Option, + pub common_tray_icon: Option, - pub sysproxy_tray_icon: Option, + /// sysproxy tray icon + pub sysproxy_tray_icon: Option, - pub tun_tray_icon: Option, + /// tun tray icon + pub tun_tray_icon: Option, /// clash tun mode pub enable_tun_mode: Option, diff --git a/src-tauri/src/core/tray.rs b/src-tauri/src/core/tray.rs index aeb74f7a..dc8e9f18 100644 --- a/src-tauri/src/core/tray.rs +++ b/src-tauri/src/core/tray.rs @@ -1,4 +1,9 @@ -use crate::{cmds, config::Config, feat, utils::resolve}; +use crate::{ + cmds, + config::Config, + feat, + utils::{dirs, resolve}, +}; use anyhow::Result; use tauri::{ api, AppHandle, CustomMenuItem, Manager, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, @@ -129,17 +134,17 @@ impl Tray { let verge = verge.latest(); 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 common_tray_icon = verge.common_tray_icon.clone().unwrap_or("".to_string()); - let sysproxy_tray_icon = verge.sysproxy_tray_icon.clone().unwrap_or("".to_string()); - let tun_tray_icon = verge.tun_tray_icon.clone().unwrap_or("".to_string()); + let common_tray_icon = verge.common_tray_icon.as_ref().unwrap_or(&false); + let sysproxy_tray_icon = verge.sysproxy_tray_icon.as_ref().unwrap_or(&false); + let tun_tray_icon = verge.tun_tray_icon.as_ref().unwrap_or(&false); let mut indication_icon = if *system_proxy { #[cfg(not(target_os = "macos"))] let mut icon = include_bytes!("../../icons/tray-icon-sys.png").to_vec(); #[cfg(target_os = "macos")] let mut icon = include_bytes!("../../icons/mac-tray-icon-sys.png").to_vec(); - if !sysproxy_tray_icon.is_empty() { - let path = std::path::Path::new(&sysproxy_tray_icon); + if *sysproxy_tray_icon { + let path = dirs::app_home_dir()?.join("icons").join("sysproxy.png"); if path.exists() { icon = std::fs::read(path).unwrap(); } @@ -150,8 +155,8 @@ impl Tray { let mut icon = include_bytes!("../../icons/tray-icon.png").to_vec(); #[cfg(target_os = "macos")] let mut icon = include_bytes!("../../icons/mac-tray-icon.png").to_vec(); - if !common_tray_icon.is_empty() { - let path = std::path::Path::new(&common_tray_icon); + if *common_tray_icon { + let path = dirs::app_home_dir()?.join("icons").join("common.png"); if path.exists() { icon = std::fs::read(path).unwrap(); } @@ -164,8 +169,8 @@ impl Tray { let mut icon = include_bytes!("../../icons/tray-icon-tun.png").to_vec(); #[cfg(target_os = "macos")] let mut icon = include_bytes!("../../icons/mac-tray-icon-tun.png").to_vec(); - if !tun_tray_icon.is_empty() { - let path = std::path::Path::new(&tun_tray_icon); + if *tun_tray_icon { + let path = dirs::app_home_dir()?.join("icons").join("tun.png"); if path.exists() { icon = std::fs::read(path).unwrap(); } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 8256f9da..4ea83ba1 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -55,6 +55,8 @@ fn main() -> std::io::Result<()> { cmds::get_verge_config, cmds::patch_verge_config, cmds::test_delay, + cmds::get_app_dir, + cmds::copy_icon_file, cmds::exit_app, // cmds::update_hotkeys, // profile diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 86ef23ec..ae042c4d 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -62,6 +62,9 @@ "protocol": { "asset": true, "assetScope": ["**"] + }, + "path": { + "all": true } }, "windows": [], diff --git a/src/components/setting/mods/layout-viewer.tsx b/src/components/setting/mods/layout-viewer.tsx index e97cc184..c3cd0ba0 100644 --- a/src/components/setting/mods/layout-viewer.tsx +++ b/src/components/setting/mods/layout-viewer.tsx @@ -1,4 +1,4 @@ -import { forwardRef, useImperativeHandle, useState } from "react"; +import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; import { useTranslation } from "react-i18next"; import { List, Switch, Button } from "@mui/material"; import { useVerge } from "@/hooks/use-verge"; @@ -7,12 +7,32 @@ import { SettingItem } from "./setting-comp"; import { GuardState } from "./guard-state"; import { open as openDialog } from "@tauri-apps/api/dialog"; import { convertFileSrc } from "@tauri-apps/api/tauri"; +import { copyIconFile, getAppDir } from "@/services/cmds"; +import { join } from "@tauri-apps/api/path"; export const LayoutViewer = forwardRef((props, ref) => { const { t } = useTranslation(); const { verge, patchVerge, mutateVerge } = useVerge(); const [open, setOpen] = useState(false); + const [commonIcon, setCommonIcon] = useState(""); + const [sysproxyIcon, setSysproxyIcon] = useState(""); + const [tunIcon, setTunIcon] = useState(""); + + useEffect(() => { + initIconPath(); + }, []); + + async function initIconPath() { + const appDir = await getAppDir(); + const icon_dir = await join(appDir, "icons"); + const common_icon = await join(icon_dir, "common.png"); + const sysproxy_icon = await join(icon_dir, "sysproxy.png"); + const tun_icon = await join(icon_dir, "tun.png"); + setCommonIcon(common_icon); + setSysproxyIcon(sysproxy_icon); + setTunIcon(tun_icon); + } useImperativeHandle(ref, () => ({ open: () => setOpen(true), @@ -75,17 +95,15 @@ export const LayoutViewer = forwardRef((props, ref) => { variant="outlined" size="small" startIcon={ - verge?.common_tray_icon && ( - + verge?.common_tray_icon && + commonIcon && ( + ) } onClick={async () => { if (verge?.common_tray_icon) { - onChangeData({ common_tray_icon: "" }); - patchVerge({ common_tray_icon: "" }); + onChangeData({ common_tray_icon: false }); + patchVerge({ common_tray_icon: false }); } else { const path = await openDialog({ directory: false, @@ -98,8 +116,9 @@ export const LayoutViewer = forwardRef((props, ref) => { ], }); if (path?.length) { - onChangeData({ common_tray_icon: `${path}` }); - patchVerge({ common_tray_icon: `${path}` }); + await copyIconFile(`${path}`, "common.png"); + onChangeData({ common_tray_icon: true }); + patchVerge({ common_tray_icon: true }); } } }} @@ -120,17 +139,15 @@ export const LayoutViewer = forwardRef((props, ref) => { variant="outlined" size="small" startIcon={ - verge?.sysproxy_tray_icon && ( - + verge?.sysproxy_tray_icon && + sysproxyIcon && ( + ) } onClick={async () => { if (verge?.sysproxy_tray_icon) { - onChangeData({ sysproxy_tray_icon: "" }); - patchVerge({ sysproxy_tray_icon: "" }); + onChangeData({ sysproxy_tray_icon: false }); + patchVerge({ sysproxy_tray_icon: false }); } else { const path = await openDialog({ directory: false, @@ -143,8 +160,9 @@ export const LayoutViewer = forwardRef((props, ref) => { ], }); if (path?.length) { - onChangeData({ sysproxy_tray_icon: `${path}` }); - patchVerge({ sysproxy_tray_icon: `${path}` }); + await copyIconFile(`${path}`, "sysproxy.png"); + onChangeData({ sysproxy_tray_icon: true }); + patchVerge({ sysproxy_tray_icon: true }); } } }} @@ -165,17 +183,13 @@ export const LayoutViewer = forwardRef((props, ref) => { variant="outlined" size="small" startIcon={ - verge?.tun_tray_icon && ( - - ) + verge?.tun_tray_icon && + tunIcon && } onClick={async () => { if (verge?.tun_tray_icon) { - onChangeData({ tun_tray_icon: "" }); - patchVerge({ tun_tray_icon: "" }); + onChangeData({ tun_tray_icon: false }); + patchVerge({ tun_tray_icon: false }); } else { const path = await openDialog({ directory: false, @@ -188,8 +202,9 @@ export const LayoutViewer = forwardRef((props, ref) => { ], }); if (path?.length) { - onChangeData({ tun_tray_icon: `${path}` }); - patchVerge({ tun_tray_icon: `${path}` }); + await copyIconFile(`${path}`, "tun.png"); + onChangeData({ tun_tray_icon: true }); + patchVerge({ tun_tray_icon: true }); } } }} diff --git a/src/services/cmds.ts b/src/services/cmds.ts index 1b813f88..85b363e6 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -139,6 +139,10 @@ export async function grantPermission(core: string) { return invoke("grant_permission", { core }); } +export async function getAppDir() { + return invoke("get_app_dir"); +} + export async function openAppDir() { return invoke("open_app_dir").catch((err) => Notice.error(err?.message || err.toString(), 1500) @@ -212,3 +216,10 @@ export async function getPortableFlag() { export async function exitApp() { return invoke("exit_app"); } + +export async function copyIconFile( + path: string, + name: "common.png" | "sysproxy.png" | "tun.png" +) { + return invoke("copy_icon_file", { path, name }); +} diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 8d63e40a..ba28ee08 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -200,9 +200,9 @@ interface IVergeConfig { theme_mode?: "light" | "dark" | "system"; traffic_graph?: boolean; enable_memory_usage?: boolean; - common_tray_icon?: string; - sysproxy_tray_icon?: string; - tun_tray_icon?: string; + common_tray_icon?: boolean; + sysproxy_tray_icon?: boolean; + tun_tray_icon?: boolean; enable_tun_mode?: boolean; enable_auto_launch?: boolean; enable_service_mode?: boolean;