mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 03:32:36 +08:00
chore: update
This commit is contained in:
parent
d45929c604
commit
507d52bcb9
12
package.json
12
package.json
|
@ -28,7 +28,15 @@
|
||||||
"@mui/lab": "5.0.0-alpha.149",
|
"@mui/lab": "5.0.0-alpha.149",
|
||||||
"@mui/material": "^5.16.0",
|
"@mui/material": "^5.16.0",
|
||||||
"@mui/x-data-grid": "^7.9.0",
|
"@mui/x-data-grid": "^7.9.0",
|
||||||
"@tauri-apps/api": "^1.6.0",
|
"@tauri-apps/api": "2.0.0-rc.4",
|
||||||
|
"@tauri-apps/plugin-clipboard-manager": "2.0.0-rc.0",
|
||||||
|
"@tauri-apps/plugin-dialog": "^2.0.0-rc",
|
||||||
|
"@tauri-apps/plugin-fs": "^2.0.0-rc",
|
||||||
|
"@tauri-apps/plugin-global-shortcut": "^2.0.0-rc",
|
||||||
|
"@tauri-apps/plugin-notification": "^2.0.0-rc",
|
||||||
|
"@tauri-apps/plugin-process": "^2.0.0-rc",
|
||||||
|
"@tauri-apps/plugin-shell": "^2.0.0-rc",
|
||||||
|
"@tauri-apps/plugin-updater": "^2.0.0-rc",
|
||||||
"@types/json-schema": "^7.0.15",
|
"@types/json-schema": "^7.0.15",
|
||||||
"ahooks": "^3.8.0",
|
"ahooks": "^3.8.0",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
|
@ -60,7 +68,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@actions/github": "^5.1.1",
|
"@actions/github": "^5.1.1",
|
||||||
"@tauri-apps/cli": "^1.6.0",
|
"@tauri-apps/cli": "2.0.0-rc.8",
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
|
|
205
pnpm-lock.yaml
205
pnpm-lock.yaml
|
@ -38,8 +38,32 @@ importers:
|
||||||
specifier: ^7.9.0
|
specifier: ^7.9.0
|
||||||
version: 7.9.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 7.9.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
"@tauri-apps/api":
|
"@tauri-apps/api":
|
||||||
specifier: ^1.6.0
|
specifier: 2.0.0-rc.4
|
||||||
version: 1.6.0
|
version: 2.0.0-rc.4
|
||||||
|
"@tauri-apps/plugin-clipboard-manager":
|
||||||
|
specifier: 2.0.0-rc.0
|
||||||
|
version: 2.0.0-rc.0
|
||||||
|
"@tauri-apps/plugin-dialog":
|
||||||
|
specifier: ^2.0.0-rc
|
||||||
|
version: 2.0.0-rc.0
|
||||||
|
"@tauri-apps/plugin-fs":
|
||||||
|
specifier: ^2.0.0-rc
|
||||||
|
version: 2.0.0-rc.1
|
||||||
|
"@tauri-apps/plugin-global-shortcut":
|
||||||
|
specifier: ^2.0.0-rc
|
||||||
|
version: 2.0.0-rc.0
|
||||||
|
"@tauri-apps/plugin-notification":
|
||||||
|
specifier: ^2.0.0-rc
|
||||||
|
version: 2.0.0-rc.0
|
||||||
|
"@tauri-apps/plugin-process":
|
||||||
|
specifier: ^2.0.0-rc
|
||||||
|
version: 2.0.0-rc.0
|
||||||
|
"@tauri-apps/plugin-shell":
|
||||||
|
specifier: ^2.0.0-rc
|
||||||
|
version: 2.0.0-rc.0
|
||||||
|
"@tauri-apps/plugin-updater":
|
||||||
|
specifier: ^2.0.0-rc
|
||||||
|
version: 2.0.0-rc.0
|
||||||
"@types/json-schema":
|
"@types/json-schema":
|
||||||
specifier: ^7.0.15
|
specifier: ^7.0.15
|
||||||
version: 7.0.15
|
version: 7.0.15
|
||||||
|
@ -129,8 +153,8 @@ importers:
|
||||||
specifier: ^5.1.1
|
specifier: ^5.1.1
|
||||||
version: 5.1.1
|
version: 5.1.1
|
||||||
"@tauri-apps/cli":
|
"@tauri-apps/cli":
|
||||||
specifier: ^1.6.0
|
specifier: 2.0.0-rc.8
|
||||||
version: 1.6.0
|
version: 2.0.0-rc.8
|
||||||
"@types/fs-extra":
|
"@types/fs-extra":
|
||||||
specifier: ^9.0.13
|
specifier: ^9.0.13
|
||||||
version: 9.0.13
|
version: 9.0.13
|
||||||
|
@ -2076,111 +2100,158 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@svgr/core": "*"
|
"@svgr/core": "*"
|
||||||
|
|
||||||
"@tauri-apps/api@1.6.0":
|
"@tauri-apps/api@2.0.0-rc.4":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==,
|
integrity: sha512-UNiIhhKG08j4ooss2oEEVexffmWkgkYlC2M3GcX3VPtNsqFgVNL8Mcw/4Y7rO9M9S+ffAMnLOF5ypzyuyb8tyg==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 14.6.0", npm: ">= 6.6.0", yarn: ">= 1.19.1" }
|
|
||||||
|
|
||||||
"@tauri-apps/cli-darwin-arm64@1.6.0":
|
"@tauri-apps/cli-darwin-arm64@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-SNRwUD9nqGxY47mbY1CGTt/jqyQOU7Ps7Mx/mpgahL0FVUDiCEY/5L9QfEPPhEgccgcelEVn7i6aQHIkHyUtCA==,
|
integrity: sha512-XDjFLfCz7gOsKg9qFyK7S9EbrdcLhWE2bSTvHDpnFdMc+DcjMR4O3HuCO7SrPmmFUf86OknYFiuMPEUoHf0Fiw==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
"@tauri-apps/cli-darwin-x64@1.6.0":
|
"@tauri-apps/cli-darwin-x64@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-g2/uDR/eeH2arvuawA4WwaEOqv/7jDO/ZLNI3JlBjP5Pk8GGb3Kdy0ro1xQzF94mtk2mOnOXa4dMgAet4sUJ1A==,
|
integrity: sha512-vYuITao7qq45jzTXRFdAcB+rVBULmofksWsKzoi+cgI8R0kcfB3bts+FRBdV3j+fkbpBQKpriW6Y6gdOzbf6Ow==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf@1.6.0":
|
"@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-EVwf4oRkQyG8BpSrk0gqO7oA0sDM2MdNDtJpMfleYFEgCxLIOGZKNqaOW3M7U+0Y4qikmG3TtRK+ngc8Ymtrjg==,
|
integrity: sha512-iW1gJyRBvwxCeBEu+ain18v8FtFBhrsqepzuUyOy7hZJWUMPdKHJhbFVz6xp3RGZf5ycsLUr3ZhqMB3vKtv7iQ==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-arm64-gnu@1.6.0":
|
"@tauri-apps/cli-linux-arm64-gnu@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-YdpY17cAySrhK9dX4BUVEmhAxE2o+6skIEFg8iN/xrDwRxhaNPI9I80YXPatUTX54Kx55T5++25VJG9+3iw83A==,
|
integrity: sha512-k1HQHpu59B8JteXALCSdCQBUVb+ytsg1u/QEWPzCm7mFhzr7jqdfBjQVAKt0T5rdQQTcNtK341oB7izuXmJE2A==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-arm64-musl@1.6.0":
|
"@tauri-apps/cli-linux-arm64-musl@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-4U628tuf2U8pMr4tIBJhEkrFwt+46dwhXrDlpdyWSZtnop5RJAVKHODm0KbWns4xGKfTW1F3r6sSv+2ZxLcISA==,
|
integrity: sha512-tMotP7J/dMqCL8zPCwtMwjeO3SK1yxU9bUMZ3mwdAtf+3xr2d2hpmGo4KXk5r2jQee9+dIC3IBXexFhrVJGRHA==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-x64-gnu@1.6.0":
|
"@tauri-apps/cli-linux-x64-gnu@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-AKRzp76fVUaJyXj5KRJT9bJyhwZyUnRQU0RqIRqOtZCT5yr6qGP8rjtQ7YhCIzWrseBlOllc3Qvbgw3Yl0VQcA==,
|
integrity: sha512-AnLghADQgt4oyp4rQyjpKfGpdAqofd+SRO9kht5d4c0RSViqwHBjIxrCt9FDhBpBwwkC6T6NNuQqaofZSnOH6Q==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-x64-musl@1.6.0":
|
"@tauri-apps/cli-linux-x64-musl@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-0edIdq6aMBTaRMIXddHfyAFL361JqulLLd2Wi2aoOie7DkQ2MYh6gv3hA7NB9gqFwNIGE+xtJ4BkXIP2tSGPlg==,
|
integrity: sha512-jv/uiXI2K41/XMA2vnKMcpdv1tKvez70HHvBoIwHhelmXV5V6Tpu5fTMEAXbA6WbJNfcFRi0kd55YRBOS0DZcw==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
"@tauri-apps/cli-win32-arm64-msvc@1.6.0":
|
"@tauri-apps/cli-win32-arm64-msvc@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-QwWpWk4ubcwJ1rljsRAmINgB2AwkyzZhpYbalA+MmzyYMREcdXWGkyixWbRZgqc6fEWEBmq5UG73qz5eBJiIKg==,
|
integrity: sha512-wctgwSfuyJ0lXBzQSzGq5TAy2m9VZichZPPJ7GitYzdHbqIRLmvxM1abRen7HikP1lpjdmjl96/kWQOebEV0qw==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
"@tauri-apps/cli-win32-ia32-msvc@1.6.0":
|
"@tauri-apps/cli-win32-ia32-msvc@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-Vtw0yxO9+aEFuhuxQ57ALG43tjECopRimRuKGbtZYDCriB/ty5TrT3QWMdy0dxBkpDTu3Rqsz30sbDzw6tlP3Q==,
|
integrity: sha512-BBjoAezNpHscGhBICHrt+X+IyJIh9jYnaEIGvbCIMcGB6sSDxvtttw4ef9+4jNh3JixotOR2mwIudTc1H9HffQ==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
"@tauri-apps/cli-win32-x64-msvc@1.6.0":
|
"@tauri-apps/cli-win32-x64-msvc@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-h54FHOvGi7+LIfRchzgZYSCHB1HDlP599vWXQQJ/XnwJY+6Rwr2E5bOe/EhqoG8rbGkfK0xX3KPAvXPbUlmggg==,
|
integrity: sha512-1pgDw2woeyDMvXctmqc53LBxsaAYqiRNUVgwvzlmzJDbUHv4+Pj4B1OGKQh1YKlsmks8LK3mK9uSbk+k1OLZhw==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
"@tauri-apps/cli@1.6.0":
|
"@tauri-apps/cli@2.0.0-rc.8":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-DBBpBl6GhTzm8ImMbKkfaZ4fDTykWrC7Q5OXP4XqD91recmDEn2LExuvuiiS3HYe7uP8Eb5B9NPHhqJb+Zo7qQ==,
|
integrity: sha512-hB6Pa0IaJs/As3Hc5IOiiK4Ilh9jspEA+2uPURCRQg4BkzQWwQzNdGQ4gjAzFNFAWPzy/4uuIXdnd1a+jC4wLA==,
|
||||||
}
|
}
|
||||||
engines: { node: ">= 10" }
|
engines: { node: ">= 10" }
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-clipboard-manager@2.0.0-rc.0":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-2fS3wbRQEtorkk3Np2msJUeKCXRqLQ9sSo2FzlFdUPYNzThsu43uWCF55McGLAfltNOvXQIcQLUBf05jbBL/5w==,
|
||||||
|
}
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-dialog@2.0.0-rc.0":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-DPOXYe8SQ6Radk/67EOdaomlxL7oF99JO/ZUaPp1IBEs3Wro7lhlz63CfdKIBfKIZTLJLzP1R7/EiPL/GTA3Bg==,
|
||||||
|
}
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-fs@2.0.0-rc.1":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-r6N5dqBNXy9YAK9XbiEqAq3ZKBIN+TWevE7ZFmSRdvdSB1urrLweYu4wxycY2kDaDPzSeeOIJhCmqdNrFT9OSA==,
|
||||||
|
}
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-global-shortcut@2.0.0-rc.0":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-rcefV4AG+vnbTtGc07hDn4Uj8u//NpuqHVg1CShACyiCS0q2sZrDVC3qPN3RGhzQyeIOPq4bY1kQRHODffKXZA==,
|
||||||
|
}
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-notification@2.0.0-rc.0":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-0qsT/kvxQ6Ky4g6eQ4SUiHXzM4szTVc6thjz9vnGPYaApLoZrCJ9GdG+vEqeB+cT2dvE+wmxUFETh3ZXYVw8UA==,
|
||||||
|
}
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-process@2.0.0-rc.0":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-Z12D/kmQzG1vCVf+jLXPhPDUA0pEjFrsg4p0uwO2sotVLM9287IuTM+aIz9cuAYOxFLKcsnDG7amSCL9IfA1gw==,
|
||||||
|
}
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-shell@2.0.0-rc.0":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-bhUcQcrqZoK8H1DFXapr5r1Z75oh6Kd5Tltz97XpZFLREEqp+KhN2Fvyh8r/fKAyenYsTYUIsDsyGdjdueuF9g==,
|
||||||
|
}
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-updater@2.0.0-rc.0":
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-EKajf/sBpFif0cwXhTo3BmNvTZ2t2DDLRyhA8FFKugZNoOeqU97bHhPT5DIqMUPRE1tyDk9o7sXm8dKf7oz+EA==,
|
||||||
|
}
|
||||||
|
|
||||||
"@types/babel__core@7.20.5":
|
"@types/babel__core@7.20.5":
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
@ -5959,50 +6030,82 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
"@tauri-apps/api@1.6.0": {}
|
"@tauri-apps/api@2.0.0-rc.4": {}
|
||||||
|
|
||||||
"@tauri-apps/cli-darwin-arm64@1.6.0":
|
"@tauri-apps/cli-darwin-arm64@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-darwin-x64@1.6.0":
|
"@tauri-apps/cli-darwin-x64@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf@1.6.0":
|
"@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-arm64-gnu@1.6.0":
|
"@tauri-apps/cli-linux-arm64-gnu@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-arm64-musl@1.6.0":
|
"@tauri-apps/cli-linux-arm64-musl@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-x64-gnu@1.6.0":
|
"@tauri-apps/cli-linux-x64-gnu@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-linux-x64-musl@1.6.0":
|
"@tauri-apps/cli-linux-x64-musl@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-win32-arm64-msvc@1.6.0":
|
"@tauri-apps/cli-win32-arm64-msvc@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-win32-ia32-msvc@1.6.0":
|
"@tauri-apps/cli-win32-ia32-msvc@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli-win32-x64-msvc@1.6.0":
|
"@tauri-apps/cli-win32-x64-msvc@2.0.0-rc.8":
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
"@tauri-apps/cli@1.6.0":
|
"@tauri-apps/cli@2.0.0-rc.8":
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@tauri-apps/cli-darwin-arm64": 1.6.0
|
"@tauri-apps/cli-darwin-arm64": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-darwin-x64": 1.6.0
|
"@tauri-apps/cli-darwin-x64": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf": 1.6.0
|
"@tauri-apps/cli-linux-arm-gnueabihf": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-linux-arm64-gnu": 1.6.0
|
"@tauri-apps/cli-linux-arm64-gnu": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-linux-arm64-musl": 1.6.0
|
"@tauri-apps/cli-linux-arm64-musl": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-linux-x64-gnu": 1.6.0
|
"@tauri-apps/cli-linux-x64-gnu": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-linux-x64-musl": 1.6.0
|
"@tauri-apps/cli-linux-x64-musl": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-win32-arm64-msvc": 1.6.0
|
"@tauri-apps/cli-win32-arm64-msvc": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-win32-ia32-msvc": 1.6.0
|
"@tauri-apps/cli-win32-ia32-msvc": 2.0.0-rc.8
|
||||||
"@tauri-apps/cli-win32-x64-msvc": 1.6.0
|
"@tauri-apps/cli-win32-x64-msvc": 2.0.0-rc.8
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-clipboard-manager@2.0.0-rc.0":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-dialog@2.0.0-rc.0":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-fs@2.0.0-rc.1":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-global-shortcut@2.0.0-rc.0":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-notification@2.0.0-rc.0":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-process@2.0.0-rc.0":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-shell@2.0.0-rc.0":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-updater@2.0.0-rc.0":
|
||||||
|
dependencies:
|
||||||
|
"@tauri-apps/api": 2.0.0-rc.4
|
||||||
|
|
||||||
"@types/babel__core@7.20.5":
|
"@types/babel__core@7.20.5":
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
2819
src-tauri/Cargo.lock
generated
2819
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,7 @@ edition = "2021"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version="1", features = [] }
|
tauri-build = { version= "2.0.0-rc", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
warp = "0.3"
|
warp = "0.3"
|
||||||
|
@ -32,13 +32,19 @@ delay_timer = "0.11"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
auto-launch = "0.5.0"
|
auto-launch = "0.5.0"
|
||||||
percent-encoding = "2.3.1"
|
percent-encoding = "2.3.1"
|
||||||
window-shadows = { version = "0.2" }
|
window-shadows = { version = "0.2.2" }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
|
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
|
||||||
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
||||||
tauri = { version="1", features = [ "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
|
tauri = { version= "2.0.0-rc", features = [ "protocol-asset", "devtools", "tray-icon", "image-ico", "image-png"] }
|
||||||
network-interface = { version = "2.0.0", features = ["serde"] }
|
network-interface = { version = "2.0.0", features = ["serde"] }
|
||||||
|
tauri-plugin-shell = "2.0.0-rc"
|
||||||
|
tauri-plugin-dialog = "2.0.0-rc"
|
||||||
|
tauri-plugin-fs = "2.0.0-rc"
|
||||||
|
tauri-plugin-notification = "2.0.0-rc"
|
||||||
|
tauri-plugin-process = "2.0.0-rc"
|
||||||
|
tauri-plugin-clipboard-manager = "2.1.0-beta.7"
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
runas = "=1.2.0"
|
runas = "=1.2.0"
|
||||||
deelevate = "0.2.0"
|
deelevate = "0.2.0"
|
||||||
|
@ -46,6 +52,10 @@ winreg = "0.52.0"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
users = "0.11.0"
|
users = "0.11.0"
|
||||||
|
|
||||||
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
|
tauri-plugin-global-shortcut = "2.0.0-rc"
|
||||||
|
tauri-plugin-updater = "2.0.0-rc"
|
||||||
#openssl
|
#openssl
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
5
src-tauri/capabilities/desktop.json
Normal file
5
src-tauri/capabilities/desktop.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"identifier": "desktop-capability",
|
||||||
|
"platforms": ["macOS", "windows", "linux"],
|
||||||
|
"permissions": ["global-shortcut:default", "updater:default"]
|
||||||
|
}
|
65
src-tauri/capabilities/migrated.json
Normal file
65
src-tauri/capabilities/migrated.json
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
"identifier": "migrated",
|
||||||
|
"description": "permissions that were migrated from v1",
|
||||||
|
"local": true,
|
||||||
|
"windows": ["main"],
|
||||||
|
"permissions": [
|
||||||
|
"core:default",
|
||||||
|
"fs:allow-read-file",
|
||||||
|
"fs:allow-exists",
|
||||||
|
{
|
||||||
|
"identifier": "fs:scope",
|
||||||
|
"allow": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
||||||
|
},
|
||||||
|
"core:window:allow-create",
|
||||||
|
"core:window:allow-center",
|
||||||
|
"core:window:allow-request-user-attention",
|
||||||
|
"core:window:allow-set-resizable",
|
||||||
|
"core:window:allow-set-maximizable",
|
||||||
|
"core:window:allow-set-minimizable",
|
||||||
|
"core:window:allow-set-closable",
|
||||||
|
"core:window:allow-set-title",
|
||||||
|
"core:window:allow-maximize",
|
||||||
|
"core:window:allow-unmaximize",
|
||||||
|
"core:window:allow-minimize",
|
||||||
|
"core:window:allow-unminimize",
|
||||||
|
"core:window:allow-show",
|
||||||
|
"core:window:allow-hide",
|
||||||
|
"core:window:allow-close",
|
||||||
|
"core:window:allow-set-decorations",
|
||||||
|
"core:window:allow-set-always-on-top",
|
||||||
|
"core:window:allow-set-content-protected",
|
||||||
|
"core:window:allow-set-size",
|
||||||
|
"core:window:allow-set-min-size",
|
||||||
|
"core:window:allow-set-max-size",
|
||||||
|
"core:window:allow-set-position",
|
||||||
|
"core:window:allow-set-fullscreen",
|
||||||
|
"core:window:allow-set-focus",
|
||||||
|
"core:window:allow-set-icon",
|
||||||
|
"core:window:allow-set-skip-taskbar",
|
||||||
|
"core:window:allow-set-cursor-grab",
|
||||||
|
"core:window:allow-set-cursor-visible",
|
||||||
|
"core:window:allow-set-cursor-icon",
|
||||||
|
"core:window:allow-set-cursor-position",
|
||||||
|
"core:window:allow-set-ignore-cursor-events",
|
||||||
|
"core:window:allow-start-dragging",
|
||||||
|
"core:webview:allow-print",
|
||||||
|
"shell:allow-execute",
|
||||||
|
"shell:allow-open",
|
||||||
|
"dialog:allow-open",
|
||||||
|
"notification:default",
|
||||||
|
"global-shortcut:allow-is-registered",
|
||||||
|
"global-shortcut:allow-register",
|
||||||
|
"global-shortcut:allow-register-all",
|
||||||
|
"global-shortcut:allow-unregister",
|
||||||
|
"global-shortcut:allow-unregister-all",
|
||||||
|
"process:allow-restart",
|
||||||
|
"process:allow-exit",
|
||||||
|
"clipboard-manager:allow-read-text",
|
||||||
|
"clipboard-manager:allow-write-text",
|
||||||
|
"shell:default",
|
||||||
|
"dialog:default",
|
||||||
|
"fs:default",
|
||||||
|
"notification:default"
|
||||||
|
]
|
||||||
|
}
|
3811
src-tauri/gen/schemas/acl-manifests.json
Normal file
3811
src-tauri/gen/schemas/acl-manifests.json
Normal file
File diff suppressed because it is too large
Load Diff
74
src-tauri/gen/schemas/capabilities.json
Normal file
74
src-tauri/gen/schemas/capabilities.json
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
{
|
||||||
|
"desktop-capability": {
|
||||||
|
"identifier": "desktop-capability",
|
||||||
|
"description": "",
|
||||||
|
"local": true,
|
||||||
|
"permissions": ["global-shortcut:default", "updater:default"],
|
||||||
|
"platforms": ["macOS", "windows", "linux"]
|
||||||
|
},
|
||||||
|
"migrated": {
|
||||||
|
"identifier": "migrated",
|
||||||
|
"description": "permissions that were migrated from v1",
|
||||||
|
"local": true,
|
||||||
|
"windows": ["main"],
|
||||||
|
"permissions": [
|
||||||
|
"core:default",
|
||||||
|
"fs:allow-read-file",
|
||||||
|
"fs:allow-exists",
|
||||||
|
{
|
||||||
|
"identifier": "fs:scope",
|
||||||
|
"allow": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
||||||
|
},
|
||||||
|
"core:window:allow-create",
|
||||||
|
"core:window:allow-center",
|
||||||
|
"core:window:allow-request-user-attention",
|
||||||
|
"core:window:allow-set-resizable",
|
||||||
|
"core:window:allow-set-maximizable",
|
||||||
|
"core:window:allow-set-minimizable",
|
||||||
|
"core:window:allow-set-closable",
|
||||||
|
"core:window:allow-set-title",
|
||||||
|
"core:window:allow-maximize",
|
||||||
|
"core:window:allow-unmaximize",
|
||||||
|
"core:window:allow-minimize",
|
||||||
|
"core:window:allow-unminimize",
|
||||||
|
"core:window:allow-show",
|
||||||
|
"core:window:allow-hide",
|
||||||
|
"core:window:allow-close",
|
||||||
|
"core:window:allow-set-decorations",
|
||||||
|
"core:window:allow-set-always-on-top",
|
||||||
|
"core:window:allow-set-content-protected",
|
||||||
|
"core:window:allow-set-size",
|
||||||
|
"core:window:allow-set-min-size",
|
||||||
|
"core:window:allow-set-max-size",
|
||||||
|
"core:window:allow-set-position",
|
||||||
|
"core:window:allow-set-fullscreen",
|
||||||
|
"core:window:allow-set-focus",
|
||||||
|
"core:window:allow-set-icon",
|
||||||
|
"core:window:allow-set-skip-taskbar",
|
||||||
|
"core:window:allow-set-cursor-grab",
|
||||||
|
"core:window:allow-set-cursor-visible",
|
||||||
|
"core:window:allow-set-cursor-icon",
|
||||||
|
"core:window:allow-set-cursor-position",
|
||||||
|
"core:window:allow-set-ignore-cursor-events",
|
||||||
|
"core:window:allow-start-dragging",
|
||||||
|
"core:webview:allow-print",
|
||||||
|
"shell:allow-execute",
|
||||||
|
"shell:allow-open",
|
||||||
|
"dialog:allow-open",
|
||||||
|
"notification:default",
|
||||||
|
"global-shortcut:allow-is-registered",
|
||||||
|
"global-shortcut:allow-register",
|
||||||
|
"global-shortcut:allow-register-all",
|
||||||
|
"global-shortcut:allow-unregister",
|
||||||
|
"global-shortcut:allow-unregister-all",
|
||||||
|
"process:allow-restart",
|
||||||
|
"process:allow-exit",
|
||||||
|
"clipboard-manager:allow-read-text",
|
||||||
|
"clipboard-manager:allow-write-text",
|
||||||
|
"shell:default",
|
||||||
|
"dialog:default",
|
||||||
|
"fs:default",
|
||||||
|
"notification:default"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
5171
src-tauri/gen/schemas/desktop-schema.json
Normal file
5171
src-tauri/gen/schemas/desktop-schema.json
Normal file
File diff suppressed because it is too large
Load Diff
5171
src-tauri/gen/schemas/macOS-schema.json
Normal file
5171
src-tauri/gen/schemas/macOS-schema.json
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -10,8 +10,8 @@ use network_interface::NetworkInterface;
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use sysproxy::{Autoproxy, Sysproxy};
|
use sysproxy::{Autoproxy, Sysproxy};
|
||||||
use tauri::{api, Manager};
|
|
||||||
type CmdResult<T = ()> = Result<T, String>;
|
type CmdResult<T = ()> = Result<T, String>;
|
||||||
|
use tauri::Manager;
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn copy_clash_env(app_handle: tauri::AppHandle) -> CmdResult {
|
pub fn copy_clash_env(app_handle: tauri::AppHandle) -> CmdResult {
|
||||||
|
@ -361,7 +361,7 @@ pub fn get_network_interfaces_info() -> CmdResult<Vec<NetworkInterface>> {
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn open_devtools(app_handle: tauri::AppHandle) {
|
pub fn open_devtools(app_handle: tauri::AppHandle) {
|
||||||
if let Some(window) = app_handle.get_window("main") {
|
if let Some(window) = app_handle.get_webview_window("main") {
|
||||||
if !window.is_devtools_open() {
|
if !window.is_devtools_open() {
|
||||||
window.open_devtools();
|
window.open_devtools();
|
||||||
} else {
|
} else {
|
||||||
|
@ -374,7 +374,6 @@ pub fn open_devtools(app_handle: tauri::AppHandle) {
|
||||||
pub fn exit_app(app_handle: tauri::AppHandle) {
|
pub fn exit_app(app_handle: tauri::AppHandle) {
|
||||||
let _ = resolve::save_window_size_position(&app_handle, true);
|
let _ = resolve::save_window_size_position(&app_handle, true);
|
||||||
resolve::resolve_reset();
|
resolve::resolve_reset();
|
||||||
api::process::kill_children();
|
|
||||||
app_handle.exit(0);
|
app_handle.exit(0);
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,22 @@ use crate::config::*;
|
||||||
use crate::core::{clash_api, handle, logger::Logger, service};
|
use crate::core::{clash_api, handle, logger::Logger, service};
|
||||||
use crate::log_err;
|
use crate::log_err;
|
||||||
use crate::utils::dirs;
|
use crate::utils::dirs;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{fs, io::Write, sync::Arc, time::Duration};
|
||||||
use sysinfo::{ProcessRefreshKind, RefreshKind, System};
|
use sysinfo::{ProcessRefreshKind, RefreshKind, System};
|
||||||
use tauri::api::process::{Command, CommandChild, CommandEvent};
|
use tauri::AppHandle;
|
||||||
|
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
||||||
|
use tauri_plugin_shell::ShellExt;
|
||||||
|
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CoreManager {
|
pub struct CoreManager {
|
||||||
|
app_handle: Arc<Mutex<Option<AppHandle>>>,
|
||||||
sidecar: Arc<Mutex<Option<CommandChild>>>,
|
sidecar: Arc<Mutex<Option<CommandChild>>>,
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use_service_mode: Arc<Mutex<bool>>,
|
use_service_mode: Arc<Mutex<bool>>,
|
||||||
}
|
}
|
||||||
|
@ -24,12 +27,14 @@ impl CoreManager {
|
||||||
static CORE_MANAGER: OnceCell<CoreManager> = OnceCell::new();
|
static CORE_MANAGER: OnceCell<CoreManager> = OnceCell::new();
|
||||||
|
|
||||||
CORE_MANAGER.get_or_init(|| CoreManager {
|
CORE_MANAGER.get_or_init(|| CoreManager {
|
||||||
|
app_handle: Arc::new(Mutex::new(None)),
|
||||||
sidecar: Arc::new(Mutex::new(None)),
|
sidecar: Arc::new(Mutex::new(None)),
|
||||||
use_service_mode: Arc::new(Mutex::new(false)),
|
use_service_mode: Arc::new(Mutex::new(false)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self) -> Result<()> {
|
pub fn init(&self, app_handle: &AppHandle) -> Result<()> {
|
||||||
|
*self.app_handle.lock() = Some(app_handle.clone());
|
||||||
tauri::async_runtime::spawn(async {
|
tauri::async_runtime::spawn(async {
|
||||||
// 启动clash
|
// 启动clash
|
||||||
log_err!(Self::global().run_core().await);
|
log_err!(Self::global().run_core().await);
|
||||||
|
@ -39,7 +44,7 @@ impl CoreManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 检查订阅是否正确
|
/// 检查订阅是否正确
|
||||||
pub fn check_config(&self) -> Result<()> {
|
pub async fn check_config(&self) -> Result<()> {
|
||||||
let config_path = Config::generate_file(ConfigType::Check)?;
|
let config_path = Config::generate_file(ConfigType::Check)?;
|
||||||
let config_path = dirs::path_to_str(&config_path)?;
|
let config_path = dirs::path_to_str(&config_path)?;
|
||||||
|
|
||||||
|
@ -62,19 +67,29 @@ impl CoreManager {
|
||||||
|
|
||||||
let test_dir = dirs::app_home_dir()?.join("test");
|
let test_dir = dirs::app_home_dir()?.join("test");
|
||||||
let test_dir = dirs::path_to_str(&test_dir)?;
|
let test_dir = dirs::path_to_str(&test_dir)?;
|
||||||
|
let app_handle_option = {
|
||||||
|
let lock = self.app_handle.lock();
|
||||||
|
lock.as_ref().cloned()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(app_handle) = app_handle_option {
|
||||||
|
let output = app_handle
|
||||||
|
.shell()
|
||||||
|
.sidecar(clash_core)?
|
||||||
|
.args(["-t", "-d", test_dir, "-f", config_path])
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
|
||||||
let output = Command::new_sidecar(clash_core)?
|
if !output.status.success() {
|
||||||
.args(["-t", "-d", test_dir, "-f", config_path])
|
let stdout = String::from_utf8(output.stdout).unwrap_or_default();
|
||||||
.output()?;
|
let error = clash_api::parse_check_output(stdout.clone());
|
||||||
|
let error = match !error.is_empty() {
|
||||||
if !output.status.success() {
|
true => error,
|
||||||
let error = clash_api::parse_check_output(output.stdout.clone());
|
false => stdout.clone(),
|
||||||
let error = match !error.is_empty() {
|
};
|
||||||
true => error,
|
Logger::global().set_log(stdout.clone());
|
||||||
false => output.stdout.clone(),
|
bail!("{error}");
|
||||||
};
|
}
|
||||||
Logger::global().set_log(output.stdout);
|
|
||||||
bail!("{error}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -156,37 +171,54 @@ impl CoreManager {
|
||||||
|
|
||||||
let args = vec!["-d", app_dir, "-f", config_path];
|
let args = vec!["-d", app_dir, "-f", config_path];
|
||||||
|
|
||||||
let cmd = Command::new_sidecar(clash_core)?;
|
let app_handle = self.app_handle.lock();
|
||||||
let (mut rx, cmd_child) = cmd.args(args).spawn()?;
|
|
||||||
|
|
||||||
let mut sidecar = self.sidecar.lock();
|
if let Some(app_handle) = app_handle.as_ref() {
|
||||||
*sidecar = Some(cmd_child);
|
let cmd = app_handle.shell().sidecar(clash_core)?;
|
||||||
drop(sidecar);
|
let (mut rx, cmd_child) = cmd.args(args).spawn()?;
|
||||||
|
|
||||||
tauri::async_runtime::spawn(async move {
|
// 将pid写入文件中
|
||||||
while let Some(event) = rx.recv().await {
|
crate::log_err!((|| {
|
||||||
match event {
|
let pid = cmd_child.pid();
|
||||||
CommandEvent::Stdout(line) => {
|
let path = dirs::clash_pid_path()?;
|
||||||
log::info!(target: "app", "[mihomo]: {line}");
|
fs::File::create(path)
|
||||||
Logger::global().set_log(line);
|
.context("failed to create the pid file")?
|
||||||
|
.write(format!("{pid}").as_bytes())
|
||||||
|
.context("failed to write pid to the file")?;
|
||||||
|
<Result<()>>::Ok(())
|
||||||
|
})());
|
||||||
|
|
||||||
|
let mut sidecar = self.sidecar.lock();
|
||||||
|
*sidecar = Some(cmd_child);
|
||||||
|
drop(sidecar);
|
||||||
|
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
while let Some(event) = rx.recv().await {
|
||||||
|
match event {
|
||||||
|
CommandEvent::Stdout(line) => {
|
||||||
|
let line = String::from_utf8(line).unwrap_or_default();
|
||||||
|
log::info!(target: "app", "[mihomo]: {line}");
|
||||||
|
Logger::global().set_log(line);
|
||||||
|
}
|
||||||
|
CommandEvent::Stderr(err) => {
|
||||||
|
let err = String::from_utf8(err).unwrap_or_default();
|
||||||
|
log::error!(target: "app", "[mihomo]: {err}");
|
||||||
|
Logger::global().set_log(err);
|
||||||
|
}
|
||||||
|
CommandEvent::Error(err) => {
|
||||||
|
log::error!(target: "app", "[mihomo]: {err}");
|
||||||
|
Logger::global().set_log(err);
|
||||||
|
}
|
||||||
|
CommandEvent::Terminated(_) => {
|
||||||
|
log::info!(target: "app", "mihomo core terminated");
|
||||||
|
let _ = CoreManager::global().recover_core();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
CommandEvent::Stderr(err) => {
|
|
||||||
log::error!(target: "app", "[mihomo]: {err}");
|
|
||||||
Logger::global().set_log(err);
|
|
||||||
}
|
|
||||||
CommandEvent::Error(err) => {
|
|
||||||
log::error!(target: "app", "[mihomo]: {err}");
|
|
||||||
Logger::global().set_log(err);
|
|
||||||
}
|
|
||||||
CommandEvent::Terminated(_) => {
|
|
||||||
log::info!(target: "app", "mihomo core terminated");
|
|
||||||
let _ = CoreManager::global().recover_core();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -268,7 +300,7 @@ impl CoreManager {
|
||||||
// 更新订阅
|
// 更新订阅
|
||||||
Config::generate().await?;
|
Config::generate().await?;
|
||||||
|
|
||||||
self.check_config()?;
|
self.check_config().await?;
|
||||||
|
|
||||||
// 清掉旧日志
|
// 清掉旧日志
|
||||||
Logger::global().clear_log();
|
Logger::global().clear_log();
|
||||||
|
@ -296,7 +328,7 @@ impl CoreManager {
|
||||||
Config::generate().await?;
|
Config::generate().await?;
|
||||||
|
|
||||||
// 检查订阅是否正常
|
// 检查订阅是否正常
|
||||||
self.check_config()?;
|
self.check_config().await?;
|
||||||
|
|
||||||
// 更新运行时订阅
|
// 更新运行时订阅
|
||||||
let path = Config::generate_file(ConfigType::Run)?;
|
let path = Config::generate_file(ConfigType::Run)?;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::{bail, Result};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tauri::{AppHandle, Manager, Window};
|
use tauri::{AppHandle, WebviewWindow, Manager, Emitter};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct Handle {
|
pub struct Handle {
|
||||||
|
@ -20,15 +20,15 @@ impl Handle {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self, app_handle: AppHandle) {
|
pub fn init(&self, app_handle: &AppHandle) {
|
||||||
*self.app_handle.lock() = Some(app_handle);
|
*self.app_handle.lock() = Some(app_handle.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_window(&self) -> Option<Window> {
|
pub fn get_window(&self) -> Option<WebviewWindow> {
|
||||||
self.app_handle
|
self.app_handle
|
||||||
.lock()
|
.lock()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|a| a.get_window("main"))
|
.and_then(|a| a.get_webview_window("main"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_clash() {
|
pub fn refresh_clash() {
|
||||||
|
|
|
@ -3,11 +3,11 @@ use anyhow::{bail, Result};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
use tauri::{AppHandle, GlobalShortcutManager};
|
use tauri::AppHandle;
|
||||||
|
use tauri_plugin_global_shortcut::GlobalShortcutExt;
|
||||||
|
|
||||||
pub struct Hotkey {
|
pub struct Hotkey {
|
||||||
current: Arc<Mutex<Vec<String>>>, // 保存当前的热键设置
|
current: Arc<Mutex<Vec<String>>>, // 保存当前的热键设置
|
||||||
|
|
||||||
app_handle: Arc<Mutex<Option<AppHandle>>>,
|
app_handle: Arc<Mutex<Option<AppHandle>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,8 @@ impl Hotkey {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self, app_handle: AppHandle) -> Result<()> {
|
pub fn init(&self, app_handle: &AppHandle) -> Result<()> {
|
||||||
*self.app_handle.lock() = Some(app_handle);
|
*self.app_handle.lock() = Some(app_handle.clone());
|
||||||
|
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
|
|
||||||
if let Some(hotkeys) = verge.latest().hotkeys.as_ref() {
|
if let Some(hotkeys) = verge.latest().hotkeys.as_ref() {
|
||||||
|
@ -49,18 +48,14 @@ impl Hotkey {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_manager(&self) -> Result<impl GlobalShortcutManager> {
|
fn register(&self, hotkey: &str, func: &str) -> Result<()> {
|
||||||
let app_handle = self.app_handle.lock();
|
let app_handle = self.app_handle.lock();
|
||||||
if app_handle.is_none() {
|
if app_handle.is_none() {
|
||||||
bail!("failed to get the hotkey manager");
|
bail!("failed to get the hotkey manager");
|
||||||
}
|
}
|
||||||
Ok(app_handle.as_ref().unwrap().global_shortcut_manager())
|
let manager = app_handle.as_ref().unwrap().global_shortcut();
|
||||||
}
|
|
||||||
|
|
||||||
fn register(&self, hotkey: &str, func: &str) -> Result<()> {
|
if manager.is_registered(hotkey) {
|
||||||
let mut manager = self.get_manager()?;
|
|
||||||
|
|
||||||
if manager.is_registered(hotkey)? {
|
|
||||||
manager.unregister(hotkey)?;
|
manager.unregister(hotkey)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,17 +66,22 @@ impl Hotkey {
|
||||||
"clash_mode_direct" => || feat::change_clash_mode("direct".into()),
|
"clash_mode_direct" => || feat::change_clash_mode("direct".into()),
|
||||||
"toggle_system_proxy" => feat::toggle_system_proxy,
|
"toggle_system_proxy" => feat::toggle_system_proxy,
|
||||||
"toggle_tun_mode" => feat::toggle_tun_mode,
|
"toggle_tun_mode" => feat::toggle_tun_mode,
|
||||||
|
|
||||||
_ => bail!("invalid function \"{func}\""),
|
_ => bail!("invalid function \"{func}\""),
|
||||||
};
|
};
|
||||||
|
|
||||||
manager.register(hotkey, f)?;
|
let _ = manager.on_shortcut(hotkey, move |_, _, _| f());
|
||||||
log::info!(target: "app", "register hotkey {hotkey} {func}");
|
log::info!(target: "app", "register hotkey {hotkey} {func}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unregister(&self, hotkey: &str) -> Result<()> {
|
fn unregister(&self, hotkey: &str) -> Result<()> {
|
||||||
self.get_manager()?.unregister(hotkey)?;
|
let app_handle = self.app_handle.lock();
|
||||||
|
if app_handle.is_none() {
|
||||||
|
bail!("failed to get the hotkey manager");
|
||||||
|
}
|
||||||
|
let manager = app_handle.as_ref().unwrap().global_shortcut();
|
||||||
|
manager.unregister(hotkey)?;
|
||||||
|
|
||||||
log::info!(target: "app", "unregister hotkey {hotkey}");
|
log::info!(target: "app", "unregister hotkey {hotkey}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -153,8 +153,10 @@ impl Hotkey {
|
||||||
|
|
||||||
impl Drop for Hotkey {
|
impl Drop for Hotkey {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Ok(mut manager) = self.get_manager() {
|
if let Some(app_handle) = self.app_handle.lock().as_ref() {
|
||||||
let _ = manager.unregister_all();
|
if let Err(e) = app_handle.global_shortcut().unregister_all() {
|
||||||
|
log::error!("Error unregistering all hotkeys: {:?}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,14 @@ use crate::{
|
||||||
utils::{dirs, resolve},
|
utils::{dirs, resolve},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tauri::{
|
use tauri::menu::{MenuBuilder, MenuEvent, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder};
|
||||||
api, AppHandle, CustomMenuItem, Manager, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
|
use tauri::tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder, TrayIconEvent};
|
||||||
SystemTraySubmenu,
|
use tauri::{AppHandle, Manager};
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Tray {}
|
pub struct Tray {}
|
||||||
|
|
||||||
impl Tray {
|
impl Tray {
|
||||||
pub fn tray_menu(app_handle: &AppHandle) -> SystemTrayMenu {
|
pub fn update_systray(app_handle: &AppHandle) -> Result<()> {
|
||||||
let zh = { Config::verge().latest().language == Some("zh".into()) };
|
let zh = { Config::verge().latest().language == Some("zh".into()) };
|
||||||
|
|
||||||
let version = app_handle.package_info().version.to_string();
|
|
||||||
|
|
||||||
macro_rules! t {
|
macro_rules! t {
|
||||||
($en: expr, $zh: expr) => {
|
($en: expr, $zh: expr) => {
|
||||||
if zh {
|
if zh {
|
||||||
|
@ -28,80 +23,92 @@ impl Tray {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemTrayMenu::new()
|
let version = app_handle.package_info().version.to_string();
|
||||||
.add_item(CustomMenuItem::new(
|
|
||||||
"open_window",
|
let open_window = MenuItemBuilder::with_id("open_window", t!("Dashboard", "打开面板"))
|
||||||
t!("Dashboard", "打开面板"),
|
.build(app_handle)?;
|
||||||
))
|
let rule_mode =
|
||||||
.add_native_item(SystemTrayMenuItem::Separator)
|
MenuItemBuilder::with_id("rule_mode", t!("Rule Mode", "规则模式")).build(app_handle)?;
|
||||||
.add_item(CustomMenuItem::new(
|
let global_mode = MenuItemBuilder::with_id("global_mode", t!("Global Mode", "全局模式"))
|
||||||
"rule_mode",
|
.build(app_handle)?;
|
||||||
t!("Rule Mode", "规则模式"),
|
let direct_mode = MenuItemBuilder::with_id("direct_mode", t!("Direct Mode", "直连模式"))
|
||||||
))
|
.build(app_handle)?;
|
||||||
.add_item(CustomMenuItem::new(
|
let system_proxy = MenuItemBuilder::with_id("system_proxy", t!("System Proxy", "系统代理"))
|
||||||
"global_mode",
|
.build(app_handle)?;
|
||||||
t!("Global Mode", "全局模式"),
|
let tun_mode =
|
||||||
))
|
MenuItemBuilder::with_id("tun_mode", t!("TUN Mode", "Tun 模式")).build(app_handle)?;
|
||||||
.add_item(CustomMenuItem::new(
|
let copy_env = MenuItemBuilder::with_id("copy_env", t!("Copy Env", "复制环境变量"))
|
||||||
"direct_mode",
|
.build(app_handle)?;
|
||||||
t!("Direct Mode", "直连模式"),
|
let open_app_dir = MenuItemBuilder::with_id("open_app_dir", t!("App Dir", "应用目录"))
|
||||||
))
|
.build(app_handle)?;
|
||||||
.add_native_item(SystemTrayMenuItem::Separator)
|
let open_core_dir = MenuItemBuilder::with_id("open_core_dir", t!("Core Dir", "内核目录"))
|
||||||
.add_item(CustomMenuItem::new(
|
.build(app_handle)?;
|
||||||
"system_proxy",
|
let open_logs_dir = MenuItemBuilder::with_id("open_logs_dir", t!("Logs Dir", "日志目录"))
|
||||||
t!("System Proxy", "系统代理"),
|
.build(app_handle)?;
|
||||||
))
|
let open_dir = SubmenuBuilder::with_id(app_handle, "open_dir", t!("Open Dir", "打开目录"))
|
||||||
.add_item(CustomMenuItem::new("tun_mode", t!("TUN Mode", "Tun 模式")))
|
.items(&[&open_app_dir, &open_core_dir, &open_logs_dir])
|
||||||
.add_item(CustomMenuItem::new(
|
.build()?;
|
||||||
"copy_env",
|
let restart_clash =
|
||||||
t!("Copy Env", "复制环境变量"),
|
MenuItemBuilder::with_id("restart_clash", t!("Restart Clash", "重启 Clash"))
|
||||||
))
|
.build(app_handle)?;
|
||||||
.add_submenu(SystemTraySubmenu::new(
|
let restart_app = MenuItemBuilder::with_id("restart_app", t!("Restart App", "重启应用"))
|
||||||
t!("Open Dir", "打开目录"),
|
.build(app_handle)?;
|
||||||
SystemTrayMenu::new()
|
let app_version = MenuItemBuilder::with_id("app_version", format!("Version {version}"))
|
||||||
.add_item(CustomMenuItem::new(
|
.build(app_handle)?;
|
||||||
"open_app_dir",
|
let more = SubmenuBuilder::with_id(app_handle, "more", t!("More", "更多"))
|
||||||
t!("App Dir", "应用目录"),
|
.items(&[&restart_clash, &restart_app, &app_version])
|
||||||
))
|
.build()?;
|
||||||
.add_item(CustomMenuItem::new(
|
let quit = MenuItemBuilder::with_id("quit", t!("Quit", "退出"))
|
||||||
"open_core_dir",
|
.accelerator("CmdOrControl+Q")
|
||||||
t!("Core Dir", "内核目录"),
|
.build(app_handle)?;
|
||||||
))
|
let separator = PredefinedMenuItem::separator(app_handle)?;
|
||||||
.add_item(CustomMenuItem::new(
|
let menu = MenuBuilder::new(app_handle)
|
||||||
"open_logs_dir",
|
.items(&[
|
||||||
t!("Logs Dir", "日志目录"),
|
&open_window,
|
||||||
)),
|
&separator,
|
||||||
))
|
&rule_mode,
|
||||||
.add_submenu(SystemTraySubmenu::new(
|
&global_mode,
|
||||||
t!("More", "更多"),
|
&direct_mode,
|
||||||
SystemTrayMenu::new()
|
&separator,
|
||||||
.add_item(CustomMenuItem::new(
|
&system_proxy,
|
||||||
"restart_clash",
|
&tun_mode,
|
||||||
t!("Restart Clash", "重启 Clash"),
|
©_env,
|
||||||
))
|
&open_dir,
|
||||||
.add_item(CustomMenuItem::new(
|
&more,
|
||||||
"restart_app",
|
&separator,
|
||||||
t!("Restart App", "重启应用"),
|
&quit,
|
||||||
))
|
])
|
||||||
.add_item(
|
.build()?;
|
||||||
CustomMenuItem::new("app_version", format!("Version {version}")).disabled(),
|
|
||||||
),
|
let _ = TrayIconBuilder::with_id("verge_tray")
|
||||||
))
|
.menu(&menu)
|
||||||
.add_native_item(SystemTrayMenuItem::Separator)
|
.on_menu_event(Self::on_menu_event)
|
||||||
.add_item(CustomMenuItem::new("quit", t!("Quit", "退出")))
|
.on_tray_icon_event(|tray, event| {
|
||||||
}
|
let tray_event = { Config::verge().latest().tray_event.clone() };
|
||||||
|
let tray_event: String = tray_event.unwrap_or("main_window".into());
|
||||||
|
if let TrayIconEvent::Click {
|
||||||
|
button: MouseButton::Left,
|
||||||
|
button_state: MouseButtonState::Up,
|
||||||
|
..
|
||||||
|
} = event
|
||||||
|
{
|
||||||
|
let app = tray.app_handle();
|
||||||
|
match tray_event.as_str() {
|
||||||
|
"system_proxy" => feat::toggle_system_proxy(),
|
||||||
|
"tun_mode" => feat::toggle_tun_mode(),
|
||||||
|
"main_window" => resolve::create_window(app),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build(app_handle);
|
||||||
|
|
||||||
pub fn update_systray(app_handle: &AppHandle) -> Result<()> {
|
|
||||||
app_handle
|
|
||||||
.tray_handle()
|
|
||||||
.set_menu(Tray::tray_menu(app_handle))?;
|
|
||||||
Tray::update_part(app_handle)?;
|
Tray::update_part(app_handle)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_part(app_handle: &AppHandle) -> Result<()> {
|
pub fn update_part(app_handle: &AppHandle) -> Result<()> {
|
||||||
let zh = { Config::verge().latest().language == Some("zh".into()) };
|
let zh = { Config::verge().latest().language == Some("zh".into()) };
|
||||||
|
|
||||||
let version = app_handle.package_info().version.to_string();
|
let version = app_handle.package_info().version.to_string();
|
||||||
|
|
||||||
macro_rules! t {
|
macro_rules! t {
|
||||||
|
@ -124,225 +131,263 @@ impl Tray {
|
||||||
.to_owned()
|
.to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let tray = app_handle.tray_handle();
|
if let Some(menu) = app_handle.menu() {
|
||||||
|
if let Some(item) = menu.get("rule_mode") {
|
||||||
|
let item = item.as_check_menuitem().unwrap();
|
||||||
|
let _ = item.set_checked(mode == "rule");
|
||||||
|
}
|
||||||
|
if let Some(item) = menu.get("global_mode") {
|
||||||
|
let item = item.as_check_menuitem().unwrap();
|
||||||
|
let _ = item.set_checked(mode == "global");
|
||||||
|
}
|
||||||
|
if let Some(item) = menu.get("direct_mode") {
|
||||||
|
let item = item.as_check_menuitem().unwrap();
|
||||||
|
let _ = item.set_checked(mode == "direct");
|
||||||
|
}
|
||||||
|
|
||||||
let _ = tray.get_item("rule_mode").set_selected(mode == "rule");
|
#[cfg(target_os = "linux")]
|
||||||
let _ = tray.get_item("global_mode").set_selected(mode == "global");
|
match mode.as_str() {
|
||||||
let _ = tray.get_item("direct_mode").set_selected(mode == "direct");
|
"rule" => {
|
||||||
|
if let Some(item) = menu.get("rule_mode") {
|
||||||
|
let _ = item
|
||||||
|
.as_menuitem()
|
||||||
|
.unwrap()
|
||||||
|
.set_text(t!("Rule Mode ✔", "规则模式 ✔"));
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
if let Some(item) = menu.get("global_mode") {
|
||||||
match mode.as_str() {
|
let _ = item
|
||||||
"rule" => {
|
.as_menuitem()
|
||||||
let _ = tray
|
.unwrap()
|
||||||
.get_item("rule_mode")
|
.set_text(t!("Global Mode", "全局模式"));
|
||||||
.set_title(t!("Rule Mode ✔", "规则模式 ✔"));
|
}
|
||||||
let _ = tray
|
|
||||||
.get_item("global_mode")
|
|
||||||
.set_title(t!("Global Mode", "全局模式"));
|
|
||||||
let _ = tray
|
|
||||||
.get_item("direct_mode")
|
|
||||||
.set_title(t!("Direct Mode", "直连模式"));
|
|
||||||
}
|
|
||||||
"global" => {
|
|
||||||
let _ = tray
|
|
||||||
.get_item("rule_mode")
|
|
||||||
.set_title(t!("Rule Mode", "规则模式"));
|
|
||||||
let _ = tray
|
|
||||||
.get_item("global_mode")
|
|
||||||
.set_title(t!("Global Mode ✔", "全局模式 ✔"));
|
|
||||||
let _ = tray
|
|
||||||
.get_item("direct_mode")
|
|
||||||
.set_title(t!("Direct Mode", "直连模式"));
|
|
||||||
}
|
|
||||||
"direct" => {
|
|
||||||
let _ = tray
|
|
||||||
.get_item("rule_mode")
|
|
||||||
.set_title(t!("Rule Mode", "规则模式"));
|
|
||||||
let _ = tray
|
|
||||||
.get_item("global_mode")
|
|
||||||
.set_title(t!("Global Mode", "全局模式"));
|
|
||||||
let _ = tray
|
|
||||||
.get_item("direct_mode")
|
|
||||||
.set_title(t!("Direct Mode ✔", "直连模式 ✔"));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let verge = Config::verge();
|
if let Some(item) = menu.get("direct_mode") {
|
||||||
let verge = verge.latest();
|
let _ = item
|
||||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
.as_menuitem()
|
||||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
.unwrap()
|
||||||
#[cfg(target_os = "macos")]
|
.set_text(t!("Direct Mode", "直连模式"));
|
||||||
let tray_icon = verge.tray_icon.clone().unwrap_or("monochrome".to_string());
|
}
|
||||||
let common_tray_icon = verge.common_tray_icon.as_ref().unwrap_or(&false);
|
|
||||||
let sysproxy_tray_icon = verge.sysproxy_tray_icon.as_ref().unwrap_or(&false);
|
|
||||||
let tun_tray_icon = verge.tun_tray_icon.as_ref().unwrap_or(&false);
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
match tray_icon.as_str() {
|
|
||||||
"monochrome" => {
|
|
||||||
let _ = tray.set_icon_as_template(true);
|
|
||||||
}
|
|
||||||
"colorful" => {
|
|
||||||
let _ = tray.set_icon_as_template(false);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
let mut indication_icon = if *system_proxy {
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
let mut icon = match tray_icon.as_str() {
|
|
||||||
"monochrome" => include_bytes!("../../icons/tray-icon-sys-mono.ico").to_vec(),
|
|
||||||
"colorful" => include_bytes!("../../icons/tray-icon-sys.ico").to_vec(),
|
|
||||||
_ => include_bytes!("../../icons/tray-icon-sys-mono.ico").to_vec(),
|
|
||||||
};
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
let mut icon = include_bytes!("../../icons/tray-icon-sys.ico").to_vec();
|
|
||||||
|
|
||||||
if *sysproxy_tray_icon {
|
|
||||||
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
|
||||||
let png_path = icon_dir_path.join("sysproxy.png");
|
|
||||||
let ico_path = icon_dir_path.join("sysproxy.ico");
|
|
||||||
if ico_path.exists() {
|
|
||||||
icon = std::fs::read(ico_path).unwrap();
|
|
||||||
} else if png_path.exists() {
|
|
||||||
icon = std::fs::read(png_path).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
"global" => {
|
||||||
icon
|
if let Some(item) = menu.get("rule_mode") {
|
||||||
} else {
|
let _ = item
|
||||||
#[cfg(target_os = "macos")]
|
.as_menuitem()
|
||||||
let mut icon = match tray_icon.as_str() {
|
.unwrap()
|
||||||
"monochrome" => include_bytes!("../../icons/tray-icon-mono.ico").to_vec(),
|
.set_text(t!("Rule Mode", "规则模式"));
|
||||||
"colorful" => include_bytes!("../../icons/tray-icon.ico").to_vec(),
|
}
|
||||||
_ => include_bytes!("../../icons/tray-icon-mono.ico").to_vec(),
|
|
||||||
};
|
if let Some(item) = menu.get("global_mode") {
|
||||||
#[cfg(not(target_os = "macos"))]
|
let _ = item
|
||||||
let mut icon = include_bytes!("../../icons/tray-icon.ico").to_vec();
|
.as_menuitem()
|
||||||
if *common_tray_icon {
|
.unwrap()
|
||||||
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
.set_text(t!("Global Mode ✔", "全局模式 ✔"));
|
||||||
let png_path = icon_dir_path.join("common.png");
|
}
|
||||||
let ico_path = icon_dir_path.join("common.ico");
|
|
||||||
if ico_path.exists() {
|
if let Some(item) = menu.get("direct_mode") {
|
||||||
icon = std::fs::read(ico_path).unwrap();
|
let _ = item
|
||||||
} else if png_path.exists() {
|
.as_menuitem()
|
||||||
icon = std::fs::read(png_path).unwrap();
|
.unwrap()
|
||||||
|
.set_text(t!("Direct Mode", "直连模式"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
"direct" => {
|
||||||
icon
|
if let Some(item) = menu.get("rule_mode") {
|
||||||
};
|
let _ = item
|
||||||
|
.as_menuitem()
|
||||||
if *tun_mode {
|
.unwrap()
|
||||||
#[cfg(target_os = "macos")]
|
.set_text(t!("Rule Mode", "规则模式"));
|
||||||
let mut icon = match tray_icon.as_str() {
|
}
|
||||||
"monochrome" => include_bytes!("../../icons/tray-icon-tun-mono.ico").to_vec(),
|
if let Some(item) = menu.get("global_mode") {
|
||||||
"colorful" => include_bytes!("../../icons/tray-icon-tun.ico").to_vec(),
|
let _ = item
|
||||||
_ => include_bytes!("../../icons/tray-icon-tun-mono.ico").to_vec(),
|
.as_menuitem()
|
||||||
};
|
.unwrap()
|
||||||
#[cfg(not(target_os = "macos"))]
|
.set_text(t!("Global Mode", "全局模式"));
|
||||||
let mut icon = include_bytes!("../../icons/tray-icon-tun.ico").to_vec();
|
}
|
||||||
if *tun_tray_icon {
|
if let Some(item) = menu.get("direct_mode") {
|
||||||
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
let _ = item
|
||||||
let png_path = icon_dir_path.join("tun.png");
|
.as_menuitem()
|
||||||
let ico_path = icon_dir_path.join("tun.ico");
|
.unwrap()
|
||||||
if ico_path.exists() {
|
.set_text(t!("Direct Mode ✔", "直连模式 ✔"));
|
||||||
icon = std::fs::read(ico_path).unwrap();
|
}
|
||||||
} else if png_path.exists() {
|
|
||||||
icon = std::fs::read(png_path).unwrap();
|
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
indication_icon = icon
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = tray.set_icon(tauri::Icon::Raw(indication_icon));
|
let verge = Config::verge();
|
||||||
|
let verge = verge.latest();
|
||||||
|
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||||
|
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let tray_icon = verge.tray_icon.clone().unwrap_or("monochrome".to_string());
|
||||||
|
let common_tray_icon = verge.common_tray_icon.as_ref().unwrap_or(&false);
|
||||||
|
let sysproxy_tray_icon = verge.sysproxy_tray_icon.as_ref().unwrap_or(&false);
|
||||||
|
let tun_tray_icon = verge.tun_tray_icon.as_ref().unwrap_or(&false);
|
||||||
|
let tray: TrayIcon = app_handle.tray_by_id("verge_tray").unwrap();
|
||||||
|
|
||||||
let _ = tray.get_item("system_proxy").set_selected(*system_proxy);
|
#[cfg(target_os = "macos")]
|
||||||
let _ = tray.get_item("tun_mode").set_selected(*tun_mode);
|
match tray_icon.as_str() {
|
||||||
#[cfg(target_os = "linux")]
|
"monochrome" => {
|
||||||
{
|
let _ = tray.set_icon_as_template(true);
|
||||||
if *system_proxy {
|
}
|
||||||
let _ = tray
|
"colorful" => {
|
||||||
.get_item("system_proxy")
|
let _ = tray.set_icon_as_template(false);
|
||||||
.set_title(t!("System Proxy ✔", "系统代理 ✔"));
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let mut indication_icon = if *system_proxy {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let mut icon = match tray_icon.as_str() {
|
||||||
|
"monochrome" => include_bytes!("../../icons/tray-icon-sys-mono.ico").to_vec(),
|
||||||
|
"colorful" => include_bytes!("../../icons/tray-icon-sys.ico").to_vec(),
|
||||||
|
_ => include_bytes!("../../icons/tray-icon-sys-mono.ico").to_vec(),
|
||||||
|
};
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let mut icon = include_bytes!("../../icons/tray-icon-sys.ico").to_vec();
|
||||||
|
|
||||||
|
if *sysproxy_tray_icon {
|
||||||
|
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
||||||
|
let png_path = icon_dir_path.join("sysproxy.png");
|
||||||
|
let ico_path = icon_dir_path.join("sysproxy.ico");
|
||||||
|
if ico_path.exists() {
|
||||||
|
icon = std::fs::read(ico_path).unwrap();
|
||||||
|
} else if png_path.exists() {
|
||||||
|
icon = std::fs::read(png_path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
icon
|
||||||
} else {
|
} else {
|
||||||
let _ = tray
|
#[cfg(target_os = "macos")]
|
||||||
.get_item("system_proxy")
|
let mut icon = match tray_icon.as_str() {
|
||||||
.set_title(t!("System Proxy", "系统代理"));
|
"monochrome" => include_bytes!("../../icons/tray-icon-mono.ico").to_vec(),
|
||||||
}
|
"colorful" => include_bytes!("../../icons/tray-icon.ico").to_vec(),
|
||||||
|
_ => include_bytes!("../../icons/tray-icon-mono.ico").to_vec(),
|
||||||
|
};
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let mut icon = include_bytes!("../../icons/tray-icon.ico").to_vec();
|
||||||
|
if *common_tray_icon {
|
||||||
|
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
||||||
|
let png_path = icon_dir_path.join("common.png");
|
||||||
|
let ico_path = icon_dir_path.join("common.ico");
|
||||||
|
if ico_path.exists() {
|
||||||
|
icon = std::fs::read(ico_path).unwrap();
|
||||||
|
} else if png_path.exists() {
|
||||||
|
icon = std::fs::read(png_path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
icon
|
||||||
|
};
|
||||||
if *tun_mode {
|
if *tun_mode {
|
||||||
let _ = tray
|
#[cfg(target_os = "macos")]
|
||||||
.get_item("tun_mode")
|
let mut icon = match tray_icon.as_str() {
|
||||||
.set_title(t!("TUN Mode ✔", "Tun 模式 ✔"));
|
"monochrome" => include_bytes!("../../icons/tray-icon-tun-mono.ico").to_vec(),
|
||||||
} else {
|
"colorful" => include_bytes!("../../icons/tray-icon-tun.ico").to_vec(),
|
||||||
let _ = tray
|
_ => include_bytes!("../../icons/tray-icon-tun-mono.ico").to_vec(),
|
||||||
.get_item("tun_mode")
|
};
|
||||||
.set_title(t!("TUN Mode", "Tun 模式"));
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let mut icon = include_bytes!("../../icons/tray-icon-tun.ico").to_vec();
|
||||||
|
if *tun_tray_icon {
|
||||||
|
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
||||||
|
let png_path = icon_dir_path.join("tun.png");
|
||||||
|
let ico_path = icon_dir_path.join("tun.ico");
|
||||||
|
if ico_path.exists() {
|
||||||
|
icon = std::fs::read(ico_path).unwrap();
|
||||||
|
} else if png_path.exists() {
|
||||||
|
icon = std::fs::read(png_path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indication_icon = icon
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let switch_map = {
|
let _ = tray.set_icon(Some(tauri::image::Image::from_bytes(&indication_icon)?));
|
||||||
let mut map = std::collections::HashMap::new();
|
if let Some(item) = menu.get("system_proxy") {
|
||||||
map.insert(true, "on");
|
let item = item.as_check_menuitem().unwrap();
|
||||||
map.insert(false, "off");
|
let _ = item.set_checked(mode == "system_proxy");
|
||||||
map
|
}
|
||||||
};
|
if let Some(item) = menu.get("tun_mode") {
|
||||||
|
let item = item.as_check_menuitem().unwrap();
|
||||||
|
let _ = item.set_checked(mode == "tun_mode");
|
||||||
|
}
|
||||||
|
|
||||||
let mut current_profile_name = "None".to_string();
|
#[cfg(target_os = "linux")]
|
||||||
let profiles = Config::profiles();
|
{
|
||||||
let profiles = profiles.latest();
|
if let Some(item) = menu.get("system_proxy") {
|
||||||
if let Some(current_profile_uid) = profiles.get_current() {
|
if *system_proxy {
|
||||||
let current_profile = profiles.get_item(¤t_profile_uid);
|
let _ = item
|
||||||
current_profile_name = match ¤t_profile.unwrap().name {
|
.as_menuitem()
|
||||||
Some(profile_name) => profile_name.to_string(),
|
.unwrap()
|
||||||
None => current_profile_name,
|
.set_text(t!("System Proxy ✔", "系统代理 ✔"));
|
||||||
|
} else {
|
||||||
|
let _ = item
|
||||||
|
.as_menuitem()
|
||||||
|
.unwrap()
|
||||||
|
.set_text(t!("System Proxy", "系统代理"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(item) = menu.get("tun_mode") {
|
||||||
|
if *tun_mode {
|
||||||
|
let _ = item
|
||||||
|
.as_menuitem()
|
||||||
|
.unwrap()
|
||||||
|
.set_text(t!("TUN Mode ✔", "Tun 模式 ✔"));
|
||||||
|
} else {
|
||||||
|
let _ = item
|
||||||
|
.as_menuitem()
|
||||||
|
.unwrap()
|
||||||
|
.set_text(t!("TUN Mode", "Tun 模式"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let switch_map = {
|
||||||
|
let mut map = std::collections::HashMap::new();
|
||||||
|
map.insert(true, "on");
|
||||||
|
map.insert(false, "off");
|
||||||
|
map
|
||||||
};
|
};
|
||||||
};
|
|
||||||
let _ = tray.set_tooltip(&format!(
|
let mut current_profile_name = "None".to_string();
|
||||||
"Clash Verge {version}\n{}: {}\n{}: {}\n{}: {}",
|
let profiles = Config::profiles();
|
||||||
t!("SysProxy", "系统代理"),
|
let profiles = profiles.latest();
|
||||||
switch_map[system_proxy],
|
if let Some(current_profile_uid) = profiles.get_current() {
|
||||||
t!("TUN", "Tun模式"),
|
let current_profile = profiles.get_item(¤t_profile_uid);
|
||||||
switch_map[tun_mode],
|
current_profile_name = match ¤t_profile.unwrap().name {
|
||||||
t!("Profile", "当前订阅"),
|
Some(profile_name) => profile_name.to_string(),
|
||||||
current_profile_name
|
None => current_profile_name,
|
||||||
));
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = tray.set_tooltip(Some(&format!(
|
||||||
|
"Clash Verge {version}\n{}: {}\n{}: {}\n{}: {}",
|
||||||
|
t!("SysProxy", "系统代理"),
|
||||||
|
switch_map[system_proxy],
|
||||||
|
t!("TUN", "Tun模式"),
|
||||||
|
switch_map[tun_mode],
|
||||||
|
t!("Profile", "当前订阅"),
|
||||||
|
current_profile_name
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_click(app_handle: &AppHandle) {
|
pub fn on_menu_event(app_handle: &AppHandle, event: MenuEvent) {
|
||||||
let tray_event = { Config::verge().latest().tray_event.clone() };
|
match event.id.as_ref() {
|
||||||
let tray_event = tray_event.unwrap_or("main_window".into());
|
mode @ ("rule_mode" | "global_mode" | "direct_mode") => {
|
||||||
match tray_event.as_str() {
|
let mode = &mode[0..mode.len() - 5];
|
||||||
|
feat::change_clash_mode(mode.into());
|
||||||
|
}
|
||||||
|
"open_window" => resolve::create_window(app_handle),
|
||||||
"system_proxy" => feat::toggle_system_proxy(),
|
"system_proxy" => feat::toggle_system_proxy(),
|
||||||
"tun_mode" => feat::toggle_tun_mode(),
|
"tun_mode" => feat::toggle_tun_mode(),
|
||||||
"main_window" => resolve::create_window(app_handle),
|
"copy_env" => feat::copy_clash_env(app_handle),
|
||||||
_ => {}
|
"open_app_dir" => crate::log_err!(cmds::open_app_dir()),
|
||||||
}
|
"open_core_dir" => crate::log_err!(cmds::open_core_dir()),
|
||||||
}
|
"open_logs_dir" => crate::log_err!(cmds::open_logs_dir()),
|
||||||
|
"restart_clash" => feat::restart_clash_core(),
|
||||||
pub fn on_system_tray_event(app_handle: &AppHandle, event: SystemTrayEvent) {
|
"restart_app" => tauri::process::restart(&app_handle.env()),
|
||||||
match event {
|
"quit" => cmds::exit_app(app_handle.clone()),
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
SystemTrayEvent::LeftClick { .. } => Tray::on_click(app_handle),
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
SystemTrayEvent::RightClick { .. } => Tray::on_click(app_handle),
|
|
||||||
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
|
|
||||||
mode @ ("rule_mode" | "global_mode" | "direct_mode") => {
|
|
||||||
let mode = &mode[0..mode.len() - 5];
|
|
||||||
feat::change_clash_mode(mode.into());
|
|
||||||
}
|
|
||||||
"open_window" => resolve::create_window(app_handle),
|
|
||||||
"system_proxy" => feat::toggle_system_proxy(),
|
|
||||||
"tun_mode" => feat::toggle_tun_mode(),
|
|
||||||
"copy_env" => feat::copy_clash_env(app_handle),
|
|
||||||
"open_app_dir" => crate::log_err!(cmds::open_app_dir()),
|
|
||||||
"open_core_dir" => crate::log_err!(cmds::open_core_dir()),
|
|
||||||
"open_logs_dir" => crate::log_err!(cmds::open_logs_dir()),
|
|
||||||
"restart_clash" => feat::restart_clash_core(),
|
|
||||||
"restart_app" => api::process::restart(&app_handle.env()),
|
|
||||||
"quit" => cmds::exit_app(app_handle.clone()),
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,15 @@ use crate::log_err;
|
||||||
use crate::utils::resolve;
|
use crate::utils::resolve;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use tauri::{AppHandle, ClipboardManager, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
|
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||||
|
|
||||||
// 打开面板
|
// 打开面板
|
||||||
pub fn open_or_close_dashboard() {
|
pub fn open_or_close_dashboard() {
|
||||||
let handle = handle::Handle::global();
|
let handle = handle::Handle::global();
|
||||||
let app_handle = handle.app_handle.lock();
|
let app_handle = handle.app_handle.lock();
|
||||||
if let Some(app_handle) = app_handle.as_ref() {
|
if let Some(app_handle) = app_handle.as_ref() {
|
||||||
if let Some(window) = app_handle.get_window("main") {
|
if let Some(window) = app_handle.get_webview_window("main") {
|
||||||
if let Ok(true) = window.is_focused() {
|
if let Ok(true) = window.is_focused() {
|
||||||
let _ = window.close();
|
let _ = window.close();
|
||||||
return;
|
return;
|
||||||
|
@ -319,8 +320,7 @@ pub fn copy_clash_env(app_handle: &AppHandle) {
|
||||||
let cmd: String = format!("set http_proxy={http_proxy}\r\nset https_proxy={http_proxy}");
|
let cmd: String = format!("set http_proxy={http_proxy}\r\nset https_proxy={http_proxy}");
|
||||||
let ps: String = format!("$env:HTTP_PROXY=\"{http_proxy}\"; $env:HTTPS_PROXY=\"{http_proxy}\"");
|
let ps: String = format!("$env:HTTP_PROXY=\"{http_proxy}\"; $env:HTTPS_PROXY=\"{http_proxy}\"");
|
||||||
|
|
||||||
let mut cliboard = app_handle.clipboard_manager();
|
let cliboard = app_handle.clipboard();
|
||||||
|
|
||||||
let env_type = { Config::verge().latest().env_type.clone() };
|
let env_type = { Config::verge().latest().env_type.clone() };
|
||||||
let env_type = match env_type {
|
let env_type = match env_type {
|
||||||
Some(env_type) => env_type,
|
Some(env_type) => env_type,
|
||||||
|
|
|
@ -11,7 +11,7 @@ mod feat;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use crate::utils::{init, resolve, server};
|
use crate::utils::{init, resolve, server};
|
||||||
use tauri::{api, SystemTray};
|
use tauri::tray::TrayIconBuilder;
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
// 单例检测
|
// 单例检测
|
||||||
|
@ -34,14 +34,37 @@ fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut builder = tauri::Builder::default()
|
let mut builder = tauri::Builder::default()
|
||||||
.system_tray(SystemTray::new())
|
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||||
|
.plugin(tauri_plugin_clipboard_manager::init())
|
||||||
|
.plugin(tauri_plugin_process::init())
|
||||||
|
.plugin(tauri_plugin_global_shortcut::Builder::new().build())
|
||||||
|
.plugin(tauri_plugin_notification::init())
|
||||||
|
.plugin(tauri_plugin_fs::init())
|
||||||
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
.plugin(tauri_plugin_shell::init())
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
|
TrayIconBuilder::new().build(app)?;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
use tauri::menu::MenuBuilder;
|
||||||
|
let _ = MenuBuilder::new(app)
|
||||||
|
.copy()
|
||||||
|
.paste()
|
||||||
|
.undo()
|
||||||
|
.redo()
|
||||||
|
.cut()
|
||||||
|
.select_all()
|
||||||
|
.quit()
|
||||||
|
.close_window()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
tauri::async_runtime::block_on(async move {
|
tauri::async_runtime::block_on(async move {
|
||||||
resolve::resolve_setup(app).await;
|
resolve::resolve_setup(app).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.on_system_tray_event(core::tray::Tray::on_system_tray_event)
|
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
// common
|
// common
|
||||||
cmds::get_sys_proxy,
|
cmds::get_sys_proxy,
|
||||||
|
@ -97,26 +120,6 @@ fn main() -> std::io::Result<()> {
|
||||||
cmds::clash_api_get_proxy_delay
|
cmds::clash_api_get_proxy_delay
|
||||||
]);
|
]);
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
use tauri::{Menu, MenuItem, Submenu};
|
|
||||||
|
|
||||||
builder = builder.menu(
|
|
||||||
Menu::new().add_submenu(Submenu::new(
|
|
||||||
"Edit",
|
|
||||||
Menu::new()
|
|
||||||
.add_native_item(MenuItem::Undo)
|
|
||||||
.add_native_item(MenuItem::Redo)
|
|
||||||
.add_native_item(MenuItem::Copy)
|
|
||||||
.add_native_item(MenuItem::Paste)
|
|
||||||
.add_native_item(MenuItem::Cut)
|
|
||||||
.add_native_item(MenuItem::SelectAll)
|
|
||||||
.add_native_item(MenuItem::CloseWindow)
|
|
||||||
.add_native_item(MenuItem::Quit),
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let app = builder
|
let app = builder
|
||||||
.build(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
@ -125,10 +128,6 @@ fn main() -> std::io::Result<()> {
|
||||||
tauri::RunEvent::ExitRequested { api, .. } => {
|
tauri::RunEvent::ExitRequested { api, .. } => {
|
||||||
api.prevent_exit();
|
api.prevent_exit();
|
||||||
}
|
}
|
||||||
tauri::RunEvent::Updater(tauri::UpdaterEvent::Downloaded) => {
|
|
||||||
resolve::resolve_reset();
|
|
||||||
api::process::kill_children();
|
|
||||||
}
|
|
||||||
tauri::RunEvent::WindowEvent { label, event, .. } => {
|
tauri::RunEvent::WindowEvent { label, event, .. } => {
|
||||||
if label == "main" {
|
if label == "main" {
|
||||||
match event {
|
match event {
|
||||||
|
|
|
@ -2,10 +2,7 @@ use crate::core::handle;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tauri::{
|
use tauri::Manager;
|
||||||
api::path::{data_dir, resource_dir},
|
|
||||||
Env,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[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.clash-verge-rev.clash-verge-rev";
|
||||||
|
@ -48,9 +45,21 @@ pub fn app_home_dir() -> Result<PathBuf> {
|
||||||
return Ok(PathBuf::from(app_dir).join(".config").join(APP_ID));
|
return Ok(PathBuf::from(app_dir).join(".config").join(APP_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(data_dir()
|
let handle = handle::Handle::global();
|
||||||
.ok_or(anyhow::anyhow!("failed to get app home dir"))?
|
let app_handle = handle.app_handle.lock();
|
||||||
.join(APP_ID))
|
|
||||||
|
if let Some(app_handle) = app_handle.as_ref() {
|
||||||
|
match app_handle.path().data_dir() {
|
||||||
|
Ok(dir) => {
|
||||||
|
return Ok(dir.join(APP_ID));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to get the app home directory: {}", e);
|
||||||
|
return Err(anyhow::anyhow!("Failed to get the app homedirectory"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(anyhow::anyhow!("failed to get the app home dir"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the resources dir
|
/// get the resources dir
|
||||||
|
@ -58,10 +67,15 @@ pub fn app_resources_dir() -> Result<PathBuf> {
|
||||||
let handle = handle::Handle::global();
|
let handle = handle::Handle::global();
|
||||||
let app_handle = handle.app_handle.lock();
|
let app_handle = handle.app_handle.lock();
|
||||||
if let Some(app_handle) = app_handle.as_ref() {
|
if let Some(app_handle) = app_handle.as_ref() {
|
||||||
let res_dir = resource_dir(app_handle.package_info(), &Env::default())
|
match app_handle.path().resource_dir() {
|
||||||
.ok_or(anyhow::anyhow!("failed to get the resource dir"))?
|
Ok(dir) => {
|
||||||
.join("resources");
|
return Ok(dir.join("resources"));
|
||||||
return Ok(res_dir);
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to get the resource directory: {}", e);
|
||||||
|
return Err(anyhow::anyhow!("Failed to get the resource directory"));
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
Err(anyhow::anyhow!("failed to get the resource dir"))
|
Err(anyhow::anyhow!("failed to get the resource dir"))
|
||||||
}
|
}
|
||||||
|
@ -88,6 +102,10 @@ pub fn profiles_path() -> Result<PathBuf> {
|
||||||
Ok(app_home_dir()?.join(PROFILE_YAML))
|
Ok(app_home_dir()?.join(PROFILE_YAML))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clash_pid_path() -> Result<PathBuf> {
|
||||||
|
Ok(app_home_dir()?.join("clash.pid"))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
pub fn service_path() -> Result<PathBuf> {
|
pub fn service_path() -> Result<PathBuf> {
|
||||||
Ok(app_resources_dir()?.join("clash-verge-service"))
|
Ok(app_resources_dir()?.join("clash-verge-service"))
|
||||||
|
|
|
@ -4,10 +4,8 @@ use nanoid::nanoid;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::{fs, path::PathBuf, str::FromStr};
|
use std::{fs, path::PathBuf, str::FromStr};
|
||||||
use tauri::{
|
use tauri_plugin_shell::ShellExt;
|
||||||
api::shell::{open, Program},
|
|
||||||
Manager,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// read data from yaml as struct T
|
/// read data from yaml as struct T
|
||||||
pub fn read_yaml<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
|
pub fn read_yaml<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
|
||||||
|
@ -104,20 +102,7 @@ pub fn get_last_part_and_decode(url: &str) -> Option<String> {
|
||||||
/// open file
|
/// open file
|
||||||
/// use vscode by default
|
/// use vscode by default
|
||||||
pub fn open_file(app: tauri::AppHandle, path: PathBuf) -> Result<()> {
|
pub fn open_file(app: tauri::AppHandle, path: PathBuf) -> Result<()> {
|
||||||
#[cfg(target_os = "macos")]
|
app.shell().open(path.to_string_lossy(), None).unwrap();
|
||||||
let code = "Visual Studio Code";
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
let code = "code";
|
|
||||||
|
|
||||||
let _ = match Program::from_str(code) {
|
|
||||||
Ok(code) => open(&app.shell_scope(), path.to_string_lossy(), Some(code)),
|
|
||||||
Err(err) => {
|
|
||||||
log::error!(target: "app", "Can't find VScode `{err}`");
|
|
||||||
// default open
|
|
||||||
open(&app.shell_scope(), path.to_string_lossy(), None)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,8 @@ use log4rs::encode::pattern::PatternEncoder;
|
||||||
use std::fs::{self, DirEntry};
|
use std::fs::{self, DirEntry};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tauri::api::process::Command;
|
use tauri::AppHandle;
|
||||||
|
use tauri_plugin_shell::ShellExt;
|
||||||
|
|
||||||
/// initialize this instance's log file
|
/// initialize this instance's log file
|
||||||
fn init_log() -> Result<()> {
|
fn init_log() -> Result<()> {
|
||||||
|
@ -296,43 +297,39 @@ pub fn init_scheme() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn startup_script() -> Result<()> {
|
pub async fn startup_script(app_handle: &AppHandle) -> Result<()> {
|
||||||
let path = {
|
let script_path = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
let verge = verge.latest();
|
let verge = verge.latest();
|
||||||
verge.startup_script.clone().unwrap_or("".to_string())
|
verge.startup_script.clone().unwrap_or("".to_string())
|
||||||
};
|
};
|
||||||
|
|
||||||
if !path.is_empty() {
|
if script_path.is_empty() {
|
||||||
let mut shell = "";
|
return Ok(());
|
||||||
if path.ends_with(".sh") {
|
|
||||||
shell = "bash";
|
|
||||||
}
|
|
||||||
if path.ends_with(".ps1") {
|
|
||||||
shell = "powershell";
|
|
||||||
}
|
|
||||||
if path.ends_with(".bat") {
|
|
||||||
shell = "powershell";
|
|
||||||
}
|
|
||||||
if shell.is_empty() {
|
|
||||||
return Err(anyhow::anyhow!("unsupported script: {path}"));
|
|
||||||
}
|
|
||||||
let current_dir = PathBuf::from(path.clone());
|
|
||||||
if !current_dir.exists() {
|
|
||||||
return Err(anyhow::anyhow!("script not found: {path}"));
|
|
||||||
}
|
|
||||||
let current_dir = current_dir.parent();
|
|
||||||
match current_dir {
|
|
||||||
Some(dir) => {
|
|
||||||
let _ = Command::new(shell)
|
|
||||||
.current_dir(dir.to_path_buf())
|
|
||||||
.args([path])
|
|
||||||
.output()?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let _ = Command::new(shell).args([path]).output()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let shell_type = if script_path.ends_with(".sh") {
|
||||||
|
"bash"
|
||||||
|
} else if script_path.ends_with(".ps1") || script_path.ends_with(".bat") {
|
||||||
|
"powershell"
|
||||||
|
} else {
|
||||||
|
return Err(anyhow::anyhow!("unsupported script extension: {}", script_path));
|
||||||
|
};
|
||||||
|
|
||||||
|
let script_dir = PathBuf::from(&script_path);
|
||||||
|
if !script_dir.exists() {
|
||||||
|
return Err(anyhow::anyhow!("script not found: {}", script_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent_dir = script_dir.parent();
|
||||||
|
let working_dir = parent_dir.unwrap_or(script_dir.as_ref());
|
||||||
|
|
||||||
|
app_handle
|
||||||
|
.shell()
|
||||||
|
.command(shell_type)
|
||||||
|
.current_dir(working_dir.to_path_buf())
|
||||||
|
.args(&[script_path])
|
||||||
|
.output().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,12 @@ use anyhow::Result;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use tauri::api::notification;
|
|
||||||
use tauri::{App, AppHandle, Manager};
|
use tauri::{App, AppHandle, Manager};
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
use window_shadows::set_shadow;
|
// use window_shadows::set_shadow;
|
||||||
|
use tauri_plugin_notification::NotificationExt;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub static VERSION: OnceCell<String> = OnceCell::new();
|
pub static VERSION: OnceCell<String> = OnceCell::new();
|
||||||
|
|
||||||
|
@ -33,14 +35,14 @@ pub fn find_unused_port() -> Result<u16> {
|
||||||
/// handle something when start app
|
/// handle something when start app
|
||||||
pub async fn resolve_setup(app: &mut App) {
|
pub async fn resolve_setup(app: &mut App) {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
app.set_activation_policy(tauri::ActivationPolicy::Accessory);
|
app.set_activation_policy(tauri::ActivationPolicy::Regular);
|
||||||
let version = app.package_info().version.to_string();
|
let version = app.package_info().version.to_string();
|
||||||
handle::Handle::global().init(app.app_handle());
|
handle::Handle::global().init(app.app_handle());
|
||||||
VERSION.get_or_init(|| version.clone());
|
VERSION.get_or_init(|| version.clone());
|
||||||
|
|
||||||
log_err!(init::init_resources());
|
log_err!(init::init_resources());
|
||||||
log_err!(init::init_scheme());
|
log_err!(init::init_scheme());
|
||||||
log_err!(init::startup_script());
|
log_err!(init::startup_script(app.app_handle()).await);
|
||||||
// 处理随机端口
|
// 处理随机端口
|
||||||
let enable_random_port = Config::verge().latest().enable_random_port.unwrap_or(false);
|
let enable_random_port = Config::verge().latest().enable_random_port.unwrap_or(false);
|
||||||
|
|
||||||
|
@ -74,7 +76,7 @@ pub async fn resolve_setup(app: &mut App) {
|
||||||
log_err!(Config::init_config().await);
|
log_err!(Config::init_config().await);
|
||||||
|
|
||||||
log::trace!("launch core");
|
log::trace!("launch core");
|
||||||
log_err!(CoreManager::global().init());
|
log_err!(CoreManager::global().init(app.app_handle()));
|
||||||
|
|
||||||
// setup a simple http server for singleton
|
// setup a simple http server for singleton
|
||||||
log::trace!("launch embed server");
|
log::trace!("launch embed server");
|
||||||
|
@ -115,17 +117,17 @@ pub fn resolve_reset() {
|
||||||
|
|
||||||
/// create main window
|
/// create main window
|
||||||
pub fn create_window(app_handle: &AppHandle) {
|
pub fn create_window(app_handle: &AppHandle) {
|
||||||
if let Some(window) = app_handle.get_window("main") {
|
if let Some(window) = app_handle.get_webview_window("main") {
|
||||||
trace_err!(window.unminimize(), "set win unminimize");
|
trace_err!(window.unminimize(), "set win unminimize");
|
||||||
trace_err!(window.show(), "set win visible");
|
trace_err!(window.show(), "set win visible");
|
||||||
trace_err!(window.set_focus(), "set win focus");
|
trace_err!(window.set_focus(), "set win focus");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut builder = tauri::window::WindowBuilder::new(
|
let mut builder = tauri::WebviewWindowBuilder::new(
|
||||||
app_handle,
|
app_handle,
|
||||||
"main".to_string(),
|
"main".to_string(),
|
||||||
tauri::WindowUrl::App("index.html".into()),
|
tauri::WebviewUrl::App("index.html".into()),
|
||||||
)
|
)
|
||||||
.title("Clash Verge")
|
.title("Clash Verge")
|
||||||
.visible(false)
|
.visible(false)
|
||||||
|
@ -199,8 +201,8 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||||
trace_err!(win.center(), "set win center");
|
trace_err!(win.center(), "set win center");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
// #[cfg(not(target_os = "linux"))]
|
||||||
trace_err!(set_shadow(&win, true), "set win shadow");
|
// trace_err!(set_shadow(&win, true), "set win shadow");
|
||||||
if is_maximized {
|
if is_maximized {
|
||||||
trace_err!(win.maximize(), "set win maximize");
|
trace_err!(win.maximize(), "set win maximize");
|
||||||
}
|
}
|
||||||
|
@ -221,7 +223,7 @@ pub fn save_window_size_position(app_handle: &AppHandle, save_to_file: bool) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
let win = app_handle
|
let win = app_handle
|
||||||
.get_window("main")
|
.get_webview_window("main")
|
||||||
.ok_or(anyhow::anyhow!("failed to get window"))?;
|
.ok_or(anyhow::anyhow!("failed to get window"))?;
|
||||||
|
|
||||||
let scale = win.scale_factor()?;
|
let scale = win.scale_factor()?;
|
||||||
|
@ -241,21 +243,30 @@ pub async fn resolve_scheme(param: String) -> Result<()> {
|
||||||
let url = param
|
let url = param
|
||||||
.trim_start_matches("clash://install-config/?url=")
|
.trim_start_matches("clash://install-config/?url=")
|
||||||
.trim_start_matches("clash://install-config?url=");
|
.trim_start_matches("clash://install-config?url=");
|
||||||
match import_profile(url.to_string(), None).await {
|
|
||||||
Ok(_) => {
|
let handle = handle::Handle::global();
|
||||||
notification::Notification::new(crate::utils::dirs::APP_ID)
|
let app_handle = handle.app_handle.lock();
|
||||||
.title("Clash Verge")
|
if let Some(app_handle) = app_handle.as_ref() {
|
||||||
.body("Import profile success")
|
match import_profile(url.to_string(), None).await {
|
||||||
.show()
|
Ok(_) => {
|
||||||
.unwrap();
|
app_handle
|
||||||
}
|
.notification()
|
||||||
Err(e) => {
|
.builder()
|
||||||
notification::Notification::new(crate::utils::dirs::APP_ID)
|
.title("Clash Verge")
|
||||||
.title("Clash Verge")
|
.body("Import profile success")
|
||||||
.body(format!("Import profile failed: {e}"))
|
.show()
|
||||||
.show()
|
.unwrap();
|
||||||
.unwrap();
|
}
|
||||||
log::error!("Import profile failed: {e}");
|
Err(e) => {
|
||||||
|
app_handle
|
||||||
|
.notification()
|
||||||
|
.builder()
|
||||||
|
.title("Clash Verge")
|
||||||
|
.body(format!("Import profile failed: {e}"))
|
||||||
|
.show()
|
||||||
|
.unwrap();
|
||||||
|
log::error!("Import profile failed: {e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
extern crate warp;
|
extern crate warp;
|
||||||
|
|
||||||
use super::resolve;
|
use super::resolve;
|
||||||
use crate::{
|
use crate::config::{Config, IVerge, DEFAULT_PAC};
|
||||||
config::{Config, IVerge, DEFAULT_PAC},
|
|
||||||
log_err,
|
|
||||||
};
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use port_scanner::local_port_available;
|
use port_scanner::local_port_available;
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
|
use warp::http::StatusCode;
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Debug)]
|
#[derive(serde::Deserialize, Debug)]
|
||||||
struct QueryParam {
|
struct QueryParam {}
|
||||||
param: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// check whether there is already exists
|
/// check whether there is already exists
|
||||||
pub async fn check_singleton() -> Result<()> {
|
pub async fn check_singleton() -> Result<()> {
|
||||||
|
@ -56,14 +52,15 @@ pub async fn check_singleton() -> Result<()> {
|
||||||
|
|
||||||
/// 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(app_handle: AppHandle) {
|
pub fn embed_server(app_handle: &AppHandle) {
|
||||||
let port = IVerge::get_singleton_port();
|
let port = IVerge::get_singleton_port();
|
||||||
|
|
||||||
|
let handle = app_handle.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
let ping = warp::path!("commands" / "ping").map(move || "ok");
|
let ping = warp::path!("commands" / "ping").map(move || "ok");
|
||||||
|
|
||||||
let visible = warp::path!("commands" / "visible").map(move || {
|
let visible = warp::path!("commands" / "visible").map(move || {
|
||||||
resolve::create_window(&app_handle);
|
resolve::create_window(&handle);
|
||||||
"ok"
|
"ok"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -87,9 +84,9 @@ pub fn embed_server(app_handle: AppHandle) {
|
||||||
.and(warp::query::<QueryParam>())
|
.and(warp::query::<QueryParam>())
|
||||||
.and_then(scheme_handler);
|
.and_then(scheme_handler);
|
||||||
|
|
||||||
async fn scheme_handler(query: QueryParam) -> Result<impl warp::Reply, Infallible> {
|
async fn scheme_handler(_: QueryParam) -> Result<impl warp::Reply, Infallible> {
|
||||||
log_err!(resolve::resolve_scheme(query.param).await);
|
//let _ = resolve::resolve_scheme(query.param).await;
|
||||||
Ok("ok")
|
Ok(warp::reply::with_status("Ok", StatusCode::OK))
|
||||||
}
|
}
|
||||||
let commands = ping.or(visible).or(pac).or(scheme);
|
let commands = ping.or(visible).or(pac).or(scheme);
|
||||||
warp::serve(commands).run(([127, 0, 0, 1], port)).await;
|
warp::serve(commands).run(([127, 0, 0, 1], port)).await;
|
||||||
|
|
|
@ -1,82 +1,49 @@
|
||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"package": {
|
"bundle": {
|
||||||
"productName": "Clash Verge",
|
"active": true,
|
||||||
"version": "1.7.7"
|
"longDescription": "A Clash Meta GUI based on tauri.",
|
||||||
|
"icon": [
|
||||||
|
"icons/32x32.png",
|
||||||
|
"icons/128x128.png",
|
||||||
|
"icons/128x128@2x.png",
|
||||||
|
"icons/icon.icns",
|
||||||
|
"icons/icon.ico"
|
||||||
|
],
|
||||||
|
"resources": ["resources"],
|
||||||
|
"publisher": "Clash Verge Rev",
|
||||||
|
"externalBin": ["sidecar/verge-mihomo", "sidecar/verge-mihomo-alpha"],
|
||||||
|
"copyright": "GNU General Public License v3.0",
|
||||||
|
"category": "DeveloperTool",
|
||||||
|
"shortDescription": "A Clash Meta GUI based on tauri.",
|
||||||
|
"createUpdaterArtifacts": "v1Compatible"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"distDir": "../dist",
|
"beforeBuildCommand": "pnpm run web:build",
|
||||||
"devPath": "http://localhost:3000/",
|
"frontendDist": "../dist",
|
||||||
"beforeDevCommand": "pnpm run web:dev",
|
"beforeDevCommand": "pnpm run web:dev",
|
||||||
"beforeBuildCommand": "pnpm run web:build"
|
"devUrl": "http://localhost:3000/"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"productName": "Clash Verge",
|
||||||
"bundle": {
|
"version": "1.7.7",
|
||||||
"active": true,
|
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"plugins": {
|
||||||
"icon": [
|
|
||||||
"icons/32x32.png",
|
|
||||||
"icons/128x128.png",
|
|
||||||
"icons/128x128@2x.png",
|
|
||||||
"icons/icon.icns",
|
|
||||||
"icons/icon.ico"
|
|
||||||
],
|
|
||||||
"resources": ["resources"],
|
|
||||||
"publisher": "Clash Verge Rev",
|
|
||||||
"externalBin": ["sidecar/verge-mihomo", "sidecar/verge-mihomo-alpha"],
|
|
||||||
"copyright": "GNU General Public License v3.0",
|
|
||||||
"category": "DeveloperTool",
|
|
||||||
"shortDescription": "A Clash Meta GUI based on tauri.",
|
|
||||||
"longDescription": "A Clash Meta GUI based on tauri."
|
|
||||||
},
|
|
||||||
"updater": {
|
"updater": {
|
||||||
"active": true,
|
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK",
|
||||||
"endpoints": [
|
"endpoints": [
|
||||||
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
|
"https://download.clashverge.dev/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-proxy.json",
|
||||||
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update.json"
|
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update.json"
|
||||||
],
|
]
|
||||||
"dialog": false,
|
|
||||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
|
|
||||||
},
|
|
||||||
"allowlist": {
|
|
||||||
"shell": {
|
|
||||||
"all": true
|
|
||||||
},
|
|
||||||
"window": {
|
|
||||||
"all": true
|
|
||||||
},
|
|
||||||
"process": {
|
|
||||||
"all": true
|
|
||||||
},
|
|
||||||
"globalShortcut": {
|
|
||||||
"all": true
|
|
||||||
},
|
|
||||||
"clipboard": {
|
|
||||||
"all": true
|
|
||||||
},
|
|
||||||
"notification": {
|
|
||||||
"all": true
|
|
||||||
},
|
|
||||||
"dialog": {
|
|
||||||
"all": false,
|
|
||||||
"open": true
|
|
||||||
},
|
|
||||||
"protocol": {
|
|
||||||
"asset": true,
|
|
||||||
"assetScope": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"all": true
|
|
||||||
},
|
|
||||||
"fs": {
|
|
||||||
"exists": true,
|
|
||||||
"readFile": true,
|
|
||||||
"scope": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"windows": [],
|
|
||||||
"security": {
|
|
||||||
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: asset: 'unsafe-eval' 'unsafe-inline' 'self';"
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"security": {
|
||||||
|
"assetProtocol": {
|
||||||
|
"scope": ["$APPDATA/**", "$RESOURCE/../**", "**"],
|
||||||
|
"enable": true
|
||||||
|
},
|
||||||
|
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: asset: 'unsafe-eval' 'unsafe-inline' 'self';; connect-src ipc: http://ipc.localhost"
|
||||||
|
},
|
||||||
|
"windows": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"tauri": {
|
"bundle": {
|
||||||
"systemTray": {
|
"targets": ["deb", "rpm"],
|
||||||
"iconPath": "icons/tray-icon.ico"
|
"linux": {
|
||||||
},
|
|
||||||
"bundle": {
|
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
|
||||||
"targets": ["deb", "rpm"],
|
|
||||||
"deb": {
|
"deb": {
|
||||||
"depends": ["openssl"],
|
"depends": ["openssl"],
|
||||||
"desktopTemplate": "./template/clash-verge.desktop",
|
"desktopTemplate": "./template/clash-verge.desktop",
|
||||||
|
@ -22,5 +18,10 @@
|
||||||
"obsoletes": ["clash-verge"]
|
"obsoletes": ["clash-verge"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"trayIcon": {
|
||||||
|
"iconPath": "icons/tray-icon.ico"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,13 @@
|
||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"tauri": {
|
"bundle": {
|
||||||
"systemTray": {
|
"targets": ["app", "dmg"],
|
||||||
"iconPath": "icons/tray-icon-mono.ico",
|
"macOS": {
|
||||||
"iconAsTemplate": true
|
"frameworks": [],
|
||||||
},
|
"minimumSystemVersion": "10.15",
|
||||||
"bundle": {
|
"exceptionDomain": "",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"signingIdentity": null,
|
||||||
"targets": ["app", "dmg", "updater"],
|
"entitlements": null,
|
||||||
"macOS": {
|
|
||||||
"frameworks": [],
|
|
||||||
"minimumSystemVersion": "10.15",
|
|
||||||
"exceptionDomain": "",
|
|
||||||
"signingIdentity": null,
|
|
||||||
"entitlements": null
|
|
||||||
},
|
|
||||||
"dmg": {
|
"dmg": {
|
||||||
"background": "images/background.png",
|
"background": "images/background.png",
|
||||||
"appPosition": {
|
"appPosition": {
|
||||||
|
@ -35,5 +28,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"trayIcon": {
|
||||||
|
"iconPath": "icons/tray-icon-mono.ico",
|
||||||
|
"iconAsTemplate": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,28 @@
|
||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"tauri": {
|
"bundle": {
|
||||||
"systemTray": {
|
"targets": ["nsis"],
|
||||||
"iconPath": "icons/tray-icon.ico"
|
"windows": {
|
||||||
},
|
"certificateThumbprint": null,
|
||||||
"bundle": {
|
"digestAlgorithm": "sha256",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"timestampUrl": "",
|
||||||
"targets": ["nsis", "updater"],
|
"webviewInstallMode": {
|
||||||
"windows": {
|
"type": "embedBootstrapper",
|
||||||
"certificateThumbprint": null,
|
"silent": true
|
||||||
"digestAlgorithm": "sha256",
|
},
|
||||||
"timestampUrl": "",
|
"nsis": {
|
||||||
"webviewInstallMode": {
|
"displayLanguageSelector": true,
|
||||||
"type": "embedBootstrapper",
|
"installerIcon": "icons/icon.ico",
|
||||||
"silent": true
|
"languages": ["SimpChinese", "English"],
|
||||||
},
|
"installMode": "perMachine",
|
||||||
"nsis": {
|
"template": "./template/installer.nsi"
|
||||||
"displayLanguageSelector": true,
|
|
||||||
"installerIcon": "icons/icon.ico",
|
|
||||||
"languages": ["SimpChinese", "English"],
|
|
||||||
"license": "../LICENSE",
|
|
||||||
"installMode": "perMachine",
|
|
||||||
"template": "./template/installer.nsi"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"trayIcon": {
|
||||||
|
"iconPath": "icons/tray-icon.ico",
|
||||||
|
"iconAsTemplate": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ import {
|
||||||
ErrorRounded,
|
ErrorRounded,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { appWindow } from "@tauri-apps/api/window";
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||||
|
const appWindow = getCurrentWebviewWindow();
|
||||||
interface InnerProps {
|
interface InnerProps {
|
||||||
type: string;
|
type: string;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Button, ButtonGroup } from "@mui/material";
|
import { Button, ButtonGroup } from "@mui/material";
|
||||||
import { appWindow } from "@tauri-apps/api/window";
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||||
import {
|
import {
|
||||||
CloseRounded,
|
CloseRounded,
|
||||||
CropSquareRounded,
|
CropSquareRounded,
|
||||||
|
@ -9,6 +9,7 @@ import {
|
||||||
PushPinRounded,
|
PushPinRounded,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
const appWindow = getCurrentWebviewWindow();
|
||||||
|
|
||||||
export const LayoutControl = () => {
|
export const LayoutControl = () => {
|
||||||
const minWidth = 40;
|
const minWidth = 40;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
import { checkUpdate } from "@tauri-apps/api/updater";
|
import { check } from "@tauri-apps/plugin-updater";
|
||||||
import { UpdateViewer } from "../setting/mods/update-viewer";
|
import { UpdateViewer } from "../setting/mods/update-viewer";
|
||||||
import { DialogRef } from "../base";
|
import { DialogRef } from "../base";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
|
@ -19,7 +19,7 @@ export const UpdateButton = (props: Props) => {
|
||||||
|
|
||||||
const { data: updateInfo } = useSWR(
|
const { data: updateInfo } = useSWR(
|
||||||
auto_check_update || auto_check_update === null ? "checkUpdate" : null,
|
auto_check_update || auto_check_update === null ? "checkUpdate" : null,
|
||||||
checkUpdate,
|
check,
|
||||||
{
|
{
|
||||||
errorRetryCount: 2,
|
errorRetryCount: 2,
|
||||||
revalidateIfStale: false,
|
revalidateIfStale: false,
|
||||||
|
@ -27,7 +27,7 @@ export const UpdateButton = (props: Props) => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!updateInfo?.shouldUpdate) return null;
|
if (!updateInfo?.available) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { alpha, createTheme, Shadows, Theme } from "@mui/material";
|
import { alpha, createTheme, Shadows, Theme } from "@mui/material";
|
||||||
import { appWindow } from "@tauri-apps/api/window";
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||||
import { useSetThemeMode, useThemeMode } from "@/services/states";
|
import { useSetThemeMode, useThemeMode } from "@/services/states";
|
||||||
import { defaultTheme, defaultDarkTheme } from "@/pages/_theme";
|
import { defaultTheme, defaultDarkTheme } from "@/pages/_theme";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
|
const appWindow = getCurrentWebviewWindow();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* custom theme
|
* custom theme
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
import { useThemeMode } from "@/services/states";
|
import { useThemeMode } from "@/services/states";
|
||||||
import { Notice } from "@/components/base";
|
import { Notice } from "@/components/base";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { appWindow } from "@tauri-apps/api/window";
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
import debounce from "@/utils/debounce";
|
import debounce from "@/utils/debounce";
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import { type JSONSchema7 } from "json-schema";
|
||||||
import metaSchema from "meta-json-schema/schemas/meta-json-schema.json";
|
import metaSchema from "meta-json-schema/schemas/meta-json-schema.json";
|
||||||
import mergeSchema from "meta-json-schema/schemas/clash-verge-merge-json-schema.json";
|
import mergeSchema from "meta-json-schema/schemas/clash-verge-merge-json-schema.json";
|
||||||
import pac from "types-pac/pac.d.ts?raw";
|
import pac from "types-pac/pac.d.ts?raw";
|
||||||
|
const appWindow = getCurrentWebviewWindow();
|
||||||
|
|
||||||
type Language = "yaml" | "javascript" | "css";
|
type Language = "yaml" | "javascript" | "css";
|
||||||
type Schema<T extends Language> = LanguageSchemaMap[T];
|
type Schema<T extends Language> = LanguageSchemaMap[T];
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { DeleteForeverRounded, UndoRounded } from "@mui/icons-material";
|
||||||
import { useSortable } from "@dnd-kit/sortable";
|
import { useSortable } from "@dnd-kit/sortable";
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
import { downloadIconCache } from "@/services/cmds";
|
import { downloadIconCache } from "@/services/cmds";
|
||||||
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
interface Props {
|
interface Props {
|
||||||
type: "prepend" | "original" | "delete" | "append";
|
type: "prepend" | "original" | "delete" | "append";
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { EditorViewer } from "@/components/profile/editor-viewer";
|
||||||
import { ProfileBox } from "./profile-box";
|
import { ProfileBox } from "./profile-box";
|
||||||
import parseTraffic from "@/utils/parse-traffic";
|
import parseTraffic from "@/utils/parse-traffic";
|
||||||
import { ConfirmViewer } from "@/components/profile/confirm-viewer";
|
import { ConfirmViewer } from "@/components/profile/confirm-viewer";
|
||||||
import { open } from "@tauri-apps/api/shell";
|
import { open } from "@tauri-apps/plugin-shell";
|
||||||
import { ProxiesEditorViewer } from "./proxies-editor-viewer";
|
import { ProxiesEditorViewer } from "./proxies-editor-viewer";
|
||||||
const round = keyframes`
|
const round = keyframes`
|
||||||
from { transform: rotate(0deg); }
|
from { transform: rotate(0deg); }
|
||||||
|
|
|
@ -19,7 +19,7 @@ import type { IRenderItem } from "./use-render-list";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { useThemeMode } from "@/services/states";
|
import { useThemeMode } from "@/services/states";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||||
import { downloadIconCache } from "@/services/cmds";
|
import { downloadIconCache } from "@/services/cmds";
|
||||||
|
|
||||||
interface RenderProps {
|
interface RenderProps {
|
||||||
|
|
|
@ -12,11 +12,11 @@ import {
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base";
|
import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base";
|
||||||
import { GuardState } from "./guard-state";
|
import { GuardState } from "./guard-state";
|
||||||
import { open as openDialog } from "@tauri-apps/api/dialog";
|
import { open as openDialog } from "@tauri-apps/plugin-dialog";
|
||||||
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||||
import { copyIconFile, getAppDir } from "@/services/cmds";
|
import { copyIconFile, getAppDir } from "@/services/cmds";
|
||||||
import { join } from "@tauri-apps/api/path";
|
import { join } from "@tauri-apps/api/path";
|
||||||
import { exists } from "@tauri-apps/api/fs";
|
import { exists } from "@tauri-apps/plugin-fs";
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
|
|
||||||
const OS = getSystem();
|
const OS = getSystem();
|
||||||
|
@ -186,7 +186,7 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
onChangeData({ common_tray_icon: false });
|
onChangeData({ common_tray_icon: false });
|
||||||
patchVerge({ common_tray_icon: false });
|
patchVerge({ common_tray_icon: false });
|
||||||
} else {
|
} else {
|
||||||
const path = await openDialog({
|
const selected = await openDialog({
|
||||||
directory: false,
|
directory: false,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
filters: [
|
filters: [
|
||||||
|
@ -196,8 +196,8 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
if (path?.length) {
|
if (selected?.path.length) {
|
||||||
await copyIconFile(`${path}`, "common");
|
await copyIconFile(`${selected.path}`, "common");
|
||||||
await initIconPath();
|
await initIconPath();
|
||||||
onChangeData({ common_tray_icon: true });
|
onChangeData({ common_tray_icon: true });
|
||||||
patchVerge({ common_tray_icon: true });
|
patchVerge({ common_tray_icon: true });
|
||||||
|
@ -232,7 +232,7 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
onChangeData({ sysproxy_tray_icon: false });
|
onChangeData({ sysproxy_tray_icon: false });
|
||||||
patchVerge({ sysproxy_tray_icon: false });
|
patchVerge({ sysproxy_tray_icon: false });
|
||||||
} else {
|
} else {
|
||||||
const path = await openDialog({
|
const selected = await openDialog({
|
||||||
directory: false,
|
directory: false,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
filters: [
|
filters: [
|
||||||
|
@ -242,8 +242,8 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
if (path?.length) {
|
if (selected?.path.length) {
|
||||||
await copyIconFile(`${path}`, "sysproxy");
|
await copyIconFile(`${selected.path}`, "sysproxy");
|
||||||
await initIconPath();
|
await initIconPath();
|
||||||
onChangeData({ sysproxy_tray_icon: true });
|
onChangeData({ sysproxy_tray_icon: true });
|
||||||
patchVerge({ sysproxy_tray_icon: true });
|
patchVerge({ sysproxy_tray_icon: true });
|
||||||
|
@ -276,7 +276,7 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
onChangeData({ tun_tray_icon: false });
|
onChangeData({ tun_tray_icon: false });
|
||||||
patchVerge({ tun_tray_icon: false });
|
patchVerge({ tun_tray_icon: false });
|
||||||
} else {
|
} else {
|
||||||
const path = await openDialog({
|
const selected = await openDialog({
|
||||||
directory: false,
|
directory: false,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
filters: [
|
filters: [
|
||||||
|
@ -286,8 +286,8 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
if (path?.length) {
|
if (selected?.path.length) {
|
||||||
await copyIconFile(`${path}`, "tun");
|
await copyIconFile(`${selected.path}`, "tun");
|
||||||
await initIconPath();
|
await initIconPath();
|
||||||
onChangeData({ tun_tray_icon: true });
|
onChangeData({ tun_tray_icon: true });
|
||||||
patchVerge({ tun_tray_icon: true });
|
patchVerge({ tun_tray_icon: true });
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||||
import { getNetworkInterfacesInfo } from "@/services/cmds";
|
import { getNetworkInterfacesInfo } from "@/services/cmds";
|
||||||
import { alpha, Box, Button, Chip, IconButton } from "@mui/material";
|
import { alpha, Box, Button, Chip, IconButton } from "@mui/material";
|
||||||
import { ContentCopyRounded } from "@mui/icons-material";
|
import { ContentCopyRounded } from "@mui/icons-material";
|
||||||
import { writeText } from "@tauri-apps/api/clipboard";
|
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
|
||||||
|
|
||||||
export const NetworkInterfaceViewer = forwardRef<DialogRef>((props, ref) => {
|
export const NetworkInterfaceViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
|
@ -3,13 +3,13 @@ import { forwardRef, useImperativeHandle, useState, useMemo } from "react";
|
||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import { Box, LinearProgress, Button } from "@mui/material";
|
import { Box, LinearProgress, Button } from "@mui/material";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { relaunch } from "@tauri-apps/api/process";
|
import { relaunch } from "@tauri-apps/plugin-process";
|
||||||
import { checkUpdate, installUpdate } from "@tauri-apps/api/updater";
|
import { check as checkUpdate } from "@tauri-apps/plugin-updater";
|
||||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||||
import { useUpdateState, useSetUpdateState } from "@/services/states";
|
import { useUpdateState, useSetUpdateState } from "@/services/states";
|
||||||
import { listen, Event, UnlistenFn } from "@tauri-apps/api/event";
|
import { listen, Event, UnlistenFn } from "@tauri-apps/api/event";
|
||||||
import { portableFlag } from "@/pages/_layout";
|
import { portableFlag } from "@/pages/_layout";
|
||||||
import { open as openUrl } from "@tauri-apps/api/shell";
|
import { open as openUrl } from "@tauri-apps/plugin-shell";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
let eventListener: UnlistenFn | null = null;
|
let eventListener: UnlistenFn | null = null;
|
||||||
|
@ -38,17 +38,17 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const markdownContent = useMemo(() => {
|
const markdownContent = useMemo(() => {
|
||||||
if (!updateInfo?.manifest?.body) {
|
if (!updateInfo?.body) {
|
||||||
return "New Version is available";
|
return "New Version is available";
|
||||||
}
|
}
|
||||||
return updateInfo?.manifest?.body;
|
return updateInfo?.body;
|
||||||
}, [updateInfo]);
|
}, [updateInfo]);
|
||||||
|
|
||||||
const breakChangeFlag = useMemo(() => {
|
const breakChangeFlag = useMemo(() => {
|
||||||
if (!updateInfo?.manifest?.body) {
|
if (!updateInfo?.body) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return updateInfo?.manifest?.body.toLowerCase().includes("break change");
|
return updateInfo?.body.toLowerCase().includes("break change");
|
||||||
}, [updateInfo]);
|
}, [updateInfo]);
|
||||||
|
|
||||||
const onUpdate = useLockFn(async () => {
|
const onUpdate = useLockFn(async () => {
|
||||||
|
@ -56,7 +56,7 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
Notice.error(t("Portable Updater Error"));
|
Notice.error(t("Portable Updater Error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!updateInfo?.manifest?.body) return;
|
if (!updateInfo?.body) return;
|
||||||
if (breakChangeFlag) {
|
if (breakChangeFlag) {
|
||||||
Notice.error(t("Break Change Update Error"));
|
Notice.error(t("Break Change Update Error"));
|
||||||
return;
|
return;
|
||||||
|
@ -77,7 +77,7 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await installUpdate();
|
await updateInfo.install();
|
||||||
await relaunch();
|
await relaunch();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
Notice.error(err?.message || err.toString());
|
Notice.error(err?.message || err.toString());
|
||||||
|
@ -91,14 +91,14 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
open={open}
|
open={open}
|
||||||
title={
|
title={
|
||||||
<Box display="flex" justifyContent="space-between">
|
<Box display="flex" justifyContent="space-between">
|
||||||
{`New Version v${updateInfo?.manifest?.version}`}
|
{`New Version v${updateInfo?.version}`}
|
||||||
<Box>
|
<Box>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openUrl(
|
openUrl(
|
||||||
`https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/v${updateInfo?.manifest?.version}`
|
`https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/v${updateInfo?.version}`
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
import { useCallback, useRef } from "react";
|
import { useCallback, useRef } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { open } from "@tauri-apps/api/dialog";
|
import { open } from "@tauri-apps/plugin-dialog";
|
||||||
import {
|
import { Button, MenuItem, Select, Input, Typography } from "@mui/material";
|
||||||
Button,
|
|
||||||
MenuItem,
|
|
||||||
Select,
|
|
||||||
Input,
|
|
||||||
Typography,
|
|
||||||
Box,
|
|
||||||
} from "@mui/material";
|
|
||||||
import {
|
import {
|
||||||
exitApp,
|
exitApp,
|
||||||
openAppDir,
|
openAppDir,
|
||||||
|
@ -17,7 +10,7 @@ import {
|
||||||
openDevTools,
|
openDevTools,
|
||||||
copyClashEnv,
|
copyClashEnv,
|
||||||
} from "@/services/cmds";
|
} from "@/services/cmds";
|
||||||
import { checkUpdate } from "@tauri-apps/api/updater";
|
import { check as checkUpdate } from "@tauri-apps/plugin-updater";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { version } from "@root/package.json";
|
import { version } from "@root/package.json";
|
||||||
import { DialogRef, Notice } from "@/components/base";
|
import { DialogRef, Notice } from "@/components/base";
|
||||||
|
@ -67,7 +60,7 @@ const SettingVerge = ({ onError }: Props) => {
|
||||||
const onCheckUpdate = async () => {
|
const onCheckUpdate = async () => {
|
||||||
try {
|
try {
|
||||||
const info = await checkUpdate();
|
const info = await checkUpdate();
|
||||||
if (!info?.shouldUpdate) {
|
if (!info?.available) {
|
||||||
Notice.success(t("Currently on the Latest Version"));
|
Notice.success(t("Currently on the Latest Version"));
|
||||||
} else {
|
} else {
|
||||||
updateRef.current?.open();
|
updateRef.current?.open();
|
||||||
|
@ -191,7 +184,7 @@ const SettingVerge = ({ onError }: Props) => {
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const path = await open({
|
const selected = await open({
|
||||||
directory: false,
|
directory: false,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
filters: [
|
filters: [
|
||||||
|
@ -201,9 +194,9 @@ const SettingVerge = ({ onError }: Props) => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
if (path?.length) {
|
if (selected?.path.length) {
|
||||||
onChangeData({ startup_script: `${path}` });
|
onChangeData({ startup_script: `${selected.path}` });
|
||||||
patchVerge({ startup_script: `${path}` });
|
patchVerge({ startup_script: `${selected.path}` });
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { TestBox } from "./test-box";
|
||||||
import delayManager from "@/services/delay";
|
import delayManager from "@/services/delay";
|
||||||
import { cmdTestDelay, downloadIconCache } from "@/services/cmds";
|
import { cmdTestDelay, downloadIconCache } from "@/services/cmds";
|
||||||
import { listen, UnlistenFn } from "@tauri-apps/api/event";
|
import { listen, UnlistenFn } from "@tauri-apps/api/event";
|
||||||
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useRoutes } from "react-router-dom";
|
import { useLocation, useRoutes } from "react-router-dom";
|
||||||
import { List, Paper, ThemeProvider, SvgIcon } from "@mui/material";
|
import { List, Paper, ThemeProvider, SvgIcon } from "@mui/material";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import { appWindow } from "@tauri-apps/api/window";
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||||
import { routers } from "./_routers";
|
import { routers } from "./_routers";
|
||||||
import { getAxios } from "@/services/api";
|
import { getAxios } from "@/services/api";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
|
@ -28,6 +28,7 @@ import { getPortableFlag } from "@/services/cmds";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { TransitionGroup, CSSTransition } from "react-transition-group";
|
import { TransitionGroup, CSSTransition } from "react-transition-group";
|
||||||
|
const appWindow = getCurrentWebviewWindow();
|
||||||
export let portableFlag = false;
|
export let portableFlag = false;
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
|
@ -48,8 +48,8 @@ import { ConfigViewer } from "@/components/setting/mods/config-viewer";
|
||||||
import { throttle } from "lodash-es";
|
import { throttle } from "lodash-es";
|
||||||
import { BaseStyledTextField } from "@/components/base/base-styled-text-field";
|
import { BaseStyledTextField } from "@/components/base/base-styled-text-field";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import { readTextFile } from "@tauri-apps/api/fs";
|
import { readTextFile } from "@tauri-apps/plugin-fs";
|
||||||
import { readText } from "@tauri-apps/api/clipboard";
|
import { readText } from "@tauri-apps/plugin-clipboard-manager";
|
||||||
|
|
||||||
const ProfilePage = () => {
|
const ProfilePage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { Notice } from "@/components/base";
|
import { Notice } from "@/components/base";
|
||||||
|
|
||||||
export async function copyClashEnv() {
|
export async function copyClashEnv() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user