Prechádzať zdrojové kódy

refactor: Optimize implementation of Custom tray icon

MystiPanda 1 rok pred
rodič
commit
51bcc77cb3

+ 1 - 1
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

+ 27 - 0
src-tauri/src/cmds.rs

@@ -267,6 +267,33 @@ pub async fn test_delay(url: String) -> CmdResult<u32> {
     Ok(feat::test_delay(url).await.unwrap_or(10000u32))
 }
 
+#[tauri::command]
+pub fn get_app_dir() -> CmdResult<String> {
+    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<String> {
+    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);

+ 5 - 3
src-tauri/src/config/verge.rs

@@ -37,11 +37,13 @@ pub struct IVerge {
     pub enable_memory_usage: Option<bool>,
 
     /// common tray icon
-    pub common_tray_icon: Option<String>,
+    pub common_tray_icon: Option<bool>,
 
-    pub sysproxy_tray_icon: Option<String>,
+    /// sysproxy tray icon
+    pub sysproxy_tray_icon: Option<bool>,
 
-    pub tun_tray_icon: Option<String>,
+    /// tun tray icon
+    pub tun_tray_icon: Option<bool>,
 
     /// clash tun mode
     pub enable_tun_mode: Option<bool>,

+ 15 - 10
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();
                 }

+ 2 - 0
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

+ 3 - 0
src-tauri/tauri.conf.json

@@ -62,6 +62,9 @@
       "protocol": {
         "asset": true,
         "assetScope": ["**"]
+      },
+      "path": {
+        "all": true
       }
     },
     "windows": [],

+ 44 - 29
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<DialogRef>((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<DialogRef>((props, ref) => {
               variant="outlined"
               size="small"
               startIcon={
-                verge?.common_tray_icon && (
-                  <img
-                    height="20px"
-                    src={convertFileSrc(verge?.common_tray_icon)}
-                  />
+                verge?.common_tray_icon &&
+                commonIcon && (
+                  <img height="20px" src={convertFileSrc(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<DialogRef>((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<DialogRef>((props, ref) => {
               variant="outlined"
               size="small"
               startIcon={
-                verge?.sysproxy_tray_icon && (
-                  <img
-                    height="20px"
-                    src={convertFileSrc(verge?.sysproxy_tray_icon)}
-                  />
+                verge?.sysproxy_tray_icon &&
+                sysproxyIcon && (
+                  <img height="20px" src={convertFileSrc(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<DialogRef>((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<DialogRef>((props, ref) => {
               variant="outlined"
               size="small"
               startIcon={
-                verge?.tun_tray_icon && (
-                  <img
-                    height="20px"
-                    src={convertFileSrc(verge?.tun_tray_icon)}
-                  />
-                )
+                verge?.tun_tray_icon &&
+                tunIcon && <img height="20px" src={convertFileSrc(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<DialogRef>((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 });
                   }
                 }
               }}

+ 11 - 0
src/services/cmds.ts

@@ -139,6 +139,10 @@ export async function grantPermission(core: string) {
   return invoke<void>("grant_permission", { core });
 }
 
+export async function getAppDir() {
+  return invoke<string>("get_app_dir");
+}
+
 export async function openAppDir() {
   return invoke<void>("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<void>("copy_icon_file", { path, name });
+}

+ 3 - 3
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;