mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-06 05:03:45 +08:00
feat: Support Custom Tray Icon
This commit is contained in:
parent
447f7530af
commit
6f546a424e
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
## v1.5.2
|
## v1.5.2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- 支持自定义延迟测试超时时间
|
- 支持自定义延迟测试超时时间
|
||||||
|
@ -39,7 +39,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
|
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
|
||||||
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
||||||
auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
|
auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
|
||||||
tauri = { version = "1.5", features = [ "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 = [ "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]
|
[target.'cfg(windows)'.dependencies]
|
||||||
runas = "=1.0.0" # 高版本会返回错误 Status
|
runas = "=1.0.0" # 高版本会返回错误 Status
|
||||||
|
@ -36,6 +36,13 @@ pub struct IVerge {
|
|||||||
/// show memory info (only for Clash Meta)
|
/// show memory info (only for Clash Meta)
|
||||||
pub enable_memory_usage: Option<bool>,
|
pub enable_memory_usage: Option<bool>,
|
||||||
|
|
||||||
|
/// common tray icon
|
||||||
|
pub common_tray_icon: Option<String>,
|
||||||
|
|
||||||
|
pub sysproxy_tray_icon: Option<String>,
|
||||||
|
|
||||||
|
pub tun_tray_icon: Option<String>,
|
||||||
|
|
||||||
/// clash tun mode
|
/// clash tun mode
|
||||||
pub enable_tun_mode: Option<bool>,
|
pub enable_tun_mode: Option<bool>,
|
||||||
|
|
||||||
@ -204,6 +211,9 @@ impl IVerge {
|
|||||||
patch!(startup_script);
|
patch!(startup_script);
|
||||||
patch!(traffic_graph);
|
patch!(traffic_graph);
|
||||||
patch!(enable_memory_usage);
|
patch!(enable_memory_usage);
|
||||||
|
patch!(common_tray_icon);
|
||||||
|
patch!(sysproxy_tray_icon);
|
||||||
|
patch!(tun_tray_icon);
|
||||||
|
|
||||||
patch!(enable_tun_mode);
|
patch!(enable_tun_mode);
|
||||||
patch!(enable_service_mode);
|
patch!(enable_service_mode);
|
||||||
|
@ -129,26 +129,47 @@ impl Tray {
|
|||||||
let verge = verge.latest();
|
let verge = verge.latest();
|
||||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
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 = 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 mut indication_icon = if *system_proxy {
|
let mut indication_icon = if *system_proxy {
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
let icon = include_bytes!("../../icons/tray-icon-sys.png").to_vec();
|
let mut icon = include_bytes!("../../icons/tray-icon-sys.png").to_vec();
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let icon = include_bytes!("../../icons/mac-tray-icon-sys.png").to_vec();
|
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 path.exists() {
|
||||||
|
icon = std::fs::read(path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
icon
|
icon
|
||||||
} else {
|
} else {
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
let icon = include_bytes!("../../icons/tray-icon.png").to_vec();
|
let mut icon = include_bytes!("../../icons/tray-icon.png").to_vec();
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let icon = include_bytes!("../../icons/mac-tray-icon.png").to_vec();
|
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 path.exists() {
|
||||||
|
icon = std::fs::read(path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
icon
|
icon
|
||||||
};
|
};
|
||||||
|
|
||||||
if *tun_mode {
|
if *tun_mode {
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
let icon = include_bytes!("../../icons/tray-icon-tun.png").to_vec();
|
let mut icon = include_bytes!("../../icons/tray-icon-tun.png").to_vec();
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let icon = include_bytes!("../../icons/mac-tray-icon-tun.png").to_vec();
|
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 path.exists() {
|
||||||
|
icon = std::fs::read(path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
indication_icon = icon
|
indication_icon = icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +230,9 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
|||||||
let proxy_bypass = patch.system_proxy_bypass;
|
let proxy_bypass = patch.system_proxy_bypass;
|
||||||
let language = patch.language;
|
let language = patch.language;
|
||||||
let port = patch.verge_mixed_port;
|
let port = patch.verge_mixed_port;
|
||||||
|
let common_tray_icon = patch.common_tray_icon;
|
||||||
|
let sysproxy_tray_icon = patch.sysproxy_tray_icon;
|
||||||
|
let tun_tray_icon = patch.tun_tray_icon;
|
||||||
|
|
||||||
match {
|
match {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
@ -269,7 +272,12 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
|||||||
|
|
||||||
if language.is_some() {
|
if language.is_some() {
|
||||||
handle::Handle::update_systray()?;
|
handle::Handle::update_systray()?;
|
||||||
} else if system_proxy.or(tun_mode).is_some() {
|
} else if system_proxy.is_some()
|
||||||
|
|| tun_mode.is_some()
|
||||||
|
|| common_tray_icon.is_some()
|
||||||
|
|| sysproxy_tray_icon.is_some()
|
||||||
|
|| tun_tray_icon.is_some()
|
||||||
|
{
|
||||||
handle::Handle::update_systray_part()?;
|
handle::Handle::update_systray_part()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +58,15 @@
|
|||||||
"dialog": {
|
"dialog": {
|
||||||
"all": false,
|
"all": false,
|
||||||
"open": true
|
"open": true
|
||||||
|
},
|
||||||
|
"protocol": {
|
||||||
|
"asset": true,
|
||||||
|
"assetScope": ["**"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"windows": [],
|
"windows": [],
|
||||||
"security": {
|
"security": {
|
||||||
"csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src http: https: data: 'self';"
|
"csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src asset: http: https: data: 'self';"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { forwardRef, useImperativeHandle, useState } from "react";
|
import { forwardRef, useImperativeHandle, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { List, Switch } from "@mui/material";
|
import { List, Switch, Button } from "@mui/material";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||||
import { SettingItem } from "./setting-comp";
|
import { SettingItem } from "./setting-comp";
|
||||||
import { GuardState } from "./guard-state";
|
import { GuardState } from "./guard-state";
|
||||||
|
import { open as openDialog } from "@tauri-apps/api/dialog";
|
||||||
|
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
||||||
|
|
||||||
export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -61,6 +63,141 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
<Switch edge="end" />
|
<Switch edge="end" />
|
||||||
</GuardState>
|
</GuardState>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
|
<SettingItem label={t("Common Tray Icon")}>
|
||||||
|
<GuardState
|
||||||
|
value={verge?.common_tray_icon}
|
||||||
|
onCatch={onError}
|
||||||
|
onChange={(e) => onChangeData({ common_tray_icon: e })}
|
||||||
|
onGuard={(e) => patchVerge({ common_tray_icon: e })}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
startIcon={
|
||||||
|
verge?.common_tray_icon && (
|
||||||
|
<img
|
||||||
|
height="20px"
|
||||||
|
src={convertFileSrc(verge?.common_tray_icon)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={async () => {
|
||||||
|
if (verge?.common_tray_icon) {
|
||||||
|
onChangeData({ common_tray_icon: "" });
|
||||||
|
patchVerge({ common_tray_icon: "" });
|
||||||
|
} else {
|
||||||
|
const path = await openDialog({
|
||||||
|
directory: false,
|
||||||
|
multiple: false,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: "Tray Icon Image",
|
||||||
|
extensions: ["png"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
if (path?.length) {
|
||||||
|
onChangeData({ common_tray_icon: `${path}` });
|
||||||
|
patchVerge({ common_tray_icon: `${path}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{verge?.common_tray_icon ? t("Clear") : t("Browse")}
|
||||||
|
</Button>
|
||||||
|
</GuardState>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
|
<SettingItem label={t("System Proxy Tray Icon")}>
|
||||||
|
<GuardState
|
||||||
|
value={verge?.sysproxy_tray_icon}
|
||||||
|
onCatch={onError}
|
||||||
|
onChange={(e) => onChangeData({ sysproxy_tray_icon: e })}
|
||||||
|
onGuard={(e) => patchVerge({ sysproxy_tray_icon: e })}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
startIcon={
|
||||||
|
verge?.sysproxy_tray_icon && (
|
||||||
|
<img
|
||||||
|
height="20px"
|
||||||
|
src={convertFileSrc(verge?.sysproxy_tray_icon)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={async () => {
|
||||||
|
if (verge?.sysproxy_tray_icon) {
|
||||||
|
onChangeData({ sysproxy_tray_icon: "" });
|
||||||
|
patchVerge({ sysproxy_tray_icon: "" });
|
||||||
|
} else {
|
||||||
|
const path = await openDialog({
|
||||||
|
directory: false,
|
||||||
|
multiple: false,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: "Tray Icon Image",
|
||||||
|
extensions: ["png"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
if (path?.length) {
|
||||||
|
onChangeData({ sysproxy_tray_icon: `${path}` });
|
||||||
|
patchVerge({ sysproxy_tray_icon: `${path}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{verge?.sysproxy_tray_icon ? t("Clear") : t("Browse")}
|
||||||
|
</Button>
|
||||||
|
</GuardState>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
|
<SettingItem label={t("Tun Tray Icon")}>
|
||||||
|
<GuardState
|
||||||
|
value={verge?.tun_tray_icon}
|
||||||
|
onCatch={onError}
|
||||||
|
onChange={(e) => onChangeData({ tun_tray_icon: e })}
|
||||||
|
onGuard={(e) => patchVerge({ tun_tray_icon: e })}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
startIcon={
|
||||||
|
verge?.tun_tray_icon && (
|
||||||
|
<img
|
||||||
|
height="20px"
|
||||||
|
src={convertFileSrc(verge?.tun_tray_icon)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={async () => {
|
||||||
|
if (verge?.tun_tray_icon) {
|
||||||
|
onChangeData({ tun_tray_icon: "" });
|
||||||
|
patchVerge({ tun_tray_icon: "" });
|
||||||
|
} else {
|
||||||
|
const path = await openDialog({
|
||||||
|
directory: false,
|
||||||
|
multiple: false,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: "Tray Icon Image",
|
||||||
|
extensions: ["png"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
if (path?.length) {
|
||||||
|
onChangeData({ tun_tray_icon: `${path}` });
|
||||||
|
patchVerge({ tun_tray_icon: `${path}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{verge?.tun_tray_icon ? t("Clear") : t("Browse")}
|
||||||
|
</Button>
|
||||||
|
</GuardState>
|
||||||
|
</SettingItem>
|
||||||
</List>
|
</List>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
@ -110,6 +110,9 @@
|
|||||||
"Hotkey Setting": "Hotkey Setting",
|
"Hotkey Setting": "Hotkey Setting",
|
||||||
"Traffic Graph": "Traffic Graph",
|
"Traffic Graph": "Traffic Graph",
|
||||||
"Memory Usage": "Memory Usage",
|
"Memory Usage": "Memory Usage",
|
||||||
|
"Common Tray Icon": "Common Tray Icon",
|
||||||
|
"System Proxy Tray Icon": "System Proxy Tray Icon",
|
||||||
|
"Tun Tray Icon": "Tun Tray Icon",
|
||||||
"Language": "Language",
|
"Language": "Language",
|
||||||
"Open App Dir": "Open App Dir",
|
"Open App Dir": "Open App Dir",
|
||||||
"Open Core Dir": "Open Core Dir",
|
"Open Core Dir": "Open Core Dir",
|
||||||
|
@ -110,6 +110,9 @@
|
|||||||
"Hotkey Setting": "热键设置",
|
"Hotkey Setting": "热键设置",
|
||||||
"Traffic Graph": "流量图显",
|
"Traffic Graph": "流量图显",
|
||||||
"Memory Usage": "内存使用",
|
"Memory Usage": "内存使用",
|
||||||
|
"Common Tray Icon": "常规托盘图标",
|
||||||
|
"System Proxy Tray Icon": "系统代理托盘图标",
|
||||||
|
"Tun Tray Icon": "Tun模式托盘图标",
|
||||||
"Language": "语言设置",
|
"Language": "语言设置",
|
||||||
"Open App Dir": "应用目录",
|
"Open App Dir": "应用目录",
|
||||||
"Open Core Dir": "内核目录",
|
"Open Core Dir": "内核目录",
|
||||||
|
3
src/services/types.d.ts
vendored
3
src/services/types.d.ts
vendored
@ -200,6 +200,9 @@ interface IVergeConfig {
|
|||||||
theme_mode?: "light" | "dark" | "system";
|
theme_mode?: "light" | "dark" | "system";
|
||||||
traffic_graph?: boolean;
|
traffic_graph?: boolean;
|
||||||
enable_memory_usage?: boolean;
|
enable_memory_usage?: boolean;
|
||||||
|
common_tray_icon?: string;
|
||||||
|
sysproxy_tray_icon?: string;
|
||||||
|
tun_tray_icon?: string;
|
||||||
enable_tun_mode?: boolean;
|
enable_tun_mode?: boolean;
|
||||||
enable_auto_launch?: boolean;
|
enable_auto_launch?: boolean;
|
||||||
enable_service_mode?: boolean;
|
enable_service_mode?: boolean;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user