Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df595f4835 | ||
|
|
63e4d2f686 | ||
|
|
971580def8 | ||
|
|
ffd32426b5 | ||
|
|
d2d26cc822 | ||
|
|
a373b0b6eb | ||
|
|
f515fa1443 | ||
|
|
e32e83d45e | ||
|
|
7be3cdeb65 | ||
|
|
b234b9166d | ||
|
|
2c485b5efb | ||
|
|
b7d7e1a1af | ||
|
|
01be6ae70a | ||
|
|
445eaadac3 | ||
|
|
d5b1dfddee | ||
|
|
c68ea04f06 | ||
|
|
9abc30b60c | ||
|
|
1f7561298c | ||
|
|
611c5757e0 | ||
|
|
ab56e82173 | ||
|
|
34350fadb6 | ||
|
|
77786da53f | ||
|
|
f794ca5426 |
2
.github/FUNDING.yml
vendored
@@ -1 +1 @@
|
||||
github: clash-verge-rev
|
||||
custom: ['https://t.me/tribute/app?startapp=dtfk','https://t.me/tribute/app?startapp=dtLE']
|
||||
|
||||
17
.github/workflows/release.yml
vendored
@@ -90,7 +90,7 @@ jobs:
|
||||
<a href="https://github.com/coolcoala/clash-verge-rev-lite/releases/download/v${{ env.VERSION }}/Koala.Clash_x64.dmg"><img src="https://img.shields.io/badge/DMG-default?style=flat&logo=apple&label=Intel"></a><br>
|
||||
> :warning: **Warning**
|
||||
If you get a notification that the application is corrupted when you run it on macOS, run this command:<br>
|
||||
<code>sudo xattr -r -c /Applications/Clash\ Verge\ Rev\ Lite.app</code>
|
||||
<code>sudo xattr -r -c /Applications/Koala\ Clash.app</code>
|
||||
|
||||
### Linux
|
||||
<a href="https://github.com/coolcoala/clash-verge-rev-lite/releases/download/v${{ env.VERSION }}/Koala.Clash_amd64.deb"><img src="https://img.shields.io/badge/x64-default?style=flat&logo=debian&label=DEB"> </a><br>
|
||||
@@ -178,6 +178,11 @@ jobs:
|
||||
pnpm i
|
||||
pnpm run prebuild ${{ matrix.target }}
|
||||
|
||||
- name: Create .p8 file
|
||||
run: |
|
||||
mkdir -p ~/.appstoreconnect/private_keys
|
||||
echo "${{ secrets.APPLE_API_KEY_CONTENT }}" > ~/.appstoreconnect/private_keys/AuthKey_${{ secrets.APPLE_API_KEY }}.p8
|
||||
|
||||
- name: Tauri build
|
||||
id: build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
@@ -186,6 +191,12 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
||||
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
||||
APPLE_API_KEY_PATH: "~/.appstoreconnect/private_keys/AuthKey_${{ secrets.APPLE_API_KEY }}.p8"
|
||||
with:
|
||||
tauriScript: pnpm
|
||||
args: --target ${{ matrix.target }}
|
||||
@@ -236,6 +247,8 @@ jobs:
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/dmg/*.dmg
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/macos/*.tar.gz
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/macos/*.tar.gz.sig
|
||||
|
||||
release-for-linux-arm:
|
||||
name: Release Build for Linux ARM
|
||||
@@ -563,6 +576,7 @@ jobs:
|
||||
UPDATE_LOGS="More new features are now supported. Check for detailed changelog soon."
|
||||
else
|
||||
echo "Using found update logs"
|
||||
UPDATE_LOGS=$(echo "$UPDATE_LOGS" | sed 's/^## \(v.*\)/\*\1\*/')
|
||||
fi
|
||||
|
||||
cat > release.txt << EOF
|
||||
@@ -580,6 +594,7 @@ jobs:
|
||||
to: ${{ secrets.TELEGRAM_TO_CHANNEL }}
|
||||
token: ${{ secrets.TELEGRAM_TOKEN }}
|
||||
message_file: release.txt
|
||||
format: markdown
|
||||
|
||||
- name: notify to group
|
||||
uses: appleboy/telegram-action@master
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
## v0.2.5
|
||||
|
||||
- new main page
|
||||
- fixed issue with opening via shortcut
|
||||
- fixed logo in sidebar
|
||||
- fixed issue with changing tray settings
|
||||
- name changed to koala clash
|
||||
- added signing for installer on macOS
|
||||
|
||||
## v0.2.4
|
||||
|
||||
- added auto-scaling and scaling via key combination
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "0.2.4",
|
||||
"name": "koala-clash",
|
||||
"version": "0.2.5",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev",
|
||||
|
||||
@@ -42,9 +42,9 @@ async function resolvePortable() {
|
||||
|
||||
const zip = new AdmZip();
|
||||
|
||||
zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "Koala Clash.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "koala-mihomo.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "koala-mihomo-alpha.exe"));
|
||||
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
||||
zip.addLocalFolder(
|
||||
path.join(
|
||||
|
||||
@@ -35,9 +35,9 @@ async function resolvePortable() {
|
||||
}
|
||||
const zip = new AdmZip();
|
||||
|
||||
zip.addLocalFile(path.join(releaseDir, "clash-verge.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "koala-clash.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "koala-mihomo.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "koala-mihomo-alpha.exe"));
|
||||
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
||||
zip.addLocalFolder(configDir, ".config");
|
||||
|
||||
|
||||
@@ -175,8 +175,8 @@ function clashMetaAlpha() {
|
||||
const zipFile = `${name}-${META_ALPHA_VERSION}.${urlExt}`;
|
||||
|
||||
return {
|
||||
name: "verge-mihomo-alpha",
|
||||
targetFile: `verge-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||
name: "koala-mihomo-alpha",
|
||||
targetFile: `koala-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||
exeFile,
|
||||
zipFile,
|
||||
downloadURL,
|
||||
@@ -192,8 +192,8 @@ function clashMeta() {
|
||||
const zipFile = `${name}-${META_VERSION}.${urlExt}`;
|
||||
|
||||
return {
|
||||
name: "verge-mihomo",
|
||||
targetFile: `verge-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||
name: "koala-mihomo",
|
||||
targetFile: `koala-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||
exeFile,
|
||||
zipFile,
|
||||
downloadURL,
|
||||
@@ -381,7 +381,7 @@ const resolvePlugin = async () => {
|
||||
// service chmod
|
||||
const resolveServicePermission = async () => {
|
||||
const serviceExecutables = [
|
||||
"clash-verge-service*",
|
||||
"koala-clash-service*",
|
||||
"install-service*",
|
||||
"uninstall-service*",
|
||||
];
|
||||
@@ -429,14 +429,14 @@ async function resolveLocales() {
|
||||
/**
|
||||
* main
|
||||
*/
|
||||
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service/releases/download/${SIDECAR_HOST}`;
|
||||
const SERVICE_URL = `https://github.com/coolcoala/koala-clash-service/releases/download/${SIDECAR_HOST}`;
|
||||
|
||||
const resolveService = () => {
|
||||
let ext = platform === "win32" ? ".exe" : "";
|
||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||
resolveResource({
|
||||
file: "clash-verge-service" + suffix + ext,
|
||||
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
||||
file: "koala-clash-service" + suffix + ext,
|
||||
downloadURL: `${SERVICE_URL}/koala-clash-service${ext}`,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -489,13 +489,13 @@ const resolveWinSysproxy = () =>
|
||||
const tasks = [
|
||||
// { name: "clash", func: resolveClash, retry: 5 },
|
||||
{
|
||||
name: "verge-mihomo-alpha",
|
||||
name: "koala-mihomo-alpha",
|
||||
func: () =>
|
||||
getLatestAlphaVersion().then(() => resolveSidecar(clashMetaAlpha())),
|
||||
retry: 5,
|
||||
},
|
||||
{
|
||||
name: "verge-mihomo",
|
||||
name: "koala-mihomo",
|
||||
func: () =>
|
||||
getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())),
|
||||
retry: 5,
|
||||
|
||||
192
src-tauri/Cargo.lock
generated
@@ -1059,80 +1059,6 @@ dependencies = [
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"boa_engine",
|
||||
"chrono",
|
||||
"deelevate",
|
||||
"delay_timer",
|
||||
"dirs 6.0.0",
|
||||
"dunce",
|
||||
"futures",
|
||||
"gethostname 1.0.2",
|
||||
"getrandom 0.3.3",
|
||||
"hex",
|
||||
"hmac",
|
||||
"image",
|
||||
"imageproc",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"log4rs",
|
||||
"machine-uid",
|
||||
"mihomo_api",
|
||||
"nanoid",
|
||||
"network-interface",
|
||||
"once_cell",
|
||||
"open",
|
||||
"os_info",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"port_scanner",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest_dav",
|
||||
"runas",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2 0.10.9",
|
||||
"sys-locale",
|
||||
"sysinfo",
|
||||
"sysproxy",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-autostart",
|
||||
"tauri-plugin-clipboard-manager",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-devtools",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-fs",
|
||||
"tauri-plugin-global-shortcut",
|
||||
"tauri-plugin-notification",
|
||||
"tauri-plugin-process",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-updater",
|
||||
"tauri-plugin-window-state",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-tungstenite 0.27.0",
|
||||
"tungstenite 0.27.0",
|
||||
"url",
|
||||
"users",
|
||||
"warp",
|
||||
"winapi",
|
||||
"winreg 0.55.0",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "5.4.0"
|
||||
@@ -3622,6 +3548,81 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "koala-clash"
|
||||
version = "0.2.5"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"boa_engine",
|
||||
"chrono",
|
||||
"deelevate",
|
||||
"delay_timer",
|
||||
"dirs 6.0.0",
|
||||
"dunce",
|
||||
"futures",
|
||||
"gethostname 1.0.2",
|
||||
"getrandom 0.3.3",
|
||||
"hex",
|
||||
"hmac",
|
||||
"image",
|
||||
"imageproc",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"log4rs",
|
||||
"machine-uid",
|
||||
"mihomo_api",
|
||||
"nanoid",
|
||||
"network-interface",
|
||||
"once_cell",
|
||||
"open",
|
||||
"os_info",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"port_scanner",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest_dav",
|
||||
"runas",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2 0.10.9",
|
||||
"sys-locale",
|
||||
"sysinfo",
|
||||
"sysproxy",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-autostart",
|
||||
"tauri-plugin-clipboard-manager",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-devtools",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-fs",
|
||||
"tauri-plugin-global-shortcut",
|
||||
"tauri-plugin-notification",
|
||||
"tauri-plugin-process",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-single-instance",
|
||||
"tauri-plugin-updater",
|
||||
"tauri-plugin-window-state",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-tungstenite 0.27.0",
|
||||
"tungstenite 0.27.0",
|
||||
"url",
|
||||
"users",
|
||||
"warp",
|
||||
"winapi",
|
||||
"winreg 0.55.0",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchikiki"
|
||||
version = "0.8.8-speedreader"
|
||||
@@ -3887,11 +3888,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "machine-uid"
|
||||
version = "0.2.0"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f1595709b0a7386bcd56ba34d250d626e5503917d05d32cdccddcd68603e212"
|
||||
checksum = "0c4506fa0abb0a2ea93f5862f55973da0a662d2ad0e98f337a1c5aac657f0892"
|
||||
dependencies = [
|
||||
"winreg 0.6.2",
|
||||
"libc",
|
||||
"winreg 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6846,9 +6848,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.35.2"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e"
|
||||
checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
@@ -7294,6 +7296,21 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-single-instance"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50a0e5a4ce43cb3a733c3aef85e8478bc769dac743c615e26639cbf5d953faf7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-updater"
|
||||
version = "2.9.0"
|
||||
@@ -9323,15 +9340,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
@@ -9568,9 +9576,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "5.7.1"
|
||||
version = "5.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3a7c7cee313d044fca3f48fa782cb750c79e4ca76ba7bc7718cd4024cdf6f68"
|
||||
checksum = "4bb4f9a464286d42851d18a605f7193b8febaf5b0919d71c6399b7b26e5b0aad"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-executor",
|
||||
@@ -9602,9 +9610,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "5.7.1"
|
||||
version = "5.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17e7e5eec1550f747e71a058df81a9a83813ba0f6a95f39c4e218bdc7ba366a"
|
||||
checksum = "ef9859f68ee0c4ee2e8cde84737c78e3f4c54f946f2a38645d0d4c7a95327659"
|
||||
dependencies = [
|
||||
"proc-macro-crate 3.3.0",
|
||||
"proc-macro2",
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "0.2.4"
|
||||
description = "clash verge"
|
||||
name = "koala-clash"
|
||||
version = "0.2.5"
|
||||
description = "koala clash"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda", "coolcoala"]
|
||||
license = "GPL-3.0-only"
|
||||
repository = "https://github.com/coolcoala/clash-verge-rev-lite.git"
|
||||
default-run = "clash-verge"
|
||||
default-run = "koala-clash"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[package.metadata.bundle]
|
||||
identifier = "io.github.clash-verge-rev.clash-verge-rev"
|
||||
identifier = "io.github.koala-clash"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.3.0", features = [] }
|
||||
@@ -18,7 +18,7 @@ tauri-build = { version = "2.3.0", features = [] }
|
||||
[dependencies]
|
||||
url = "2.5.4"
|
||||
os_info = "3.0"
|
||||
machine-uid = "0.2"
|
||||
machine-uid = "0.5.3"
|
||||
warp = "0.3.7"
|
||||
anyhow = "1.0.98"
|
||||
dirs = "6.0"
|
||||
@@ -28,7 +28,7 @@ dunce = "1.0.5"
|
||||
log4rs = "1.3.0"
|
||||
nanoid = "0.4"
|
||||
chrono = "0.4.41"
|
||||
sysinfo = "0.35.2"
|
||||
sysinfo = "0.36.1"
|
||||
boa_engine = "0.20.0"
|
||||
serde_json = "1.0.140"
|
||||
serde_yaml = "0.9.34-deprecated"
|
||||
@@ -110,6 +110,7 @@ users = "0.11.0"
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
tauri-plugin-autostart = "2.5.0"
|
||||
tauri-plugin-global-shortcut = "2.3.0"
|
||||
tauri-plugin-single-instance = "2"
|
||||
tauri-plugin-updater = "2.9.0"
|
||||
|
||||
[features]
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 64 KiB |
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
chmod +x /usr/bin/install-service
|
||||
chmod +x /usr/bin/uninstall-service
|
||||
chmod +x /usr/bin/clash-verge-service
|
||||
chmod +x /usr/bin/koala-clash-service
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<false/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>io.github.clash-verge-rev.clash-verge-rev</string>
|
||||
<string>io.github.koala-clash</string>
|
||||
</array>
|
||||
<key>com.apple.security.inherit</key>
|
||||
<true/>
|
||||
|
||||
@@ -427,52 +427,52 @@ Function .onInit
|
||||
!endif
|
||||
FunctionEnd
|
||||
|
||||
!macro CheckAllVergeProcesses
|
||||
; Check if clash-verge-service.exe is running
|
||||
!macro CheckAllKoalaProcesses
|
||||
; Check if koala-clash-service.exe is running
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "clash-verge-service.exe"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "koala-clash-service.exe"
|
||||
!else
|
||||
nsis_tauri_utils::FindProcess "clash-verge-service.exe"
|
||||
nsis_tauri_utils::FindProcess "koala-clash-service.exe"
|
||||
!endif
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
DetailPrint "Kill clash-verge-service.exe..."
|
||||
DetailPrint "Kill koala-clash-service.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "clash-verge-service.exe"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "koala-clash-service.exe"
|
||||
!else
|
||||
nsis_tauri_utils::KillProcess "clash-verge-service.exe"
|
||||
nsis_tauri_utils::KillProcess "koala-clash-service.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
|
||||
; Check if verge-mihomo-alpha.exe is running
|
||||
; Check if koala-mihomo-alpha.exe is running
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "verge-mihomo-alpha.exe"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "koala-mihomo-alpha.exe"
|
||||
!else
|
||||
nsis_tauri_utils::FindProcess "verge-mihomo-alpha.exe"
|
||||
nsis_tauri_utils::FindProcess "koala-mihomo-alpha.exe"
|
||||
!endif
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
DetailPrint "Kill verge-mihomo-alpha.exe..."
|
||||
DetailPrint "Kill koala-mihomo-alpha.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "verge-mihomo-alpha.exe"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "koala-mihomo-alpha.exe"
|
||||
!else
|
||||
nsis_tauri_utils::KillProcess "verge-mihomo-alpha.exe"
|
||||
nsis_tauri_utils::KillProcess "koala-mihomo-alpha.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
|
||||
; Check if verge-mihomo.exe is running
|
||||
; Check if koala-mihomo.exe is running
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "verge-mihomo.exe"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "koala-mihomo.exe"
|
||||
!else
|
||||
nsis_tauri_utils::FindProcess "verge-mihomo.exe"
|
||||
nsis_tauri_utils::FindProcess "koala-mihomo.exe"
|
||||
!endif
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
DetailPrint "Kill verge-mihomo.exe..."
|
||||
DetailPrint "Kill koala-mihomo.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "verge-mihomo.exe"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "koala-mihomo.exe"
|
||||
!else
|
||||
nsis_tauri_utils::KillProcess "verge-mihomo.exe"
|
||||
nsis_tauri_utils::KillProcess "koala-mihomo.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
|
||||
@@ -509,22 +509,22 @@ FunctionEnd
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
!macro StartVergeService
|
||||
!macro StartKoalaService
|
||||
; Check if the service exists
|
||||
SimpleSC::ExistsService "clash_verge_service"
|
||||
SimpleSC::ExistsService "koala_clash_service"
|
||||
Pop $0 ; 0:service exists;other: service not exists
|
||||
; Service exists
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
; Check if the service is running
|
||||
SimpleSC::ServiceIsRunning "clash_verge_service"
|
||||
SimpleSC::ServiceIsRunning "koala_clash_service"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
${If} $1 == 0
|
||||
DetailPrint "Restart Clash Verge Service..."
|
||||
SimpleSC::StartService "clash_verge_service" "" 30
|
||||
DetailPrint "Restart Koala Clash Service..."
|
||||
SimpleSC::StartService "koala_clash_service" "" 30
|
||||
${EndIf}
|
||||
${ElseIf} $0 != 0
|
||||
Push $0
|
||||
@@ -535,35 +535,35 @@ FunctionEnd
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
!macro RemoveVergeService
|
||||
!macro RemoveKoalaService
|
||||
; Check if the service exists
|
||||
SimpleSC::ExistsService "clash_verge_service"
|
||||
SimpleSC::ExistsService "koala_clash_service"
|
||||
Pop $0 ; 0:service exists;other: service not exists
|
||||
; Service exists
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
; Check if the service is running
|
||||
SimpleSC::ServiceIsRunning "clash_verge_service"
|
||||
SimpleSC::ServiceIsRunning "koala_clash_service"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
${If} $1 == 1
|
||||
DetailPrint "Stop Clash Verge Service..."
|
||||
SimpleSC::StopService "clash_verge_service" 1 30
|
||||
DetailPrint "Stop Koala Clash Service..."
|
||||
SimpleSC::StopService "koala_clash_service" 1 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
${If} $0 == 0
|
||||
DetailPrint "Removing Clash Verge Service..."
|
||||
SimpleSC::RemoveService "clash_verge_service"
|
||||
DetailPrint "Removing Koala Clash Service..."
|
||||
SimpleSC::RemoveService "koala_clash_service"
|
||||
${ElseIf} $0 != 0
|
||||
Push $0
|
||||
SimpleSC::GetErrorMessage
|
||||
Pop $0
|
||||
MessageBox MB_OK|MB_ICONSTOP "Clash Verge Service Stop Error ($0)"
|
||||
MessageBox MB_OK|MB_ICONSTOP "Koala Clash Service Stop Error ($0)"
|
||||
${EndIf}
|
||||
${ElseIf} $1 == 0
|
||||
DetailPrint "Removing Clash Verge Service..."
|
||||
SimpleSC::RemoveService "clash_verge_service"
|
||||
DetailPrint "Removing Koala Clash Service..."
|
||||
SimpleSC::RemoveService "koala_clash_service"
|
||||
${EndIf}
|
||||
${ElseIf} $0 != 0
|
||||
Push $0
|
||||
@@ -764,7 +764,7 @@ Section Install
|
||||
SetOutPath $INSTDIR
|
||||
nsExec::Exec 'netsh int tcp res'
|
||||
!insertmacro CheckIfAppIsRunning
|
||||
!insertmacro CheckAllVergeProcesses
|
||||
!insertmacro CheckAllKoalaProcesses
|
||||
|
||||
; 清理自启动注册表项
|
||||
DetailPrint "Cleaning auto-launch registry entries..."
|
||||
@@ -772,32 +772,32 @@ Section Install
|
||||
StrCpy $R1 "Software\Microsoft\Windows\CurrentVersion\Run"
|
||||
|
||||
SetRegView 64
|
||||
; 清理旧版本的注册表项 (Clash Verge)
|
||||
ReadRegStr $R2 HKCU "$R1" "Clash Verge"
|
||||
; 清理旧版本的注册表项 (Koala Clash)
|
||||
ReadRegStr $R2 HKCU "$R1" "Koala Clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKCU "$R1" "Clash Verge"
|
||||
DeleteRegValue HKCU "$R1" "Koala Clash"
|
||||
${EndIf}
|
||||
|
||||
ReadRegStr $R2 HKLM "$R1" "Clash Verge"
|
||||
ReadRegStr $R2 HKLM "$R1" "Koala Clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKLM "$R1" "Clash Verge"
|
||||
DeleteRegValue HKLM "$R1" "Koala Clash"
|
||||
${EndIf}
|
||||
|
||||
; 清理新版本的注册表项 (clash-verge)
|
||||
ReadRegStr $R2 HKCU "$R1" "clash-verge"
|
||||
; 清理新版本的注册表项 (koala-clash)
|
||||
ReadRegStr $R2 HKCU "$R1" "koala-clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKCU "$R1" "clash-verge"
|
||||
DeleteRegValue HKCU "$R1" "koala-clash"
|
||||
${EndIf}
|
||||
|
||||
ReadRegStr $R2 HKLM "$R1" "clash-verge"
|
||||
ReadRegStr $R2 HKLM "$R1" "koala-clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKLM "$R1" "clash-verge"
|
||||
DeleteRegValue HKLM "$R1" "koala-clash"
|
||||
${EndIf}
|
||||
|
||||
; Delete old files before installation
|
||||
; Delete clash-verge.desktop
|
||||
IfFileExists "$INSTDIR\Clash Verge.exe" 0 +2
|
||||
Delete "$INSTDIR\Clash Verge.exe"
|
||||
; Delete koala-clash.desktop
|
||||
IfFileExists "$INSTDIR\Koala Clash.exe" 0 +2
|
||||
Delete "$INSTDIR\Koala Clash.exe"
|
||||
|
||||
; Copy main executable
|
||||
File "${MAINBINARYSRCPATH}"
|
||||
@@ -815,7 +815,7 @@ Section Install
|
||||
File /a "/oname={{this}}" "{{@key}}"
|
||||
{{/each}}
|
||||
|
||||
!insertmacro StartVergeService
|
||||
!insertmacro StartKoalaService
|
||||
|
||||
; Create uninstaller
|
||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||
@@ -918,11 +918,11 @@ FunctionEnd
|
||||
Section Uninstall
|
||||
;删除 window-state.json 文件
|
||||
SetShellVarContext current
|
||||
Delete "$APPDATA\io.github.clash-verge-rev.clash-verge-rev\window-state.json"
|
||||
Delete "$APPDATA\io.github.koala-clash\window-state.json"
|
||||
|
||||
!insertmacro CheckIfAppIsRunning
|
||||
!insertmacro CheckAllVergeProcesses
|
||||
!insertmacro RemoveVergeService
|
||||
!insertmacro CheckAllKoalaProcesses
|
||||
!insertmacro RemoveKoalaService
|
||||
|
||||
; 清理自启动注册表项
|
||||
DetailPrint "Cleaning auto-launch registry entries..."
|
||||
@@ -930,26 +930,26 @@ Section Uninstall
|
||||
StrCpy $R1 "Software\Microsoft\Windows\CurrentVersion\Run"
|
||||
|
||||
SetRegView 64
|
||||
; 清理旧版本的注册表项 (Clash Verge)
|
||||
ReadRegStr $R2 HKCU "$R1" "Clash Verge"
|
||||
; 清理旧版本的注册表项 (Koala Clash)
|
||||
ReadRegStr $R2 HKCU "$R1" "Koala Clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKCU "$R1" "Clash Verge"
|
||||
DeleteRegValue HKCU "$R1" "Koala Clash"
|
||||
${EndIf}
|
||||
|
||||
ReadRegStr $R2 HKLM "$R1" "Clash Verge"
|
||||
ReadRegStr $R2 HKLM "$R1" "Koala Clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKLM "$R1" "Clash Verge"
|
||||
DeleteRegValue HKLM "$R1" "Koala Clash"
|
||||
${EndIf}
|
||||
|
||||
; 清理新版本的注册表项 (clash-verge)
|
||||
ReadRegStr $R2 HKCU "$R1" "clash-verge"
|
||||
; 清理新版本的注册表项 (koala-clash)
|
||||
ReadRegStr $R2 HKCU "$R1" "koala-clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKCU "$R1" "clash-verge"
|
||||
DeleteRegValue HKCU "$R1" "koala-clash"
|
||||
${EndIf}
|
||||
|
||||
ReadRegStr $R2 HKLM "$R1" "clash-verge"
|
||||
ReadRegStr $R2 HKLM "$R1" "koala-clash"
|
||||
${If} $R2 != ""
|
||||
DeleteRegValue HKLM "$R1" "clash-verge"
|
||||
DeleteRegValue HKLM "$R1" "koala-clash"
|
||||
${EndIf}
|
||||
|
||||
; Delete the app directory and its content from disk
|
||||
@@ -966,9 +966,9 @@ Section Uninstall
|
||||
Delete "$INSTDIR\\{{this}}"
|
||||
{{/each}}
|
||||
|
||||
; Delete clash-verge.desktop
|
||||
IfFileExists "$INSTDIR\Clash Verge.exe" 0 +2
|
||||
Delete "$INSTDIR\Clash Verge.exe"
|
||||
; Delete koala-clash.desktop
|
||||
IfFileExists "$INSTDIR\Koala Clash.exe" 0 +2
|
||||
Delete "$INSTDIR\Koala Clash.exe"
|
||||
|
||||
; Delete uninstaller
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
@@ -982,20 +982,20 @@ Section Uninstall
|
||||
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
||||
!insertmacro UnpinShortcut "$DESKTOP\${PRODUCTNAME}.lnk"
|
||||
; 兼容旧名称快捷方式
|
||||
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\clash-verge.lnk"
|
||||
!insertmacro UnpinShortcut "$DESKTOP\clash-verge.lnk"
|
||||
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\koala-clash.lnk"
|
||||
!insertmacro UnpinShortcut "$DESKTOP\koala-clash.lnk"
|
||||
|
||||
; Remove start menu shortcut
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
|
||||
Delete "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
||||
; 兼容旧名称快捷方式
|
||||
Delete "$SMPROGRAMS\$AppStartMenuFolder\clash-verge.lnk"
|
||||
Delete "$SMPROGRAMS\$AppStartMenuFolder\koala-clash.lnk"
|
||||
RMDir "$SMPROGRAMS\$AppStartMenuFolder"
|
||||
|
||||
; Remove desktop shortcuts
|
||||
Delete "$DESKTOP\${PRODUCTNAME}.lnk"
|
||||
; 兼容旧名称快捷方式
|
||||
Delete "$DESKTOP\clash-verge.lnk"
|
||||
Delete "$DESKTOP\koala-clash.lnk"
|
||||
|
||||
; Remove registry information for add/remove programs
|
||||
!if "${INSTALLMODE}" == "both"
|
||||
@@ -1017,7 +1017,7 @@ Section Uninstall
|
||||
|
||||
;删除 window-state.json 文件
|
||||
SetShellVarContext current
|
||||
Delete "$APPDATA\io.github.clash-verge-rev.clash-verge-rev\window-state.json"
|
||||
Delete "$APPDATA\io.github.koala-clash\window-state.json"
|
||||
|
||||
${GetOptions} $CMDLINE "/P" $R0
|
||||
IfErrors +2 0
|
||||
|
||||
@@ -176,7 +176,34 @@ pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResu
|
||||
/// 删除配置文件
|
||||
#[tauri::command]
|
||||
pub async fn delete_profile(index: String) -> CmdResult {
|
||||
let should_update = wrap_err!({ Config::profiles().data().delete_item(index) })?;
|
||||
let should_update;
|
||||
|
||||
{
|
||||
let profiles_config = Config::profiles();
|
||||
let mut profiles_data = profiles_config.data();
|
||||
should_update = profiles_data.delete_item(index.clone()).map_err(|e| e.to_string())?;
|
||||
|
||||
let was_last_profile = profiles_data.items.as_ref().map_or(true, |items| {
|
||||
!items.iter().any(|item|
|
||||
item.itype == Some("remote".to_string()) || item.itype == Some("local".to_string())
|
||||
)
|
||||
});
|
||||
|
||||
if was_last_profile {
|
||||
logging!(info, Type::Cmd, true, "The last profile has been deleted. Disabling proxy modes...");
|
||||
let verge_config = Config::verge();
|
||||
let mut verge_data = verge_config.data();
|
||||
|
||||
if verge_data.enable_tun_mode == Some(true) || verge_data.enable_system_proxy == Some(true) {
|
||||
verge_data.enable_tun_mode = Some(false);
|
||||
verge_data.enable_system_proxy = Some(false);
|
||||
verge_data.save_file().map_err(|e| e.to_string())?;
|
||||
|
||||
handle::Handle::refresh_verge();
|
||||
handle::Handle::notice_message("info", "All profiles deleted, proxy disabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除后自动清理冗余文件
|
||||
let _ = Config::profiles().latest().auto_cleanup();
|
||||
|
||||
@@ -129,7 +129,7 @@ impl IClashTemp {
|
||||
help::save_yaml(
|
||||
&dirs::clash_path()?,
|
||||
&self.0,
|
||||
Some("# Generated by Clash Verge"),
|
||||
Some("# Generated by Koala Clash"),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ use once_cell::sync::OnceCell;
|
||||
use std::path::PathBuf;
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
|
||||
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
|
||||
pub const RUNTIME_CONFIG: &str = "koala-clash.yaml";
|
||||
pub const CHECK_CONFIG: &str = "koala-clash-check.yaml";
|
||||
|
||||
pub struct Config {
|
||||
clash_config: Draft<Box<IClashTemp>>,
|
||||
@@ -141,7 +141,7 @@ impl Config {
|
||||
.as_ref()
|
||||
.ok_or(anyhow!("failed to get runtime config"))?;
|
||||
|
||||
help::save_yaml(&path, &config, Some("# Generated by Clash Verge"))?;
|
||||
help::save_yaml(&path, &config, Some("# Generated by Koala Clash"))?;
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ use crate::utils::{
|
||||
tmpl,
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use reqwest::StatusCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::Mapping;
|
||||
use std::{fs, time::Duration};
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use url::Url;
|
||||
|
||||
use super::Config;
|
||||
@@ -407,7 +407,8 @@ impl PrfItem {
|
||||
Some(value) => {
|
||||
let str_value = value.to_str().unwrap_or("");
|
||||
if let Some(b64_data) = str_value.strip_prefix("base64:") {
|
||||
STANDARD.decode(b64_data)
|
||||
STANDARD
|
||||
.decode(b64_data)
|
||||
.ok()
|
||||
.and_then(|bytes| String::from_utf8(bytes).ok())
|
||||
} else {
|
||||
@@ -423,7 +424,7 @@ impl PrfItem {
|
||||
bail!(announce_msg.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let announce_url = match header.get("announce-url") {
|
||||
Some(value) => {
|
||||
let str_value = value.to_str().unwrap_or("");
|
||||
@@ -436,7 +437,8 @@ impl PrfItem {
|
||||
Some(value) => {
|
||||
let str_value = value.to_str().unwrap_or("");
|
||||
if let Some(b64_data) = str_value.strip_prefix("base64:") {
|
||||
STANDARD.decode(b64_data)
|
||||
STANDARD
|
||||
.decode(b64_data)
|
||||
.ok()
|
||||
.and_then(|bytes| String::from_utf8(bytes).ok())
|
||||
} else {
|
||||
@@ -448,7 +450,9 @@ impl PrfItem {
|
||||
|
||||
let uid = help::get_uid("R");
|
||||
let file = format!("{uid}.yaml");
|
||||
let name = name.or(profile_title).unwrap_or(filename.unwrap_or("Remote File".into()));
|
||||
let name = name
|
||||
.or(profile_title)
|
||||
.unwrap_or(filename.unwrap_or("Remote File".into()));
|
||||
let data = resp.text_with_charset("utf-8").await?;
|
||||
|
||||
// process the charset "UTF-8 with BOM"
|
||||
|
||||
@@ -66,7 +66,7 @@ impl IProfiles {
|
||||
help::save_yaml(
|
||||
&dirs::profiles_path()?,
|
||||
self,
|
||||
Some("# Profiles Config for Clash Verge"),
|
||||
Some("# Profiles Config for Koala Clash"),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ pub struct IVergeTheme {
|
||||
|
||||
impl IVerge {
|
||||
/// 有效的clash核心名称
|
||||
pub const VALID_CLASH_CORES: &'static [&'static str] = &["verge-mihomo", "verge-mihomo-alpha"];
|
||||
pub const VALID_CLASH_CORES: &'static [&'static str] = &["koala-mihomo", "koala-mihomo-alpha"];
|
||||
|
||||
/// 验证并修正配置文件中的clash_core值
|
||||
pub fn validate_and_fix_config() -> Result<()> {
|
||||
@@ -257,10 +257,10 @@ impl IVerge {
|
||||
warn,
|
||||
Type::Config,
|
||||
true,
|
||||
"启动时发现无效的clash_core配置: '{}', 将自动修正为 'verge-mihomo'",
|
||||
"启动时发现无效的clash_core配置: '{}', 将自动修正为 'koala-mihomo'",
|
||||
core
|
||||
);
|
||||
config.clash_core = Some("verge-mihomo".to_string());
|
||||
config.clash_core = Some("koala-mihomo".to_string());
|
||||
needs_fix = true;
|
||||
}
|
||||
} else {
|
||||
@@ -268,16 +268,16 @@ impl IVerge {
|
||||
info,
|
||||
Type::Config,
|
||||
true,
|
||||
"启动时发现未配置clash_core, 将设置为默认值 'verge-mihomo'"
|
||||
"启动时发现未配置clash_core, 将设置为默认值 'koala-mihomo'"
|
||||
);
|
||||
config.clash_core = Some("verge-mihomo".to_string());
|
||||
config.clash_core = Some("koala-mihomo".to_string());
|
||||
needs_fix = true;
|
||||
}
|
||||
|
||||
// 修正后保存配置
|
||||
if needs_fix {
|
||||
logging!(info, Type::Config, true, "正在保存修正后的配置文件...");
|
||||
help::save_yaml(&config_path, &config, Some("# Clash Verge Config"))?;
|
||||
help::save_yaml(&config_path, &config, Some("# Koala Clash Config"))?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Config,
|
||||
@@ -321,7 +321,7 @@ impl IVerge {
|
||||
pub fn get_valid_clash_core(&self) -> String {
|
||||
self.clash_core
|
||||
.clone()
|
||||
.unwrap_or_else(|| "verge-mihomo".to_string())
|
||||
.unwrap_or_else(|| "koala-mihomo".to_string())
|
||||
}
|
||||
|
||||
fn get_system_language() -> String {
|
||||
@@ -340,18 +340,15 @@ impl IVerge {
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "{err}");
|
||||
Self::template()
|
||||
}
|
||||
}
|
||||
dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)).unwrap_or_else(|err| {
|
||||
log::error!(target: "app", "{err}");
|
||||
Self::template()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn template() -> Self {
|
||||
Self {
|
||||
clash_core: Some("verge-mihomo".into()),
|
||||
clash_core: Some("koala-mihomo".into()),
|
||||
language: Some(Self::get_system_language()),
|
||||
theme_mode: Some("system".into()),
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
@@ -415,7 +412,7 @@ impl IVerge {
|
||||
|
||||
/// Save IVerge App Config
|
||||
pub fn save_file(&self) -> Result<()> {
|
||||
help::save_yaml(&dirs::verge_path()?, &self, Some("# Clash Verge Config"))
|
||||
help::save_yaml(&dirs::verge_path()?, &self, Some("# Koala Clash Config"))
|
||||
}
|
||||
|
||||
/// patch verge config
|
||||
|
||||
@@ -108,7 +108,7 @@ impl WebDavClient {
|
||||
reqwest::Client::builder()
|
||||
.danger_accept_invalid_certs(true)
|
||||
.timeout(Duration::from_secs(op.timeout()))
|
||||
.user_agent(format!("clash-verge/{APP_VERSION} ({OS} WebDAV-Client)"))
|
||||
.user_agent(format!("koala-clash/{APP_VERSION} ({OS} WebDAV-Client)"))
|
||||
.redirect(reqwest::redirect::Policy::custom(|attempt| {
|
||||
// 允许所有请求类型的重定向,包括PUT
|
||||
if attempt.previous().len() >= 5 {
|
||||
|
||||
@@ -146,7 +146,7 @@ impl CoreManager {
|
||||
help::save_yaml(
|
||||
&runtime_path,
|
||||
&Config::clash().latest().0,
|
||||
Some("# Clash Verge Runtime"),
|
||||
Some("# Koala Clash Runtime"),
|
||||
)?;
|
||||
handle::Handle::notice_message(msg_type, msg_content);
|
||||
Ok(())
|
||||
@@ -443,7 +443,7 @@ impl CoreManager {
|
||||
child_guard.as_ref().map(|child| child.pid())
|
||||
};
|
||||
|
||||
let target_processes = ["verge-mihomo", "verge-mihomo-alpha"];
|
||||
let target_processes = ["koala-mihomo", "koala-mihomo-alpha"];
|
||||
|
||||
// 并行查找所有目标进程
|
||||
let mut process_futures = Vec::new();
|
||||
|
||||
@@ -578,7 +578,7 @@ pub async fn check_ipc_service_status() -> Result<JsonResponse> {
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Service, true, "IPC通信失败: {}", e);
|
||||
bail!("无法连接到Clash Verge Service: {}", e)
|
||||
bail!("无法连接到Koala Clash Service: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -667,7 +667,7 @@ pub async fn check_service_version() -> Result<String> {
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Service, true, "IPC通信失败: {}", e);
|
||||
bail!("无法连接到Clash Verge Service: {}", e)
|
||||
bail!("无法连接到Koala Clash Service: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,7 +814,7 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Service, true, "启动核心IPC通信失败: {}", e);
|
||||
bail!("无法连接到Clash Verge Service: {}", e)
|
||||
bail!("无法连接到Koala Clash Service: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -910,7 +910,7 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
|
||||
let payload = serde_json::json!({});
|
||||
let response = send_ipc_request(IpcCommand::StopClash, payload)
|
||||
.await
|
||||
.context("无法连接到Clash Verge Service")?;
|
||||
.context("无法连接到Koala Clash Service")?;
|
||||
|
||||
if !response.success {
|
||||
bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string()));
|
||||
|
||||
@@ -6,9 +6,9 @@ use sha2::{Digest, Sha256};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
const IPC_SOCKET_NAME: &str = if cfg!(windows) {
|
||||
r"\\.\pipe\clash-verge-service"
|
||||
r"\\.\pipe\koala-clash-service"
|
||||
} else {
|
||||
"/tmp/clash-verge-service.sock"
|
||||
"/tmp/koala-clash-service.sock"
|
||||
};
|
||||
|
||||
// 定义命令类型
|
||||
@@ -43,7 +43,7 @@ pub struct IpcResponse {
|
||||
fn derive_secret_key() -> Vec<u8> {
|
||||
// to do
|
||||
// 从系统安全存储中获取或从程序安装时生成的密钥文件中读取
|
||||
let unique_app_id = "clash-verge-app-secret-fuck-me-until-daylight";
|
||||
let unique_app_id = "koala-clash-app-secret-fuck-me-until-daylight";
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(unique_app_id.as_bytes());
|
||||
hasher.finalize().to_vec()
|
||||
|
||||
@@ -414,7 +414,7 @@ impl Tray {
|
||||
|
||||
if let Some(tray) = app_handle.tray_by_id("main") {
|
||||
let _ = tray.set_tooltip(Some(&format!(
|
||||
"Clash Verge {version}\n{}: {}\n{}: {}\n{}: {}",
|
||||
"Koala Clash {version}\n{}: {}\n{}: {}\n{}: {}",
|
||||
t("SysProxy"),
|
||||
switch_map[system_proxy],
|
||||
t("TUN"),
|
||||
@@ -601,16 +601,6 @@ fn create_tray_menu(
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let direct_mode = &CheckMenuItem::with_id(
|
||||
app_handle,
|
||||
"direct_mode",
|
||||
t("Direct Mode"),
|
||||
true,
|
||||
mode == "direct",
|
||||
hotkeys.get("clash_mode_direct").map(|s| s.as_str()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let profiles = &Submenu::with_id_and_items(
|
||||
app_handle,
|
||||
"profiles",
|
||||
@@ -650,45 +640,6 @@ fn create_tray_menu(
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let copy_env =
|
||||
&MenuItem::with_id(app_handle, "copy_env", t("Copy Env"), true, None::<&str>).unwrap();
|
||||
|
||||
let open_app_dir = &MenuItem::with_id(
|
||||
app_handle,
|
||||
"open_app_dir",
|
||||
t("Conf Dir"),
|
||||
true,
|
||||
None::<&str>,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let open_core_dir = &MenuItem::with_id(
|
||||
app_handle,
|
||||
"open_core_dir",
|
||||
t("Core Dir"),
|
||||
true,
|
||||
None::<&str>,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let open_logs_dir = &MenuItem::with_id(
|
||||
app_handle,
|
||||
"open_logs_dir",
|
||||
t("Logs Dir"),
|
||||
true,
|
||||
None::<&str>,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let open_dir = &Submenu::with_id_and_items(
|
||||
app_handle,
|
||||
"open_dir",
|
||||
t("Open Dir"),
|
||||
true,
|
||||
&[open_app_dir, open_core_dir, open_logs_dir],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let restart_clash = &MenuItem::with_id(
|
||||
app_handle,
|
||||
"restart_clash",
|
||||
@@ -736,7 +687,6 @@ fn create_tray_menu(
|
||||
separator,
|
||||
rule_mode,
|
||||
global_mode,
|
||||
direct_mode,
|
||||
separator,
|
||||
profiles,
|
||||
separator,
|
||||
@@ -744,8 +694,6 @@ fn create_tray_menu(
|
||||
tun_mode,
|
||||
separator,
|
||||
lighteweight_mode,
|
||||
copy_env,
|
||||
open_dir,
|
||||
more,
|
||||
separator,
|
||||
quit,
|
||||
@@ -789,16 +737,6 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
||||
"tun_mode" => {
|
||||
feat::toggle_tun_mode(None);
|
||||
}
|
||||
"copy_env" => feat::copy_clash_env(),
|
||||
"open_app_dir" => {
|
||||
let _ = cmd::open_app_dir();
|
||||
}
|
||||
"open_core_dir" => {
|
||||
let _ = cmd::open_core_dir();
|
||||
}
|
||||
"open_logs_dir" => {
|
||||
let _ = cmd::open_logs_dir();
|
||||
}
|
||||
"restart_clash" => feat::restart_clash_core(),
|
||||
"restart_app" => feat::restart_app(),
|
||||
"entry_lightweight_mode" => {
|
||||
|
||||
@@ -108,8 +108,8 @@ impl ChainSupport {
|
||||
(self, core.as_str()),
|
||||
(ChainSupport::All, _)
|
||||
| (ChainSupport::Clash, "clash")
|
||||
| (ChainSupport::ClashMeta, "verge-mihomo")
|
||||
| (ChainSupport::ClashMetaAlpha, "verge-mihomo-alpha")
|
||||
| (ChainSupport::ClashMeta, "koala-mihomo")
|
||||
| (ChainSupport::ClashMetaAlpha, "koala-mihomo-alpha")
|
||||
),
|
||||
None => true,
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ mod utils;
|
||||
use crate::{
|
||||
core::hotkey,
|
||||
process::AsyncHandler,
|
||||
utils::{resolve, resolve::resolve_scheme, server},
|
||||
utils::{resolve, resolve::resolve_scheme},
|
||||
};
|
||||
use config::Config;
|
||||
use std::sync::{Mutex, Once};
|
||||
@@ -90,33 +90,6 @@ pub fn run() {
|
||||
|
||||
let _ = utils::dirs::init_portable_flag();
|
||||
|
||||
// 异步单例检测
|
||||
AsyncHandler::spawn(move || async move {
|
||||
logging!(info, Type::Setup, true, "开始检查单例实例...");
|
||||
match timeout(Duration::from_secs(3), server::check_singleton()).await {
|
||||
Ok(result) => {
|
||||
if result.is_err() {
|
||||
logging!(info, Type::Setup, true, "检测到已有应用实例运行");
|
||||
if let Some(app_handle) = AppHandleManager::global().get() {
|
||||
app_handle.exit(0);
|
||||
} else {
|
||||
std::process::exit(0);
|
||||
}
|
||||
} else {
|
||||
logging!(info, Type::Setup, true, "未检测到其他应用实例");
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Setup,
|
||||
true,
|
||||
"单例检查超时,假定没有其他实例运行"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
|
||||
@@ -125,6 +98,13 @@ pub fn run() {
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut builder = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
let _ = window.show();
|
||||
let _ = window.unminimize();
|
||||
let _ = window.set_focus();
|
||||
}
|
||||
}))
|
||||
.plugin(tauri_plugin_notification::init())
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
@@ -364,6 +344,10 @@ pub fn run() {
|
||||
} => {
|
||||
if !has_visible_windows {
|
||||
AppHandleManager::global().set_activation_policy_regular();
|
||||
if let Some(window) = app_handle.get_webview_window("main") {
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
}
|
||||
}
|
||||
AppHandleManager::global().init(app_handle.clone());
|
||||
}
|
||||
@@ -384,7 +368,6 @@ pub fn run() {
|
||||
match event {
|
||||
tauri::WindowEvent::CloseRequested { api, .. } => {
|
||||
#[cfg(target_os = "macos")]
|
||||
AppHandleManager::global().set_activation_policy_accessory();
|
||||
if core::handle::Handle::global().is_exiting() {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ pub fn get_exe_path() -> Result<PathBuf> {
|
||||
pub fn create_shortcut() -> Result<()> {
|
||||
let exe_path = get_exe_path()?;
|
||||
let startup_dir = get_startup_dir()?;
|
||||
let shortcut_path = startup_dir.join("Clash-Verge.lnk");
|
||||
let shortcut_path = startup_dir.join("Koala-Clash.lnk");
|
||||
|
||||
// 如果快捷方式已存在,直接返回成功
|
||||
if shortcut_path.exists() {
|
||||
@@ -77,7 +77,7 @@ pub fn create_shortcut() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn remove_shortcut() -> Result<()> {
|
||||
let startup_dir = get_startup_dir()?;
|
||||
let shortcut_path = startup_dir.join("Clash-Verge.lnk");
|
||||
let shortcut_path = startup_dir.join("Koala-Clash.lnk");
|
||||
|
||||
// 如果快捷方式不存在,直接返回成功
|
||||
if !shortcut_path.exists() {
|
||||
@@ -96,7 +96,7 @@ pub fn remove_shortcut() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn is_shortcut_enabled() -> Result<bool> {
|
||||
let startup_dir = get_startup_dir()?;
|
||||
let shortcut_path = startup_dir.join("Clash-Verge.lnk");
|
||||
let shortcut_path = startup_dir.join("Koala-Clash.lnk");
|
||||
|
||||
Ok(shortcut_path.exists())
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ use std::{fs, path::PathBuf};
|
||||
use tauri::Manager;
|
||||
|
||||
#[cfg(not(feature = "verge-dev"))]
|
||||
pub static APP_ID: &str = "io.github.clash-verge-rev.clash-verge-rev";
|
||||
pub static APP_ID: &str = "io.github.koala-clash";
|
||||
#[cfg(not(feature = "verge-dev"))]
|
||||
pub static BACKUP_DIR: &str = "clash-verge-rev-backup";
|
||||
pub static BACKUP_DIR: &str = "io.github.koala-clash-backup";
|
||||
|
||||
#[cfg(feature = "verge-dev")]
|
||||
pub static APP_ID: &str = "io.github.clash-verge-rev.clash-verge-rev.dev";
|
||||
pub static APP_ID: &str = "io.github.koala-clash.dev";
|
||||
#[cfg(feature = "verge-dev")]
|
||||
pub static BACKUP_DIR: &str = "clash-verge-rev-backup-dev";
|
||||
pub static BACKUP_DIR: &str = "io.github.koala-clash-backup-dev";
|
||||
|
||||
pub static PORTABLE_FLAG: OnceCell<bool> = OnceCell::new();
|
||||
|
||||
@@ -188,13 +188,13 @@ pub fn profiles_path() -> Result<PathBuf> {
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn service_path() -> Result<PathBuf> {
|
||||
let res_dir = app_resources_dir()?;
|
||||
Ok(res_dir.join("clash-verge-service"))
|
||||
Ok(res_dir.join("koala-clash-service"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn service_path() -> Result<PathBuf> {
|
||||
let res_dir = app_resources_dir()?;
|
||||
Ok(res_dir.join("clash-verge-service.exe"))
|
||||
Ok(res_dir.join("koala-clash-service.exe"))
|
||||
}
|
||||
|
||||
pub fn service_log_file() -> Result<PathBuf> {
|
||||
|
||||
@@ -246,7 +246,7 @@ fn init_dns_config() -> Result<()> {
|
||||
help::save_yaml(
|
||||
&dns_path,
|
||||
&default_dns_config,
|
||||
Some("# Clash Verge DNS Config"),
|
||||
Some("# Koala Clash DNS Config"),
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -274,14 +274,14 @@ pub fn init_config() -> Result<()> {
|
||||
|
||||
crate::log_err!(dirs::clash_path().map(|path| {
|
||||
if !path.exists() {
|
||||
help::save_yaml(&path, &IClashTemp::template().0, Some("# Clash Vergeasu"))?;
|
||||
help::save_yaml(&path, &IClashTemp::template().0, Some("# Koala Clash"))?;
|
||||
}
|
||||
<Result<()>>::Ok(())
|
||||
}));
|
||||
|
||||
crate::log_err!(dirs::verge_path().map(|path| {
|
||||
if !path.exists() {
|
||||
help::save_yaml(&path, &IVerge::template(), Some("# Clash Verge"))?;
|
||||
help::save_yaml(&path, &IVerge::template(), Some("# Koala Clash"))?;
|
||||
}
|
||||
<Result<()>>::Ok(())
|
||||
}));
|
||||
@@ -291,7 +291,7 @@ pub fn init_config() -> Result<()> {
|
||||
|
||||
crate::log_err!(dirs::profiles_path().map(|path| {
|
||||
if !path.exists() {
|
||||
help::save_yaml(&path, &IProfiles::template(), Some("# Clash Verge"))?;
|
||||
help::save_yaml(&path, &IProfiles::template(), Some("# Koala Clash"))?;
|
||||
}
|
||||
<Result<()>>::Ok(())
|
||||
}));
|
||||
@@ -371,8 +371,8 @@ pub fn init_scheme() -> Result<()> {
|
||||
|
||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||
let (clash, _) = hkcu.create_subkey("Software\\Classes\\Clash")?;
|
||||
clash.set_value("", &"Clash Verge")?;
|
||||
clash.set_value("URL Protocol", &"Clash Verge URL Scheme Protocol")?;
|
||||
clash.set_value("", &"Koala Clash")?;
|
||||
clash.set_value("URL Protocol", &"Koala Clash URL Scheme Protocol")?;
|
||||
let (default_icon, _) = hkcu.create_subkey("Software\\Classes\\Clash\\DefaultIcon")?;
|
||||
default_icon.set_value("", &app_exe)?;
|
||||
let (command, _) = hkcu.create_subkey("Software\\Classes\\Clash\\Shell\\Open\\Command")?;
|
||||
@@ -384,7 +384,7 @@ pub fn init_scheme() -> Result<()> {
|
||||
pub fn init_scheme() -> Result<()> {
|
||||
let output = std::process::Command::new("xdg-mime")
|
||||
.arg("default")
|
||||
.arg("clash-verge.desktop")
|
||||
.arg("koala-clash.desktop")
|
||||
.arg("x-scheme-handler/clash")
|
||||
.output()?;
|
||||
if !output.status.success() {
|
||||
|
||||
@@ -8,6 +8,6 @@ pub mod network;
|
||||
pub mod notification;
|
||||
pub mod resolve;
|
||||
pub mod server;
|
||||
pub mod sys_info;
|
||||
pub mod tmpl;
|
||||
pub mod window_manager;
|
||||
pub mod sys_info;
|
||||
|
||||
@@ -40,7 +40,7 @@ impl NetworkManager {
|
||||
// 创建专用的异步运行时,线程数限制为4个
|
||||
let runtime = Builder::new_multi_thread()
|
||||
.worker_threads(4)
|
||||
.thread_name("clash-verge-network")
|
||||
.thread_name("koala-clash-network")
|
||||
.enable_io()
|
||||
.enable_time()
|
||||
.build()
|
||||
@@ -323,8 +323,8 @@ impl NetworkManager {
|
||||
use crate::utils::resolve::VERSION;
|
||||
|
||||
let version = match VERSION.get() {
|
||||
Some(v) => format!("clash-verge/v{v}"),
|
||||
None => "clash-verge/unknown".to_string(),
|
||||
Some(v) => format!("koala-clash/v{v}"),
|
||||
None => "koala-clash/unknown".to_string(),
|
||||
};
|
||||
|
||||
builder = builder.user_agent(version);
|
||||
|
||||
@@ -549,7 +549,7 @@ pub async fn resolve_scheme(param: String) -> Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
if link_parsed.scheme() == "clash" || link_parsed.scheme() == "clash-verge" {
|
||||
if link_parsed.scheme() == "clash" || link_parsed.scheme() == "koala-clash" {
|
||||
let mut name: Option<String> = None;
|
||||
let mut url_param: Option<String> = None;
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@ use crate::{
|
||||
process::AsyncHandler,
|
||||
utils::logging::Type,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use port_scanner::local_port_available;
|
||||
use anyhow::Result;
|
||||
use std::convert::Infallible;
|
||||
use warp::Filter;
|
||||
|
||||
@@ -17,32 +16,6 @@ struct QueryParam {
|
||||
param: String,
|
||||
}
|
||||
|
||||
/// check whether there is already exists
|
||||
pub async fn check_singleton() -> Result<()> {
|
||||
let port = IVerge::get_singleton_port();
|
||||
if !local_port_available(port) {
|
||||
let argvs: Vec<String> = std::env::args().collect();
|
||||
if argvs.len() > 1 {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
let param = argvs[1].as_str();
|
||||
if param.starts_with("clash:") {
|
||||
let _ = reqwest::get(format!(
|
||||
"http://127.0.0.1:{port}/commands/scheme?param={param}"
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let _ = reqwest::get(format!("http://127.0.0.1:{port}/commands/visible")).await;
|
||||
}
|
||||
log::error!("failed to setup singleton listen server");
|
||||
bail!("app exists");
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The embed server only be used to implement singleton process
|
||||
/// maybe it can be used as pac server later
|
||||
pub fn embed_server() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Some config file template
|
||||
|
||||
/// template for new a profile item
|
||||
pub const ITEM_LOCAL: &str = "# Profile Template for Clash Verge
|
||||
pub const ITEM_LOCAL: &str = "# Profile Template for Koala Clash
|
||||
|
||||
proxies: []
|
||||
|
||||
@@ -11,13 +11,13 @@ rules: []
|
||||
";
|
||||
|
||||
/// enhanced profile
|
||||
pub const ITEM_MERGE: &str = "# Profile Enhancement Merge Template for Clash Verge
|
||||
pub const ITEM_MERGE: &str = "# Profile Enhancement Merge Template for Koala Clash
|
||||
|
||||
profile:
|
||||
store-selected: true
|
||||
";
|
||||
|
||||
pub const ITEM_MERGE_EMPTY: &str = "# Profile Enhancement Merge Template for Clash Verge
|
||||
pub const ITEM_MERGE_EMPTY: &str = "# Profile Enhancement Merge Template for Koala Clash
|
||||
|
||||
";
|
||||
|
||||
@@ -30,7 +30,7 @@ function main(config, profileName) {
|
||||
";
|
||||
|
||||
/// enhanced profile
|
||||
pub const ITEM_RULES: &str = "# Profile Enhancement Rules Template for Clash Verge
|
||||
pub const ITEM_RULES: &str = "# Profile Enhancement Rules Template for Koala Clash
|
||||
|
||||
prepend: []
|
||||
|
||||
@@ -40,7 +40,7 @@ delete: []
|
||||
";
|
||||
|
||||
/// enhanced profile
|
||||
pub const ITEM_PROXIES: &str = "# Profile Enhancement Proxies Template for Clash Verge
|
||||
pub const ITEM_PROXIES: &str = "# Profile Enhancement Proxies Template for Koala Clash
|
||||
|
||||
prepend: []
|
||||
|
||||
@@ -50,7 +50,7 @@ delete: []
|
||||
";
|
||||
|
||||
/// enhanced profile
|
||||
pub const ITEM_GROUPS: &str = "# Profile Enhancement Groups Template for Clash Verge
|
||||
pub const ITEM_GROUPS: &str = "# Profile Enhancement Groups Template for Koala Clash
|
||||
|
||||
prepend: []
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.5",
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"bundle": {
|
||||
"active": true,
|
||||
@@ -13,7 +13,7 @@
|
||||
],
|
||||
"resources": ["resources", "resources/locales/*"],
|
||||
"publisher": "Koala Clash",
|
||||
"externalBin": ["sidecar/verge-mihomo", "sidecar/verge-mihomo-alpha"],
|
||||
"externalBin": ["sidecar/koala-mihomo", "sidecar/koala-mihomo-alpha"],
|
||||
"copyright": "GNU General Public License v3.0",
|
||||
"category": "DeveloperTool",
|
||||
"shortDescription": "Koala Clash",
|
||||
@@ -26,7 +26,7 @@
|
||||
"devUrl": "http://localhost:3000/"
|
||||
},
|
||||
"productName": "Koala Clash",
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"identifier": "io.github.koala-clash",
|
||||
"plugins": {
|
||||
"updater": {
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IERCQjQ1QjQ0QUJDQTU1RTkKUldUcFZjcXJSRnUwMjdXSERoZVQ1R0hHRDMrT3VkSmpvbDJmb01sN3ZpYWhVYnEwaWpYUWU4YU0K",
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"deep-link": {
|
||||
"desktop": {
|
||||
"schemes": ["clash", "clash-verge"]
|
||||
"schemes": ["clash", "koala-clash"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"identifier": "io.github.koala-clash",
|
||||
"bundle": {
|
||||
"targets": ["deb", "rpm"],
|
||||
"linux": {
|
||||
"deb": {
|
||||
"depends": ["openssl"],
|
||||
"desktopTemplate": "./packages/linux/clash-verge.desktop",
|
||||
"provides": ["clash-verge"],
|
||||
"conflicts": ["clash-verge"],
|
||||
"replaces": ["clash-verge"],
|
||||
"desktopTemplate": "./packages/linux/koala-clash.desktop",
|
||||
"provides": ["koala-clash"],
|
||||
"conflicts": ["koala-clash"],
|
||||
"replaces": ["koala-clash"],
|
||||
"postInstallScript": "./packages/linux/post-install.sh",
|
||||
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
||||
},
|
||||
"rpm": {
|
||||
"depends": ["openssl"],
|
||||
"desktopTemplate": "./packages/linux/clash-verge.desktop",
|
||||
"provides": ["clash-verge"],
|
||||
"conflicts": ["clash-verge"],
|
||||
"obsoletes": ["clash-verge"],
|
||||
"desktopTemplate": "./packages/linux/koala-clash.desktop",
|
||||
"provides": ["koala-clash"],
|
||||
"conflicts": ["koala-clash"],
|
||||
"obsoletes": ["koala-clash"],
|
||||
"postInstallScript": "./packages/linux/post-install.sh",
|
||||
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
||||
}
|
||||
},
|
||||
"externalBin": [
|
||||
"./resources/clash-verge-service",
|
||||
"./resources/koala-clash-service",
|
||||
"./resources/install-service",
|
||||
"./resources/uninstall-service",
|
||||
"./sidecar/verge-mihomo",
|
||||
"./sidecar/verge-mihomo-alpha"
|
||||
"./sidecar/koala-mihomo",
|
||||
"./sidecar/koala-mihomo-alpha"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"identifier": "io.github.koala-clash",
|
||||
"productName": "Koala Clash",
|
||||
"bundle": {
|
||||
"targets": ["app", "dmg"],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"identifier": "io.github.koala-clash",
|
||||
"bundle": {
|
||||
"targets": ["nsis"],
|
||||
"windows": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"identifier": "io.github.koala-clash",
|
||||
"bundle": {
|
||||
"targets": ["nsis"],
|
||||
"windows": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"identifier": "io.github.koala-clash",
|
||||
"bundle": {
|
||||
"targets": ["nsis"],
|
||||
"windows": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"identifier": "io.github.koala-clash",
|
||||
"bundle": {
|
||||
"targets": ["nsis"],
|
||||
"windows": {
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { AppDataProvider } from "./providers/app-data-provider";
|
||||
import { ThemeProvider } from "@/components/layout/theme-provider";
|
||||
import Layout from "./pages/_layout";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<AppDataProvider>
|
||||
<Layout />
|
||||
</AppDataProvider>
|
||||
</ThemeProvider>
|
||||
<AppDataProvider>
|
||||
<Layout />
|
||||
</AppDataProvider>
|
||||
);
|
||||
}
|
||||
export default App;
|
||||
|
||||
|
Before Width: | Height: | Size: 576 KiB After Width: | Height: | Size: 1.1 MiB |
@@ -1,50 +1,108 @@
|
||||
<svg version="1.1" id="layout1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 117 27" style="enable-background:new 0 0 117 27;" xml:space="preserve">
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_1_" x="-39.9" width="157" height="27"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_00000023248255305809236420000007367745325967865768_">
|
||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
||||
</clipPath>
|
||||
<g style="clip-path:url(#SVGID_00000023248255305809236420000007367745325967865768_);">
|
||||
<path class="st1" d="M115.9,21.4c-0.5,0.3-1.1,0.5-1.8,0.7c-0.7,0.1-1.3,0.2-1.9,0.2c-2.1,0-3.8-0.5-4.9-1.5
|
||||
c-1.1-1-1.6-2.4-1.6-4.3c0-1.8,0.5-3.2,1.5-4.2c1-1,2.3-1.5,4-1.5c1.7,0,3,0.5,4,1.5c1,1,1.5,2.3,1.5,4.2c0,0.2,0,0.5,0,0.9h-7.8
|
||||
c0.3,1.7,1.4,2.6,3.4,2.6c1.4,0,2.6-0.4,3.7-1.2V21.4z M113.6,15.2c-0.2-0.7-0.5-1.2-0.9-1.5c-0.4-0.3-0.9-0.5-1.5-0.5
|
||||
c-0.6,0-1,0.2-1.4,0.5c-0.4,0.3-0.7,0.8-0.8,1.5H113.6z"/>
|
||||
<path class="st1" d="M98.5,26.6c-0.8,0-1.6-0.1-2.5-0.2c-0.8-0.1-1.5-0.3-2.2-0.5v-2.6c1.4,0.3,2.9,0.5,4.3,0.5
|
||||
c0.9,0,1.6-0.2,2.1-0.6c0.5-0.4,0.7-1,0.7-1.7c-0.7,0.5-1.6,0.7-2.6,0.7c-1,0-1.9-0.2-2.6-0.7c-0.7-0.5-1.3-1.1-1.7-2
|
||||
c-0.4-0.9-0.6-1.8-0.6-2.9c0-1.1,0.2-2.1,0.6-2.9c0.4-0.9,1-1.5,1.7-2c0.7-0.5,1.6-0.7,2.6-0.7c0.9,0,1.8,0.3,2.6,0.9v-0.7h3.1V22
|
||||
C104,25,102.2,26.6,98.5,26.6z M96.4,16.6c0,0.6,0.1,1.2,0.4,1.7c0.3,0.5,0.6,0.9,1,1.2c0.4,0.3,0.8,0.4,1.3,0.4
|
||||
c0.3,0,0.7-0.1,1.1-0.2c0.4-0.2,0.8-0.5,1.1-1l0.1-0.4v-3.7c-0.3-0.6-0.6-0.9-1.1-1.1c-0.4-0.2-0.8-0.3-1.2-0.3
|
||||
c-0.5,0-0.9,0.1-1.3,0.4c-0.4,0.3-0.7,0.7-1,1.2C96.6,15.4,96.4,16,96.4,16.6z"/>
|
||||
<path class="st1" d="M89.2,11.2v1.2c0.3-0.4,0.8-0.7,1.2-0.9c0.5-0.2,1-0.3,1.5-0.3c0.3,0,0.6,0,0.9,0.1v2.5
|
||||
c-0.4-0.1-0.7-0.1-1.1-0.1c-0.5,0-1,0.1-1.4,0.3c-0.5,0.2-0.8,0.4-1.1,0.8V22H86V11.2H89.2z"/>
|
||||
<path class="st1" d="M83.7,21.4c-0.5,0.3-1.1,0.5-1.8,0.7c-0.7,0.1-1.3,0.2-1.9,0.2c-2.1,0-3.8-0.5-4.9-1.5
|
||||
c-1.1-1-1.6-2.4-1.6-4.3c0-1.8,0.5-3.2,1.5-4.2c1-1,2.3-1.5,4-1.5c1.7,0,3,0.5,4,1.5c1,1,1.5,2.3,1.5,4.2c0,0.2,0,0.5,0,0.9h-7.8
|
||||
C76.9,19.1,78,20,80,20c1.4,0,2.6-0.4,3.7-1.2V21.4z M81.4,15.2c-0.2-0.7-0.5-1.2-0.9-1.5c-0.4-0.3-0.9-0.5-1.5-0.5
|
||||
c-0.6,0-1,0.2-1.4,0.5c-0.4,0.3-0.7,0.8-0.8,1.5H81.4z"/>
|
||||
<path class="st1" d="M59.5,8h3.6l3.4,11.8h0.1L69.9,8h3.6l-4.3,14h-5.3L59.5,8z"/>
|
||||
<path class="st1" d="M46.4,6.6v5.7c0.5-0.4,1-0.7,1.6-0.9c0.6-0.2,1.2-0.3,1.8-0.3c1,0,1.8,0.3,2.4,0.9c0.6,0.6,0.9,1.4,0.9,2.3
|
||||
V22h-3.2v-7.1c0-0.4-0.2-0.7-0.5-0.9c-0.3-0.3-0.7-0.4-1.1-0.4c-0.3,0-0.6,0.1-0.9,0.2c-0.4,0.2-0.7,0.4-1,0.6V22h-3.2V6.6H46.4z"
|
||||
/>
|
||||
<path class="st1" d="M37.9,22.2c-0.8,0-1.6,0-2.5-0.2c-0.8-0.2-1.5-0.4-2.2-0.8v-2.9c0.5,0.4,1.2,0.7,2,1c0.8,0.3,1.5,0.4,2,0.3
|
||||
c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.3-0.3,0.3-0.5c0.1-0.4,0-0.7-0.3-0.9c-0.3-0.2-0.8-0.4-1.5-0.6c-0.8-0.2-1.5-0.5-1.9-0.8
|
||||
c-0.5-0.3-0.8-0.6-1.1-1c-0.2-0.4-0.4-0.9-0.4-1.5c0-0.6,0.2-1.2,0.5-1.6c0.3-0.5,0.8-0.9,1.5-1.2c0.7-0.3,1.4-0.4,2.2-0.4
|
||||
c0.6,0,1.2,0.1,1.8,0.2c0.6,0.1,1.1,0.3,1.5,0.4v2.6c-0.4-0.2-0.9-0.4-1.5-0.6c-0.6-0.2-1.1-0.3-1.5-0.3c-0.9,0-1.4,0.2-1.5,0.7
|
||||
c0,0.3,0.1,0.5,0.4,0.7c0.3,0.2,0.7,0.4,1.3,0.6c0.8,0.3,1.5,0.5,2,0.8c0.5,0.3,0.9,0.6,1.2,1c0.3,0.4,0.4,1,0.4,1.6
|
||||
c0,1-0.4,1.8-1.1,2.4C40,21.9,39,22.2,37.9,22.2z"/>
|
||||
<path class="st1" d="M25.8,22.3c-1,0-1.9-0.2-2.7-0.7c-0.7-0.5-1.3-1.1-1.7-2c-0.4-0.8-0.6-1.8-0.6-2.9c0-1.1,0.2-2.1,0.6-2.9
|
||||
c0.4-0.9,1-1.5,1.7-2c0.7-0.5,1.6-0.7,2.6-0.7c0.5,0,0.9,0.1,1.4,0.3c0.5,0.2,0.9,0.4,1.3,0.7v-0.7h3.2v8.3c0,1.1,0.1,1.9,0.4,2.5
|
||||
h-3c-0.1-0.2-0.2-0.4-0.2-0.7C27.9,21.9,26.9,22.3,25.8,22.3z M23.9,16.6c0,0.6,0.1,1.2,0.4,1.7c0.3,0.5,0.6,0.9,1,1.2
|
||||
c0.4,0.3,0.8,0.4,1.3,0.4c0.3,0,0.7-0.1,1.1-0.2c0.4-0.1,0.7-0.5,1-0.9v-4.5c-0.3-0.5-0.6-0.8-1-0.9c-0.4-0.1-0.7-0.2-1.1-0.2
|
||||
c-0.5,0-0.9,0.1-1.3,0.4c-0.4,0.3-0.7,0.7-1,1.2C24,15.4,23.9,16,23.9,16.6z"/>
|
||||
<path class="st1" d="M18.5,22.2c-1.2,0-2.1-0.3-2.7-1c-0.6-0.7-0.9-1.7-0.9-3V6.6H18v10.8c0,0.5,0,0.9,0.1,1.2
|
||||
c0.1,0.3,0.2,0.5,0.4,0.6c0.1,0.1,0.3,0.2,0.5,0.2c0.2,0,0.5,0,1,0v2.6H18.5z"/>
|
||||
<path class="st1" d="M8.8,22.3c-1.5,0-2.9-0.3-4.1-0.8C3.6,20.9,2.7,20,2,19c-0.7-1.1-1-2.3-1-3.8c0-1.5,0.3-2.9,1-4
|
||||
c0.7-1.1,1.6-2,2.7-2.6c1.2-0.6,2.5-0.9,4-0.9c0.7,0,1.5,0.1,2.3,0.2s1.4,0.3,1.9,0.6V11c-1.3-0.5-2.6-0.7-3.8-0.7
|
||||
c-1.4,0-2.5,0.4-3.4,1.2c-0.9,0.8-1.3,2-1.3,3.7c0,0.9,0.2,1.7,0.6,2.3c0.4,0.7,1,1.2,1.7,1.6c0.7,0.4,1.4,0.6,2.2,0.6l0.4,0
|
||||
c0.6,0,1.2-0.1,1.8-0.3c0.6-0.2,1.1-0.4,1.6-0.7v2.8c-0.6,0.3-1.2,0.5-1.8,0.6C10.4,22.2,9.6,22.3,8.8,22.3z"/>
|
||||
</g>
|
||||
<svg width="1024" height="963" viewBox="0 0 1024 963" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_f_40_29)">
|
||||
<ellipse cx="512" cy="516" rx="254" ry="216" fill="url(#paint0_radial_40_29)" fill-opacity="0.3"/>
|
||||
</g>
|
||||
<g style="mix-blend-mode:hard-light" filter="url(#filter1_f_40_29)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M253.555 253.691C234.166 257.325 210.787 267.678 194.817 279.704C167.671 300.145 143 336.666 143 356.409C143 364.909 148.741 370.132 158.085 370.132C161.927 370.132 162.182 370.298 161.535 372.382C161.15 373.62 160.598 381.832 160.308 390.632C159.843 404.693 160.039 407.723 161.922 415.632C165.896 432.325 175.89 449.337 188.675 461.172C204.384 475.712 222.721 483.721 246.31 486.344C256.49 487.476 257.088 487.667 256.498 489.589C255.106 494.128 254.72 539.224 255.981 549.919C259.914 583.268 273.139 615.139 294.865 643.632C306.099 658.365 327.932 678.511 345 689.893C389.521 719.583 458.858 734.6 535.26 731.098C567.926 729.601 590.289 726.361 615.5 719.475C682.821 701.087 736.946 652.57 757.886 591.84C766.113 567.983 768.638 548.162 767.596 515.632C767.226 504.082 766.675 493.013 766.37 491.033L765.817 487.435L774.158 486.74C817.12 483.16 850.475 457.074 861.243 418.632C863.868 409.261 864.639 388.453 862.753 377.882L861.37 370.132L865.435 370.13C873.132 370.128 881 363.641 881 357.298C881 349.587 875.454 334.787 868.01 322.632C833.048 265.543 764.751 237.996 710.358 259.044C700.723 262.772 689.715 269.233 678 278.038C667.891 285.635 644.942 308.477 640 315.862C637.584 319.472 636.036 320.902 635 320.482C615.25 312.464 578.262 303.843 547 299.972C533.368 298.284 489.859 298.263 475.5 299.938C447.293 303.227 421.534 308.84 399.752 316.442L387.004 320.891L382.317 314.262C376.27 305.71 356.765 286.218 346.479 278.449C331.01 266.765 317.133 259.319 303 255.12C293.122 252.185 265.803 251.396 253.555 253.691ZM525.775 474.141C542.235 479.919 552.81 493.069 560.962 517.895C572.367 552.627 577.508 595.826 572.237 612.632C569.49 621.391 566.737 625.917 560.043 632.68C553.631 639.158 543.575 644.286 532.5 646.726C522.255 648.984 501.437 649.041 491.343 646.839C461.912 640.42 447.619 620.374 449.483 588.132C451.047 561.084 460.42 521.584 470.009 501.632C476.59 487.939 487.236 478.078 499.762 474.074C507.624 471.56 518.502 471.589 525.775 474.141ZM389.384 484.362C395.107 486.072 401.281 492.491 402.955 498.473C406.617 511.549 396.619 525.041 383.218 525.11C364.274 525.207 354.944 501.775 368.761 488.803C374.23 483.668 381.688 482.062 389.384 484.362ZM648.277 484.192C656.216 486.397 662.933 495.325 662.978 503.733C663.025 512.411 659.127 518.893 651.611 522.639C642.535 527.161 632.471 525.166 626.243 517.61C613.065 501.623 628.229 478.625 648.277 484.192Z" stroke="url(#paint1_linear_40_29)" stroke-width="6" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<g style="mix-blend-mode:hard-light" filter="url(#filter2_f_40_29)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M253.555 253.691C234.166 257.325 210.787 267.678 194.817 279.704C167.671 300.145 143 336.666 143 356.409C143 364.909 148.741 370.132 158.085 370.132C161.927 370.132 162.182 370.298 161.535 372.382C161.15 373.62 160.598 381.832 160.308 390.632C159.843 404.693 160.039 407.723 161.922 415.632C165.896 432.325 175.89 449.337 188.675 461.172C204.384 475.712 222.721 483.721 246.31 486.344C256.49 487.476 257.088 487.667 256.498 489.589C255.106 494.128 254.72 539.224 255.981 549.919C259.914 583.268 273.139 615.139 294.865 643.632C306.099 658.365 327.932 678.511 345 689.893C389.521 719.583 458.858 734.6 535.26 731.098C567.926 729.601 590.289 726.361 615.5 719.475C682.821 701.087 736.946 652.57 757.886 591.84C766.113 567.983 768.638 548.162 767.596 515.632C767.226 504.082 766.675 493.013 766.37 491.033L765.817 487.435L774.158 486.74C817.12 483.16 850.475 457.074 861.243 418.632C863.868 409.261 864.639 388.453 862.753 377.882L861.37 370.132L865.435 370.13C873.132 370.128 881 363.641 881 357.298C881 349.587 875.454 334.787 868.01 322.632C833.048 265.543 764.751 237.996 710.358 259.044C700.723 262.772 689.715 269.233 678 278.038C667.891 285.635 644.942 308.477 640 315.862C637.584 319.472 636.036 320.902 635 320.482C615.25 312.464 578.262 303.843 547 299.972C533.368 298.284 489.859 298.263 475.5 299.938C447.293 303.227 421.534 308.84 399.752 316.442L387.004 320.891L382.317 314.262C376.27 305.71 356.765 286.218 346.479 278.449C331.01 266.765 317.133 259.319 303 255.12C293.122 252.185 265.803 251.396 253.555 253.691ZM525.775 474.141C542.235 479.919 552.81 493.069 560.962 517.895C572.367 552.627 577.508 595.826 572.237 612.632C569.49 621.391 566.737 625.917 560.043 632.68C553.631 639.158 543.575 644.286 532.5 646.726C522.255 648.984 501.437 649.041 491.343 646.839C461.912 640.42 447.619 620.374 449.483 588.132C451.047 561.084 460.42 521.584 470.009 501.632C476.59 487.939 487.236 478.078 499.762 474.074C507.624 471.56 518.502 471.589 525.775 474.141ZM389.384 484.362C395.107 486.072 401.281 492.491 402.955 498.473C406.617 511.549 396.619 525.041 383.218 525.11C364.274 525.207 354.944 501.775 368.761 488.803C374.23 483.668 381.688 482.062 389.384 484.362ZM648.277 484.192C656.216 486.397 662.933 495.325 662.978 503.733C663.025 512.411 659.127 518.893 651.611 522.639C642.535 527.161 632.471 525.166 626.243 517.61C613.065 501.623 628.229 478.625 648.277 484.192Z" stroke="url(#paint2_linear_40_29)" stroke-opacity="0.7" stroke-width="8" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<g style="mix-blend-mode:hard-light" filter="url(#filter3_f_40_29)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M253.555 253.691C234.166 257.325 210.787 267.678 194.817 279.704C167.671 300.145 143 336.666 143 356.409C143 364.909 148.741 370.132 158.085 370.132C161.927 370.132 162.182 370.298 161.535 372.382C161.15 373.62 160.598 381.832 160.308 390.632C159.843 404.693 160.039 407.723 161.922 415.632C165.896 432.325 175.89 449.337 188.675 461.172C204.384 475.712 222.721 483.721 246.31 486.344C256.49 487.476 257.088 487.667 256.498 489.589C255.106 494.128 254.72 539.224 255.981 549.919C259.914 583.268 273.139 615.139 294.865 643.632C306.099 658.365 327.932 678.511 345 689.893C389.521 719.583 458.858 734.6 535.26 731.098C567.926 729.601 590.289 726.361 615.5 719.475C682.821 701.087 736.946 652.57 757.886 591.84C766.113 567.983 768.638 548.162 767.596 515.632C767.226 504.082 766.675 493.013 766.37 491.033L765.817 487.435L774.158 486.74C817.12 483.16 850.475 457.074 861.243 418.632C863.868 409.261 864.639 388.453 862.753 377.882L861.37 370.132L865.435 370.13C873.132 370.128 881 363.641 881 357.298C881 349.587 875.454 334.787 868.01 322.632C833.048 265.543 764.751 237.996 710.358 259.044C700.723 262.772 689.715 269.233 678 278.038C667.891 285.635 644.942 308.477 640 315.862C637.584 319.472 636.036 320.902 635 320.482C615.25 312.464 578.262 303.843 547 299.972C533.368 298.284 489.859 298.263 475.5 299.938C447.293 303.227 421.534 308.84 399.752 316.442L387.004 320.891L382.317 314.262C376.27 305.71 356.765 286.218 346.479 278.449C331.01 266.765 317.133 259.319 303 255.12C293.122 252.185 265.803 251.396 253.555 253.691ZM525.775 474.141C542.235 479.919 552.81 493.069 560.962 517.895C572.367 552.627 577.508 595.826 572.237 612.632C569.49 621.391 566.737 625.917 560.043 632.68C553.631 639.158 543.575 644.286 532.5 646.726C522.255 648.984 501.437 649.041 491.343 646.839C461.912 640.42 447.619 620.374 449.483 588.132C451.047 561.084 460.42 521.584 470.009 501.632C476.59 487.939 487.236 478.078 499.762 474.074C507.624 471.56 518.502 471.589 525.775 474.141ZM389.384 484.362C395.107 486.072 401.281 492.491 402.955 498.473C406.617 511.549 396.619 525.041 383.218 525.11C364.274 525.207 354.944 501.775 368.761 488.803C374.23 483.668 381.688 482.062 389.384 484.362ZM648.277 484.192C656.216 486.397 662.933 495.325 662.978 503.733C663.025 512.411 659.127 518.893 651.611 522.639C642.535 527.161 632.471 525.166 626.243 517.61C613.065 501.623 628.229 478.625 648.277 484.192Z" stroke="url(#paint3_linear_40_29)" stroke-opacity="0.4" stroke-width="7" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<g style="mix-blend-mode:hard-light" filter="url(#filter4_ddif_40_29)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M253.555 253.691C234.166 257.325 210.787 267.678 194.817 279.704C167.671 300.145 143 336.666 143 356.409C143 364.909 148.741 370.132 158.085 370.132C161.927 370.132 162.182 370.298 161.535 372.382C161.15 373.62 160.598 381.832 160.308 390.632C159.843 404.693 160.039 407.723 161.922 415.632C165.896 432.325 175.89 449.337 188.675 461.172C204.384 475.712 222.721 483.721 246.31 486.344C256.49 487.476 257.088 487.667 256.498 489.589C255.106 494.128 254.72 539.224 255.981 549.919C259.914 583.268 273.139 615.139 294.865 643.632C306.099 658.365 327.932 678.511 345 689.893C389.521 719.583 458.858 734.6 535.26 731.098C567.926 729.601 590.289 726.361 615.5 719.475C682.821 701.087 736.946 652.57 757.886 591.84C766.113 567.983 768.638 548.162 767.596 515.632C767.226 504.082 766.675 493.013 766.37 491.033L765.817 487.435L774.158 486.74C817.12 483.16 850.475 457.074 861.243 418.632C863.868 409.261 864.639 388.453 862.753 377.882L861.37 370.132L865.435 370.13C873.132 370.128 881 363.641 881 357.298C881 349.587 875.454 334.787 868.01 322.632C833.048 265.543 764.751 237.996 710.358 259.044C700.723 262.772 689.715 269.233 678 278.038C667.891 285.635 644.942 308.477 640 315.862C637.584 319.472 636.036 320.902 635 320.482C615.25 312.464 578.262 303.843 547 299.972C533.368 298.284 489.859 298.263 475.5 299.938C447.293 303.227 421.534 308.84 399.752 316.442L387.004 320.891L382.317 314.262C376.27 305.71 356.765 286.218 346.479 278.449C331.01 266.765 317.133 259.319 303 255.12C293.122 252.185 265.803 251.396 253.555 253.691ZM525.775 474.141C542.235 479.919 552.81 493.069 560.962 517.895C572.367 552.627 577.508 595.826 572.237 612.632C569.49 621.391 566.737 625.917 560.043 632.68C553.631 639.158 543.575 644.286 532.5 646.726C522.255 648.984 501.437 649.041 491.343 646.839C461.912 640.42 447.619 620.374 449.483 588.132C451.047 561.084 460.42 521.584 470.009 501.632C476.59 487.939 487.236 478.078 499.762 474.074C507.624 471.56 518.502 471.589 525.775 474.141ZM389.384 484.362C395.107 486.072 401.281 492.491 402.955 498.473C406.617 511.549 396.619 525.041 383.218 525.11C364.274 525.207 354.944 501.775 368.761 488.803C374.23 483.668 381.688 482.062 389.384 484.362ZM648.277 484.192C656.216 486.397 662.933 495.325 662.978 503.733C663.025 512.411 659.127 518.893 651.611 522.639C642.535 527.161 632.471 525.166 626.243 517.61C613.065 501.623 628.229 478.625 648.277 484.192Z" stroke="url(#paint4_linear_40_29)" stroke-opacity="0.01" stroke-width="5" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<g filter="url(#filter5_f_40_29)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M253.555 253.691C234.166 257.325 210.787 267.678 194.817 279.704C167.671 300.145 143 336.666 143 356.409C143 364.909 148.741 370.132 158.085 370.132C161.927 370.132 162.182 370.298 161.535 372.382C161.15 373.62 160.598 381.832 160.308 390.632C159.843 404.693 160.039 407.723 161.922 415.632C165.896 432.325 175.89 449.337 188.675 461.172C204.384 475.712 222.721 483.721 246.31 486.344C256.49 487.476 257.088 487.667 256.498 489.589C255.106 494.128 254.72 539.224 255.981 549.919C259.914 583.268 273.139 615.139 294.865 643.632C306.099 658.365 327.932 678.511 345 689.893C389.521 719.583 458.858 734.6 535.26 731.098C567.926 729.601 590.289 726.361 615.5 719.475C682.821 701.087 736.946 652.57 757.886 591.84C766.113 567.983 768.638 548.162 767.596 515.632C767.226 504.082 766.675 493.013 766.37 491.033L765.817 487.435L774.158 486.74C817.12 483.16 850.475 457.074 861.243 418.632C863.868 409.261 864.639 388.453 862.753 377.882L861.37 370.132L865.435 370.13C873.132 370.128 881 363.641 881 357.298C881 349.587 875.454 334.787 868.01 322.632C833.048 265.543 764.751 237.996 710.358 259.044C700.723 262.772 689.715 269.233 678 278.038C667.891 285.635 644.942 308.477 640 315.862C637.584 319.472 636.036 320.902 635 320.482C615.25 312.464 578.262 303.843 547 299.972C533.368 298.284 489.859 298.263 475.5 299.938C447.293 303.227 421.534 308.84 399.752 316.442L387.004 320.891L382.317 314.262C376.27 305.71 356.765 286.218 346.479 278.449C331.01 266.765 317.133 259.319 303 255.12C293.122 252.185 265.803 251.396 253.555 253.691ZM525.775 474.141C542.235 479.919 552.81 493.069 560.962 517.895C572.367 552.627 577.508 595.826 572.237 612.632C569.49 621.391 566.737 625.917 560.043 632.68C553.631 639.158 543.575 644.286 532.5 646.726C522.255 648.984 501.437 649.041 491.343 646.839C461.912 640.42 447.619 620.374 449.483 588.132C451.047 561.084 460.42 521.584 470.009 501.632C476.59 487.939 487.236 478.078 499.762 474.074C507.624 471.56 518.502 471.589 525.775 474.141ZM389.384 484.362C395.107 486.072 401.281 492.491 402.955 498.473C406.617 511.549 396.619 525.041 383.218 525.11C364.274 525.207 354.944 501.775 368.761 488.803C374.23 483.668 381.688 482.062 389.384 484.362ZM648.277 484.192C656.216 486.397 662.933 495.325 662.978 503.733C663.025 512.411 659.127 518.893 651.611 522.639C642.535 527.161 632.471 525.166 626.243 517.61C613.065 501.623 628.229 478.625 648.277 484.192Z" stroke="url(#paint5_linear_40_29)" stroke-width="9.5" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<g filter="url(#filter6_f_40_29)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M253.555 253.691C234.166 257.325 210.787 267.678 194.817 279.704C167.671 300.145 143 336.666 143 356.409C143 364.909 148.741 370.132 158.085 370.132C161.927 370.132 162.182 370.298 161.535 372.382C161.15 373.62 160.598 381.832 160.308 390.632C159.843 404.693 160.039 407.723 161.922 415.632C165.896 432.325 175.89 449.337 188.675 461.172C204.384 475.712 222.721 483.721 246.31 486.344C256.49 487.476 257.088 487.667 256.498 489.589C255.106 494.128 254.72 539.224 255.981 549.919C259.914 583.268 273.139 615.139 294.865 643.632C306.099 658.365 327.932 678.511 345 689.893C389.521 719.583 458.858 734.6 535.26 731.098C567.926 729.601 590.289 726.361 615.5 719.475C682.821 701.087 736.946 652.57 757.886 591.84C766.113 567.983 768.638 548.162 767.596 515.632C767.226 504.082 766.675 493.013 766.37 491.033L765.817 487.435L774.158 486.74C817.12 483.16 850.475 457.074 861.243 418.632C863.868 409.261 864.639 388.453 862.753 377.882L861.37 370.132L865.435 370.13C873.132 370.128 881 363.641 881 357.298C881 349.587 875.454 334.787 868.01 322.632C833.048 265.543 764.751 237.996 710.358 259.044C700.723 262.772 689.715 269.233 678 278.038C667.891 285.635 644.942 308.477 640 315.862C637.584 319.472 636.036 320.902 635 320.482C615.25 312.464 578.262 303.843 547 299.972C533.368 298.284 489.859 298.263 475.5 299.938C447.293 303.227 421.534 308.84 399.752 316.442L387.004 320.891L382.317 314.262C376.27 305.71 356.765 286.218 346.479 278.449C331.01 266.765 317.133 259.319 303 255.12C293.122 252.185 265.803 251.396 253.555 253.691ZM525.775 474.141C542.235 479.919 552.81 493.069 560.962 517.895C572.367 552.627 577.508 595.826 572.237 612.632C569.49 621.391 566.737 625.917 560.043 632.68C553.631 639.158 543.575 644.286 532.5 646.726C522.255 648.984 501.437 649.041 491.343 646.839C461.912 640.42 447.619 620.374 449.483 588.132C451.047 561.084 460.42 521.584 470.009 501.632C476.59 487.939 487.236 478.078 499.762 474.074C507.624 471.56 518.502 471.589 525.775 474.141ZM389.384 484.362C395.107 486.072 401.281 492.491 402.955 498.473C406.617 511.549 396.619 525.041 383.218 525.11C364.274 525.207 354.944 501.775 368.761 488.803C374.23 483.668 381.688 482.062 389.384 484.362ZM648.277 484.192C656.216 486.397 662.933 495.325 662.978 503.733C663.025 512.411 659.127 518.893 651.611 522.639C642.535 527.161 632.471 525.166 626.243 517.61C613.065 501.623 628.229 478.625 648.277 484.192Z" stroke="white" stroke-width="2.9" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f_40_29" x="-42" y="0" width="1108" height="1032" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="150" result="effect1_foregroundBlur_40_29"/>
|
||||
</filter>
|
||||
<filter id="filter1_f_40_29" x="118.94" y="227.932" width="786.12" height="527.726" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="10.53" result="effect1_foregroundBlur_40_29"/>
|
||||
</filter>
|
||||
<filter id="filter2_f_40_29" x="89" y="197.99" width="846" height="587.608" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="25" result="effect1_foregroundBlur_40_29"/>
|
||||
</filter>
|
||||
<filter id="filter3_f_40_29" x="132.48" y="241.471" width="759.04" height="500.647" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="3.51" result="effect1_foregroundBlur_40_29"/>
|
||||
</filter>
|
||||
<filter id="filter4_ddif_40_29" x="110.5" y="219.494" width="803" height="544.604" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="3.9"/>
|
||||
<feGaussianBlur stdDeviation="1.5"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.109804 0 0 0 0 0.886275 0 0 0 0 0.968627 0 0 0 1 0"/>
|
||||
<feBlend mode="multiply" in2="BackgroundImageFix" result="effect1_dropShadow_40_29"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="7.02"/>
|
||||
<feGaussianBlur stdDeviation="4.563"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.819608 0 0 0 0 0.054902 0 0 0 0 0.996078 0 0 0 1 0"/>
|
||||
<feBlend mode="color-dodge" in2="effect1_dropShadow_40_29" result="effect2_dropShadow_40_29"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_40_29" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dx="-0.39" dy="0.78"/>
|
||||
<feGaussianBlur stdDeviation="0.195"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect3_innerShadow_40_29"/>
|
||||
<feGaussianBlur stdDeviation="15" result="effect4_foregroundBlur_40_29"/>
|
||||
</filter>
|
||||
<filter id="filter5_f_40_29" x="137.15" y="246.138" width="749.7" height="491.31" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="0.55" result="effect1_foregroundBlur_40_29"/>
|
||||
</filter>
|
||||
<filter id="filter6_f_40_29" x="137.15" y="246.146" width="749.7" height="491.302" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="2.2" result="effect1_foregroundBlur_40_29"/>
|
||||
</filter>
|
||||
<radialGradient id="paint0_radial_40_29" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(512 516) rotate(20.8768) scale(331.625 512.736)">
|
||||
<stop stop-color="#0CF6F7"/>
|
||||
<stop offset="1" stop-color="#D10EFE"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint1_linear_40_29" x1="826.587" y1="628.647" x2="310.413" y2="316.853" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0CF6F7"/>
|
||||
<stop offset="0.461563" stop-color="#6B86FA"/>
|
||||
<stop offset="1" stop-color="#D10EFE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_40_29" x1="826.587" y1="628.647" x2="310.413" y2="316.853" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0CF6F7"/>
|
||||
<stop offset="0.225986" stop-color="#6B86FA"/>
|
||||
<stop offset="0.673077" stop-color="#6B86FA"/>
|
||||
<stop offset="1" stop-color="#D10EFE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_40_29" x1="826.587" y1="628.647" x2="310.413" y2="316.853" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0CF6F7"/>
|
||||
<stop offset="0.225986" stop-color="#6B86FA"/>
|
||||
<stop offset="0.673077" stop-color="#6B86FA"/>
|
||||
<stop offset="1" stop-color="#D10EFE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear_40_29" x1="826.587" y1="628.647" x2="310.413" y2="316.853" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0CF6F7"/>
|
||||
<stop offset="0.225986" stop-color="#6B86FA"/>
|
||||
<stop offset="0.673077" stop-color="#6B86FA"/>
|
||||
<stop offset="1" stop-color="#D10EFE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear_40_29" x1="826.587" y1="628.647" x2="310.413" y2="316.853" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0CF6F7"/>
|
||||
<stop offset="0.461563" stop-color="#6B86FA"/>
|
||||
<stop offset="1" stop-color="#D10EFE"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 21 KiB |
422
src/assets/image/map.svg
Normal file
|
After Width: | Height: | Size: 453 KiB |
@@ -1,30 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Toaster, toast } from "sonner";
|
||||
import { useEffect, useSyncExternalStore } from "react";
|
||||
import {
|
||||
getSnapshotNotices,
|
||||
hideNotice,
|
||||
subscribeNotices,
|
||||
} from "@/services/noticeService";
|
||||
|
||||
export const NoticeManager = () => {
|
||||
const currentNotices = useSyncExternalStore(
|
||||
subscribeNotices,
|
||||
getSnapshotNotices,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
for (const notice of currentNotices) {
|
||||
const toastId = toast(notice.message, {
|
||||
id: notice.id,
|
||||
duration: notice.duration,
|
||||
onDismiss: (t) => {
|
||||
hideNotice(t.id as number);
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [currentNotices]);
|
||||
|
||||
return <Toaster />;
|
||||
};
|
||||
@@ -5,4 +5,3 @@ export { BaseLoading } from "./base-loading";
|
||||
export { BaseErrorBoundary } from "./base-error-boundary";
|
||||
export { Switch } from "./base-switch";
|
||||
export { BaseLoadingOverlay } from "./base-loading-overlay";
|
||||
export { NoticeManager } from "./NoticeManager";
|
||||
|
||||
64
src/components/home/power-button.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import { cn } from '@root/lib/utils';
|
||||
import { Power } from 'lucide-react';
|
||||
|
||||
export interface PowerButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
checked?: boolean;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
export const PowerButton = React.forwardRef<HTMLButtonElement, PowerButtonProps>(
|
||||
({ className, checked = false, loading = false, ...props }, ref) => {
|
||||
const state = checked ? 'on' : 'off';
|
||||
|
||||
return (
|
||||
<div className="relative flex items-center justify-center h-44 w-44">
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
'absolute h-28 w-28 rounded-full blur-3xl transition-all duration-500',
|
||||
state === 'on' ? 'bg-green-400/60' : 'bg-red-500/40',
|
||||
props.disabled && 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
|
||||
<button
|
||||
ref={ref}
|
||||
type="button"
|
||||
disabled={loading || props.disabled}
|
||||
data-state={state}
|
||||
className={cn(
|
||||
'relative z-10 flex items-center justify-center h-36 w-36 rounded-full border-2',
|
||||
'backdrop-blur-sm bg-white/10 border-white/20',
|
||||
'text-red-500 shadow-[0_0_30px_rgba(239,68,68,0.6)]',
|
||||
'data-[state=on]:text-green-500 dark:data-[state=on]:text-white',
|
||||
'data-[state=on]:shadow-[0_0_50px_rgba(34,197,94,1)]',
|
||||
'transition-all duration-300 hover:scale-105 active:scale-95 focus:outline-none',
|
||||
'disabled:cursor-not-allowed disabled:scale-100',
|
||||
|
||||
// Стили ТОЛЬКО для отключенного состояния (но не для загрузки)
|
||||
(props.disabled && !loading) && 'grayscale opacity-50 shadow-none bg-slate-100/70 border-slate-300/80',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<Power className={cn(
|
||||
"h-20 w-20",
|
||||
!props.disabled && "active:scale-90 transition-transform duration-300"
|
||||
)} />
|
||||
</button>
|
||||
|
||||
{loading && (
|
||||
<div className="absolute inset-0 flex items-center justify-center z-20">
|
||||
<div className={cn(
|
||||
'h-full w-full animate-spin rounded-full border-4',
|
||||
'border-transparent',
|
||||
checked ? 'border-t-green-500' : 'border-t-red-500',
|
||||
'blur-xs'
|
||||
)} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import { UpdateButton } from "@/components/layout/update-button";
|
||||
import React from "react";
|
||||
import { SheetClose } from '@/components/ui/sheet';
|
||||
import logo from "@/assets/image/logo.png"
|
||||
|
||||
const menuItems = [
|
||||
{ title: 'Home', url: '/home', icon: Home },
|
||||
@@ -48,7 +49,7 @@ export function AppSidebar() {
|
||||
)}
|
||||
>
|
||||
<img
|
||||
src="./assets/image/logo.png"
|
||||
src={logo}
|
||||
alt="logo"
|
||||
className="h-6 w-6 flex-shrink-0"
|
||||
/>
|
||||
|
||||
@@ -1,47 +1,52 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useSetThemeMode, useThemeMode } from "@/services/states";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import { getCurrentWebviewWindow, WebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import { Theme } from "@tauri-apps/api/window";
|
||||
|
||||
export const useCustomTheme = () => {
|
||||
const appWindow = useMemo(() => getCurrentWebviewWindow(), []);
|
||||
const appWindow: WebviewWindow = useMemo(() => getCurrentWebviewWindow(), []);
|
||||
const { verge } = useVerge();
|
||||
const { theme_mode } = verge ?? {};
|
||||
|
||||
const mode = useThemeMode();
|
||||
const setMode = useSetThemeMode();
|
||||
|
||||
const [systemTheme, setSystemTheme] = useState(
|
||||
() => window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setMode(
|
||||
theme_mode === "light" || theme_mode === "dark" ? theme_mode : "system",
|
||||
theme_mode === "light" || theme_mode === "dark" ? theme_mode : "system",
|
||||
);
|
||||
}, [theme_mode, setMode]);
|
||||
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (mode !== 'system') return;
|
||||
|
||||
const activeTheme =
|
||||
mode === "system"
|
||||
? window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light"
|
||||
: mode;
|
||||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const handleChange = (e: MediaQueryListEvent) => {
|
||||
setSystemTheme(e.matches ? "dark" : "light");
|
||||
};
|
||||
|
||||
root.classList.remove("light", "dark");
|
||||
root.classList.add(activeTheme);
|
||||
appWindow.setTheme(activeTheme as Theme).catch(console.error);
|
||||
}, [mode, appWindow]);
|
||||
mediaQuery.addEventListener('change', handleChange);
|
||||
return () => mediaQuery.removeEventListener('change', handleChange);
|
||||
}, [mode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (theme_mode !== "system") return;
|
||||
const unlistenPromise = appWindow.onThemeChanged(({ payload }) => {
|
||||
setMode(payload);
|
||||
});
|
||||
return () => {
|
||||
unlistenPromise.then((f) => f());
|
||||
};
|
||||
}, [theme_mode, appWindow, setMode]);
|
||||
const root = document.documentElement;
|
||||
const activeTheme = mode === "system" ? systemTheme : mode;
|
||||
root.classList.remove("light", "dark");
|
||||
root.classList.add(activeTheme);
|
||||
|
||||
if (theme_mode === "system") {
|
||||
appWindow.setTheme(null).catch(console.error);
|
||||
} else {
|
||||
appWindow.setTheme(activeTheme as Theme).catch(console.error);
|
||||
}
|
||||
|
||||
}, [mode, systemTheme, appWindow, theme_mode]);
|
||||
|
||||
return {};
|
||||
};
|
||||
};
|
||||
@@ -296,7 +296,7 @@ export const ProfileViewer = forwardRef<ProfileViewerRef, Props>(
|
||||
</Button>
|
||||
{!isUrlValid && importUrl && (
|
||||
<p className="text-sm text-destructive px-1">
|
||||
{t("Please enter a valid URL")}
|
||||
{t("Invalid Profile URL")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -26,8 +26,8 @@ import { showNotice } from "@/services/noticeService";
|
||||
|
||||
// Константы и интерфейсы
|
||||
const VALID_CORE = [
|
||||
{ name: "Mihomo", core: "verge-mihomo", chip: "Release Version" },
|
||||
{ name: "Mihomo Alpha", core: "verge-mihomo-alpha", chip: "Alpha Version" },
|
||||
{ name: "Mihomo", core: "koala-mihomo", chip: "Release Version" },
|
||||
{ name: "Mihomo Alpha", core: "koala-mihomo-alpha", chip: "Alpha Version" },
|
||||
];
|
||||
|
||||
export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
@@ -44,7 +44,7 @@ export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
const { clash_core = "verge-mihomo" } = verge ?? {};
|
||||
const { clash_core = "koala-mihomo" } = verge ?? {};
|
||||
|
||||
const onCoreChange = useLockFn(async (core: string) => {
|
||||
if (core === clash_core) return;
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import { Loader2 } from "lucide-react";
|
||||
|
||||
const OS = getSystem();
|
||||
|
||||
@@ -69,6 +70,9 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||
|
||||
const [localConfig, setLocalConfig] = useState<Partial<IVergeConfig>>({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [commonIcon, setCommonIcon] = useState("");
|
||||
const [sysproxyIcon, setSysproxyIcon] = useState("");
|
||||
@@ -96,28 +100,26 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) initIconPath();
|
||||
}, [open, initIconPath]);
|
||||
if (open) {
|
||||
setLocalConfig(verge ?? {});
|
||||
initIconPath();
|
||||
}
|
||||
}, [open, verge, initIconPath]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => setOpen(true),
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
||||
const onError = (err: any) => {
|
||||
showNotice("error", err.message || err.toString());
|
||||
};
|
||||
const onChangeData = (patch: Partial<IVergeConfig>) => {
|
||||
mutateVerge({ ...verge, ...patch }, false);
|
||||
const handleConfigChange = (patch: Partial<IVergeConfig>) => {
|
||||
setLocalConfig(prev => ({ ...prev, ...patch }));
|
||||
};
|
||||
|
||||
const handleIconChange = useLockFn(
|
||||
async (type: "common" | "sysproxy" | "tun") => {
|
||||
const key = `${type}_tray_icon` as keyof IVergeConfig;
|
||||
if (verge?.[key]) {
|
||||
onChangeData({ [key]: false });
|
||||
await patchVerge({ [key]: false });
|
||||
if (localConfig[key]) {
|
||||
handleConfigChange({ [key]: false });
|
||||
} else {
|
||||
const selected = await openDialog({
|
||||
directory: false,
|
||||
@@ -128,72 +130,94 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const path = Array.isArray(selected) ? selected[0] : selected;
|
||||
await copyIconFile(path, type);
|
||||
await initIconPath();
|
||||
onChangeData({ [key]: true });
|
||||
await patchVerge({ [key]: true });
|
||||
handleConfigChange({ [key]: true });
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const handleSave = useLockFn(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await patchVerge(localConfig);
|
||||
showNotice("success", t("Settings saved successfully"));
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
showNotice("error", err.message || err.toString());
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t("Layout Setting")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t("Layout Setting")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="py-4 space-y-1">
|
||||
<SettingRow label={t("Memory Usage")}>
|
||||
<GuardState
|
||||
value={verge?.enable_memory_usage ?? true}
|
||||
valueProps="checked"
|
||||
onCatch={onError}
|
||||
onFormat={onSwitchFormat}
|
||||
onChange={(e) => onChangeData({ enable_memory_usage: e })}
|
||||
onGuard={(e) => patchVerge({ enable_memory_usage: e })}
|
||||
>
|
||||
<Switch />
|
||||
</GuardState>
|
||||
</SettingRow>
|
||||
<div className="py-4 space-y-1">
|
||||
{OS === "macos" && (
|
||||
<>
|
||||
<SettingRow label={t("Tray Icon")}>
|
||||
<Select
|
||||
onValueChange={(value) => handleConfigChange({ tray_icon: value as any })}
|
||||
value={localConfig.tray_icon ?? "monochrome"}
|
||||
>
|
||||
<SelectTrigger className="w-40 h-8"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="monochrome">{t("Monochrome")}</SelectItem>
|
||||
<SelectItem value="colorful">{t("Colorful")}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow label={t("Proxy Group Icon")}>
|
||||
<GuardState
|
||||
value={verge?.enable_group_icon ?? true}
|
||||
valueProps="checked"
|
||||
onCatch={onError}
|
||||
onFormat={onSwitchFormat}
|
||||
onChange={(e) => onChangeData({ enable_group_icon: e })}
|
||||
onGuard={(e) => patchVerge({ enable_group_icon: e })}
|
||||
>
|
||||
<Switch />
|
||||
</GuardState>
|
||||
</SettingRow>
|
||||
<SettingRow label={t("Enable Tray Icon")}>
|
||||
<Switch
|
||||
checked={localConfig.enable_tray_icon ?? true}
|
||||
onCheckedChange={(checked) => handleConfigChange({ enable_tray_icon: checked })}
|
||||
/>
|
||||
</SettingRow>
|
||||
</>
|
||||
)}
|
||||
|
||||
<SettingRow
|
||||
label={t("Hover Jump Navigator")}
|
||||
extra={<TooltipIcon tooltip={t("Hover Jump Navigator Info")} />}
|
||||
>
|
||||
<GuardState
|
||||
value={verge?.enable_hover_jump_navigator ?? true}
|
||||
valueProps="checked"
|
||||
onCatch={onError}
|
||||
onFormat={onSwitchFormat}
|
||||
onChange={(e) => onChangeData({ enable_hover_jump_navigator: e })}
|
||||
onGuard={(e) => patchVerge({ enable_hover_jump_navigator: e })}
|
||||
>
|
||||
<Switch />
|
||||
</GuardState>
|
||||
</SettingRow>
|
||||
</div>
|
||||
<SettingRow label={t("Common Tray Icon")}>
|
||||
<Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("common")}>
|
||||
{localConfig.common_tray_icon && commonIcon && (
|
||||
<img src={convertFileSrc(commonIcon)} className="h-5 mr-2" alt="common tray icon" />
|
||||
)}
|
||||
{localConfig.common_tray_icon ? t("Clear") : t("Browse")}
|
||||
</Button>
|
||||
</SettingRow>
|
||||
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="outline">
|
||||
{t("Close")}
|
||||
<SettingRow label={t("System Proxy Tray Icon")}>
|
||||
<Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("sysproxy")}>
|
||||
{localConfig.sysproxy_tray_icon && sysproxyIcon && (
|
||||
<img src={convertFileSrc(sysproxyIcon)} className="h-5 mr-2" alt="system proxy tray icon" />
|
||||
)}
|
||||
{localConfig.sysproxy_tray_icon ? t("Clear") : t("Browse")}
|
||||
</Button>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow label={t("Tun Tray Icon")}>
|
||||
<Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("tun")}>
|
||||
{localConfig.tun_tray_icon && tunIcon && (
|
||||
<img src={convertFileSrc(tunIcon)} className="h-5 mr-2" alt="tun mode tray icon" />
|
||||
)}
|
||||
{localConfig.tun_tray_icon ? t("Clear") : t("Browse")}
|
||||
</Button>
|
||||
</SettingRow>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="outline">{t("Cancel")}</Button>
|
||||
</DialogClose>
|
||||
<Button type="button" onClick={handleSave} disabled={loading}>
|
||||
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
{t("Save")}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useRef, useState } from "react";
|
||||
import {useMemo, useRef, useState} from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { mutate } from "swr";
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {useProfiles} from "@/hooks/use-profiles";
|
||||
|
||||
const isWIN = getSystem() === "windows";
|
||||
interface Props {
|
||||
@@ -106,6 +107,12 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||
const { installServiceAndRestartCore } = useServiceInstaller();
|
||||
|
||||
const { profiles } = useProfiles();
|
||||
const hasProfiles = useMemo(() => {
|
||||
const items = profiles?.items ?? [];
|
||||
return items.some(p => p.type === 'local' || p.type === 'remote');
|
||||
}, [profiles]);
|
||||
|
||||
const {
|
||||
actualState: systemProxyActualState,
|
||||
indicator: systemProxyIndicator,
|
||||
@@ -261,7 +268,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
}}
|
||||
onCatch={onError}
|
||||
>
|
||||
<Switch disabled={!isTunAvailable} />
|
||||
<Switch disabled={!isTunAvailable || !hasProfiles} />
|
||||
</GuardState>
|
||||
</SettingRow>
|
||||
|
||||
@@ -297,7 +304,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
}}
|
||||
onCatch={onError}
|
||||
>
|
||||
<Switch />
|
||||
<Switch disabled={!hasProfiles} />
|
||||
</GuardState>
|
||||
</SettingRow>
|
||||
|
||||
|
||||
@@ -188,24 +188,22 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
|
||||
{OS !== "linux" && (
|
||||
<SettingRow
|
||||
label={
|
||||
<LabelWithIcon
|
||||
icon={MousePointerClick}
|
||||
text={t("Tray Click Event")}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<LabelWithIcon
|
||||
icon={MousePointerClick}
|
||||
text={t("Tray Click Event")}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<GuardState
|
||||
value={tray_event ?? "main_window"}
|
||||
onCatch={onError}
|
||||
onFormat={(v) => v}
|
||||
onChange={(e) => onChangeData({ tray_event: e })}
|
||||
onGuard={(e) => patchVerge({ tray_event: e })}
|
||||
value={tray_event ?? "main_window"}
|
||||
onCatch={onError}
|
||||
onFormat={(v) => v}
|
||||
onChange={(e) => onChangeData({ tray_event: e })}
|
||||
onGuard={(e) => patchVerge({ tray_event: e })}
|
||||
onChangeProps="onValueChange"
|
||||
>
|
||||
<Select
|
||||
onValueChange={(value) => onChangeData({ tray_event: value })}
|
||||
value={tray_event}
|
||||
>
|
||||
<Select>
|
||||
<SelectTrigger className="w-40 h-8">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@variant dark .dark &;
|
||||
@theme {
|
||||
--tailwind-darkMode: 'class';
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
@@ -129,3 +131,21 @@
|
||||
svg {
|
||||
stroke-width: var(--icon-stroke-width, 2);
|
||||
}
|
||||
|
||||
|
||||
@keyframes gradient-wave {
|
||||
0% {
|
||||
background-position: -200% center;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% center;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-gradient-wave {
|
||||
background-size: 200% auto;
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
color: transparent;
|
||||
animation: gradient-wave 2s linear infinite;
|
||||
}
|
||||
|
||||
@@ -675,5 +675,8 @@
|
||||
"Template": "Template",
|
||||
"Select a template...": "Select a template...",
|
||||
"Default Template": "Ru-bundle template",
|
||||
"Template without RU Rules": "Without-ru template"
|
||||
"Template without RU Rules": "Without-ru template",
|
||||
"Stopping Core...": "Stopping Core...",
|
||||
"Uninstalling Service...": "Uninstalling Service...",
|
||||
"Try running core as Sidecar...": "Try running core as Sidecar..."
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@
|
||||
"Success Color": "Цвет успеха",
|
||||
"Font Family": "Семейство шрифтов",
|
||||
"CSS Injection": "Внедрение CSS",
|
||||
"Layout Setting": "Настройки раскладки",
|
||||
"Layout Setting": "Настройки макета",
|
||||
"Traffic Graph": "График трафика",
|
||||
"Memory Usage": "Использование памяти",
|
||||
"Memory Cleanup": "Нажмите, чтобы очистить память",
|
||||
@@ -401,8 +401,8 @@
|
||||
"Proxy Daemon Duration Cannot be Less than 1 Second": "Продолжительность работы прокси-демона не может быть меньше 1 секунды",
|
||||
"Invalid Bypass Format": "Неверный формат обхода",
|
||||
"Waiting for service to be ready...": "Ожидание готовности сервиса...",
|
||||
"Service not ready, retrying attempt {count}/{total}...": "Служба не готова, повторная попытка {count}/{total}...",
|
||||
"Failed to check service status, retrying attempt {count}/{total}...": "Не удалось проверить состояние службы, повторная попытка {count}/{total}...",
|
||||
"Service not ready, retrying attempt {count}/{total}...": "Служба не готова, повторная попытка {{count}}/{{total}}...",
|
||||
"Failed to check service status, retrying attempt {count}/{total}...": "Не удалось проверить состояние службы, повторная попытка {{count}}/{{total}}...",
|
||||
"Service did not become ready after attempts. Proceeding with core restart.": "Служба не была готова после нескольких попыток. Продолжаем перезапуск ядра.",
|
||||
"Restarting Core...": "Перезапуск ядра...",
|
||||
"Service was ready, but core restart might have issues or service became unavailable. Please check.": "Служба была готова, но при перезапуске ядра могли возникнуть проблемы или служба стала недоступна. Пожалуйста, проверьте.",
|
||||
@@ -627,7 +627,7 @@
|
||||
"DashboardToggledTitle": "Панель управления переключена",
|
||||
"DashboardToggledBody": "Видимость панели инструментов переключена с помощью горячей клавиши",
|
||||
"ClashModeChangedTitle": "Режим Clash изменен",
|
||||
"ClashModeChangedBody": "Переключено в режим {mode}",
|
||||
"ClashModeChangedBody": "Переключено в режим {{mode}}",
|
||||
"SystemProxyToggledTitle": "Системный прокси переключен",
|
||||
"SystemProxyToggledBody": "Состояние системного прокси-сервера переключена с помощью горячей клавиши",
|
||||
"TunModeToggledTitle": "Режим TUN переключен",
|
||||
@@ -638,7 +638,7 @@
|
||||
"AppQuitBody": "Приложение закрыто с помощью горячей клавиши",
|
||||
"AppHiddenTitle": "Приложение скрыто",
|
||||
"AppHiddenBody": "Окно приложения скрыто с помощью горячей клавиши",
|
||||
"Invalid Profile URL": "Неверный URL-адрес профиля. Введите URL-адрес, начинающийся с http:// или https://.",
|
||||
"Invalid Profile URL": "Неверный URL-адрес профиля. Введите URL-адрес, начинающийся с http:// или https://",
|
||||
"Saved Successfully": "Успешно сохранено",
|
||||
"Connected": "Подключено",
|
||||
"Disconnected": "Отключено",
|
||||
@@ -675,5 +675,8 @@
|
||||
"Template": "Шаблон",
|
||||
"Select a template...": "Выберите шаблон...",
|
||||
"Default Template": "Шаблон ru-bundle",
|
||||
"Template without RU Rules": "Шаблон without-ru"
|
||||
"Template without RU Rules": "Шаблон without-ru",
|
||||
"Stopping Core...": "Остановка ядра...",
|
||||
"Uninstalling Service...": "Удаление сервиса...",
|
||||
"Try running core as Sidecar...": "Попытка запустить ядро как Sidecar..."
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useClashInfo } from "@/hooks/use-clash";
|
||||
import { initGlobalLogService } from "@/services/global-log-service";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import { NoticeManager } from "@/components/base/NoticeManager";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { SidebarProvider, useSidebar } from "@/components/ui/sidebar";
|
||||
import { AppSidebar } from "@/components/layout/sidebar";
|
||||
import { useZoomControls } from "@/hooks/useZoomControls";
|
||||
@@ -472,9 +472,9 @@ const Layout = () => {
|
||||
|
||||
return (
|
||||
<SWRConfig value={{ errorRetryCount: 3 }}>
|
||||
<NoticeManager />
|
||||
<SidebarProvider defaultOpen={false}>
|
||||
<AppLayout />
|
||||
<Toaster />
|
||||
</SidebarProvider>
|
||||
</SWRConfig>
|
||||
);
|
||||
|
||||
@@ -39,6 +39,9 @@ import { updateProfile } from "@/services/cmds";
|
||||
import { SidebarTrigger } from "@/components/ui/sidebar";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
import { useAppData } from "@/providers/app-data-provider";
|
||||
import { PowerButton } from "@/components/home/power-button";
|
||||
import { cn } from "@root/lib/utils";
|
||||
import map from "../assets/image/map.svg";
|
||||
|
||||
const MinimalHomePage: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -146,7 +149,7 @@ const MinimalHomePage: React.FC = () => {
|
||||
try {
|
||||
await updateProfile(currentProfile.uid);
|
||||
toast.success(t("Profile Updated Successfully"));
|
||||
mutateProfiles(); // Обновляем данные в UI
|
||||
mutateProfiles();
|
||||
} catch (err: any) {
|
||||
toast.error(t("Failed to update profile"), { description: err.message });
|
||||
} finally {
|
||||
@@ -154,8 +157,48 @@ const MinimalHomePage: React.FC = () => {
|
||||
}
|
||||
});
|
||||
|
||||
const statusInfo = useMemo(() => {
|
||||
if (isToggling) {
|
||||
return {
|
||||
text: isProxyEnabled ? t('Disconnecting...') : t('Connecting...'),
|
||||
color: isProxyEnabled ? '#f59e0b' : '#84cc16',
|
||||
isAnimating: true,
|
||||
};
|
||||
}
|
||||
if (isProxyEnabled) {
|
||||
return {
|
||||
text: t('Connected'),
|
||||
color: '#22c55e',
|
||||
isAnimating: false,
|
||||
};
|
||||
}
|
||||
return {
|
||||
text: t('Disconnected'),
|
||||
color: '#ef4444',
|
||||
isAnimating: false,
|
||||
};
|
||||
}, [isToggling, isProxyEnabled, t]);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<div className="absolute inset-0 opacity-20 pointer-events-none z-0 [transform:translateZ(0)]">
|
||||
<img
|
||||
src={map}
|
||||
alt="World map"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isProxyEnabled && (
|
||||
<div
|
||||
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-[500px] w-[500px] rounded-full pointer-events-none z-0 transition-opacity duration-500"
|
||||
style={{
|
||||
background: 'radial-gradient(circle, rgba(34,197,94,0.3) 0%, transparent 70%)',
|
||||
filter: 'blur(100px)',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<header className="flex-shrink-0 p-5 grid grid-cols-3 items-center z-10">
|
||||
<div className="flex justify-start">
|
||||
<SidebarTrigger />
|
||||
@@ -242,15 +285,18 @@ const MinimalHomePage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="relative text-center">
|
||||
<h1
|
||||
className="text-4xl mb-2 font-semibold"
|
||||
style={{ color: isProxyEnabled ? "#22c55e" : "#ef4444" }}
|
||||
>
|
||||
{isProxyEnabled ? t("Connected") : t("Disconnected")}
|
||||
</h1>
|
||||
<div className="relative text-center">
|
||||
<h1
|
||||
className={cn(
|
||||
"text-4xl mb-2 font-semibold transition-colors duration-300",
|
||||
statusInfo.isAnimating && "animate-pulse"
|
||||
)}
|
||||
style={{ color: statusInfo.color }}
|
||||
>
|
||||
{statusInfo.text}
|
||||
</h1>
|
||||
{isProxyEnabled && (
|
||||
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-48 flex justify-center items-center text-sm text-muted-foreground gap-6">
|
||||
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-52 flex justify-center items-center text-sm text-muted-foreground gap-6">
|
||||
<div className="flex items-center gap-1">
|
||||
<ArrowDown className="h-4 w-4 text-green-500" />
|
||||
{parseTraffic(connections.downloadTotal)}
|
||||
@@ -261,23 +307,18 @@ const MinimalHomePage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="h-6 text-sm text-muted-foreground transition-opacity duration-300">
|
||||
{isToggling &&
|
||||
(isProxyEnabled ? t("Disconnecting...") : t("Connecting..."))}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="scale-[7] my-16">
|
||||
<Switch
|
||||
disabled={showTunAlert || isToggling || profileItems.length === 0}
|
||||
checked={!!isProxyEnabled}
|
||||
onCheckedChange={handleToggleProxy}
|
||||
aria-label={t("Toggle Proxy")}
|
||||
<div className="relative -translate-y-6">
|
||||
<PowerButton
|
||||
loading={isToggling}
|
||||
checked={!!isProxyEnabled}
|
||||
onClick={handleToggleProxy}
|
||||
disabled={showTunAlert || isToggling || profileItems.length === 0}
|
||||
aria-label={t("Toggle Proxy")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
{showTunAlert && (
|
||||
<div className="w-full max-w-sm">
|
||||
<Alert
|
||||
@@ -303,7 +344,7 @@ const MinimalHomePage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="w-full mt-4 flex justify-center">
|
||||
<div className="w-full max-w-sm mt-4 flex justify-center">
|
||||
{profileItems.length > 0 ? (
|
||||
<ProxySelectors />
|
||||
) : (
|
||||
|
||||
@@ -1,81 +1,25 @@
|
||||
import { ReactNode } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export interface NoticeItem {
|
||||
id: number;
|
||||
type: "success" | "error" | "info";
|
||||
message: ReactNode;
|
||||
duration: number;
|
||||
timerId?: ReturnType<typeof setTimeout>;
|
||||
}
|
||||
type NoticeType = 'success' | 'error' | 'info' | 'warning';
|
||||
|
||||
type Listener = (notices: NoticeItem[]) => void;
|
||||
export const showNotice = (type: NoticeType, message: string, duration?: number) => {
|
||||
const options = duration ? { duration } : {};
|
||||
|
||||
let nextId = 0;
|
||||
let notices: NoticeItem[] = [];
|
||||
const listeners: Set<Listener> = new Set();
|
||||
|
||||
function notifyListeners() {
|
||||
listeners.forEach((listener) => listener([...notices])); // Pass a copy
|
||||
}
|
||||
|
||||
// Shows a notification.
|
||||
|
||||
export function showNotice(
|
||||
type: "success" | "error" | "info",
|
||||
message: ReactNode,
|
||||
duration?: number,
|
||||
): number {
|
||||
const id = nextId++;
|
||||
const effectiveDuration =
|
||||
duration ?? (type === "error" ? 8000 : type === "info" ? 5000 : 3000); // Longer defaults
|
||||
|
||||
const newNotice: NoticeItem = {
|
||||
id,
|
||||
type,
|
||||
message,
|
||||
duration: effectiveDuration,
|
||||
};
|
||||
|
||||
// Auto-hide timer (only if duration is not null/0)
|
||||
if (effectiveDuration > 0) {
|
||||
newNotice.timerId = setTimeout(() => {
|
||||
hideNotice(id);
|
||||
}, effectiveDuration);
|
||||
switch (type) {
|
||||
case 'success':
|
||||
toast.success(message, options);
|
||||
break;
|
||||
case 'error':
|
||||
toast.error(message, options);
|
||||
break;
|
||||
case 'info':
|
||||
toast.info(message, options);
|
||||
break;
|
||||
case 'warning':
|
||||
toast.warning(message, options);
|
||||
break;
|
||||
default:
|
||||
toast(message, options);
|
||||
break;
|
||||
}
|
||||
|
||||
notices = [...notices, newNotice];
|
||||
notifyListeners();
|
||||
return id;
|
||||
}
|
||||
|
||||
// Hides a specific notification by its ID.
|
||||
|
||||
export function hideNotice(id: number) {
|
||||
const notice = notices.find((n) => n.id === id);
|
||||
if (notice?.timerId) {
|
||||
clearTimeout(notice.timerId); // Clear timeout if manually closed
|
||||
}
|
||||
notices = notices.filter((n) => n.id !== id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Subscribes a listener function to notice state changes.
|
||||
|
||||
export function subscribeNotices(listener: () => void) {
|
||||
listeners.add(listener);
|
||||
return () => {
|
||||
listeners.delete(listener);
|
||||
};
|
||||
}
|
||||
export function getSnapshotNotices() {
|
||||
return notices;
|
||||
}
|
||||
|
||||
// Function to clear all notices at once
|
||||
export function clearAllNotices() {
|
||||
notices.forEach((n) => {
|
||||
if (n.timerId) clearTimeout(n.timerId);
|
||||
});
|
||||
notices = [];
|
||||
notifyListeners();
|
||||
}
|
||||
};
|
||||