Compare commits

..

24 Commits

24 changed files with 154 additions and 112 deletions

View File

@@ -157,7 +157,7 @@ jobs:
- name: Portable Bundle
if: matrix.os == 'windows-latest'
run: |
pnpm portable
pnpm portable ${{ matrix.target }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}

View File

@@ -1,12 +1,12 @@
<h1 align="center">
<img src="./src/assets/image/logo.png" alt="Clash" width="128" />
<br>
Continuation of Clash Verge
Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
<br>
</h1>
<h3 align="center">
A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">tauri</a>.
A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a>.
</h3>
## Features
@@ -14,7 +14,7 @@ A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">tauri</a
- Since the clash core has been removed. The project no longer maintains the clash core, but only the Clash Meta core.
- Profiles management and enhancement (by yaml and Javascript). [Doc](https://github.com/clash-verge-rev/clash-verge-rev/wiki/%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97)
- Simple UI and supports custom theme color.
- Built-in support [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta) core.
- Built-in support [Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo) core.
- System proxy setting and guard.
#### TG Group: [@clash_verge_rev](https://t.me/clash_verge_rev)
@@ -39,13 +39,17 @@ A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">tauri</a
## Install
Download from [release](https://github.com/clash-verge-rev/clash-verge-rev/releases). Supports Windows x64, Linux x86_64 and macOS 11+
Download from [release](https://github.com/clash-verge-rev/clash-verge-rev/releases). 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.4.0/Clash.Verge_1.4.0_x64_zh-CN.msi)
- [macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.0/Clash.Verge_1.4.0_x64.dmg)
- [macOS arm](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.0/Clash.Verge_1.4.0_aarch64.dmg)
- [Linux AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.0/clash-verge_1.4.0_amd64.AppImage)
- [Linux deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.0/clash-verge_1.4.0_amd64.deb)
- [Windows x64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.2/Clash.Verge_1.4.2_x64-setup.exe)
- [Windows x86](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.2/Clash.Verge_1.4.2_x86-setup.exe)
- [macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.2/Clash.Verge_1.4.2_x64.dmg)
- [macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.2/Clash.Verge_1.4.2_aarch64.dmg)
- [Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.2/clash-verge_1.4.2_amd64.AppImage)
- [Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.2/clash-verge_1.4.2_amd64.deb)
- [Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.4.2/clash-verge_1.4.2_arm64.deb)
Or you can build it yourself. Supports Windows, Linux and macOS 10.15+

View File

@@ -1,8 +1,34 @@
## v1.4.3
### Break Changes
- 更改配置文件路径到标准目录(可以保证卸载时没有残留)
- 更改 appid 为 `io.github.clash-verge-rev.clash-verge-rev`
- 建议卸载旧版本后再安装新版本,该版本安装后不会使用旧版配置文件,你可以手动将旧版配置文件迁移到新版配置文件目录下
### Features
- 移除页面切换动画
- 更改 Tun 模式托盘图标颜色
- Portable 版本默认使用当前目录作为配置文件目录
- 禁用 Clash 字段过滤时隐藏 Clash 字段选项
- 优化拖拽时光标样式
### Bugs Fixes
- 修复 windows 下更新时没有关闭内核导致的更新失败的问题
- 修复打开文件报错的问题
- 修复 url 导入时无法获取中文配置名称的问题
- 修复 alpha 内核无法显示内存信息的问题
---
## v1.4.2
### Features
- update clash meta core to mihomo 1.17.0
- support both clash meta stable release and prerelease-alpha release
- fixed the problem of not being able to set the system proxy when there is a dial-up link on windows system [#833](https://github.com/zzzgydi/clash-verge/issues/833)
- support new clash field
- support random mixed port

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 MiB

After

Width:  |  Height:  |  Size: 6.7 MiB

View File

@@ -1,6 +1,6 @@
{
"name": "clash-verge",
"version": "1.4.2",
"version": "1.4.3",
"license": "GPL-3.0",
"scripts": {
"dev": "tauri dev -f default-meta",

View File

@@ -52,12 +52,12 @@ const META_ALPHA_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/down
let META_ALPHA_VERSION;
const META_ALPHA_MAP = {
"win32-x64": "mihomo-windows-amd64",
"win32-x64": "mihomo-windows-amd64-compatible",
"win32-ia32": "mihomo-windows-386",
"win32-arm64": "mihomo-windows-arm64",
"darwin-x64": "mihomo-darwin-amd64",
"darwin-arm64": "mihomo-darwin-arm64",
"linux-x64": "mihomo-linux-amd64",
"linux-x64": "mihomo-linux-amd64-compatible",
"linux-arm64": "mihomo-linux-arm64",
"linux-arm": "mihomo-linux-armv7",
};
@@ -80,12 +80,12 @@ const META_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download`;
let META_VERSION = "v1.17.0";
const META_MAP = {
"win32-x64": "mihomo-windows-amd64",
"win32-x64": "mihomo-windows-amd64-compatible",
"win32-ia32": "mihomo-windows-386",
"win32-arm64": "mihomo-windows-arm64",
"darwin-x64": "mihomo-darwin-amd64",
"darwin-arm64": "mihomo-darwin-arm64",
"linux-x64": "mihomo-linux-amd64",
"linux-x64": "mihomo-linux-amd64-compatible",
"linux-arm64": "mihomo-linux-arm64",
"linux-arm": "mihomo-linux-armv7",
};

View File

@@ -4,29 +4,44 @@ import AdmZip from "adm-zip";
import { createRequire } from "module";
import { getOctokit, context } from "@actions/github";
const target = process.argv.slice(2)[0];
const ARCH_MAP = {
"i686-pc-windows-msvc": "x86",
"x86_64-pc-windows-msvc": "x64",
};
/// Script for ci
/// 打包绿色版/便携版 (only Windows)
async function resolvePortable() {
if (process.platform !== "win32") return;
const releaseDir = "./src-tauri/target/release";
const releaseDir = target
? `./src-tauri/target/${target}/release`
: `./src-tauri/target/release`;
const configDir = path.join(releaseDir, ".config");
if (!(await fs.pathExists(releaseDir))) {
throw new Error("could not found the release dir");
}
await fs.mkdir(configDir);
await fs.createFile(path.join(configDir, "PORTABLE"));
const zip = new AdmZip();
zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
// zip.addLocalFile(path.join(releaseDir, "clash.exe"));
zip.addLocalFile(path.join(releaseDir, "clash-meta.exe"));
zip.addLocalFile(path.join(releaseDir, "clash-meta-alpha.exe"));
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
zip.addLocalFolder(configDir, ".config");
const require = createRequire(import.meta.url);
const packageJson = require("../package.json");
const { version } = packageJson;
const zipFile = `Clash.Verge_${version}_x64_portable.zip`;
const zipFile = `Clash.Verge_${version}_${ARCH_MAP[target]}_portable.zip`;
zip.writeZip(zipFile);
console.log("[INFO]: create portable zip successfully");

View File

@@ -47,6 +47,7 @@ async function resolveUpdater() {
"linux-x86_64": { signature: "", url: "" },
"linux-aarch64": { signature: "", url: "" },
"windows-x86_64": { signature: "", url: "" },
"windows-i686": { signature: "", url: "" },
},
};
@@ -54,39 +55,23 @@ async function resolveUpdater() {
const { name, browser_download_url } = asset;
// win64 url
if (
name.endsWith(".msi.zip") &&
name.includes("en-US") &&
name.includes("x64")
) {
if (name.endsWith("x64-setup.nsis.zip")) {
updateData.platforms.win64.url = browser_download_url;
updateData.platforms["windows-x86_64"].url = browser_download_url;
}
// win64 signature
if (
name.endsWith(".msi.zip.sig") &&
name.includes("en-US") &&
name.includes("x64")
) {
if (name.endsWith("x64-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms.win64.signature = sig;
updateData.platforms["windows-x86_64"].signature = sig;
}
// win32 url
if (
name.endsWith(".msi.zip") &&
name.includes("en-US") &&
name.includes("x86")
) {
if (name.endsWith("x86-setup.nsis.zip")) {
updateData.platforms["windows-i686"].url = browser_download_url;
}
// win32 signature
if (
name.endsWith(".msi.zip.sig") &&
name.includes("en-US") &&
name.includes("x86")
) {
if (name.endsWith("x86-setup.nsis.zip.sig")) {
const sig = await getSignature(browser_download_url);
updateData.platforms["windows-i686"].signature = sig;
}

11
src-tauri/Cargo.lock generated
View File

@@ -559,7 +559,7 @@ dependencies = [
[[package]]
name = "clash-verge"
version = "1.4.2"
version = "1.4.3"
dependencies = [
"anyhow",
"auto-launch",
@@ -575,6 +575,7 @@ dependencies = [
"once_cell",
"open 5.0.1",
"parking_lot",
"percent-encoding",
"port_scanner",
"reqwest",
"rquickjs",
@@ -3729,14 +3730,12 @@ checksum = "e60ef3b82994702bbe4e134d98aadca4b49ed04440148985678d415c68127666"
[[package]]
name = "runas"
version = "1.1.0"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49535b7c73aec5596ae2c44a6d8a7a8f8592e5744564c327fd4846750413d921"
checksum = "ed87390fefd18965ff20baae5aeb9913bcf82d2b59dc04c0f6d8f17f7be56ff2"
dependencies = [
"libc",
"security-framework-sys",
"cc",
"which 4.4.2",
"windows-sys 0.48.0",
]
[[package]]

View File

@@ -1,6 +1,6 @@
[package]
name = "clash-verge"
version = "1.4.2"
version = "1.4.3"
description = "clash verge"
authors = ["zzzgydi"]
license = "GPL-3.0"
@@ -40,10 +40,11 @@ reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
tauri = { version = "1.5", features = ["clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] }
window-vibrancy = { version = "0.4.3" }
window-shadows = { version = "0.2" }
percent-encoding = "2.3.1"
[target.'cfg(windows)'.dependencies]
runas = "=1.1.0"
runas = "=1.0.0"
deelevate = "0.2.0"
winreg = { version = "0.52", features = ["transactions"] }
windows-sys = { version = "0.52", features = ["Win32_System_LibraryLoader", "Win32_System_SystemInformation"] }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -85,7 +85,7 @@ pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
}
#[tauri::command]
pub fn view_profile(index: String) -> CmdResult {
pub fn view_profile(app_handle: tauri::AppHandle, index: String) -> CmdResult {
let file = {
wrap_err!(Config::profiles().latest().get_item(&index))?
.file
@@ -98,7 +98,7 @@ pub fn view_profile(index: String) -> CmdResult {
ret_err!("the file not found");
}
wrap_err!(help::open_file(path))
wrap_err!(help::open_file(app_handle, path))
}
#[tauri::command]

View File

@@ -263,7 +263,17 @@ impl PrfItem {
let filename = match header.get("Content-Disposition") {
Some(value) => {
let filename = value.to_str().unwrap_or("");
help::parse_str::<String>(filename, "filename=")
match help::parse_str::<String>(filename, "filename=") {
Some(filename) => Some(filename),
None => match help::parse_str::<String>(filename, "filename*=") {
Some(filename) => {
let iter = percent_encoding::percent_decode(filename.as_bytes());
let filename = iter.decode_utf8().unwrap_or_default();
filename.split("''").last().map(|s| s.to_string())
}
None => None,
},
}
}
None => None,
};

View File

@@ -77,7 +77,7 @@ pub struct IVerge {
/// 默认的延迟测试连接
pub default_latency_test: Option<String>,
/// 支持关闭字段过滤避免meta的新字段都被过滤掉默认为
/// 支持关闭字段过滤避免meta的新字段都被过滤掉默认为关闭
pub enable_clash_fields: Option<bool>,
/// 是否使用内部的脚本支持,默认为真
@@ -151,7 +151,7 @@ impl IVerge {
proxy_guard_duration: Some(30),
auto_close_connection: Some(true),
enable_builtin_enhanced: Some(true),
enable_clash_fields: Some(true),
enable_clash_fields: Some(false),
auto_log_clean: Some(3),
..Self::default()
}

View File

@@ -105,6 +105,10 @@ fn main() -> std::io::Result<()> {
api::process::kill_children();
app_handle.exit(0);
}
tauri::RunEvent::Updater(tauri::UpdaterEvent::Downloaded) => {
resolve::resolve_reset();
api::process::kill_children();
}
#[cfg(target_os = "macos")]
tauri::RunEvent::WindowEvent { label, event, .. } => {
use tauri::Manager;

View File

@@ -1,14 +1,14 @@
use anyhow::Result;
use std::path::PathBuf;
use tauri::{
api::path::{home_dir, resource_dir},
api::path::{data_dir, resource_dir},
Env, PackageInfo,
};
#[cfg(not(feature = "verge-dev"))]
static APP_DIR: &str = "clash-verge";
static APP_ID: &str = "io.github.clash-verge-rev.clash-verge-rev";
#[cfg(feature = "verge-dev")]
static APP_DIR: &str = "clash-verge-dev";
static APP_ID: &str = "io.github.clash-verge-rev.clash-verge-rev.dev";
static CLASH_CONFIG: &str = "config.yaml";
static VERGE_CONFIG: &str = "verge.yaml";
@@ -47,25 +47,23 @@ pub fn app_home_dir() -> Result<PathBuf> {
use tauri::utils::platform::current_exe;
if !PORTABLE_FLAG {
Ok(home_dir()
Ok(data_dir()
.ok_or(anyhow::anyhow!("failed to get app home dir"))?
.join(".config")
.join(APP_DIR))
.join(APP_ID))
} else {
let app_exe = current_exe()?;
let app_exe = dunce::canonicalize(app_exe)?;
let app_dir = app_exe
.parent()
.ok_or(anyhow::anyhow!("failed to get the portable app dir"))?;
Ok(PathBuf::from(app_dir).join(".config").join(APP_DIR))
Ok(PathBuf::from(app_dir).join(".config").join(APP_ID))
}
}
#[cfg(not(target_os = "windows"))]
Ok(home_dir()
Ok(data_dir()
.ok_or(anyhow::anyhow!("failed to get the app home dir"))?
.join(".config")
.join(APP_DIR))
.join("io.github.clash_verge_rev.clash_verge_rev"))
}
/// get the resources dir

View File

@@ -3,6 +3,10 @@ use nanoid::nanoid;
use serde::{de::DeserializeOwned, Serialize};
use serde_yaml::{Mapping, Value};
use std::{fs, path::PathBuf, str::FromStr};
use tauri::{
api::shell::{open, Program},
Manager,
};
/// read data from yaml as struct T
pub fn read_yaml<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
@@ -81,18 +85,20 @@ pub fn parse_str<T: FromStr>(target: &str, key: &str) -> Option<T> {
/// open file
/// use vscode by default
pub fn open_file(path: PathBuf) -> Result<()> {
pub fn open_file(app: tauri::AppHandle, path: PathBuf) -> Result<()> {
#[cfg(target_os = "macos")]
let code = "Visual Studio Code";
#[cfg(not(target_os = "macos"))]
let code = "code";
// use vscode first
if let Err(err) = open::with(&path, code) {
log::error!(target: "app", "failed to open file with VScode `{err}`");
// default open
open::that(path)?;
}
let _ = match Program::from_str(code) {
Ok(code) => open(&app.shell_scope(), &path.to_string_lossy(), Some(code)),
Err(err) => {
log::error!(target: "app", "Can't find VScode `{err}`");
// default open
open(&app.shell_scope(), &path.to_string_lossy(), None)
}
};
Ok(())
}

View File

@@ -1,7 +1,7 @@
{
"package": {
"productName": "Clash Verge",
"version": "1.4.2"
"version": "1.4.3"
},
"build": {
"distDir": "../dist",
@@ -16,8 +16,8 @@
},
"bundle": {
"active": true,
"targets": "all",
"identifier": "moe.elaina.clash.verge",
"targets": ["deb", "appimage", "nsis", "app", "dmg", "updater"],
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
@@ -29,8 +29,8 @@
"externalBin": ["sidecar/clash-meta", "sidecar/clash-meta-alpha"],
"copyright": "© 2022 zzzgydi All Rights Reserved",
"category": "DeveloperTool",
"shortDescription": "A Clash GUI based on tauri.",
"longDescription": "A Clash GUI based on tauri.",
"shortDescription": "A Clash Meta GUI based on tauri.",
"longDescription": "A Clash Meta GUI based on tauri.",
"deb": {
"depends": ["openssl"]
},
@@ -45,8 +45,15 @@
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": "",
"wix": {
"language": ["zh-CN", "en-US", "ru-RU"]
"webviewInstallMode": {
"type": "embedBootstrapper",
"silent": true
},
"nsis": {
"displayLanguageSelector": true,
"installerIcon": "icons/icon.ico",
"languages": ["SimpChinese", "English"],
"license": "../LICENSE"
}
}
},

View File

@@ -1,21 +0,0 @@
.page-enter {
opacity: 0;
clip-path: inset(0 100% 0 0); /* 完全隐藏内容 */
}
.page-enter-active {
opacity: 1;
clip-path: inset(0 0 0 0); /* 逐渐显示整个内容 */
transition: opacity 300ms, clip-path 300ms ease-in-out;
}
.page-exit {
opacity: 1;
clip-path: inset(0 0 0 0); /* 完全显示内容 */
}
.page-exit-active {
opacity: 0;
clip-path: inset(0 100% 0 0); /* 逐渐隐藏内容 */
transition: opacity 300ms, clip-path 300ms ease-in-out;
}

View File

@@ -42,7 +42,6 @@ body {
@import "./layout.scss";
@import "./page.scss";
@import "./anime.scss";
@import "./font.scss";
@media (prefers-color-scheme: dark) {

View File

@@ -47,7 +47,7 @@ export const LayoutTraffic = () => {
}, [clashInfo, pageVisible]);
/* --------- meta memory information --------- */
const isMetaCore = verge?.clash_core === "clash-meta";
const isMetaCore = verge?.clash_core?.includes("clash-meta");
const displayMemory = isMetaCore && (verge?.enable_memory_usage ?? true);
const memoryWs = useWebsocket(

View File

@@ -230,7 +230,7 @@ export const ProfileItem = (props: Props) => {
{...attributes}
{...listeners}
>
<DragIndicator sx={{ cursor: "grab" }} />
<DragIndicator sx={{ cursor: "move", marginLeft: "-6px" }} />
</Box>
<Typography

View File

@@ -75,14 +75,17 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
<BaseDialog
open={open}
title={`New Version v${updateInfo?.manifest?.version}`}
contentSx={{ minWidth: 360, maxWidth: 400, maxHeight: "50vh" }}
contentSx={{ minWidth: 360, maxWidth: 400, height: "50vh" }}
okBtn={t("Update")}
cancelBtn={t("Cancel")}
onClose={() => setOpen(false)}
onCancel={() => setOpen(false)}
onOk={onUpdate}
>
<UpdateLog dangerouslySetInnerHTML={{ __html: parseContent }} />
<UpdateLog
dangerouslySetInnerHTML={{ __html: parseContent }}
sx={{ height: "calc(100% - 10px)", overflow: "auto" }}
/>
{updateState && (
<LinearProgress
variant="buffer"

View File

@@ -38,7 +38,11 @@ const SettingClash = ({ onError }: Props) => {
const { ipv6, "allow-lan": allowLan, "log-level": logLevel } = clash ?? {};
const { enable_random_port = false, verge_mixed_port } = verge ?? {};
const {
enable_random_port = false,
verge_mixed_port,
enable_clash_fields = false,
} = verge ?? {};
const webRef = useRef<DialogRef>(null);
const fieldRef = useRef<DialogRef>(null);
@@ -112,7 +116,7 @@ const SettingClash = ({ onError }: Props) => {
<Tooltip title={t("Random Port")}>
<IconButton
color={enable_random_port ? "success" : "inherit"}
size="medium"
size="small"
onClick={() => {
Notice.success(t("After restart to take effect"), 1000);
onChangeVerge({ enable_random_port: !enable_random_port });
@@ -162,16 +166,18 @@ const SettingClash = ({ onError }: Props) => {
</IconButton>
</SettingItem>
<SettingItem label={t("Clash Field")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => fieldRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
{enable_clash_fields && (
<SettingItem label={t("Clash Field")}>
<IconButton
color="inherit"
size="small"
sx={{ my: "2px" }}
onClick={() => fieldRef.current?.open()}
>
<ArrowForward />
</IconButton>
</SettingItem>
)}
<SettingItem
label={t("Clash Core")}