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>
|
<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**
|
> :warning: **Warning**
|
||||||
If you get a notification that the application is corrupted when you run it on macOS, run this command:<br>
|
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
|
### 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>
|
<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 i
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
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
|
- name: Tauri build
|
||||||
id: build
|
id: build
|
||||||
uses: tauri-apps/tauri-action@v0
|
uses: tauri-apps/tauri-action@v0
|
||||||
@@ -186,6 +191,12 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
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:
|
with:
|
||||||
tauriScript: pnpm
|
tauriScript: pnpm
|
||||||
args: --target ${{ matrix.target }}
|
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/rpm/*.rpm
|
||||||
src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
|
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/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:
|
release-for-linux-arm:
|
||||||
name: Release Build 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."
|
UPDATE_LOGS="More new features are now supported. Check for detailed changelog soon."
|
||||||
else
|
else
|
||||||
echo "Using found update logs"
|
echo "Using found update logs"
|
||||||
|
UPDATE_LOGS=$(echo "$UPDATE_LOGS" | sed 's/^## \(v.*\)/\*\1\*/')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat > release.txt << EOF
|
cat > release.txt << EOF
|
||||||
@@ -580,6 +594,7 @@ jobs:
|
|||||||
to: ${{ secrets.TELEGRAM_TO_CHANNEL }}
|
to: ${{ secrets.TELEGRAM_TO_CHANNEL }}
|
||||||
token: ${{ secrets.TELEGRAM_TOKEN }}
|
token: ${{ secrets.TELEGRAM_TOKEN }}
|
||||||
message_file: release.txt
|
message_file: release.txt
|
||||||
|
format: markdown
|
||||||
|
|
||||||
- name: notify to group
|
- name: notify to group
|
||||||
uses: appleboy/telegram-action@master
|
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
|
## v0.2.4
|
||||||
|
|
||||||
- added auto-scaling and scaling via key combination
|
- added auto-scaling and scaling via key combination
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "clash-verge",
|
"name": "koala-clash",
|
||||||
"version": "0.2.3",
|
"version": "0.2.5",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev",
|
"dev": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev",
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ async function resolvePortable() {
|
|||||||
|
|
||||||
const zip = new AdmZip();
|
const zip = new AdmZip();
|
||||||
|
|
||||||
zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
|
zip.addLocalFile(path.join(releaseDir, "Koala Clash.exe"));
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe"));
|
zip.addLocalFile(path.join(releaseDir, "koala-mihomo.exe"));
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe"));
|
zip.addLocalFile(path.join(releaseDir, "koala-mihomo-alpha.exe"));
|
||||||
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
||||||
zip.addLocalFolder(
|
zip.addLocalFolder(
|
||||||
path.join(
|
path.join(
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ async function resolvePortable() {
|
|||||||
}
|
}
|
||||||
const zip = new AdmZip();
|
const zip = new AdmZip();
|
||||||
|
|
||||||
zip.addLocalFile(path.join(releaseDir, "clash-verge.exe"));
|
zip.addLocalFile(path.join(releaseDir, "koala-clash.exe"));
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe"));
|
zip.addLocalFile(path.join(releaseDir, "koala-mihomo.exe"));
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe"));
|
zip.addLocalFile(path.join(releaseDir, "koala-mihomo-alpha.exe"));
|
||||||
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
||||||
zip.addLocalFolder(configDir, ".config");
|
zip.addLocalFolder(configDir, ".config");
|
||||||
|
|
||||||
|
|||||||
@@ -175,8 +175,8 @@ function clashMetaAlpha() {
|
|||||||
const zipFile = `${name}-${META_ALPHA_VERSION}.${urlExt}`;
|
const zipFile = `${name}-${META_ALPHA_VERSION}.${urlExt}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "verge-mihomo-alpha",
|
name: "koala-mihomo-alpha",
|
||||||
targetFile: `verge-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
targetFile: `koala-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||||
exeFile,
|
exeFile,
|
||||||
zipFile,
|
zipFile,
|
||||||
downloadURL,
|
downloadURL,
|
||||||
@@ -192,8 +192,8 @@ function clashMeta() {
|
|||||||
const zipFile = `${name}-${META_VERSION}.${urlExt}`;
|
const zipFile = `${name}-${META_VERSION}.${urlExt}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "verge-mihomo",
|
name: "koala-mihomo",
|
||||||
targetFile: `verge-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
targetFile: `koala-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||||
exeFile,
|
exeFile,
|
||||||
zipFile,
|
zipFile,
|
||||||
downloadURL,
|
downloadURL,
|
||||||
@@ -381,7 +381,7 @@ const resolvePlugin = async () => {
|
|||||||
// service chmod
|
// service chmod
|
||||||
const resolveServicePermission = async () => {
|
const resolveServicePermission = async () => {
|
||||||
const serviceExecutables = [
|
const serviceExecutables = [
|
||||||
"clash-verge-service*",
|
"koala-clash-service*",
|
||||||
"install-service*",
|
"install-service*",
|
||||||
"uninstall-service*",
|
"uninstall-service*",
|
||||||
];
|
];
|
||||||
@@ -429,14 +429,14 @@ async function resolveLocales() {
|
|||||||
/**
|
/**
|
||||||
* main
|
* 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 = () => {
|
const resolveService = () => {
|
||||||
let ext = platform === "win32" ? ".exe" : "";
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||||
resolveResource({
|
resolveResource({
|
||||||
file: "clash-verge-service" + suffix + ext,
|
file: "koala-clash-service" + suffix + ext,
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
downloadURL: `${SERVICE_URL}/koala-clash-service${ext}`,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -489,13 +489,13 @@ const resolveWinSysproxy = () =>
|
|||||||
const tasks = [
|
const tasks = [
|
||||||
// { name: "clash", func: resolveClash, retry: 5 },
|
// { name: "clash", func: resolveClash, retry: 5 },
|
||||||
{
|
{
|
||||||
name: "verge-mihomo-alpha",
|
name: "koala-mihomo-alpha",
|
||||||
func: () =>
|
func: () =>
|
||||||
getLatestAlphaVersion().then(() => resolveSidecar(clashMetaAlpha())),
|
getLatestAlphaVersion().then(() => resolveSidecar(clashMetaAlpha())),
|
||||||
retry: 5,
|
retry: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "verge-mihomo",
|
name: "koala-mihomo",
|
||||||
func: () =>
|
func: () =>
|
||||||
getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())),
|
getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())),
|
||||||
retry: 5,
|
retry: 5,
|
||||||
|
|||||||
192
src-tauri/Cargo.lock
generated
@@ -1059,80 +1059,6 @@ dependencies = [
|
|||||||
"inout",
|
"inout",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clash-verge"
|
|
||||||
version = "0.2.3"
|
|
||||||
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]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "5.4.0"
|
version = "5.4.0"
|
||||||
@@ -3622,6 +3548,81 @@ dependencies = [
|
|||||||
"unicode-segmentation",
|
"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]]
|
[[package]]
|
||||||
name = "kuchikiki"
|
name = "kuchikiki"
|
||||||
version = "0.8.8-speedreader"
|
version = "0.8.8-speedreader"
|
||||||
@@ -3887,11 +3888,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "machine-uid"
|
name = "machine-uid"
|
||||||
version = "0.2.0"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f1595709b0a7386bcd56ba34d250d626e5503917d05d32cdccddcd68603e212"
|
checksum = "0c4506fa0abb0a2ea93f5862f55973da0a662d2ad0e98f337a1c5aac657f0892"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winreg 0.6.2",
|
"libc",
|
||||||
|
"winreg 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6846,9 +6848,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.35.2"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e"
|
checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -7294,6 +7296,21 @@ dependencies = [
|
|||||||
"tokio",
|
"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]]
|
[[package]]
|
||||||
name = "tauri-plugin-updater"
|
name = "tauri-plugin-updater"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
@@ -9323,15 +9340,6 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winreg"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@@ -9568,9 +9576,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus"
|
name = "zbus"
|
||||||
version = "5.7.1"
|
version = "5.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3a7c7cee313d044fca3f48fa782cb750c79e4ca76ba7bc7718cd4024cdf6f68"
|
checksum = "4bb4f9a464286d42851d18a605f7193b8febaf5b0919d71c6399b7b26e5b0aad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-broadcast",
|
"async-broadcast",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
@@ -9602,9 +9610,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus_macros"
|
name = "zbus_macros"
|
||||||
version = "5.7.1"
|
version = "5.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a17e7e5eec1550f747e71a058df81a9a83813ba0f6a95f39c4e218bdc7ba366a"
|
checksum = "ef9859f68ee0c4ee2e8cde84737c78e3f4c54f946f2a38645d0d4c7a95327659"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 3.3.0",
|
"proc-macro-crate 3.3.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "clash-verge"
|
name = "koala-clash"
|
||||||
version = "0.2.3"
|
version = "0.2.5"
|
||||||
description = "clash verge"
|
description = "koala clash"
|
||||||
authors = ["zzzgydi", "wonfen", "MystiPanda", "coolcoala"]
|
authors = ["zzzgydi", "wonfen", "MystiPanda", "coolcoala"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
repository = "https://github.com/coolcoala/clash-verge-rev-lite.git"
|
repository = "https://github.com/coolcoala/clash-verge-rev-lite.git"
|
||||||
default-run = "clash-verge"
|
default-run = "koala-clash"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
[package.metadata.bundle]
|
[package.metadata.bundle]
|
||||||
identifier = "io.github.clash-verge-rev.clash-verge-rev"
|
identifier = "io.github.koala-clash"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "2.3.0", features = [] }
|
tauri-build = { version = "2.3.0", features = [] }
|
||||||
@@ -18,7 +18,7 @@ tauri-build = { version = "2.3.0", features = [] }
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
url = "2.5.4"
|
url = "2.5.4"
|
||||||
os_info = "3.0"
|
os_info = "3.0"
|
||||||
machine-uid = "0.2"
|
machine-uid = "0.5.3"
|
||||||
warp = "0.3.7"
|
warp = "0.3.7"
|
||||||
anyhow = "1.0.98"
|
anyhow = "1.0.98"
|
||||||
dirs = "6.0"
|
dirs = "6.0"
|
||||||
@@ -28,7 +28,7 @@ dunce = "1.0.5"
|
|||||||
log4rs = "1.3.0"
|
log4rs = "1.3.0"
|
||||||
nanoid = "0.4"
|
nanoid = "0.4"
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
sysinfo = "0.35.2"
|
sysinfo = "0.36.1"
|
||||||
boa_engine = "0.20.0"
|
boa_engine = "0.20.0"
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
serde_yaml = "0.9.34-deprecated"
|
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]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
tauri-plugin-autostart = "2.5.0"
|
tauri-plugin-autostart = "2.5.0"
|
||||||
tauri-plugin-global-shortcut = "2.3.0"
|
tauri-plugin-global-shortcut = "2.3.0"
|
||||||
|
tauri-plugin-single-instance = "2"
|
||||||
tauri-plugin-updater = "2.9.0"
|
tauri-plugin-updater = "2.9.0"
|
||||||
|
|
||||||
[features]
|
[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: 2.4 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: 2.0 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: 2.0 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 64 KiB |
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
chmod +x /usr/bin/install-service
|
chmod +x /usr/bin/install-service
|
||||||
chmod +x /usr/bin/uninstall-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/>
|
<false/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>io.github.clash-verge-rev.clash-verge-rev</string>
|
<string>io.github.koala-clash</string>
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.security.inherit</key>
|
<key>com.apple.security.inherit</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
|||||||
@@ -427,52 +427,52 @@ Function .onInit
|
|||||||
!endif
|
!endif
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
!macro CheckAllVergeProcesses
|
!macro CheckAllKoalaProcesses
|
||||||
; Check if clash-verge-service.exe is running
|
; Check if koala-clash-service.exe is running
|
||||||
!if "${INSTALLMODE}" == "currentUser"
|
!if "${INSTALLMODE}" == "currentUser"
|
||||||
nsis_tauri_utils::FindProcessCurrentUser "clash-verge-service.exe"
|
nsis_tauri_utils::FindProcessCurrentUser "koala-clash-service.exe"
|
||||||
!else
|
!else
|
||||||
nsis_tauri_utils::FindProcess "clash-verge-service.exe"
|
nsis_tauri_utils::FindProcess "koala-clash-service.exe"
|
||||||
!endif
|
!endif
|
||||||
Pop $R0
|
Pop $R0
|
||||||
${If} $R0 = 0
|
${If} $R0 = 0
|
||||||
DetailPrint "Kill clash-verge-service.exe..."
|
DetailPrint "Kill koala-clash-service.exe..."
|
||||||
!if "${INSTALLMODE}" == "currentUser"
|
!if "${INSTALLMODE}" == "currentUser"
|
||||||
nsis_tauri_utils::KillProcessCurrentUser "clash-verge-service.exe"
|
nsis_tauri_utils::KillProcessCurrentUser "koala-clash-service.exe"
|
||||||
!else
|
!else
|
||||||
nsis_tauri_utils::KillProcess "clash-verge-service.exe"
|
nsis_tauri_utils::KillProcess "koala-clash-service.exe"
|
||||||
!endif
|
!endif
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; Check if verge-mihomo-alpha.exe is running
|
; Check if koala-mihomo-alpha.exe is running
|
||||||
!if "${INSTALLMODE}" == "currentUser"
|
!if "${INSTALLMODE}" == "currentUser"
|
||||||
nsis_tauri_utils::FindProcessCurrentUser "verge-mihomo-alpha.exe"
|
nsis_tauri_utils::FindProcessCurrentUser "koala-mihomo-alpha.exe"
|
||||||
!else
|
!else
|
||||||
nsis_tauri_utils::FindProcess "verge-mihomo-alpha.exe"
|
nsis_tauri_utils::FindProcess "koala-mihomo-alpha.exe"
|
||||||
!endif
|
!endif
|
||||||
Pop $R0
|
Pop $R0
|
||||||
${If} $R0 = 0
|
${If} $R0 = 0
|
||||||
DetailPrint "Kill verge-mihomo-alpha.exe..."
|
DetailPrint "Kill koala-mihomo-alpha.exe..."
|
||||||
!if "${INSTALLMODE}" == "currentUser"
|
!if "${INSTALLMODE}" == "currentUser"
|
||||||
nsis_tauri_utils::KillProcessCurrentUser "verge-mihomo-alpha.exe"
|
nsis_tauri_utils::KillProcessCurrentUser "koala-mihomo-alpha.exe"
|
||||||
!else
|
!else
|
||||||
nsis_tauri_utils::KillProcess "verge-mihomo-alpha.exe"
|
nsis_tauri_utils::KillProcess "koala-mihomo-alpha.exe"
|
||||||
!endif
|
!endif
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; Check if verge-mihomo.exe is running
|
; Check if koala-mihomo.exe is running
|
||||||
!if "${INSTALLMODE}" == "currentUser"
|
!if "${INSTALLMODE}" == "currentUser"
|
||||||
nsis_tauri_utils::FindProcessCurrentUser "verge-mihomo.exe"
|
nsis_tauri_utils::FindProcessCurrentUser "koala-mihomo.exe"
|
||||||
!else
|
!else
|
||||||
nsis_tauri_utils::FindProcess "verge-mihomo.exe"
|
nsis_tauri_utils::FindProcess "koala-mihomo.exe"
|
||||||
!endif
|
!endif
|
||||||
Pop $R0
|
Pop $R0
|
||||||
${If} $R0 = 0
|
${If} $R0 = 0
|
||||||
DetailPrint "Kill verge-mihomo.exe..."
|
DetailPrint "Kill koala-mihomo.exe..."
|
||||||
!if "${INSTALLMODE}" == "currentUser"
|
!if "${INSTALLMODE}" == "currentUser"
|
||||||
nsis_tauri_utils::KillProcessCurrentUser "verge-mihomo.exe"
|
nsis_tauri_utils::KillProcessCurrentUser "koala-mihomo.exe"
|
||||||
!else
|
!else
|
||||||
nsis_tauri_utils::KillProcess "verge-mihomo.exe"
|
nsis_tauri_utils::KillProcess "koala-mihomo.exe"
|
||||||
!endif
|
!endif
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
@@ -509,22 +509,22 @@ FunctionEnd
|
|||||||
${EndIf}
|
${EndIf}
|
||||||
!macroend
|
!macroend
|
||||||
|
|
||||||
!macro StartVergeService
|
!macro StartKoalaService
|
||||||
; Check if the service exists
|
; Check if the service exists
|
||||||
SimpleSC::ExistsService "clash_verge_service"
|
SimpleSC::ExistsService "koala_clash_service"
|
||||||
Pop $0 ; 0:service exists;other: service not exists
|
Pop $0 ; 0:service exists;other: service not exists
|
||||||
; Service exists
|
; Service exists
|
||||||
${If} $0 == 0
|
${If} $0 == 0
|
||||||
Push $0
|
Push $0
|
||||||
; Check if the service is running
|
; 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 $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||||
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
||||||
${If} $0 == 0
|
${If} $0 == 0
|
||||||
Push $0
|
Push $0
|
||||||
${If} $1 == 0
|
${If} $1 == 0
|
||||||
DetailPrint "Restart Clash Verge Service..."
|
DetailPrint "Restart Koala Clash Service..."
|
||||||
SimpleSC::StartService "clash_verge_service" "" 30
|
SimpleSC::StartService "koala_clash_service" "" 30
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${ElseIf} $0 != 0
|
${ElseIf} $0 != 0
|
||||||
Push $0
|
Push $0
|
||||||
@@ -535,35 +535,35 @@ FunctionEnd
|
|||||||
${EndIf}
|
${EndIf}
|
||||||
!macroend
|
!macroend
|
||||||
|
|
||||||
!macro RemoveVergeService
|
!macro RemoveKoalaService
|
||||||
; Check if the service exists
|
; Check if the service exists
|
||||||
SimpleSC::ExistsService "clash_verge_service"
|
SimpleSC::ExistsService "koala_clash_service"
|
||||||
Pop $0 ; 0:service exists;other: service not exists
|
Pop $0 ; 0:service exists;other: service not exists
|
||||||
; Service exists
|
; Service exists
|
||||||
${If} $0 == 0
|
${If} $0 == 0
|
||||||
Push $0
|
Push $0
|
||||||
; Check if the service is running
|
; 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 $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||||
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
||||||
${If} $0 == 0
|
${If} $0 == 0
|
||||||
Push $0
|
Push $0
|
||||||
${If} $1 == 1
|
${If} $1 == 1
|
||||||
DetailPrint "Stop Clash Verge Service..."
|
DetailPrint "Stop Koala Clash Service..."
|
||||||
SimpleSC::StopService "clash_verge_service" 1 30
|
SimpleSC::StopService "koala_clash_service" 1 30
|
||||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||||
${If} $0 == 0
|
${If} $0 == 0
|
||||||
DetailPrint "Removing Clash Verge Service..."
|
DetailPrint "Removing Koala Clash Service..."
|
||||||
SimpleSC::RemoveService "clash_verge_service"
|
SimpleSC::RemoveService "koala_clash_service"
|
||||||
${ElseIf} $0 != 0
|
${ElseIf} $0 != 0
|
||||||
Push $0
|
Push $0
|
||||||
SimpleSC::GetErrorMessage
|
SimpleSC::GetErrorMessage
|
||||||
Pop $0
|
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}
|
${EndIf}
|
||||||
${ElseIf} $1 == 0
|
${ElseIf} $1 == 0
|
||||||
DetailPrint "Removing Clash Verge Service..."
|
DetailPrint "Removing Koala Clash Service..."
|
||||||
SimpleSC::RemoveService "clash_verge_service"
|
SimpleSC::RemoveService "koala_clash_service"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${ElseIf} $0 != 0
|
${ElseIf} $0 != 0
|
||||||
Push $0
|
Push $0
|
||||||
@@ -764,7 +764,7 @@ Section Install
|
|||||||
SetOutPath $INSTDIR
|
SetOutPath $INSTDIR
|
||||||
nsExec::Exec 'netsh int tcp res'
|
nsExec::Exec 'netsh int tcp res'
|
||||||
!insertmacro CheckIfAppIsRunning
|
!insertmacro CheckIfAppIsRunning
|
||||||
!insertmacro CheckAllVergeProcesses
|
!insertmacro CheckAllKoalaProcesses
|
||||||
|
|
||||||
; 清理自启动注册表项
|
; 清理自启动注册表项
|
||||||
DetailPrint "Cleaning auto-launch registry entries..."
|
DetailPrint "Cleaning auto-launch registry entries..."
|
||||||
@@ -772,32 +772,32 @@ Section Install
|
|||||||
StrCpy $R1 "Software\Microsoft\Windows\CurrentVersion\Run"
|
StrCpy $R1 "Software\Microsoft\Windows\CurrentVersion\Run"
|
||||||
|
|
||||||
SetRegView 64
|
SetRegView 64
|
||||||
; 清理旧版本的注册表项 (Clash Verge)
|
; 清理旧版本的注册表项 (Koala Clash)
|
||||||
ReadRegStr $R2 HKCU "$R1" "Clash Verge"
|
ReadRegStr $R2 HKCU "$R1" "Koala Clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKCU "$R1" "Clash Verge"
|
DeleteRegValue HKCU "$R1" "Koala Clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
ReadRegStr $R2 HKLM "$R1" "Clash Verge"
|
ReadRegStr $R2 HKLM "$R1" "Koala Clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKLM "$R1" "Clash Verge"
|
DeleteRegValue HKLM "$R1" "Koala Clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; 清理新版本的注册表项 (clash-verge)
|
; 清理新版本的注册表项 (koala-clash)
|
||||||
ReadRegStr $R2 HKCU "$R1" "clash-verge"
|
ReadRegStr $R2 HKCU "$R1" "koala-clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKCU "$R1" "clash-verge"
|
DeleteRegValue HKCU "$R1" "koala-clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
ReadRegStr $R2 HKLM "$R1" "clash-verge"
|
ReadRegStr $R2 HKLM "$R1" "koala-clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKLM "$R1" "clash-verge"
|
DeleteRegValue HKLM "$R1" "koala-clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; Delete old files before installation
|
; Delete old files before installation
|
||||||
; Delete clash-verge.desktop
|
; Delete koala-clash.desktop
|
||||||
IfFileExists "$INSTDIR\Clash Verge.exe" 0 +2
|
IfFileExists "$INSTDIR\Koala Clash.exe" 0 +2
|
||||||
Delete "$INSTDIR\Clash Verge.exe"
|
Delete "$INSTDIR\Koala Clash.exe"
|
||||||
|
|
||||||
; Copy main executable
|
; Copy main executable
|
||||||
File "${MAINBINARYSRCPATH}"
|
File "${MAINBINARYSRCPATH}"
|
||||||
@@ -815,7 +815,7 @@ Section Install
|
|||||||
File /a "/oname={{this}}" "{{@key}}"
|
File /a "/oname={{this}}" "{{@key}}"
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
!insertmacro StartVergeService
|
!insertmacro StartKoalaService
|
||||||
|
|
||||||
; Create uninstaller
|
; Create uninstaller
|
||||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
@@ -918,11 +918,11 @@ FunctionEnd
|
|||||||
Section Uninstall
|
Section Uninstall
|
||||||
;删除 window-state.json 文件
|
;删除 window-state.json 文件
|
||||||
SetShellVarContext current
|
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 CheckIfAppIsRunning
|
||||||
!insertmacro CheckAllVergeProcesses
|
!insertmacro CheckAllKoalaProcesses
|
||||||
!insertmacro RemoveVergeService
|
!insertmacro RemoveKoalaService
|
||||||
|
|
||||||
; 清理自启动注册表项
|
; 清理自启动注册表项
|
||||||
DetailPrint "Cleaning auto-launch registry entries..."
|
DetailPrint "Cleaning auto-launch registry entries..."
|
||||||
@@ -930,26 +930,26 @@ Section Uninstall
|
|||||||
StrCpy $R1 "Software\Microsoft\Windows\CurrentVersion\Run"
|
StrCpy $R1 "Software\Microsoft\Windows\CurrentVersion\Run"
|
||||||
|
|
||||||
SetRegView 64
|
SetRegView 64
|
||||||
; 清理旧版本的注册表项 (Clash Verge)
|
; 清理旧版本的注册表项 (Koala Clash)
|
||||||
ReadRegStr $R2 HKCU "$R1" "Clash Verge"
|
ReadRegStr $R2 HKCU "$R1" "Koala Clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKCU "$R1" "Clash Verge"
|
DeleteRegValue HKCU "$R1" "Koala Clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
ReadRegStr $R2 HKLM "$R1" "Clash Verge"
|
ReadRegStr $R2 HKLM "$R1" "Koala Clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKLM "$R1" "Clash Verge"
|
DeleteRegValue HKLM "$R1" "Koala Clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; 清理新版本的注册表项 (clash-verge)
|
; 清理新版本的注册表项 (koala-clash)
|
||||||
ReadRegStr $R2 HKCU "$R1" "clash-verge"
|
ReadRegStr $R2 HKCU "$R1" "koala-clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKCU "$R1" "clash-verge"
|
DeleteRegValue HKCU "$R1" "koala-clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
ReadRegStr $R2 HKLM "$R1" "clash-verge"
|
ReadRegStr $R2 HKLM "$R1" "koala-clash"
|
||||||
${If} $R2 != ""
|
${If} $R2 != ""
|
||||||
DeleteRegValue HKLM "$R1" "clash-verge"
|
DeleteRegValue HKLM "$R1" "koala-clash"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; Delete the app directory and its content from disk
|
; Delete the app directory and its content from disk
|
||||||
@@ -966,9 +966,9 @@ Section Uninstall
|
|||||||
Delete "$INSTDIR\\{{this}}"
|
Delete "$INSTDIR\\{{this}}"
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
; Delete clash-verge.desktop
|
; Delete koala-clash.desktop
|
||||||
IfFileExists "$INSTDIR\Clash Verge.exe" 0 +2
|
IfFileExists "$INSTDIR\Koala Clash.exe" 0 +2
|
||||||
Delete "$INSTDIR\Clash Verge.exe"
|
Delete "$INSTDIR\Koala Clash.exe"
|
||||||
|
|
||||||
; Delete uninstaller
|
; Delete uninstaller
|
||||||
Delete "$INSTDIR\uninstall.exe"
|
Delete "$INSTDIR\uninstall.exe"
|
||||||
@@ -982,20 +982,20 @@ Section Uninstall
|
|||||||
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
||||||
!insertmacro UnpinShortcut "$DESKTOP\${PRODUCTNAME}.lnk"
|
!insertmacro UnpinShortcut "$DESKTOP\${PRODUCTNAME}.lnk"
|
||||||
; 兼容旧名称快捷方式
|
; 兼容旧名称快捷方式
|
||||||
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\clash-verge.lnk"
|
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\koala-clash.lnk"
|
||||||
!insertmacro UnpinShortcut "$DESKTOP\clash-verge.lnk"
|
!insertmacro UnpinShortcut "$DESKTOP\koala-clash.lnk"
|
||||||
|
|
||||||
; Remove start menu shortcut
|
; Remove start menu shortcut
|
||||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
|
!insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
|
||||||
Delete "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
Delete "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk"
|
||||||
; 兼容旧名称快捷方式
|
; 兼容旧名称快捷方式
|
||||||
Delete "$SMPROGRAMS\$AppStartMenuFolder\clash-verge.lnk"
|
Delete "$SMPROGRAMS\$AppStartMenuFolder\koala-clash.lnk"
|
||||||
RMDir "$SMPROGRAMS\$AppStartMenuFolder"
|
RMDir "$SMPROGRAMS\$AppStartMenuFolder"
|
||||||
|
|
||||||
; Remove desktop shortcuts
|
; Remove desktop shortcuts
|
||||||
Delete "$DESKTOP\${PRODUCTNAME}.lnk"
|
Delete "$DESKTOP\${PRODUCTNAME}.lnk"
|
||||||
; 兼容旧名称快捷方式
|
; 兼容旧名称快捷方式
|
||||||
Delete "$DESKTOP\clash-verge.lnk"
|
Delete "$DESKTOP\koala-clash.lnk"
|
||||||
|
|
||||||
; Remove registry information for add/remove programs
|
; Remove registry information for add/remove programs
|
||||||
!if "${INSTALLMODE}" == "both"
|
!if "${INSTALLMODE}" == "both"
|
||||||
@@ -1017,7 +1017,7 @@ Section Uninstall
|
|||||||
|
|
||||||
;删除 window-state.json 文件
|
;删除 window-state.json 文件
|
||||||
SetShellVarContext current
|
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
|
${GetOptions} $CMDLINE "/P" $R0
|
||||||
IfErrors +2 0
|
IfErrors +2 0
|
||||||
|
|||||||
@@ -176,7 +176,34 @@ pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResu
|
|||||||
/// 删除配置文件
|
/// 删除配置文件
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn delete_profile(index: String) -> CmdResult {
|
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();
|
let _ = Config::profiles().latest().auto_cleanup();
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ impl IClashTemp {
|
|||||||
help::save_yaml(
|
help::save_yaml(
|
||||||
&dirs::clash_path()?,
|
&dirs::clash_path()?,
|
||||||
&self.0,
|
&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 std::path::PathBuf;
|
||||||
use tokio::time::{sleep, Duration};
|
use tokio::time::{sleep, Duration};
|
||||||
|
|
||||||
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
|
pub const RUNTIME_CONFIG: &str = "koala-clash.yaml";
|
||||||
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
|
pub const CHECK_CONFIG: &str = "koala-clash-check.yaml";
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
clash_config: Draft<Box<IClashTemp>>,
|
clash_config: Draft<Box<IClashTemp>>,
|
||||||
@@ -141,7 +141,7 @@ impl Config {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(anyhow!("failed to get runtime config"))?;
|
.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)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use crate::utils::{
|
|||||||
tmpl,
|
tmpl,
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
|
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::{fs, time::Duration};
|
use std::{fs, time::Duration};
|
||||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use super::Config;
|
use super::Config;
|
||||||
@@ -407,7 +407,8 @@ impl PrfItem {
|
|||||||
Some(value) => {
|
Some(value) => {
|
||||||
let str_value = value.to_str().unwrap_or("");
|
let str_value = value.to_str().unwrap_or("");
|
||||||
if let Some(b64_data) = str_value.strip_prefix("base64:") {
|
if let Some(b64_data) = str_value.strip_prefix("base64:") {
|
||||||
STANDARD.decode(b64_data)
|
STANDARD
|
||||||
|
.decode(b64_data)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|bytes| String::from_utf8(bytes).ok())
|
.and_then(|bytes| String::from_utf8(bytes).ok())
|
||||||
} else {
|
} else {
|
||||||
@@ -423,7 +424,7 @@ impl PrfItem {
|
|||||||
bail!(announce_msg.clone());
|
bail!(announce_msg.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let announce_url = match header.get("announce-url") {
|
let announce_url = match header.get("announce-url") {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let str_value = value.to_str().unwrap_or("");
|
let str_value = value.to_str().unwrap_or("");
|
||||||
@@ -436,7 +437,8 @@ impl PrfItem {
|
|||||||
Some(value) => {
|
Some(value) => {
|
||||||
let str_value = value.to_str().unwrap_or("");
|
let str_value = value.to_str().unwrap_or("");
|
||||||
if let Some(b64_data) = str_value.strip_prefix("base64:") {
|
if let Some(b64_data) = str_value.strip_prefix("base64:") {
|
||||||
STANDARD.decode(b64_data)
|
STANDARD
|
||||||
|
.decode(b64_data)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|bytes| String::from_utf8(bytes).ok())
|
.and_then(|bytes| String::from_utf8(bytes).ok())
|
||||||
} else {
|
} else {
|
||||||
@@ -448,7 +450,9 @@ impl PrfItem {
|
|||||||
|
|
||||||
let uid = help::get_uid("R");
|
let uid = help::get_uid("R");
|
||||||
let file = format!("{uid}.yaml");
|
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?;
|
let data = resp.text_with_charset("utf-8").await?;
|
||||||
|
|
||||||
// process the charset "UTF-8 with BOM"
|
// process the charset "UTF-8 with BOM"
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ impl IProfiles {
|
|||||||
help::save_yaml(
|
help::save_yaml(
|
||||||
&dirs::profiles_path()?,
|
&dirs::profiles_path()?,
|
||||||
self,
|
self,
|
||||||
Some("# Profiles Config for Clash Verge"),
|
Some("# Profiles Config for Koala Clash"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ pub struct IVergeTheme {
|
|||||||
|
|
||||||
impl IVerge {
|
impl IVerge {
|
||||||
/// 有效的clash核心名称
|
/// 有效的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值
|
/// 验证并修正配置文件中的clash_core值
|
||||||
pub fn validate_and_fix_config() -> Result<()> {
|
pub fn validate_and_fix_config() -> Result<()> {
|
||||||
@@ -257,10 +257,10 @@ impl IVerge {
|
|||||||
warn,
|
warn,
|
||||||
Type::Config,
|
Type::Config,
|
||||||
true,
|
true,
|
||||||
"启动时发现无效的clash_core配置: '{}', 将自动修正为 'verge-mihomo'",
|
"启动时发现无效的clash_core配置: '{}', 将自动修正为 'koala-mihomo'",
|
||||||
core
|
core
|
||||||
);
|
);
|
||||||
config.clash_core = Some("verge-mihomo".to_string());
|
config.clash_core = Some("koala-mihomo".to_string());
|
||||||
needs_fix = true;
|
needs_fix = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -268,16 +268,16 @@ impl IVerge {
|
|||||||
info,
|
info,
|
||||||
Type::Config,
|
Type::Config,
|
||||||
true,
|
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;
|
needs_fix = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修正后保存配置
|
// 修正后保存配置
|
||||||
if needs_fix {
|
if needs_fix {
|
||||||
logging!(info, Type::Config, true, "正在保存修正后的配置文件...");
|
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!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::Config,
|
Type::Config,
|
||||||
@@ -321,7 +321,7 @@ impl IVerge {
|
|||||||
pub fn get_valid_clash_core(&self) -> String {
|
pub fn get_valid_clash_core(&self) -> String {
|
||||||
self.clash_core
|
self.clash_core
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| "verge-mihomo".to_string())
|
.unwrap_or_else(|| "koala-mihomo".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_system_language() -> String {
|
fn get_system_language() -> String {
|
||||||
@@ -340,18 +340,15 @@ impl IVerge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
|
dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)).unwrap_or_else(|err| {
|
||||||
Ok(config) => config,
|
log::error!(target: "app", "{err}");
|
||||||
Err(err) => {
|
Self::template()
|
||||||
log::error!(target: "app", "{err}");
|
})
|
||||||
Self::template()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn template() -> Self {
|
pub fn template() -> Self {
|
||||||
Self {
|
Self {
|
||||||
clash_core: Some("verge-mihomo".into()),
|
clash_core: Some("koala-mihomo".into()),
|
||||||
language: Some(Self::get_system_language()),
|
language: Some(Self::get_system_language()),
|
||||||
theme_mode: Some("system".into()),
|
theme_mode: Some("system".into()),
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
@@ -415,7 +412,7 @@ impl IVerge {
|
|||||||
|
|
||||||
/// Save IVerge App Config
|
/// Save IVerge App Config
|
||||||
pub fn save_file(&self) -> Result<()> {
|
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
|
/// patch verge config
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ impl WebDavClient {
|
|||||||
reqwest::Client::builder()
|
reqwest::Client::builder()
|
||||||
.danger_accept_invalid_certs(true)
|
.danger_accept_invalid_certs(true)
|
||||||
.timeout(Duration::from_secs(op.timeout()))
|
.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| {
|
.redirect(reqwest::redirect::Policy::custom(|attempt| {
|
||||||
// 允许所有请求类型的重定向,包括PUT
|
// 允许所有请求类型的重定向,包括PUT
|
||||||
if attempt.previous().len() >= 5 {
|
if attempt.previous().len() >= 5 {
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ impl CoreManager {
|
|||||||
help::save_yaml(
|
help::save_yaml(
|
||||||
&runtime_path,
|
&runtime_path,
|
||||||
&Config::clash().latest().0,
|
&Config::clash().latest().0,
|
||||||
Some("# Clash Verge Runtime"),
|
Some("# Koala Clash Runtime"),
|
||||||
)?;
|
)?;
|
||||||
handle::Handle::notice_message(msg_type, msg_content);
|
handle::Handle::notice_message(msg_type, msg_content);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -443,7 +443,7 @@ impl CoreManager {
|
|||||||
child_guard.as_ref().map(|child| child.pid())
|
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();
|
let mut process_futures = Vec::new();
|
||||||
|
|||||||
@@ -578,7 +578,7 @@ pub async fn check_ipc_service_status() -> Result<JsonResponse> {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "IPC通信失败: {}", 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) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "IPC通信失败: {}", 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) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Service, true, "启动核心IPC通信失败: {}", 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 payload = serde_json::json!({});
|
||||||
let response = send_ipc_request(IpcCommand::StopClash, payload)
|
let response = send_ipc_request(IpcCommand::StopClash, payload)
|
||||||
.await
|
.await
|
||||||
.context("无法连接到Clash Verge Service")?;
|
.context("无法连接到Koala Clash Service")?;
|
||||||
|
|
||||||
if !response.success {
|
if !response.success {
|
||||||
bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string()));
|
bail!(response.error.unwrap_or_else(|| "停止核心失败".to_string()));
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ use sha2::{Digest, Sha256};
|
|||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
const IPC_SOCKET_NAME: &str = if cfg!(windows) {
|
const IPC_SOCKET_NAME: &str = if cfg!(windows) {
|
||||||
r"\\.\pipe\clash-verge-service"
|
r"\\.\pipe\koala-clash-service"
|
||||||
} else {
|
} else {
|
||||||
"/tmp/clash-verge-service.sock"
|
"/tmp/koala-clash-service.sock"
|
||||||
};
|
};
|
||||||
|
|
||||||
// 定义命令类型
|
// 定义命令类型
|
||||||
@@ -43,7 +43,7 @@ pub struct IpcResponse {
|
|||||||
fn derive_secret_key() -> Vec<u8> {
|
fn derive_secret_key() -> Vec<u8> {
|
||||||
// to do
|
// 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();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(unique_app_id.as_bytes());
|
hasher.update(unique_app_id.as_bytes());
|
||||||
hasher.finalize().to_vec()
|
hasher.finalize().to_vec()
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ impl Tray {
|
|||||||
|
|
||||||
if let Some(tray) = app_handle.tray_by_id("main") {
|
if let Some(tray) = app_handle.tray_by_id("main") {
|
||||||
let _ = tray.set_tooltip(Some(&format!(
|
let _ = tray.set_tooltip(Some(&format!(
|
||||||
"Clash Verge {version}\n{}: {}\n{}: {}\n{}: {}",
|
"Koala Clash {version}\n{}: {}\n{}: {}\n{}: {}",
|
||||||
t("SysProxy"),
|
t("SysProxy"),
|
||||||
switch_map[system_proxy],
|
switch_map[system_proxy],
|
||||||
t("TUN"),
|
t("TUN"),
|
||||||
@@ -601,16 +601,6 @@ fn create_tray_menu(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.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(
|
let profiles = &Submenu::with_id_and_items(
|
||||||
app_handle,
|
app_handle,
|
||||||
"profiles",
|
"profiles",
|
||||||
@@ -650,45 +640,6 @@ fn create_tray_menu(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.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(
|
let restart_clash = &MenuItem::with_id(
|
||||||
app_handle,
|
app_handle,
|
||||||
"restart_clash",
|
"restart_clash",
|
||||||
@@ -736,7 +687,6 @@ fn create_tray_menu(
|
|||||||
separator,
|
separator,
|
||||||
rule_mode,
|
rule_mode,
|
||||||
global_mode,
|
global_mode,
|
||||||
direct_mode,
|
|
||||||
separator,
|
separator,
|
||||||
profiles,
|
profiles,
|
||||||
separator,
|
separator,
|
||||||
@@ -744,8 +694,6 @@ fn create_tray_menu(
|
|||||||
tun_mode,
|
tun_mode,
|
||||||
separator,
|
separator,
|
||||||
lighteweight_mode,
|
lighteweight_mode,
|
||||||
copy_env,
|
|
||||||
open_dir,
|
|
||||||
more,
|
more,
|
||||||
separator,
|
separator,
|
||||||
quit,
|
quit,
|
||||||
@@ -789,16 +737,6 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
|||||||
"tun_mode" => {
|
"tun_mode" => {
|
||||||
feat::toggle_tun_mode(None);
|
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_clash" => feat::restart_clash_core(),
|
||||||
"restart_app" => feat::restart_app(),
|
"restart_app" => feat::restart_app(),
|
||||||
"entry_lightweight_mode" => {
|
"entry_lightweight_mode" => {
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ impl ChainSupport {
|
|||||||
(self, core.as_str()),
|
(self, core.as_str()),
|
||||||
(ChainSupport::All, _)
|
(ChainSupport::All, _)
|
||||||
| (ChainSupport::Clash, "clash")
|
| (ChainSupport::Clash, "clash")
|
||||||
| (ChainSupport::ClashMeta, "verge-mihomo")
|
| (ChainSupport::ClashMeta, "koala-mihomo")
|
||||||
| (ChainSupport::ClashMetaAlpha, "verge-mihomo-alpha")
|
| (ChainSupport::ClashMetaAlpha, "koala-mihomo-alpha")
|
||||||
),
|
),
|
||||||
None => true,
|
None => true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ mod utils;
|
|||||||
use crate::{
|
use crate::{
|
||||||
core::hotkey,
|
core::hotkey,
|
||||||
process::AsyncHandler,
|
process::AsyncHandler,
|
||||||
utils::{resolve, resolve::resolve_scheme, server},
|
utils::{resolve, resolve::resolve_scheme},
|
||||||
};
|
};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use std::sync::{Mutex, Once};
|
use std::sync::{Mutex, Once};
|
||||||
@@ -90,33 +90,6 @@ pub fn run() {
|
|||||||
|
|
||||||
let _ = utils::dirs::init_portable_flag();
|
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")]
|
#[cfg(target_os = "linux")]
|
||||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||||
|
|
||||||
@@ -125,6 +98,13 @@ pub fn run() {
|
|||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut builder = tauri::Builder::default()
|
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_notification::init())
|
||||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||||
.plugin(tauri_plugin_clipboard_manager::init())
|
.plugin(tauri_plugin_clipboard_manager::init())
|
||||||
@@ -364,6 +344,10 @@ pub fn run() {
|
|||||||
} => {
|
} => {
|
||||||
if !has_visible_windows {
|
if !has_visible_windows {
|
||||||
AppHandleManager::global().set_activation_policy_regular();
|
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());
|
AppHandleManager::global().init(app_handle.clone());
|
||||||
}
|
}
|
||||||
@@ -384,7 +368,6 @@ pub fn run() {
|
|||||||
match event {
|
match event {
|
||||||
tauri::WindowEvent::CloseRequested { api, .. } => {
|
tauri::WindowEvent::CloseRequested { api, .. } => {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
AppHandleManager::global().set_activation_policy_accessory();
|
|
||||||
if core::handle::Handle::global().is_exiting() {
|
if core::handle::Handle::global().is_exiting() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ pub fn get_exe_path() -> Result<PathBuf> {
|
|||||||
pub fn create_shortcut() -> Result<()> {
|
pub fn create_shortcut() -> Result<()> {
|
||||||
let exe_path = get_exe_path()?;
|
let exe_path = get_exe_path()?;
|
||||||
let startup_dir = get_startup_dir()?;
|
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() {
|
if shortcut_path.exists() {
|
||||||
@@ -77,7 +77,7 @@ pub fn create_shortcut() -> Result<()> {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn remove_shortcut() -> Result<()> {
|
pub fn remove_shortcut() -> Result<()> {
|
||||||
let startup_dir = get_startup_dir()?;
|
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() {
|
if !shortcut_path.exists() {
|
||||||
@@ -96,7 +96,7 @@ pub fn remove_shortcut() -> Result<()> {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn is_shortcut_enabled() -> Result<bool> {
|
pub fn is_shortcut_enabled() -> Result<bool> {
|
||||||
let startup_dir = get_startup_dir()?;
|
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())
|
Ok(shortcut_path.exists())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ use std::{fs, path::PathBuf};
|
|||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
|
||||||
#[cfg(not(feature = "verge-dev"))]
|
#[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"))]
|
#[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")]
|
#[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")]
|
#[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();
|
pub static PORTABLE_FLAG: OnceCell<bool> = OnceCell::new();
|
||||||
|
|
||||||
@@ -188,13 +188,13 @@ pub fn profiles_path() -> Result<PathBuf> {
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn service_path() -> Result<PathBuf> {
|
pub fn service_path() -> Result<PathBuf> {
|
||||||
let res_dir = app_resources_dir()?;
|
let res_dir = app_resources_dir()?;
|
||||||
Ok(res_dir.join("clash-verge-service"))
|
Ok(res_dir.join("koala-clash-service"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn service_path() -> Result<PathBuf> {
|
pub fn service_path() -> Result<PathBuf> {
|
||||||
let res_dir = app_resources_dir()?;
|
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> {
|
pub fn service_log_file() -> Result<PathBuf> {
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ fn init_dns_config() -> Result<()> {
|
|||||||
help::save_yaml(
|
help::save_yaml(
|
||||||
&dns_path,
|
&dns_path,
|
||||||
&default_dns_config,
|
&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| {
|
crate::log_err!(dirs::clash_path().map(|path| {
|
||||||
if !path.exists() {
|
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(())
|
<Result<()>>::Ok(())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
crate::log_err!(dirs::verge_path().map(|path| {
|
crate::log_err!(dirs::verge_path().map(|path| {
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
help::save_yaml(&path, &IVerge::template(), Some("# Clash Verge"))?;
|
help::save_yaml(&path, &IVerge::template(), Some("# Koala Clash"))?;
|
||||||
}
|
}
|
||||||
<Result<()>>::Ok(())
|
<Result<()>>::Ok(())
|
||||||
}));
|
}));
|
||||||
@@ -291,7 +291,7 @@ pub fn init_config() -> Result<()> {
|
|||||||
|
|
||||||
crate::log_err!(dirs::profiles_path().map(|path| {
|
crate::log_err!(dirs::profiles_path().map(|path| {
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
help::save_yaml(&path, &IProfiles::template(), Some("# Clash Verge"))?;
|
help::save_yaml(&path, &IProfiles::template(), Some("# Koala Clash"))?;
|
||||||
}
|
}
|
||||||
<Result<()>>::Ok(())
|
<Result<()>>::Ok(())
|
||||||
}));
|
}));
|
||||||
@@ -371,8 +371,8 @@ pub fn init_scheme() -> Result<()> {
|
|||||||
|
|
||||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||||
let (clash, _) = hkcu.create_subkey("Software\\Classes\\Clash")?;
|
let (clash, _) = hkcu.create_subkey("Software\\Classes\\Clash")?;
|
||||||
clash.set_value("", &"Clash Verge")?;
|
clash.set_value("", &"Koala Clash")?;
|
||||||
clash.set_value("URL Protocol", &"Clash Verge URL Scheme Protocol")?;
|
clash.set_value("URL Protocol", &"Koala Clash URL Scheme Protocol")?;
|
||||||
let (default_icon, _) = hkcu.create_subkey("Software\\Classes\\Clash\\DefaultIcon")?;
|
let (default_icon, _) = hkcu.create_subkey("Software\\Classes\\Clash\\DefaultIcon")?;
|
||||||
default_icon.set_value("", &app_exe)?;
|
default_icon.set_value("", &app_exe)?;
|
||||||
let (command, _) = hkcu.create_subkey("Software\\Classes\\Clash\\Shell\\Open\\Command")?;
|
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<()> {
|
pub fn init_scheme() -> Result<()> {
|
||||||
let output = std::process::Command::new("xdg-mime")
|
let output = std::process::Command::new("xdg-mime")
|
||||||
.arg("default")
|
.arg("default")
|
||||||
.arg("clash-verge.desktop")
|
.arg("koala-clash.desktop")
|
||||||
.arg("x-scheme-handler/clash")
|
.arg("x-scheme-handler/clash")
|
||||||
.output()?;
|
.output()?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ pub mod network;
|
|||||||
pub mod notification;
|
pub mod notification;
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
pub mod sys_info;
|
||||||
pub mod tmpl;
|
pub mod tmpl;
|
||||||
pub mod window_manager;
|
pub mod window_manager;
|
||||||
pub mod sys_info;
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ impl NetworkManager {
|
|||||||
// 创建专用的异步运行时,线程数限制为4个
|
// 创建专用的异步运行时,线程数限制为4个
|
||||||
let runtime = Builder::new_multi_thread()
|
let runtime = Builder::new_multi_thread()
|
||||||
.worker_threads(4)
|
.worker_threads(4)
|
||||||
.thread_name("clash-verge-network")
|
.thread_name("koala-clash-network")
|
||||||
.enable_io()
|
.enable_io()
|
||||||
.enable_time()
|
.enable_time()
|
||||||
.build()
|
.build()
|
||||||
@@ -323,8 +323,8 @@ impl NetworkManager {
|
|||||||
use crate::utils::resolve::VERSION;
|
use crate::utils::resolve::VERSION;
|
||||||
|
|
||||||
let version = match VERSION.get() {
|
let version = match VERSION.get() {
|
||||||
Some(v) => format!("clash-verge/v{v}"),
|
Some(v) => format!("koala-clash/v{v}"),
|
||||||
None => "clash-verge/unknown".to_string(),
|
None => "koala-clash/unknown".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
builder = builder.user_agent(version);
|
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 name: Option<String> = None;
|
||||||
let mut url_param: Option<String> = None;
|
let mut url_param: Option<String> = None;
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ use crate::{
|
|||||||
process::AsyncHandler,
|
process::AsyncHandler,
|
||||||
utils::logging::Type,
|
utils::logging::Type,
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::Result;
|
||||||
use port_scanner::local_port_available;
|
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
@@ -17,32 +16,6 @@ struct QueryParam {
|
|||||||
param: String,
|
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
|
/// The embed server only be used to implement singleton process
|
||||||
/// maybe it can be used as pac server later
|
/// maybe it can be used as pac server later
|
||||||
pub fn embed_server() {
|
pub fn embed_server() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Some config file template
|
//! Some config file template
|
||||||
|
|
||||||
/// template for new a profile item
|
/// 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: []
|
proxies: []
|
||||||
|
|
||||||
@@ -11,13 +11,13 @@ rules: []
|
|||||||
";
|
";
|
||||||
|
|
||||||
/// enhanced profile
|
/// 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:
|
profile:
|
||||||
store-selected: true
|
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
|
/// 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: []
|
prepend: []
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ delete: []
|
|||||||
";
|
";
|
||||||
|
|
||||||
/// enhanced profile
|
/// 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: []
|
prepend: []
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ delete: []
|
|||||||
";
|
";
|
||||||
|
|
||||||
/// enhanced profile
|
/// 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: []
|
prepend: []
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "0.2.3",
|
"version": "0.2.5",
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
],
|
],
|
||||||
"resources": ["resources", "resources/locales/*"],
|
"resources": ["resources", "resources/locales/*"],
|
||||||
"publisher": "Koala Clash",
|
"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",
|
"copyright": "GNU General Public License v3.0",
|
||||||
"category": "DeveloperTool",
|
"category": "DeveloperTool",
|
||||||
"shortDescription": "Koala Clash",
|
"shortDescription": "Koala Clash",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"devUrl": "http://localhost:3000/"
|
"devUrl": "http://localhost:3000/"
|
||||||
},
|
},
|
||||||
"productName": "Koala Clash",
|
"productName": "Koala Clash",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"identifier": "io.github.koala-clash",
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"updater": {
|
"updater": {
|
||||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IERCQjQ1QjQ0QUJDQTU1RTkKUldUcFZjcXJSRnUwMjdXSERoZVQ1R0hHRDMrT3VkSmpvbDJmb01sN3ZpYWhVYnEwaWpYUWU4YU0K",
|
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IERCQjQ1QjQ0QUJDQTU1RTkKUldUcFZjcXJSRnUwMjdXSERoZVQ1R0hHRDMrT3VkSmpvbDJmb01sN3ZpYWhVYnEwaWpYUWU4YU0K",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
},
|
},
|
||||||
"deep-link": {
|
"deep-link": {
|
||||||
"desktop": {
|
"desktop": {
|
||||||
"schemes": ["clash", "clash-verge"]
|
"schemes": ["clash", "koala-clash"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"identifier": "io.github.koala-clash",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"targets": ["deb", "rpm"],
|
"targets": ["deb", "rpm"],
|
||||||
"linux": {
|
"linux": {
|
||||||
"deb": {
|
"deb": {
|
||||||
"depends": ["openssl"],
|
"depends": ["openssl"],
|
||||||
"desktopTemplate": "./packages/linux/clash-verge.desktop",
|
"desktopTemplate": "./packages/linux/koala-clash.desktop",
|
||||||
"provides": ["clash-verge"],
|
"provides": ["koala-clash"],
|
||||||
"conflicts": ["clash-verge"],
|
"conflicts": ["koala-clash"],
|
||||||
"replaces": ["clash-verge"],
|
"replaces": ["koala-clash"],
|
||||||
"postInstallScript": "./packages/linux/post-install.sh",
|
"postInstallScript": "./packages/linux/post-install.sh",
|
||||||
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
||||||
},
|
},
|
||||||
"rpm": {
|
"rpm": {
|
||||||
"depends": ["openssl"],
|
"depends": ["openssl"],
|
||||||
"desktopTemplate": "./packages/linux/clash-verge.desktop",
|
"desktopTemplate": "./packages/linux/koala-clash.desktop",
|
||||||
"provides": ["clash-verge"],
|
"provides": ["koala-clash"],
|
||||||
"conflicts": ["clash-verge"],
|
"conflicts": ["koala-clash"],
|
||||||
"obsoletes": ["clash-verge"],
|
"obsoletes": ["koala-clash"],
|
||||||
"postInstallScript": "./packages/linux/post-install.sh",
|
"postInstallScript": "./packages/linux/post-install.sh",
|
||||||
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"externalBin": [
|
"externalBin": [
|
||||||
"./resources/clash-verge-service",
|
"./resources/koala-clash-service",
|
||||||
"./resources/install-service",
|
"./resources/install-service",
|
||||||
"./resources/uninstall-service",
|
"./resources/uninstall-service",
|
||||||
"./sidecar/verge-mihomo",
|
"./sidecar/koala-mihomo",
|
||||||
"./sidecar/verge-mihomo-alpha"
|
"./sidecar/koala-mihomo-alpha"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$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",
|
"productName": "Koala Clash",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"targets": ["app", "dmg"],
|
"targets": ["app", "dmg"],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"identifier": "io.github.koala-clash",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"targets": ["nsis"],
|
"targets": ["nsis"],
|
||||||
"windows": {
|
"windows": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"identifier": "io.github.koala-clash",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"targets": ["nsis"],
|
"targets": ["nsis"],
|
||||||
"windows": {
|
"windows": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"identifier": "io.github.koala-clash",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"targets": ["nsis"],
|
"targets": ["nsis"],
|
||||||
"windows": {
|
"windows": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"identifier": "io.github.koala-clash",
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"targets": ["nsis"],
|
"targets": ["nsis"],
|
||||||
"windows": {
|
"windows": {
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import { AppDataProvider } from "./providers/app-data-provider";
|
import { AppDataProvider } from "./providers/app-data-provider";
|
||||||
import { ThemeProvider } from "@/components/layout/theme-provider";
|
|
||||||
import Layout from "./pages/_layout";
|
import Layout from "./pages/_layout";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider>
|
<AppDataProvider>
|
||||||
<AppDataProvider>
|
<Layout />
|
||||||
<Layout />
|
</AppDataProvider>
|
||||||
</AppDataProvider>
|
|
||||||
</ThemeProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default App;
|
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"
|
<svg width="1024" height="963" viewBox="0 0 1024 963" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
viewBox="0 0 117 27" style="enable-background:new 0 0 117 27;" xml:space="preserve">
|
<g filter="url(#filter0_f_40_29)">
|
||||||
<g>
|
<ellipse cx="512" cy="516" rx="254" ry="216" fill="url(#paint0_radial_40_29)" fill-opacity="0.3"/>
|
||||||
<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>
|
|
||||||
</g>
|
</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>
|
</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 { BaseErrorBoundary } from "./base-error-boundary";
|
||||||
export { Switch } from "./base-switch";
|
export { Switch } from "./base-switch";
|
||||||
export { BaseLoadingOverlay } from "./base-loading-overlay";
|
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 { UpdateButton } from "@/components/layout/update-button";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { SheetClose } from '@/components/ui/sheet';
|
import { SheetClose } from '@/components/ui/sheet';
|
||||||
|
import logo from "@/assets/image/logo.png"
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ title: 'Home', url: '/home', icon: Home },
|
{ title: 'Home', url: '/home', icon: Home },
|
||||||
@@ -48,7 +49,7 @@ export function AppSidebar() {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="./assets/image/logo.png"
|
src={logo}
|
||||||
alt="logo"
|
alt="logo"
|
||||||
className="h-6 w-6 flex-shrink-0"
|
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 { useSetThemeMode, useThemeMode } from "@/services/states";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
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";
|
import { Theme } from "@tauri-apps/api/window";
|
||||||
|
|
||||||
export const useCustomTheme = () => {
|
export const useCustomTheme = () => {
|
||||||
const appWindow = useMemo(() => getCurrentWebviewWindow(), []);
|
const appWindow: WebviewWindow = useMemo(() => getCurrentWebviewWindow(), []);
|
||||||
const { verge } = useVerge();
|
const { verge } = useVerge();
|
||||||
const { theme_mode } = verge ?? {};
|
const { theme_mode } = verge ?? {};
|
||||||
|
|
||||||
const mode = useThemeMode();
|
const mode = useThemeMode();
|
||||||
const setMode = useSetThemeMode();
|
const setMode = useSetThemeMode();
|
||||||
|
|
||||||
|
const [systemTheme, setSystemTheme] = useState(
|
||||||
|
() => window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMode(
|
setMode(
|
||||||
theme_mode === "light" || theme_mode === "dark" ? theme_mode : "system",
|
theme_mode === "light" || theme_mode === "dark" ? theme_mode : "system",
|
||||||
);
|
);
|
||||||
}, [theme_mode, setMode]);
|
}, [theme_mode, setMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const root = document.documentElement;
|
if (mode !== 'system') return;
|
||||||
|
|
||||||
const activeTheme =
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
mode === "system"
|
const handleChange = (e: MediaQueryListEvent) => {
|
||||||
? window.matchMedia("(prefers-color-scheme: dark)").matches
|
setSystemTheme(e.matches ? "dark" : "light");
|
||||||
? "dark"
|
};
|
||||||
: "light"
|
|
||||||
: mode;
|
|
||||||
|
|
||||||
root.classList.remove("light", "dark");
|
mediaQuery.addEventListener('change', handleChange);
|
||||||
root.classList.add(activeTheme);
|
return () => mediaQuery.removeEventListener('change', handleChange);
|
||||||
appWindow.setTheme(activeTheme as Theme).catch(console.error);
|
}, [mode]);
|
||||||
}, [mode, appWindow]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (theme_mode !== "system") return;
|
const root = document.documentElement;
|
||||||
const unlistenPromise = appWindow.onThemeChanged(({ payload }) => {
|
const activeTheme = mode === "system" ? systemTheme : mode;
|
||||||
setMode(payload);
|
root.classList.remove("light", "dark");
|
||||||
});
|
root.classList.add(activeTheme);
|
||||||
return () => {
|
|
||||||
unlistenPromise.then((f) => f());
|
if (theme_mode === "system") {
|
||||||
};
|
appWindow.setTheme(null).catch(console.error);
|
||||||
}, [theme_mode, appWindow, setMode]);
|
} else {
|
||||||
|
appWindow.setTheme(activeTheme as Theme).catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [mode, systemTheme, appWindow, theme_mode]);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
@@ -296,7 +296,7 @@ export const ProfileViewer = forwardRef<ProfileViewerRef, Props>(
|
|||||||
</Button>
|
</Button>
|
||||||
{!isUrlValid && importUrl && (
|
{!isUrlValid && importUrl && (
|
||||||
<p className="text-sm text-destructive px-1">
|
<p className="text-sm text-destructive px-1">
|
||||||
{t("Please enter a valid URL")}
|
{t("Invalid Profile URL")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import { showNotice } from "@/services/noticeService";
|
|||||||
|
|
||||||
// Константы и интерфейсы
|
// Константы и интерфейсы
|
||||||
const VALID_CORE = [
|
const VALID_CORE = [
|
||||||
{ name: "Mihomo", core: "verge-mihomo", chip: "Release Version" },
|
{ name: "Mihomo", core: "koala-mihomo", chip: "Release Version" },
|
||||||
{ name: "Mihomo Alpha", core: "verge-mihomo-alpha", chip: "Alpha Version" },
|
{ name: "Mihomo Alpha", core: "koala-mihomo-alpha", chip: "Alpha Version" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
@@ -44,7 +44,7 @@ export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
close: () => setOpen(false),
|
close: () => setOpen(false),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { clash_core = "verge-mihomo" } = verge ?? {};
|
const { clash_core = "koala-mihomo" } = verge ?? {};
|
||||||
|
|
||||||
const onCoreChange = useLockFn(async (core: string) => {
|
const onCoreChange = useLockFn(async (core: string) => {
|
||||||
if (core === clash_core) return;
|
if (core === clash_core) return;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
|
import { Loader2 } from "lucide-react";
|
||||||
|
|
||||||
const OS = getSystem();
|
const OS = getSystem();
|
||||||
|
|
||||||
@@ -69,6 +70,9 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||||
|
|
||||||
|
const [localConfig, setLocalConfig] = useState<Partial<IVergeConfig>>({});
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [commonIcon, setCommonIcon] = useState("");
|
const [commonIcon, setCommonIcon] = useState("");
|
||||||
const [sysproxyIcon, setSysproxyIcon] = useState("");
|
const [sysproxyIcon, setSysproxyIcon] = useState("");
|
||||||
@@ -96,28 +100,26 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) initIconPath();
|
if (open) {
|
||||||
}, [open, initIconPath]);
|
setLocalConfig(verge ?? {});
|
||||||
|
initIconPath();
|
||||||
|
}
|
||||||
|
}, [open, verge, initIconPath]);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
open: () => setOpen(true),
|
open: () => setOpen(true),
|
||||||
close: () => setOpen(false),
|
close: () => setOpen(false),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
const handleConfigChange = (patch: Partial<IVergeConfig>) => {
|
||||||
const onError = (err: any) => {
|
setLocalConfig(prev => ({ ...prev, ...patch }));
|
||||||
showNotice("error", err.message || err.toString());
|
|
||||||
};
|
|
||||||
const onChangeData = (patch: Partial<IVergeConfig>) => {
|
|
||||||
mutateVerge({ ...verge, ...patch }, false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleIconChange = useLockFn(
|
const handleIconChange = useLockFn(
|
||||||
async (type: "common" | "sysproxy" | "tun") => {
|
async (type: "common" | "sysproxy" | "tun") => {
|
||||||
const key = `${type}_tray_icon` as keyof IVergeConfig;
|
const key = `${type}_tray_icon` as keyof IVergeConfig;
|
||||||
if (verge?.[key]) {
|
if (localConfig[key]) {
|
||||||
onChangeData({ [key]: false });
|
handleConfigChange({ [key]: false });
|
||||||
await patchVerge({ [key]: false });
|
|
||||||
} else {
|
} else {
|
||||||
const selected = await openDialog({
|
const selected = await openDialog({
|
||||||
directory: false,
|
directory: false,
|
||||||
@@ -128,72 +130,94 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
const path = Array.isArray(selected) ? selected[0] : selected;
|
const path = Array.isArray(selected) ? selected[0] : selected;
|
||||||
await copyIconFile(path, type);
|
await copyIconFile(path, type);
|
||||||
await initIconPath();
|
await initIconPath();
|
||||||
onChangeData({ [key]: true });
|
handleConfigChange({ [key]: true });
|
||||||
await patchVerge({ [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 (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogContent className="sm:max-w-md">
|
<DialogContent className="sm:max-w-md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{t("Layout Setting")}</DialogTitle>
|
<DialogTitle>{t("Layout Setting")}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="py-4 space-y-1">
|
<div className="py-4 space-y-1">
|
||||||
<SettingRow label={t("Memory Usage")}>
|
{OS === "macos" && (
|
||||||
<GuardState
|
<>
|
||||||
value={verge?.enable_memory_usage ?? true}
|
<SettingRow label={t("Tray Icon")}>
|
||||||
valueProps="checked"
|
<Select
|
||||||
onCatch={onError}
|
onValueChange={(value) => handleConfigChange({ tray_icon: value as any })}
|
||||||
onFormat={onSwitchFormat}
|
value={localConfig.tray_icon ?? "monochrome"}
|
||||||
onChange={(e) => onChangeData({ enable_memory_usage: e })}
|
>
|
||||||
onGuard={(e) => patchVerge({ enable_memory_usage: e })}
|
<SelectTrigger className="w-40 h-8"><SelectValue /></SelectTrigger>
|
||||||
>
|
<SelectContent>
|
||||||
<Switch />
|
<SelectItem value="monochrome">{t("Monochrome")}</SelectItem>
|
||||||
</GuardState>
|
<SelectItem value="colorful">{t("Colorful")}</SelectItem>
|
||||||
</SettingRow>
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</SettingRow>
|
||||||
|
|
||||||
<SettingRow label={t("Proxy Group Icon")}>
|
<SettingRow label={t("Enable Tray Icon")}>
|
||||||
<GuardState
|
<Switch
|
||||||
value={verge?.enable_group_icon ?? true}
|
checked={localConfig.enable_tray_icon ?? true}
|
||||||
valueProps="checked"
|
onCheckedChange={(checked) => handleConfigChange({ enable_tray_icon: checked })}
|
||||||
onCatch={onError}
|
/>
|
||||||
onFormat={onSwitchFormat}
|
</SettingRow>
|
||||||
onChange={(e) => onChangeData({ enable_group_icon: e })}
|
</>
|
||||||
onGuard={(e) => patchVerge({ enable_group_icon: e })}
|
)}
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</GuardState>
|
|
||||||
</SettingRow>
|
|
||||||
|
|
||||||
<SettingRow
|
<SettingRow label={t("Common Tray Icon")}>
|
||||||
label={t("Hover Jump Navigator")}
|
<Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("common")}>
|
||||||
extra={<TooltipIcon tooltip={t("Hover Jump Navigator Info")} />}
|
{localConfig.common_tray_icon && commonIcon && (
|
||||||
>
|
<img src={convertFileSrc(commonIcon)} className="h-5 mr-2" alt="common tray icon" />
|
||||||
<GuardState
|
)}
|
||||||
value={verge?.enable_hover_jump_navigator ?? true}
|
{localConfig.common_tray_icon ? t("Clear") : t("Browse")}
|
||||||
valueProps="checked"
|
</Button>
|
||||||
onCatch={onError}
|
</SettingRow>
|
||||||
onFormat={onSwitchFormat}
|
|
||||||
onChange={(e) => onChangeData({ enable_hover_jump_navigator: e })}
|
|
||||||
onGuard={(e) => patchVerge({ enable_hover_jump_navigator: e })}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</GuardState>
|
|
||||||
</SettingRow>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<DialogFooter>
|
<SettingRow label={t("System Proxy Tray Icon")}>
|
||||||
<DialogClose asChild>
|
<Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("sysproxy")}>
|
||||||
<Button type="button" variant="outline">
|
{localConfig.sysproxy_tray_icon && sysproxyIcon && (
|
||||||
{t("Close")}
|
<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>
|
</Button>
|
||||||
</DialogClose>
|
</DialogFooter>
|
||||||
</DialogFooter>
|
</DialogContent>
|
||||||
</DialogContent>
|
</Dialog>
|
||||||
</Dialog>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useRef, useState } from "react";
|
import {useMemo, useRef, useState} from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
@@ -56,6 +56,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
import {useProfiles} from "@/hooks/use-profiles";
|
||||||
|
|
||||||
const isWIN = getSystem() === "windows";
|
const isWIN = getSystem() === "windows";
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -106,6 +107,12 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||||
const { installServiceAndRestartCore } = useServiceInstaller();
|
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 {
|
const {
|
||||||
actualState: systemProxyActualState,
|
actualState: systemProxyActualState,
|
||||||
indicator: systemProxyIndicator,
|
indicator: systemProxyIndicator,
|
||||||
@@ -261,7 +268,7 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
}}
|
}}
|
||||||
onCatch={onError}
|
onCatch={onError}
|
||||||
>
|
>
|
||||||
<Switch disabled={!isTunAvailable} />
|
<Switch disabled={!isTunAvailable || !hasProfiles} />
|
||||||
</GuardState>
|
</GuardState>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
|
|
||||||
@@ -297,7 +304,7 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
}}
|
}}
|
||||||
onCatch={onError}
|
onCatch={onError}
|
||||||
>
|
>
|
||||||
<Switch />
|
<Switch disabled={!hasProfiles} />
|
||||||
</GuardState>
|
</GuardState>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
|
|
||||||
|
|||||||
@@ -188,24 +188,22 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
|||||||
|
|
||||||
{OS !== "linux" && (
|
{OS !== "linux" && (
|
||||||
<SettingRow
|
<SettingRow
|
||||||
label={
|
label={
|
||||||
<LabelWithIcon
|
<LabelWithIcon
|
||||||
icon={MousePointerClick}
|
icon={MousePointerClick}
|
||||||
text={t("Tray Click Event")}
|
text={t("Tray Click Event")}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<GuardState
|
<GuardState
|
||||||
value={tray_event ?? "main_window"}
|
value={tray_event ?? "main_window"}
|
||||||
onCatch={onError}
|
onCatch={onError}
|
||||||
onFormat={(v) => v}
|
onFormat={(v) => v}
|
||||||
onChange={(e) => onChangeData({ tray_event: e })}
|
onChange={(e) => onChangeData({ tray_event: e })}
|
||||||
onGuard={(e) => patchVerge({ tray_event: e })}
|
onGuard={(e) => patchVerge({ tray_event: e })}
|
||||||
|
onChangeProps="onValueChange"
|
||||||
>
|
>
|
||||||
<Select
|
<Select>
|
||||||
onValueChange={(value) => onChangeData({ tray_event: value })}
|
|
||||||
value={tray_event}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-40 h-8">
|
<SelectTrigger className="w-40 h-8">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "tw-animate-css";
|
@import "tw-animate-css";
|
||||||
|
|
||||||
@variant dark .dark &;
|
@theme {
|
||||||
|
--tailwind-darkMode: 'class';
|
||||||
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
@@ -129,3 +131,21 @@
|
|||||||
svg {
|
svg {
|
||||||
stroke-width: var(--icon-stroke-width, 2);
|
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",
|
"Template": "Template",
|
||||||
"Select a template...": "Select a template...",
|
"Select a template...": "Select a template...",
|
||||||
"Default Template": "Ru-bundle 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": "Цвет успеха",
|
"Success Color": "Цвет успеха",
|
||||||
"Font Family": "Семейство шрифтов",
|
"Font Family": "Семейство шрифтов",
|
||||||
"CSS Injection": "Внедрение CSS",
|
"CSS Injection": "Внедрение CSS",
|
||||||
"Layout Setting": "Настройки раскладки",
|
"Layout Setting": "Настройки макета",
|
||||||
"Traffic Graph": "График трафика",
|
"Traffic Graph": "График трафика",
|
||||||
"Memory Usage": "Использование памяти",
|
"Memory Usage": "Использование памяти",
|
||||||
"Memory Cleanup": "Нажмите, чтобы очистить память",
|
"Memory Cleanup": "Нажмите, чтобы очистить память",
|
||||||
@@ -401,8 +401,8 @@
|
|||||||
"Proxy Daemon Duration Cannot be Less than 1 Second": "Продолжительность работы прокси-демона не может быть меньше 1 секунды",
|
"Proxy Daemon Duration Cannot be Less than 1 Second": "Продолжительность работы прокси-демона не может быть меньше 1 секунды",
|
||||||
"Invalid Bypass Format": "Неверный формат обхода",
|
"Invalid Bypass Format": "Неверный формат обхода",
|
||||||
"Waiting for service to be ready...": "Ожидание готовности сервиса...",
|
"Waiting for service to be ready...": "Ожидание готовности сервиса...",
|
||||||
"Service not ready, 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}...",
|
"Failed to check service status, retrying attempt {count}/{total}...": "Не удалось проверить состояние службы, повторная попытка {{count}}/{{total}}...",
|
||||||
"Service did not become ready after attempts. Proceeding with core restart.": "Служба не была готова после нескольких попыток. Продолжаем перезапуск ядра.",
|
"Service did not become ready after attempts. Proceeding with core restart.": "Служба не была готова после нескольких попыток. Продолжаем перезапуск ядра.",
|
||||||
"Restarting Core...": "Перезапуск ядра...",
|
"Restarting Core...": "Перезапуск ядра...",
|
||||||
"Service was ready, but core restart might have issues or service became unavailable. Please check.": "Служба была готова, но при перезапуске ядра могли возникнуть проблемы или служба стала недоступна. Пожалуйста, проверьте.",
|
"Service was ready, but core restart might have issues or service became unavailable. Please check.": "Служба была готова, но при перезапуске ядра могли возникнуть проблемы или служба стала недоступна. Пожалуйста, проверьте.",
|
||||||
@@ -627,7 +627,7 @@
|
|||||||
"DashboardToggledTitle": "Панель управления переключена",
|
"DashboardToggledTitle": "Панель управления переключена",
|
||||||
"DashboardToggledBody": "Видимость панели инструментов переключена с помощью горячей клавиши",
|
"DashboardToggledBody": "Видимость панели инструментов переключена с помощью горячей клавиши",
|
||||||
"ClashModeChangedTitle": "Режим Clash изменен",
|
"ClashModeChangedTitle": "Режим Clash изменен",
|
||||||
"ClashModeChangedBody": "Переключено в режим {mode}",
|
"ClashModeChangedBody": "Переключено в режим {{mode}}",
|
||||||
"SystemProxyToggledTitle": "Системный прокси переключен",
|
"SystemProxyToggledTitle": "Системный прокси переключен",
|
||||||
"SystemProxyToggledBody": "Состояние системного прокси-сервера переключена с помощью горячей клавиши",
|
"SystemProxyToggledBody": "Состояние системного прокси-сервера переключена с помощью горячей клавиши",
|
||||||
"TunModeToggledTitle": "Режим TUN переключен",
|
"TunModeToggledTitle": "Режим TUN переключен",
|
||||||
@@ -638,7 +638,7 @@
|
|||||||
"AppQuitBody": "Приложение закрыто с помощью горячей клавиши",
|
"AppQuitBody": "Приложение закрыто с помощью горячей клавиши",
|
||||||
"AppHiddenTitle": "Приложение скрыто",
|
"AppHiddenTitle": "Приложение скрыто",
|
||||||
"AppHiddenBody": "Окно приложения скрыто с помощью горячей клавиши",
|
"AppHiddenBody": "Окно приложения скрыто с помощью горячей клавиши",
|
||||||
"Invalid Profile URL": "Неверный URL-адрес профиля. Введите URL-адрес, начинающийся с http:// или https://.",
|
"Invalid Profile URL": "Неверный URL-адрес профиля. Введите URL-адрес, начинающийся с http:// или https://",
|
||||||
"Saved Successfully": "Успешно сохранено",
|
"Saved Successfully": "Успешно сохранено",
|
||||||
"Connected": "Подключено",
|
"Connected": "Подключено",
|
||||||
"Disconnected": "Отключено",
|
"Disconnected": "Отключено",
|
||||||
@@ -675,5 +675,8 @@
|
|||||||
"Template": "Шаблон",
|
"Template": "Шаблон",
|
||||||
"Select a template...": "Выберите шаблон...",
|
"Select a template...": "Выберите шаблон...",
|
||||||
"Default Template": "Шаблон ru-bundle",
|
"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 { initGlobalLogService } from "@/services/global-log-service";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { showNotice } from "@/services/noticeService";
|
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 { SidebarProvider, useSidebar } from "@/components/ui/sidebar";
|
||||||
import { AppSidebar } from "@/components/layout/sidebar";
|
import { AppSidebar } from "@/components/layout/sidebar";
|
||||||
import { useZoomControls } from "@/hooks/useZoomControls";
|
import { useZoomControls } from "@/hooks/useZoomControls";
|
||||||
@@ -472,9 +472,9 @@ const Layout = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SWRConfig value={{ errorRetryCount: 3 }}>
|
<SWRConfig value={{ errorRetryCount: 3 }}>
|
||||||
<NoticeManager />
|
|
||||||
<SidebarProvider defaultOpen={false}>
|
<SidebarProvider defaultOpen={false}>
|
||||||
<AppLayout />
|
<AppLayout />
|
||||||
|
<Toaster />
|
||||||
</SidebarProvider>
|
</SidebarProvider>
|
||||||
</SWRConfig>
|
</SWRConfig>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ import { updateProfile } from "@/services/cmds";
|
|||||||
import { SidebarTrigger } from "@/components/ui/sidebar";
|
import { SidebarTrigger } from "@/components/ui/sidebar";
|
||||||
import parseTraffic from "@/utils/parse-traffic";
|
import parseTraffic from "@/utils/parse-traffic";
|
||||||
import { useAppData } from "@/providers/app-data-provider";
|
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 MinimalHomePage: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -146,7 +149,7 @@ const MinimalHomePage: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
await updateProfile(currentProfile.uid);
|
await updateProfile(currentProfile.uid);
|
||||||
toast.success(t("Profile Updated Successfully"));
|
toast.success(t("Profile Updated Successfully"));
|
||||||
mutateProfiles(); // Обновляем данные в UI
|
mutateProfiles();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
toast.error(t("Failed to update profile"), { description: err.message });
|
toast.error(t("Failed to update profile"), { description: err.message });
|
||||||
} finally {
|
} 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 (
|
return (
|
||||||
<div className="h-full w-full flex flex-col">
|
<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">
|
<header className="flex-shrink-0 p-5 grid grid-cols-3 items-center z-10">
|
||||||
<div className="flex justify-start">
|
<div className="flex justify-start">
|
||||||
<SidebarTrigger />
|
<SidebarTrigger />
|
||||||
@@ -242,15 +285,18 @@ const MinimalHomePage: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="relative text-center">
|
<div className="relative text-center">
|
||||||
<h1
|
<h1
|
||||||
className="text-4xl mb-2 font-semibold"
|
className={cn(
|
||||||
style={{ color: isProxyEnabled ? "#22c55e" : "#ef4444" }}
|
"text-4xl mb-2 font-semibold transition-colors duration-300",
|
||||||
>
|
statusInfo.isAnimating && "animate-pulse"
|
||||||
{isProxyEnabled ? t("Connected") : t("Disconnected")}
|
)}
|
||||||
</h1>
|
style={{ color: statusInfo.color }}
|
||||||
|
>
|
||||||
|
{statusInfo.text}
|
||||||
|
</h1>
|
||||||
{isProxyEnabled && (
|
{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">
|
<div className="flex items-center gap-1">
|
||||||
<ArrowDown className="h-4 w-4 text-green-500" />
|
<ArrowDown className="h-4 w-4 text-green-500" />
|
||||||
{parseTraffic(connections.downloadTotal)}
|
{parseTraffic(connections.downloadTotal)}
|
||||||
@@ -261,23 +307,18 @@ const MinimalHomePage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<p className="h-6 text-sm text-muted-foreground transition-opacity duration-300">
|
|
||||||
{isToggling &&
|
|
||||||
(isProxyEnabled ? t("Disconnecting...") : t("Connecting..."))}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="scale-[7] my-16">
|
<div className="relative -translate-y-6">
|
||||||
<Switch
|
<PowerButton
|
||||||
disabled={showTunAlert || isToggling || profileItems.length === 0}
|
loading={isToggling}
|
||||||
checked={!!isProxyEnabled}
|
checked={!!isProxyEnabled}
|
||||||
onCheckedChange={handleToggleProxy}
|
onClick={handleToggleProxy}
|
||||||
aria-label={t("Toggle Proxy")}
|
disabled={showTunAlert || isToggling || profileItems.length === 0}
|
||||||
|
aria-label={t("Toggle Proxy")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{showTunAlert && (
|
{showTunAlert && (
|
||||||
<div className="w-full max-w-sm">
|
<div className="w-full max-w-sm">
|
||||||
<Alert
|
<Alert
|
||||||
@@ -303,7 +344,7 @@ const MinimalHomePage: React.FC = () => {
|
|||||||
</div>
|
</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 ? (
|
{profileItems.length > 0 ? (
|
||||||
<ProxySelectors />
|
<ProxySelectors />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,81 +1,25 @@
|
|||||||
import { ReactNode } from "react";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
export interface NoticeItem {
|
type NoticeType = 'success' | 'error' | 'info' | 'warning';
|
||||||
id: number;
|
|
||||||
type: "success" | "error" | "info";
|
|
||||||
message: ReactNode;
|
|
||||||
duration: number;
|
|
||||||
timerId?: ReturnType<typeof setTimeout>;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Listener = (notices: NoticeItem[]) => void;
|
export const showNotice = (type: NoticeType, message: string, duration?: number) => {
|
||||||
|
const options = duration ? { duration } : {};
|
||||||
|
|
||||||
let nextId = 0;
|
switch (type) {
|
||||||
let notices: NoticeItem[] = [];
|
case 'success':
|
||||||
const listeners: Set<Listener> = new Set();
|
toast.success(message, options);
|
||||||
|
break;
|
||||||
function notifyListeners() {
|
case 'error':
|
||||||
listeners.forEach((listener) => listener([...notices])); // Pass a copy
|
toast.error(message, options);
|
||||||
}
|
break;
|
||||||
|
case 'info':
|
||||||
// Shows a notification.
|
toast.info(message, options);
|
||||||
|
break;
|
||||||
export function showNotice(
|
case 'warning':
|
||||||
type: "success" | "error" | "info",
|
toast.warning(message, options);
|
||||||
message: ReactNode,
|
break;
|
||||||
duration?: number,
|
default:
|
||||||
): number {
|
toast(message, options);
|
||||||
const id = nextId++;
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
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();
|
|
||||||
}
|
|
||||||