Compare commits

..

7 Commits

18 changed files with 517 additions and 778 deletions

View File

@@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [windows-latest]
platform: [windows-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout repository

View File

@@ -1,6 +1,6 @@
{
"name": "clash-verge",
"version": "0.0.5",
"version": "0.0.6",
"license": "GPL-3.0",
"scripts": {
"dev": "cargo tauri dev",

576
src-tauri/Cargo.lock generated
View File

@@ -2,22 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ab_glyph"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61caed9aec6daeee1ea38ccf5fb225e4f96c1eeead1b4a5c267324a63cf02326"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
]
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e"
[[package]]
name = "adler"
version = "1.0.2"
@@ -30,18 +14,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom 0.2.3",
"once_cell",
"serde",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@@ -51,12 +23,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "android_glue"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
[[package]]
name = "ansi_term"
version = "0.12.1"
@@ -87,6 +53,7 @@ dependencies = [
"serde_yaml",
"tauri",
"tauri-build",
"tauri-plugin-shadows",
"tokio",
"warp",
"winreg 0.10.1",
@@ -159,12 +126,6 @@ dependencies = [
"system-deps 3.2.0",
]
[[package]]
name = "atomic_refcell"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d"
[[package]]
name = "attohttpc"
version = "0.18.0"
@@ -394,15 +355,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "cgl"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
dependencies = [
"libc",
]
[[package]]
name = "chrono"
version = "0.4.19"
@@ -416,16 +368,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "clipboard-win"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342"
dependencies = [
"lazy-bytes-cast",
"winapi",
]
[[package]]
name = "cocoa"
version = "0.24.0"
@@ -478,20 +420,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "copypasta"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b"
dependencies = [
"clipboard-win",
"objc",
"objc-foundation",
"objc_id",
"smithay-clipboard",
"x11-clipboard",
]
[[package]]
name = "core-foundation"
version = "0.7.0"
@@ -757,16 +685,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "directories-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc"
dependencies = [
"cfg-if 1.0.0",
"dirs-sys-next",
]
[[package]]
name = "dirs"
version = "1.0.5"
@@ -825,21 +743,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dlib"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
dependencies = [
"libloading",
]
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "dtoa"
version = "0.4.8"
@@ -855,62 +758,12 @@ dependencies = [
"dtoa",
]
[[package]]
name = "egui"
version = "0.16.1"
source = "git+https://github.com/wusyong/egui?branch=tao#e9071d26d85ab3ae35c4f91fd053733e46c26292"
dependencies = [
"ahash",
"epaint",
"nohash-hasher",
"ron",
"serde",
]
[[package]]
name = "egui-tao"
version = "0.16.0"
source = "git+https://github.com/wusyong/egui?branch=tao#e9071d26d85ab3ae35c4f91fd053733e46c26292"
dependencies = [
"copypasta",
"egui",
"epi",
"serde",
"tao",
"webbrowser",
]
[[package]]
name = "egui_glow"
version = "0.16.0"
source = "git+https://github.com/wusyong/egui?branch=tao#e9071d26d85ab3ae35c4f91fd053733e46c26292"
dependencies = [
"egui",
"egui-tao",
"epi",
"glib",
"glow",
"gtk",
"memoffset",
"tao-glutin",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "emath"
version = "0.16.0"
source = "git+https://github.com/wusyong/egui?branch=tao#e9071d26d85ab3ae35c4f91fd053733e46c26292"
dependencies = [
"serde",
]
[[package]]
name = "embed_plist"
version = "1.2.0"
@@ -947,30 +800,6 @@ dependencies = [
"syn",
]
[[package]]
name = "epaint"
version = "0.16.0"
source = "git+https://github.com/wusyong/egui?branch=tao#e9071d26d85ab3ae35c4f91fd053733e46c26292"
dependencies = [
"ab_glyph",
"ahash",
"atomic_refcell",
"emath",
"nohash-hasher",
"serde",
]
[[package]]
name = "epi"
version = "0.16.0"
source = "git+https://github.com/wusyong/egui?branch=tao#e9071d26d85ab3ae35c4f91fd053733e46c26292"
dependencies = [
"directories-next",
"egui",
"ron",
"serde",
]
[[package]]
name = "fastrand"
version = "1.6.0"
@@ -1226,20 +1055,6 @@ dependencies = [
"system-deps 3.2.0",
]
[[package]]
name = "gdkx11"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddf04101c33123fa9ba0e0f8b966573348097451462a6845d8a2bd85251ec64c"
dependencies = [
"gdk",
"gdkx11-sys",
"gio",
"glib",
"libc",
"x11",
]
[[package]]
name = "gdkx11-sys"
version = "0.14.0"
@@ -1328,27 +1143,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "gl_generator"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
dependencies = [
"khronos_api",
"log",
"xml-rs",
]
[[package]]
name = "gl_loader"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e32d96dd5f881490e537041d5532320812ba096097f07fccb4626578da0b99d3"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "glib"
version = "0.14.8"
@@ -1406,49 +1200,6 @@ dependencies = [
"regex",
]
[[package]]
name = "glow"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919"
dependencies = [
"js-sys",
"slotmap",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "glutin_egl_sys"
version = "0.1.5"
source = "git+https://github.com/wusyong/glutin?branch=tao#deb01b1bd3019a272847f380e764355670cfd7e3"
dependencies = [
"gl_generator",
"winapi",
]
[[package]]
name = "glutin_emscripten_sys"
version = "0.1.1"
source = "git+https://github.com/wusyong/glutin?branch=tao#deb01b1bd3019a272847f380e764355670cfd7e3"
[[package]]
name = "glutin_gles2_sys"
version = "0.1.5"
source = "git+https://github.com/wusyong/glutin?branch=tao#deb01b1bd3019a272847f380e764355670cfd7e3"
dependencies = [
"gl_generator",
"objc",
]
[[package]]
name = "glutin_wgl_sys"
version = "0.1.5"
source = "git+https://github.com/wusyong/glutin?branch=tao#deb01b1bd3019a272847f380e764355670cfd7e3"
dependencies = [
"gl_generator",
]
[[package]]
name = "gobject-sys"
version = "0.14.0"
@@ -1843,12 +1594,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "khronos_api"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kuchiki"
version = "0.8.1"
@@ -1861,12 +1606,6 @@ dependencies = [
"selectors",
]
[[package]]
name = "lazy-bytes-cast"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b"
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -1902,16 +1641,6 @@ version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "libloading"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
dependencies = [
"cfg-if 1.0.0",
"winapi",
]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
@@ -2047,15 +1776,6 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memmap2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357"
dependencies = [
"libc",
]
[[package]]
name = "memoffset"
version = "0.6.5"
@@ -2081,12 +1801,6 @@ dependencies = [
"unicase",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "minisign-verify"
version = "0.2.0"
@@ -2245,42 +1959,12 @@ dependencies = [
"void",
]
[[package]]
name = "nix"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"libc",
"memoffset",
]
[[package]]
name = "nodrop"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nohash-hasher"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
[[package]]
name = "nom"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
dependencies = [
"memchr",
"minimal-lexical",
"version_check",
]
[[package]]
name = "notify-rust"
version = "4.5.5"
@@ -2479,15 +2163,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "owned_ttf_parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ef05f2882a8b3e7acc10c153ade2631f7bfc8ce00d2bf3fb8f4e9d2ae6ea5c3"
dependencies = [
"ttf-parser",
]
[[package]]
name = "pango"
version = "0.14.8"
@@ -2820,15 +2495,6 @@ version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quick-xml"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.14"
@@ -3092,17 +2758,6 @@ dependencies = [
"windows 0.29.0",
]
[[package]]
name = "ron"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678"
dependencies = [
"base64",
"bitflags",
"serde",
]
[[package]]
name = "rust-argon2"
version = "0.8.3"
@@ -3388,49 +3043,12 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "slotmap"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
dependencies = [
"version_check",
]
[[package]]
name = "smallvec"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "smithay-client-toolkit"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1325f292209cee78d5035530932422a30aa4c8fda1a16593ac083c1de211e68a"
dependencies = [
"bitflags",
"dlib",
"lazy_static",
"log",
"memmap2",
"nix 0.22.0",
"pkg-config",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
]
[[package]]
name = "smithay-clipboard"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55"
dependencies = [
"smithay-client-toolkit",
"wayland-client",
]
[[package]]
name = "socket2"
version = "0.4.2"
@@ -3630,33 +3248,6 @@ dependencies = [
"x11-dl",
]
[[package]]
name = "tao-glutin"
version = "0.1.0"
source = "git+https://github.com/wusyong/glutin?branch=tao#deb01b1bd3019a272847f380e764355670cfd7e3"
dependencies = [
"android_glue",
"cgl",
"cocoa",
"core-foundation 0.9.2",
"gdk",
"gdkx11",
"gl_loader",
"glib",
"glutin_egl_sys",
"glutin_emscripten_sys",
"glutin_gles2_sys",
"glutin_wgl_sys",
"gtk",
"lazy_static",
"libloading",
"log",
"objc",
"parking_lot",
"tao",
"winapi",
]
[[package]]
name = "tar"
version = "0.4.38"
@@ -3671,7 +3262,7 @@ dependencies = [
[[package]]
name = "tauri"
version = "1.0.0-beta.8"
source = "git+https://github.com/tauri-apps/tauri?rev=5e0d59ec#5e0d59ec7d5b75d8f128d30213c0f81e9b146406"
source = "git+https://github.com/tauri-apps/tauri?branch=next#46f2eae8aad7c6a228eaf48480d5603dae6454b4"
dependencies = [
"attohttpc",
"base64",
@@ -3680,7 +3271,6 @@ dependencies = [
"dirs-next",
"either",
"embed_plist",
"epi",
"flate2",
"futures",
"futures-lite",
@@ -3708,7 +3298,7 @@ dependencies = [
"tauri-macros",
"tauri-runtime",
"tauri-runtime-wry",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?rev=5e0d59ec)",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?branch=next)",
"tempfile",
"thiserror",
"tokio",
@@ -3734,7 +3324,7 @@ dependencies = [
[[package]]
name = "tauri-codegen"
version = "1.0.0-beta.4"
source = "git+https://github.com/tauri-apps/tauri?rev=5e0d59ec#5e0d59ec7d5b75d8f128d30213c0f81e9b146406"
source = "git+https://github.com/tauri-apps/tauri?branch=next#46f2eae8aad7c6a228eaf48480d5603dae6454b4"
dependencies = [
"blake3",
"kuchiki",
@@ -3743,7 +3333,7 @@ dependencies = [
"regex",
"serde",
"serde_json",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?rev=5e0d59ec)",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?branch=next)",
"thiserror",
"walkdir",
"zstd",
@@ -3752,7 +3342,7 @@ dependencies = [
[[package]]
name = "tauri-macros"
version = "1.0.0-beta.5"
source = "git+https://github.com/tauri-apps/tauri?rev=5e0d59ec#5e0d59ec7d5b75d8f128d30213c0f81e9b146406"
source = "git+https://github.com/tauri-apps/tauri?branch=next#46f2eae8aad7c6a228eaf48480d5603dae6454b4"
dependencies = [
"proc-macro2",
"quote",
@@ -3760,10 +3350,21 @@ dependencies = [
"tauri-codegen",
]
[[package]]
name = "tauri-plugin-shadows"
version = "0.0.0"
source = "git+https://github.com/tauri-apps/tauri-plugin-shadows#e61ff61f7f7dfac5d881e310588c3f6ceac16dba"
dependencies = [
"cocoa",
"objc",
"tauri",
"windows 0.29.0",
]
[[package]]
name = "tauri-runtime"
version = "0.2.1"
source = "git+https://github.com/tauri-apps/tauri?rev=5e0d59ec#5e0d59ec7d5b75d8f128d30213c0f81e9b146406"
source = "git+https://github.com/tauri-apps/tauri?branch=next#46f2eae8aad7c6a228eaf48480d5603dae6454b4"
dependencies = [
"gtk",
"http",
@@ -3771,7 +3372,7 @@ dependencies = [
"infer",
"serde",
"serde_json",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?rev=5e0d59ec)",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?branch=next)",
"thiserror",
"uuid",
"webview2-com",
@@ -3781,20 +3382,14 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
version = "0.2.1"
source = "git+https://github.com/tauri-apps/tauri?rev=5e0d59ec#5e0d59ec7d5b75d8f128d30213c0f81e9b146406"
source = "git+https://github.com/tauri-apps/tauri?branch=next#46f2eae8aad7c6a228eaf48480d5603dae6454b4"
dependencies = [
"egui-tao",
"egui_glow",
"epi",
"glow",
"gtk",
"ico",
"infer",
"once_cell",
"png 0.16.8",
"tao-glutin",
"tauri-runtime",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?rev=5e0d59ec)",
"tauri-utils 1.0.0-beta.3 (git+https://github.com/tauri-apps/tauri?branch=next)",
"uuid",
"webview2-com",
"windows 0.29.0",
@@ -3822,7 +3417,7 @@ dependencies = [
[[package]]
name = "tauri-utils"
version = "1.0.0-beta.3"
source = "git+https://github.com/tauri-apps/tauri?rev=5e0d59ec#5e0d59ec7d5b75d8f128d30213c0f81e9b146406"
source = "git+https://github.com/tauri-apps/tauri?branch=next#46f2eae8aad7c6a228eaf48480d5603dae6454b4"
dependencies = [
"heck 0.4.0",
"html5ever",
@@ -4101,12 +3696,6 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "ttf-parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281"
[[package]]
name = "tungstenite"
version = "0.14.0"
@@ -4388,79 +3977,6 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "wayland-client"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e256a731597b4e264d2f342e44f3708814103fbab144676fa077b6d9f3e2966"
dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix 0.22.0",
"scoped-tls",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
]
[[package]]
name = "wayland-commons"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96f28d05d154a6ae7a183f2d29906ccceae794047b3a97d35a627f483ed05ee2"
dependencies = [
"nix 0.22.0",
"once_cell",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-cursor"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcb1afc06470809fea80281128ea2ed21b730589fe5f5ef0478eb8633bc1b003"
dependencies = [
"nix 0.22.0",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-protocols"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b5199e12af7708dfb4eb6ea2f10b089d21b4b437cfde44b018ad11b093101b6"
dependencies = [
"bitflags",
"wayland-client",
"wayland-commons",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cfd5edf014d2bcfd13607f6461acc15677676eeca58df0af7c4856be5faabf1"
dependencies = [
"proc-macro2",
"quote",
"xml-rs",
]
[[package]]
name = "wayland-sys"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beb0eb50984d3efb0642b58ee2f458a62d765563bebd94049b6f9f40979f12aa"
dependencies = [
"dlib",
"lazy_static",
"pkg-config",
]
[[package]]
name = "web-sys"
version = "0.3.55"
@@ -4471,17 +3987,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webbrowser"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a"
dependencies = [
"web-sys",
"widestring",
"winapi",
]
[[package]]
name = "webkit2gtk"
version = "0.16.0"
@@ -4574,12 +4079,6 @@ dependencies = [
"cc",
]
[[package]]
name = "widestring"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
[[package]]
name = "wildmatch"
version = "2.1.0"
@@ -4817,15 +4316,6 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "x11-clipboard"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c"
dependencies = [
"xcb",
]
[[package]]
name = "x11-dl"
version = "2.19.1"
@@ -4846,26 +4336,6 @@ dependencies = [
"libc",
]
[[package]]
name = "xcb"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c"
dependencies = [
"libc",
"log",
"quick-xml",
]
[[package]]
name = "xcursor"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
dependencies = [
"nom",
]
[[package]]
name = "xml-rs"
version = "0.8.4"
@@ -4894,7 +4364,7 @@ dependencies = [
"fastrand",
"futures",
"nb-connect",
"nix 0.17.0",
"nix",
"once_cell",
"polling",
"scoped-tls",

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
description = "clash verge"
authors = ["zzzgydi"]
license = "GPL-3.0"
repository = ""
repository = "https://github.com/zzzgydi/clash-verge.git"
default-run = "app"
edition = "2021"
build = "build.rs"
@@ -19,7 +19,9 @@ serde_json = "1.0"
serde_yaml = "0.8"
serde = { version = "1.0", features = ["derive"] }
# tauri = { version = "1.0.0-beta.8", features = ["api-all", "system-tray"] }
tauri = { git = "https://github.com/tauri-apps/tauri", rev = "5e0d59ec", features = ["api-all", "system-tray"] }
# tauri = { git = "https://github.com/tauri-apps/tauri", rev = "5e0d59ec", features = ["api-all", "system-tray"] }
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next", features = ["api-all", "system-tray"] }
tauri-plugin-shadows = { git = "https://github.com/tauri-apps/tauri-plugin-shadows", features = ["tauri-impl"] }
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }

View File

@@ -8,7 +8,7 @@ use crate::{
},
};
use serde_yaml::Mapping;
use tauri::State;
use tauri::{AppHandle, Manager, State};
/// get all profiles from `profiles.yaml`
/// do not acquire the lock of ProfileLock
@@ -107,13 +107,23 @@ pub fn select_profile(
}
}
/// todo: need to check
/// delete profile item
#[tauri::command]
pub fn delete_profile(index: usize, profiles: State<'_, ProfilesState>) -> Result<(), String> {
match profiles.0.lock() {
Ok(mut profiles) => profiles.delete_item(index),
Err(_) => Err("can not get profiles lock".into()),
pub fn delete_profile(
index: usize,
clash_state: State<'_, ClashState>,
profiles_state: State<'_, ProfilesState>,
) -> Result<(), String> {
let mut profiles = profiles_state.0.lock().unwrap();
match profiles.delete_item(index) {
Ok(change) => match change {
true => {
let clash = clash_state.0.lock().unwrap();
profiles.activate(clash.info.clone())
}
false => Ok(()),
},
Err(err) => Err(err),
}
}
@@ -236,3 +246,25 @@ pub async fn patch_verge_config(
verge.config.save_file()
}
/// start dragging window
#[tauri::command]
pub fn win_drag(app_handle: AppHandle) {
let window = app_handle.get_window("main").unwrap();
window.start_dragging().unwrap();
}
/// hide the window
#[tauri::command]
pub fn win_hide(app_handle: AppHandle) {
let window = app_handle.get_window("main").unwrap();
window.hide().unwrap();
}
/// mini the window
#[tauri::command]
pub fn win_mini(app_handle: AppHandle) {
let window = app_handle.get_window("main").unwrap();
// todo: these methods still has bug on Windows
window.minimize().unwrap();
}

View File

@@ -195,7 +195,7 @@ impl ProfilesConfig {
}
/// delete the item
pub fn delete_item(&mut self, index: usize) -> Result<(), String> {
pub fn delete_item(&mut self, index: usize) -> Result<bool, String> {
let mut current = self.current.clone().unwrap_or(0);
let mut items = self.items.clone().unwrap_or(vec![]);
@@ -205,13 +205,22 @@ impl ProfilesConfig {
items.remove(index);
let mut should_change = false;
if current == index {
current = 0;
should_change = true;
} else if current > index {
current = current - 1;
}
self.current = Some(current);
self.save_file()
self.items = Some(items);
match self.save_file() {
Ok(_) => Ok(should_change),
Err(err) => Err(err),
}
}
/// activate current profile

View File

@@ -22,10 +22,10 @@ fn main() -> std::io::Result<()> {
}
let menu = SystemTrayMenu::new()
.add_item(CustomMenuItem::new("open_window", "显示应用"))
.add_item(CustomMenuItem::new("restart_clash", "重启clash"))
.add_item(CustomMenuItem::new("open_window", "Show"))
.add_item(CustomMenuItem::new("restart_clash", "Restart Clash"))
.add_native_item(SystemTrayMenuItem::Separator)
.add_item(CustomMenuItem::new("quit", "退出").accelerator("CmdOrControl+Q"));
.add_item(CustomMenuItem::new("quit", "Quit").accelerator("CmdOrControl+Q"));
tauri::Builder::default()
.manage(states::VergeState::default())
@@ -62,14 +62,21 @@ fn main() -> std::io::Result<()> {
_ => {}
})
.invoke_handler(tauri::generate_handler![
// common
cmds::restart_sidecar,
cmds::set_sys_proxy,
cmds::get_sys_proxy,
cmds::get_cur_proxy,
cmds::win_drag,
cmds::win_hide,
cmds::win_mini,
// clash
cmds::get_clash_info,
cmds::patch_clash_config,
// verge
cmds::get_verge_config,
cmds::patch_verge_config,
// profile
cmds::import_profile,
cmds::update_profile,
cmds::delete_profile,
@@ -86,10 +93,7 @@ fn main() -> std::io::Result<()> {
api.prevent_close();
app_handle.get_window(&label).unwrap().hide().unwrap();
}
tauri::Event::ExitRequested { api, .. } => {
api.prevent_exit();
}
tauri::Event::Exit => {
tauri::Event::ExitRequested { .. } => {
resolve::resolve_reset(app_handle);
api::process::kill_children();
}

View File

@@ -1,9 +1,14 @@
use super::{init, server};
use crate::{core::ProfilesConfig, states};
use tauri::{App, AppHandle, Manager};
use tauri_plugin_shadows::Shadows;
/// handle something when start app
pub fn resolve_setup(app: &App) {
// set shadow when window decorations
let window = app.get_window("main").unwrap();
window.set_shadow(true);
// setup a simple http server for singleton
server::embed_server(&app.handle());
@@ -34,7 +39,7 @@ pub fn resolve_setup(app: &App) {
/// reset system proxy
pub fn resolve_reset(app_handle: &AppHandle) {
let verge_state = app_handle.state::<states::VergeState>();
let mut verge_arc = verge_state.0.lock().unwrap();
let mut verge = verge_state.0.lock().unwrap();
verge_arc.reset_sysproxy();
verge.reset_sysproxy();
}

156
src-tauri/src/utils/sysopt.rs Normal file → Executable file
View File

@@ -1,7 +1,13 @@
use serde::{Deserialize, Serialize};
use std::io;
#[cfg(target_os = "windows")]
static DEFAULT_BYPASS: &str = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*;<local>";
#[cfg(target_os = "macos")]
static DEFAULT_BYPASS: &str =
"192.168.0.0/16\n10.0.0.0/8\n172.16.0.0/12\n127.0.0.1\nlocalhost\n*.local\ntimestamp.apple.com\n";
#[cfg(target_os = "macos")]
static MACOS_SERVICE: &str = "Wi-Fi";
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct SysProxyConfig {
@@ -29,8 +35,8 @@ impl SysProxyConfig {
}
}
/// Get the windows system proxy config
#[cfg(target_os = "windows")]
/// Get the windows system proxy config
pub fn get_sys() -> io::Result<Self> {
use winreg::enums::*;
use winreg::RegKey;
@@ -48,6 +54,43 @@ impl SysProxyConfig {
})
}
#[cfg(target_os = "macos")]
/// Get the macos system proxy config
pub fn get_sys() -> io::Result<Self> {
use std::process::Command;
let http = macproxy::get_proxy(&["-getwebproxy", MACOS_SERVICE])?;
let https = macproxy::get_proxy(&["-getsecurewebproxy", MACOS_SERVICE])?;
let sock = macproxy::get_proxy(&["-getsocksfirewallproxy", MACOS_SERVICE])?;
let mut enable = false;
let mut server = "".into();
if sock.0 == "Yes" {
enable = true;
server = sock.1;
}
if https.0 == "Yes" {
enable = true;
server = https.1;
}
if http.0 == "Yes" || !enable {
enable = http.0 == "Yes";
server = http.1;
}
let bypass_output = Command::new("networksetup")
.args(["-getproxybypassdomains", MACOS_SERVICE])
.output()?;
let bypass = std::str::from_utf8(&bypass_output.stdout).unwrap_or(DEFAULT_BYPASS);
Ok(SysProxyConfig {
enable,
server,
bypass: bypass.into(),
})
}
#[cfg(target_os = "windows")]
/// Set the windows system proxy config
pub fn set_sys(&self) -> io::Result<()> {
@@ -65,21 +108,104 @@ impl SysProxyConfig {
cur_var.set_value("ProxyServer", &self.server)?;
cur_var.set_value("ProxyOverride", &self.bypass)
}
#[cfg(target_os = "macos")]
/// Set the macos system proxy config
pub fn set_sys(&self) -> io::Result<()> {
let enable = self.enable;
let server = self.server.as_str();
macproxy::set_proxy("-setwebproxy", MACOS_SERVICE, enable, server)?;
macproxy::set_proxy("-setsecurewebproxy", MACOS_SERVICE, enable, server)?;
macproxy::set_proxy("-setsocksfirewallproxy", MACOS_SERVICE, enable, server)
}
}
// #[cfg(target_os = "macos")]
// mod macos {
// use super::*;
#[cfg(target_os = "macos")]
mod macproxy {
use super::*;
use std::process::Command;
// pub fn get_proxy_config() -> io::Result<SysProxyConfig> {
// Ok(SysProxyConfig {
// enable: false,
// server: "server".into(),
// bypass: "bypass".into(),
// })
// }
/// use networksetup
/// get the target proxy config
pub(super) fn get_proxy(args: &[&str; 2]) -> io::Result<(String, String)> {
let output = Command::new("networksetup").args(args).output()?;
match std::str::from_utf8(&output.stdout) {
Ok(stdout) => {
let enable = parse(stdout, "Enabled:");
let server = parse(stdout, "Server:");
let port = parse(stdout, "Port:");
let server = format!("{}:{}", server, port);
Ok((enable.into(), server))
}
Err(_) => Err(io::Error::from_raw_os_error(1)),
}
}
// pub fn set_proxy_config(config: &SysProxyConfig) -> io::Result<()> {
// Ok(())
// }
// }
/// use networksetup
/// set the target proxy config
pub(super) fn set_proxy(
target: &str, // like: -setwebproxy
device: &str,
enable: bool,
server: &str,
) -> io::Result<()> {
let mut split = server.split(":");
let domain = split.next();
let port = split.next();
// can not parse the field
if domain.is_none() || port.is_none() {
return Err(io::Error::from_raw_os_error(1));
}
let args = vec![target, device, domain.unwrap(), port.unwrap()];
Command::new("networksetup").args(&args).status()?;
let target_state = String::from(target) + "state";
let enable = if enable { "on" } else { "off" };
let args = vec![target_state.as_str(), device, enable];
Command::new("networksetup").args(&args).status()?;
Ok(())
}
/// parse the networksetup output
pub(super) fn parse<'a>(target: &'a str, key: &'a str) -> &'a str {
match target.find(key) {
Some(idx) => {
let idx = idx + key.len();
let value = &target[idx..];
let value = match value.find("\n") {
Some(end) => &value[..end],
None => value,
};
value.trim()
}
None => "",
}
}
#[test]
fn test_get() {
use std::process::Command;
let output = Command::new("networksetup")
.args(["-getwebproxy", "Wi-Fi"])
.output();
let output = output.unwrap();
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let enable = parse(stdout, "Enabled:");
let server = parse(stdout, "Server:");
let port = parse(stdout, "Port:");
println!("enable: {}, server: {}, port: {}", enable, server, port);
dbg!(SysProxyConfig::get_sys().unwrap());
}
#[test]
fn test_set() {
let sysproxy = SysProxyConfig::new(true, "7890".into(), None);
dbg!(sysproxy.set_sys().unwrap());
}
}

View File

@@ -1,11 +1,11 @@
{
"package": {
"productName": "clash-verge",
"version": "0.0.5"
"version": "0.0.6"
},
"build": {
"distDir": "../dist",
"devPath": "http://localhost:3000/proxy",
"devPath": "http://localhost:3000/",
"beforeDevCommand": "yarn run web:dev",
"beforeBuildCommand": "yarn run web:build"
},
@@ -62,7 +62,7 @@
"height": 600,
"resizable": true,
"fullscreen": false,
"decorations": true,
"decorations": false,
"transparent": false,
"minWidth": 600,
"minHeight": 520

View File

@@ -1,46 +1,72 @@
.layout {
width: 100%;
height: 100vh;
display: flex;
overflow: hidden;
&__sidebar {
position: relative;
&__left {
flex: 1 0 25%;
height: 100vh;
display: flex;
height: 100%;
max-width: 225px;
min-width: 125px;
overflow: hidden auto;
padding: 8px 0;
flex-direction: column;
box-sizing: border-box;
user-select: none;
overflow: hidden;
.the-logo {
flex: 0 1 180px;
width: 100%;
max-width: 180px;
max-height: 180px;
margin: 0 auto;
padding: 0 8px;
text-align: center;
box-sizing: border-box;
}
.the-menu {
flex: 1 1 75%;
overflow-y: auto;
margin-bottom: 8px;
}
.the-traffic {
flex: 0 0 60px;
> div {
margin: 0 auto;
}
}
}
&__content {
&__right {
position: relative;
flex: 1 1 75%;
height: 100vh;
overflow: auto;
height: 100%;
display: flex;
flex-direction: column;
padding: 2px 0;
box-sizing: border-box;
scrollbar-gutter: "stable";
}
&__logo {
width: 100%;
height: auto;
max-width: 180px;
max-height: 180px;
margin: 0 auto;
padding: 8px 8px 0;
user-select: none;
text-align: center;
box-sizing: border-box;
}
.the-bar {
flex: 0 0 30px;
width: 100%;
height: 30px;
padding: 0 16px;
display: flex;
align-items: center;
justify-content: flex-end;
box-sizing: border-box;
}
&__traffic {
position: absolute;
left: 0;
right: 0;
bottom: 8px;
> div {
margin: 0 auto;
.the-content {
flex: 1 1 100%;
overflow: auto;
box-sizing: border-box;
scrollbar-gutter: stable;
}
}
}

View File

@@ -8,13 +8,15 @@ import {
LinearProgress,
IconButton,
keyframes,
MenuItem,
Menu,
} from "@mui/material";
import { useSWRConfig } from "swr";
import { RefreshRounded } from "@mui/icons-material";
import { CmdType } from "../services/types";
import { updateProfile, deleteProfile } from "../services/cmds";
import parseTraffic from "../utils/parse-traffic";
import relativeTime from "dayjs/plugin/relativeTime";
import { updateProfile } from "../services/cmds";
dayjs.extend(relativeTime);
@@ -46,6 +48,8 @@ const ProfileItemComp: React.FC<Props> = (props) => {
const { mutate } = useSWRConfig();
const [loading, setLoading] = useState(false);
const [anchorEl, setAnchorEl] = useState<any>(null);
const [position, setPosition] = useState({ left: 0, top: 0 });
const { name = "Profile", extra, updated = 0 } = itemData;
const { upload = 0, download = 0, total = 0 } = extra ?? {};
@@ -55,6 +59,7 @@ const ProfileItemComp: React.FC<Props> = (props) => {
const fromnow = updated > 0 ? dayjs(updated * 1000).fromNow() : "";
const onUpdate = async () => {
setAnchorEl(null);
if (loading) return;
setLoading(true);
try {
@@ -67,98 +72,135 @@ const ProfileItemComp: React.FC<Props> = (props) => {
}
};
const onDelete = async () => {
setAnchorEl(null);
try {
await deleteProfile(index);
mutate("getProfiles");
} catch (err) {
console.error(err);
}
};
const handleContextMenu = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
const { clientX, clientY } = event;
setPosition({ top: clientY, left: clientX });
setAnchorEl(event.currentTarget);
event.preventDefault();
};
return (
<Wrapper
sx={({ palette }) => {
const { mode, primary, text, grey } = palette;
const isDark = mode === "dark";
<>
<Wrapper
sx={({ palette }) => {
const { mode, primary, text, grey } = palette;
const key = `${mode}-${selected}`;
if (selected) {
const bgcolor = isDark
? alpha(primary.main, 0.35)
: alpha(primary.main, 0.15);
const bgcolor = {
"light-true": alpha(primary.main, 0.15),
"light-false": palette.background.paper,
"dark-true": alpha(primary.main, 0.35),
"dark-false": alpha(grey[700], 0.35),
}[key]!;
return {
bgcolor,
color: isDark ? alpha(text.secondary, 0.6) : text.secondary,
"& h2": {
color: isDark ? primary.light : primary.main,
},
};
}
const bgcolor = isDark
? alpha(grey[700], 0.35)
: palette.background.paper;
return {
bgcolor,
color: isDark ? alpha(text.secondary, 0.6) : text.secondary,
"& h2": {
color: isDark ? text.primary : text.primary,
},
};
}}
onClick={onClick}
>
<Box display="flex" justifyContent="space-between">
<Typography
width="calc(100% - 40px)"
variant="h6"
component="h2"
noWrap
title={name}
>
{name}
</Typography>
const color = {
"light-true": text.secondary,
"light-false": text.secondary,
"dark-true": alpha(text.secondary, 0.6),
"dark-false": alpha(text.secondary, 0.6),
}[key]!;
<IconButton
sx={{
width: 30,
height: 30,
animation: loading ? `1s linear infinite ${round}` : "none",
}}
color="inherit"
disabled={loading}
onClick={(e) => {
e.stopPropagation();
onUpdate();
}}
>
<RefreshRounded />
</IconButton>
</Box>
const h2color = {
"light-true": primary.main,
"light-false": text.primary,
"dark-true": primary.light,
"dark-false": text.primary,
}[key]!;
<Box display="flex" justifyContent="space-between" alignItems="center">
<Typography noWrap title={`From: ${from}`}>
{from}
</Typography>
<Typography
noWrap
flex="1 0 auto"
fontSize={14}
textAlign="right"
title="updated time"
>
{fromnow}
</Typography>
</Box>
<Box
sx={{
my: 0.5,
fontSize: 14,
display: "flex",
justifyContent: "space-between",
return { bgcolor, color, "& h2": { color: h2color } };
}}
onClick={onClick}
onContextMenu={handleContextMenu}
>
<span title="used / total">
{parseTraffic(upload + download)} / {parseTraffic(total)}
</span>
<span title="expire time">{expire}</span>
</Box>
<Box display="flex" justifyContent="space-between">
<Typography
width="calc(100% - 40px)"
variant="h6"
component="h2"
noWrap
title={name}
>
{name}
</Typography>
<LinearProgress variant="determinate" value={progress} color="inherit" />
</Wrapper>
<IconButton
sx={{
width: 30,
height: 30,
animation: loading ? `1s linear infinite ${round}` : "none",
}}
color="inherit"
disabled={loading}
onClick={(e) => {
e.stopPropagation();
onUpdate();
}}
>
<RefreshRounded />
</IconButton>
</Box>
<Box display="flex" justifyContent="space-between" alignItems="center">
<Typography noWrap title={`From: ${from}`}>
{from}
</Typography>
<Typography
noWrap
flex="1 0 auto"
fontSize={14}
textAlign="right"
title="updated time"
>
{fromnow}
</Typography>
</Box>
<Box
sx={{
my: 0.5,
fontSize: 14,
display: "flex",
justifyContent: "space-between",
}}
>
<span title="used / total">
{parseTraffic(upload + download)} / {parseTraffic(total)}
</span>
<span title="expire time">{expire}</span>
</Box>
<LinearProgress
variant="determinate"
value={progress}
color="inherit"
/>
</Wrapper>
<Menu
open={!!anchorEl}
anchorEl={anchorEl}
onClose={() => setAnchorEl(null)}
anchorPosition={position}
anchorReference="anchorPosition"
>
<MenuItem onClick={onUpdate}>Update</MenuItem>
<MenuItem onClick={onDelete}>Delete</MenuItem>
{/* <MenuItem>Update(proxy)</MenuItem> */}
</Menu>
</>
);
};

View File

@@ -43,11 +43,11 @@ const SettingClash = ({ onError }: Props) => {
return (
<List>
<ListSubheader sx={{ background: "transparent" }}>
Clash设置
Clash Setting
</ListSubheader>
<SettingItem>
<ListItemText primary="局域网连接" />
<ListItemText primary="Allow Lan" />
<GuardState
value={allowLan}
valueProps="checked"
@@ -75,7 +75,7 @@ const SettingClash = ({ onError }: Props) => {
</SettingItem>
<SettingItem>
<ListItemText primary="日志等级" />
<ListItemText primary="Log Level" />
<GuardState
value={logLevel}
onCatch={onError}
@@ -94,7 +94,7 @@ const SettingClash = ({ onError }: Props) => {
</SettingItem>
<SettingItem>
<ListItemText primary="混合代理端口" />
<ListItemText primary="Mixed Port" />
<TextField
size="small"
value={mixedPort!}

View File

@@ -39,10 +39,12 @@ const SettingVerge = ({ onError }: Props) => {
return (
<List>
<ListSubheader sx={{ background: "transparent" }}></ListSubheader>
<ListSubheader sx={{ background: "transparent" }}>
Common Setting
</ListSubheader>
<SettingItem>
<ListItemText primary="外观主题" />
<ListItemText primary="Theme Mode" />
<GuardState
value={mode === "dark"}
valueProps="checked"
@@ -58,7 +60,7 @@ const SettingVerge = ({ onError }: Props) => {
</SettingItem>
<SettingItem>
<ListItemText primary="开机自启" />
<ListItemText primary="Self Start" />
<GuardState
value={startup}
valueProps="checked"
@@ -74,7 +76,7 @@ const SettingVerge = ({ onError }: Props) => {
</SettingItem>
<SettingItem>
<ListItemText primary="设置系统代理" />
<ListItemText primary="System Proxy" />
<GuardState
value={proxy}
valueProps="checked"

View File

@@ -2,12 +2,18 @@ import { useEffect, useMemo } from "react";
import useSWR, { SWRConfig } from "swr";
import { Route, Routes } from "react-router-dom";
import { useRecoilState } from "recoil";
import { createTheme, List, Paper, ThemeProvider } from "@mui/material";
import {
createTheme,
IconButton,
List,
Paper,
ThemeProvider,
} from "@mui/material";
import { HorizontalRuleRounded, CloseRounded } from "@mui/icons-material";
import { atomPaletteMode } from "../states/setting";
import { getVergeConfig } from "../services/cmds";
import { getVergeConfig, windowDrag, windowHide } from "../services/cmds";
import LogoSvg from "../assets/image/logo.svg";
import LogPage from "./log";
import HomePage from "./home";
import ProfilePage from "./profile";
import ProxyPage from "./proxy";
import SettingPage from "./setting";
@@ -17,24 +23,29 @@ import Traffic from "../components/traffic";
const routers = [
{
label: "代理",
link: "/proxy",
label: "Proxy",
link: "/",
ele: ProxyPage,
},
{
label: "配置",
label: "Profile",
link: "/profile",
ele: ProfilePage,
},
{
label: "连接",
label: "Connections",
link: "/connections",
ele: ConnectionsPage,
},
{
label: "日志",
label: "Log",
link: "/log",
ele: LogPage,
},
{
label: "设置",
label: "Setting",
link: "/setting",
ele: SettingPage,
},
];
@@ -47,39 +58,21 @@ const Layout = () => {
}, [vergeConfig?.theme_mode]);
const theme = useMemo(() => {
if (mode === "light") {
document.documentElement.style.background = "#f5f5f5";
document.documentElement.style.setProperty(
"--selection-color",
"#f5f5f5"
);
} else {
document.documentElement.style.background = "#000";
document.documentElement.style.setProperty(
"--selection-color",
"#d5d5d5"
);
}
// const background = mode === "light" ? "#f5f5f5" : "#000";
const selectColor = mode === "light" ? "#f5f5f5" : "#d5d5d5";
const rootEle = document.documentElement;
rootEle.style.background = "transparent";
rootEle.style.setProperty("--selection-color", selectColor);
return createTheme({
breakpoints: {
values: {
xs: 0,
sm: 650,
md: 900,
lg: 1200,
xl: 1536,
},
values: { xs: 0, sm: 650, md: 900, lg: 1200, xl: 1536 },
},
palette: {
mode,
primary: {
main: "#5b5c9d",
},
text: {
primary: "#637381",
secondary: "#909399",
},
primary: { main: "#5b5c9d" },
text: { primary: "#637381", secondary: "#909399" },
},
});
}, [mode]);
@@ -88,12 +81,20 @@ const Layout = () => {
<SWRConfig value={{}}>
<ThemeProvider theme={theme}>
<Paper square elevation={0} className="layout">
<div className="layout__sidebar">
<div className="layout__logo">
<img src={LogoSvg} width="100%" alt="" />
<div className="layout__left">
<div className="the-logo">
<img
src={LogoSvg}
width="100%"
alt=""
onPointerDown={(e) => {
windowDrag();
e.preventDefault();
}}
/>
</div>
<List sx={{ userSelect: "none" }}>
<List className="the-menu">
{routers.map((router) => (
<LayoutItem key={router.label} to={router.link}>
{router.label}
@@ -101,20 +102,35 @@ const Layout = () => {
))}
</List>
<div className="layout__traffic">
<div className="the-traffic">
<Traffic />
</div>
</div>
<div className="layout__content">
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/proxy" element={<ProxyPage />} />
<Route path="/profile" element={<ProfilePage />} />
<Route path="/log" element={<LogPage />} />
<Route path="/connections" element={<ConnectionsPage />} />
<Route path="/setting" element={<SettingPage />} />
</Routes>
<div className="layout__right">
<div
className="the-bar"
onPointerDown={(e) =>
e.target === e.currentTarget && windowDrag()
}
>
{/* todo: onClick = windowMini */}
<IconButton size="small" sx={{ mx: 1 }} onClick={windowHide}>
<HorizontalRuleRounded fontSize="inherit" />
</IconButton>
<IconButton size="small" onClick={windowHide}>
<CloseRounded fontSize="inherit" />
</IconButton>
</div>
<div className="the-content">
<Routes>
{routers.map(({ link, ele: Ele }) => (
<Route path={link} element={<Ele />} />
))}
</Routes>
</div>
</div>
</Paper>
</ThemeProvider>

View File

@@ -1,11 +0,0 @@
import { Typography } from "@mui/material";
const HomePage = () => {
return (
<Typography variant="h1" textAlign="center" mt={10}>
Hello Clash!
</Typography>
);
};
export default HomePage;

View File

@@ -24,16 +24,20 @@ const ProfilePage = () => {
if (profiles.current == null) return;
if (!profiles.items) profiles.items = [];
const profile = profiles.items![profiles.current];
const current = profiles.current;
const profile = profiles.items![current];
if (!profile) return;
getProxies().then((proxiesData) => {
setTimeout(async () => {
const proxiesData = await getProxies();
mutate("getProxies", proxiesData);
// init selected array
const { selected = [] } = profile;
const selectedMap = Object.fromEntries(
selected.map((each) => [each.name!, each.now!])
);
// todo: enhance error handle
let hasChange = false;
proxiesData.groups.forEach((group) => {
@@ -52,10 +56,10 @@ const ProfilePage = () => {
name,
now,
}));
patchProfile(profiles.current!, profile).catch(console.error);
patchProfile(current!, profile).catch(console.error);
// update proxies cache
if (hasChange) mutate("getProxies", getProxies());
});
}, 100);
}, [profiles]);
const onImport = async () => {

View File

@@ -36,6 +36,18 @@ export async function restartSidecar() {
return invoke<void>("restart_sidecar");
}
export async function windowDrag() {
return invoke<void>("win_drag");
}
export async function windowHide() {
return invoke<void>("win_hide");
}
export async function windowMini() {
return invoke<void>("win_mini");
}
export async function getClashInfo() {
return invoke<CmdType.ClashInfo | null>("get_clash_info");
}