Compare commits
10 Commits
14
README.md
14
README.md
@@ -13,15 +13,15 @@ A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a
|
||||
|
||||
Click on the corresponding link below to download the installation package. Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
|
||||
|
||||
[[Windows x64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.2/Clash.Verge_1.5.2_x64-setup.exe)]
|
||||
[[Windows arm64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.2/Clash.Verge_1.5.2_arm64-setup.exe)]
|
||||
[[Windows x64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.3/Clash.Verge_1.5.3_x64-setup.exe)]
|
||||
[[Windows arm64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.3/Clash.Verge_1.5.3_arm64-setup.exe)]
|
||||
|
||||
[[macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.2/Clash.Verge_1.5.2_x64.dmg)]
|
||||
[[macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.2/Clash.Verge_1.5.2_aarch64.dmg)]
|
||||
[[macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.3/Clash.Verge_1.5.3_x64.dmg)]
|
||||
[[macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.3/Clash.Verge_1.5.3_aarch64.dmg)]
|
||||
|
||||
[[Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.2/clash-verge_1.5.2_amd64.AppImage)]
|
||||
[[Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.2/clash-verge_1.5.2_amd64.deb)]
|
||||
[[Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.2/clash-verge_1.5.2_arm64.deb)]
|
||||
[[Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.3/clash-verge_1.5.3_amd64.AppImage)]
|
||||
[[Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.3/clash-verge_1.5.3_amd64.deb)]
|
||||
[[Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.3/clash-verge_1.5.3_arm64.deb)]
|
||||
|
||||
Or you can build it yourself. Supports Windows, Linux and macOS 10.15+
|
||||
|
||||
|
||||
12
UPDATELOG.md
12
UPDATELOG.md
@@ -1,3 +1,15 @@
|
||||
## v1.5.3
|
||||
|
||||
### Features
|
||||
|
||||
- Tun 设置添加重置按钮
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- Tun 设置项显示错误的问题
|
||||
- 修改一些默认值
|
||||
- 启动时不更改启动项设置
|
||||
|
||||
## v1.5.2
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "1.5.2",
|
||||
"version": "1.5.3",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
|
||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -598,7 +598,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "1.5.2"
|
||||
version = "1.5.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto-launch",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "1.5.2"
|
||||
version = "1.5.3"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
@@ -32,12 +32,12 @@ impl IClashTemp {
|
||||
pub fn template() -> Self {
|
||||
let mut map = Mapping::new();
|
||||
let mut tun = Mapping::new();
|
||||
tun.insert("stack".into(), "gVisor".into());
|
||||
tun.insert("stack".into(), "gvisor".into());
|
||||
tun.insert("device".into(), "Meta".into());
|
||||
tun.insert("auto-route".into(), true.into());
|
||||
tun.insert("strict-route".into(), true.into());
|
||||
tun.insert("strict-route".into(), false.into());
|
||||
tun.insert("auto-detect-interface".into(), true.into());
|
||||
tun.insert("dns-hijack".into(), vec!["any:53", "tcp://any:53"].into());
|
||||
tun.insert("dns-hijack".into(), vec!["any:53"].into());
|
||||
tun.insert("mtu".into(), 9000.into());
|
||||
|
||||
map.insert("mixed-port".into(), 7897.into());
|
||||
|
||||
@@ -144,10 +144,9 @@ impl CoreManager {
|
||||
|
||||
let config_path = dirs::path_to_str(&config_path)?;
|
||||
|
||||
// fix #212
|
||||
let args = match clash_core.as_str() {
|
||||
"clash-meta" => vec!["-m", "-d", app_dir, "-f", config_path],
|
||||
"clash-meta-alpha" => vec!["-m", "-d", app_dir, "-f", config_path],
|
||||
"clash-meta" => vec!["-d", app_dir, "-f", config_path],
|
||||
"clash-meta-alpha" => vec!["-d", app_dir, "-f", config_path],
|
||||
_ => vec!["-d", app_dir, "-f", config_path],
|
||||
};
|
||||
|
||||
|
||||
@@ -148,9 +148,6 @@ impl Sysopt {
|
||||
|
||||
/// init the auto launch
|
||||
pub fn init_launch(&self) -> Result<()> {
|
||||
let enable = { Config::verge().latest().enable_auto_launch };
|
||||
let enable = enable.unwrap_or(false);
|
||||
|
||||
let app_exe = current_exe()?;
|
||||
let app_exe = dunce::canonicalize(app_exe)?;
|
||||
let app_name = app_exe
|
||||
@@ -204,28 +201,6 @@ impl Sysopt {
|
||||
.set_app_path(&app_path)
|
||||
.build()?;
|
||||
|
||||
// 避免在开发时将自启动关了
|
||||
#[cfg(feature = "verge-dev")]
|
||||
if !enable {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if enable && !auto.is_enabled().unwrap_or(false) {
|
||||
// 避免重复设置登录项
|
||||
let _ = auto.disable();
|
||||
auto.enable()?;
|
||||
} else if !enable {
|
||||
let _ = auto.disable();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
if enable {
|
||||
auto.enable()?;
|
||||
}
|
||||
|
||||
*self.auto_launch.lock() = Some(auto);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "Clash Verge",
|
||||
"version": "1.5.2"
|
||||
"version": "1.5.3"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
|
||||
@@ -55,6 +55,7 @@ export const ProviderButton = () => {
|
||||
<Typography variant="h6">{t("Proxy Provider")}</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
Object.entries(data || {}).forEach(async ([key, item]) => {
|
||||
await proxyProviderUpdate(key);
|
||||
|
||||
@@ -53,6 +53,7 @@ export const ProviderButton = () => {
|
||||
<Typography variant="h6">{t("Rule Provider")}</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
Object.entries(data || {}).forEach(async ([key, item]) => {
|
||||
await ruleProviderUpdate(key);
|
||||
|
||||
@@ -194,7 +194,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.defaultLatencyTimeout}
|
||||
placeholder="http://1.1.1.1"
|
||||
placeholder="10000"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({
|
||||
...v,
|
||||
|
||||
71
src/components/setting/mods/stack-mode-switch.tsx
Normal file
71
src/components/setting/mods/stack-mode-switch.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, ButtonGroup, Tooltip } from "@mui/material";
|
||||
import { checkService } from "@/services/cmds";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import useSWR from "swr";
|
||||
|
||||
const isWIN = getSystem() === "windows";
|
||||
|
||||
interface Props {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
export const StackModeSwitch = (props: Props) => {
|
||||
const { value, onChange } = props;
|
||||
const { verge } = useVerge();
|
||||
const { enable_service_mode } = verge ?? {};
|
||||
// service mode
|
||||
const { data: serviceStatus } = useSWR(
|
||||
isWIN ? "checkService" : null,
|
||||
checkService,
|
||||
{
|
||||
revalidateIfStale: false,
|
||||
shouldRetryOnError: false,
|
||||
}
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
isWIN && (serviceStatus !== "active" || !enable_service_mode)
|
||||
? t("System and Mixed Can Only be Used in Service Mode")
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<ButtonGroup size="small" sx={{ my: "4px" }}>
|
||||
<Button
|
||||
variant={value?.toLowerCase() === "system" ? "contained" : "outlined"}
|
||||
onClick={() => onChange?.("system")}
|
||||
disabled={
|
||||
isWIN && (serviceStatus !== "active" || !enable_service_mode)
|
||||
}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
System
|
||||
</Button>
|
||||
<Button
|
||||
variant={value?.toLowerCase() === "gvisor" ? "contained" : "outlined"}
|
||||
onClick={() => onChange?.("gvisor")}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
gVisor
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={value?.toLowerCase() === "mixed" ? "contained" : "outlined"}
|
||||
onClick={() => onChange?.("mixed")}
|
||||
disabled={
|
||||
isWIN && (serviceStatus !== "active" || !enable_service_mode)
|
||||
}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
Mixed
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
@@ -5,13 +5,15 @@ import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Select,
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Switch,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||
import { StackModeSwitch } from "./stack-mode-switch";
|
||||
|
||||
export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -20,12 +22,12 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [values, setValues] = useState({
|
||||
stack: "gVisor",
|
||||
device: "Mihomo",
|
||||
stack: "gvisor",
|
||||
device: "Meta",
|
||||
autoRoute: true,
|
||||
autoDetectInterface: true,
|
||||
dnsHijack: ["any:53", "tcp://any:53"],
|
||||
strictRoute: true,
|
||||
dnsHijack: ["any:53"],
|
||||
strictRoute: false,
|
||||
mtu: 9000,
|
||||
});
|
||||
|
||||
@@ -33,12 +35,12 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
open: () => {
|
||||
setOpen(true);
|
||||
setValues({
|
||||
stack: clash?.tun.stack ?? "gVisor",
|
||||
device: clash?.tun.device ?? "Mihomo",
|
||||
stack: clash?.tun.stack ?? "gvisor",
|
||||
device: clash?.tun.device ?? "Meta",
|
||||
autoRoute: clash?.tun["auto-route"] ?? true,
|
||||
autoDetectInterface: clash?.tun["auto-detect-interface"] ?? true,
|
||||
dnsHijack: clash?.tun["dns-hijack"] ?? ["any:53", "tcp://any:53"],
|
||||
strictRoute: clash?.tun["strict-route"] ?? true,
|
||||
dnsHijack: clash?.tun["dns-hijack"] ?? ["any:53"],
|
||||
strictRoute: clash?.tun["strict-route"] ?? false,
|
||||
mtu: clash?.tun.mtu ?? 9000,
|
||||
});
|
||||
},
|
||||
@@ -73,7 +75,45 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("Tun Mode")}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between" gap={1}>
|
||||
<Typography variant="h6">{t("Tun Mode")}</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
let tun = {
|
||||
stack: "gvisor",
|
||||
device: "Meta",
|
||||
"auto-route": true,
|
||||
"auto-detect-interface": true,
|
||||
"dns-hijack": ["any:53"],
|
||||
"strict-route": false,
|
||||
mtu: 9000,
|
||||
};
|
||||
setValues({
|
||||
stack: "gvisor",
|
||||
device: "Meta",
|
||||
autoRoute: true,
|
||||
autoDetectInterface: true,
|
||||
dnsHijack: ["any:53"],
|
||||
strictRoute: false,
|
||||
mtu: 9000,
|
||||
});
|
||||
await patchClash({ tun });
|
||||
await mutateClash(
|
||||
(old) => ({
|
||||
...(old! || {}),
|
||||
tun,
|
||||
}),
|
||||
false
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("Reset to Default")}
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
contentSx={{ width: 450 }}
|
||||
okBtn={t("Save")}
|
||||
cancelBtn={t("Cancel")}
|
||||
@@ -84,23 +124,15 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Stack")} />
|
||||
<Select
|
||||
size="small"
|
||||
sx={{ width: 100, "> div": { py: "7.5px" } }}
|
||||
<StackModeSwitch
|
||||
value={values.stack}
|
||||
onChange={(e) => {
|
||||
onChange={(value) => {
|
||||
setValues((v) => ({
|
||||
...v,
|
||||
stack: e.target.value as string,
|
||||
stack: value,
|
||||
}));
|
||||
}}
|
||||
>
|
||||
{["System", "gVisor", "Mixed"].map((i) => (
|
||||
<MenuItem value={i} key={i}>
|
||||
{i}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
@@ -113,7 +145,7 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.device}
|
||||
placeholder="Mihomo"
|
||||
placeholder="Meta"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({ ...v, device: e.target.value }))
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import useSWR, { mutate } from "swr";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { getAxios, getVersion, updateConfigs } from "@/services/api";
|
||||
import {
|
||||
getAxios,
|
||||
getClashConfig,
|
||||
getVersion,
|
||||
updateConfigs,
|
||||
} from "@/services/api";
|
||||
import { getClashInfo, patchClashConfig } from "@/services/cmds";
|
||||
getClashInfo,
|
||||
patchClashConfig,
|
||||
getRuntimeConfig,
|
||||
} from "@/services/cmds";
|
||||
|
||||
export const useClash = () => {
|
||||
const { data: clash, mutate: mutateClash } = useSWR(
|
||||
"getClashConfig",
|
||||
getClashConfig
|
||||
"getRuntimeConfig",
|
||||
getRuntimeConfig
|
||||
);
|
||||
|
||||
const { data: versionData, mutate: mutateVersion } = useSWR(
|
||||
|
||||
@@ -160,7 +160,16 @@
|
||||
"Retain 30 Days": "Retain 30 Days",
|
||||
"Retain 90 Days": "Retain 90 Days",
|
||||
|
||||
"Stack": "Tun Stack",
|
||||
"Device": "Device Name",
|
||||
"Auto Route": "Auto Route",
|
||||
"Strict Route": "Strict Route",
|
||||
"Auto Detect Interface": "Auto Detect Interface",
|
||||
"DNS Hijack": "DNS Hijack",
|
||||
"MTU": "Max Transmission Unit",
|
||||
|
||||
"Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it",
|
||||
"Tun Mode Info Windows": "The Tun mode requires granting core-related permissions. Please enable service mode before using it",
|
||||
"Tun Mode Info Unix": "The Tun mode requires granting core-related permissions. Before using it, please authorize the core in the core settings"
|
||||
"Tun Mode Info Unix": "The Tun mode requires granting core-related permissions. Before using it, please authorize the core in the core settings",
|
||||
"System and Mixed Can Only be Used in Service Mode": "System and Mixed Can Only be Used in Service Mode"
|
||||
}
|
||||
|
||||
@@ -160,7 +160,17 @@
|
||||
"Retain 30 Days": "保留30天",
|
||||
"Retain 90 Days": "保留90天",
|
||||
|
||||
"Stack": "Tun 模式堆栈",
|
||||
"Device": "Tun 网卡名称",
|
||||
"Auto Route": "自动设置全局路由",
|
||||
"Strict Route": "严格路由",
|
||||
"Auto Detect Interface": "自动选择流量出口接口",
|
||||
"DNS Hijack": "DNS 劫持",
|
||||
"MTU": "最大传输单元",
|
||||
"Reset to Default": "重置为默认值",
|
||||
|
||||
"Portable Updater Error": "便携版不支持应用内更新,请手动下载替换",
|
||||
"Tun Mode Info Windows": "Tun模式需要授予内核相关权限,使用前请先开启服务模式",
|
||||
"Tun Mode Info Unix": "Tun模式需要授予内核相关权限,使用前请先在内核设置中给内核授权"
|
||||
"Tun Mode Info Unix": "Tun模式需要授予内核相关权限,使用前请先在内核设置中给内核授权",
|
||||
"System and Mixed Can Only be Used in Service Mode": "System和Mixed只能在服务模式下使用"
|
||||
}
|
||||
|
||||
@@ -90,8 +90,9 @@ export async function getClashInfo() {
|
||||
return invoke<IClashInfo | null>("get_clash_info");
|
||||
}
|
||||
|
||||
// Get runtime config which controlled by verge
|
||||
export async function getRuntimeConfig() {
|
||||
return invoke<any | null>("get_runtime_config");
|
||||
return invoke<IConfigData | null>("get_runtime_config");
|
||||
}
|
||||
|
||||
export async function getRuntimeYaml() {
|
||||
|
||||
Reference in New Issue
Block a user