Compare commits

..
Author SHA1 Message Date
oomeow d5b00acb02 Merge remote-tracking branch 'origin/dev' into fix/menu-accelerator 2026-10-22 23:58:55 +08:00
❤是纱雾酱哟~ 3d9a79a3fb fix(windows): patch executable for common-controls-v6 (#8378)
- Enhance patch logic, also patch for "example" executables

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
2026-10-22 09:59:10 +00:00
❤是纱雾酱哟~andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 8b88ddb7f2 chore(deps): update node.js to v24.22.1 (#8389)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-21 17:25:15 +00:00
Tunglies 02bd739ab6 docs: clarify issue and PR intake rules 2026-10-21 19:36:50 +08:00
renovate[bot]renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Tunglies
b6c7af82a7 chore(deps): update tauri (#8346)
* chore(deps): update tauri

* fix(deps): pin rust-ini to 0.21.1 for tauri-plugin-deep-link 2.6.2

tauri-plugin-deep-link 2.6.2 constructs ini::ParseOption with an
exhaustive struct literal, which fails to compile against rust-ini
0.21.2+ (new required fields enabled_indented_mutiline_value and
enabled_preserve_key_leading_whitespace, E0063 on linux). Upstream
fixed it in tauri-apps/plugins-workspace#3711 with ..Default::default()
but no release contains the fix yet, so downgrade rust-ini in Cargo.lock
until deep-link 2.6.3 ships.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
2026-10-21 08:25:55 +00:00
oomeow 5c07ca2309 fix(tray): skip Win-key accelerators on Windows 2026-10-13 22:21:29 +08:00
23 changed files with 510 additions and 826 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
"features": {
"ghcr.io/devcontainers/features/node:2": {
"version": "24.22.0",
"version": "24.22.1",
"pnpmVersion": "12.14.0"
},
"ghcr.io/devcontainers/features/rust:1": {
+33
View File
@@ -0,0 +1,33 @@
# Issue Guidelines / Issue 提交指引
Use these suggestions to make reports easier to assess. State what you observed
and what you could not verify; unknown details are fine.
以下建议有助于维护者评估问题。请说明实际观察到的现象和无法确认的部分;未知信息可以留空。
- Search existing issues by symptom, conditions, and outcome. Add new evidence
to an existing report when it describes the same problem.
按现象、条件和结果搜索已有 Issue。若描述的是同一问题,请在原 Issue 中补充新证据。
- Keep each issue to one distinct user problem or requested outcome. Split
unrelated findings instead of bundling an audit or checklist.
每个 Issue 聚焦一个独立的问题或需求结果;无关发现请拆开,不要把审计清单打包成一个 Issue。
- For bugs, include the version, operating system, steps, and actual versus
expected behavior when known. A root-cause diagnosis is not required. Share
only relevant logs and redact tokens or personal information.
反馈 Bug 时,尽可能提供版本、操作系统、复现步骤及实际与预期行为。无需先判断根因;只提供相关日志,并遮盖令牌和个人信息。
- For feature requests, describe the user task, current limitation, desired
outcome, and affected platforms. An implementation proposal is optional.
提交功能请求时,请描述用户要完成的任务、当前限制、期望结果和适用平台;实现方案不是必填项。
- Separate observations from guesses. An AI or scanner finding is a hypothesis
until its affected configuration, concrete impact, and supporting evidence
are stated; do not present a list of theoretical risks as confirmed bugs.
区分观察结果和推测。AI 或扫描器的发现应先视为假设;请说明受影响的配置、具体影响和支持证据,不要把理论风险清单写成已确认的 Bug。
- Do not post secrets, personal data, or sensitive exploit details in a public
issue. Ask maintainers how to share sensitive security information safely.
请勿在公开 Issue 中发布密钥、个人信息或敏感利用细节;如涉及安全敏感信息,请先询问维护者如何安全提供。
- AI assistance is welcome; human contributors do not need to disclose it. If
an AI agent or automation creates or co-authors an issue, add a final body line
such as `Assisted by: GPT-5.6 High`. Omit effort when the runtime does not
report it. Disclosure is transparency only, not evidence for or against issue
quality.
欢迎使用 AI 辅助,人工提交者无需披露。如果 Issue 由 AI Agent 或自动化创建或共同撰写,请在正文末尾添加披露行,例如 `Assisted by: GPT-5.6 High`。运行环境未提供 effort 时可省略。披露仅用于提高透明度,不作为 Issue 质量的正面或负面证据。
+4
View File
@@ -10,6 +10,8 @@ body:
value: |
## 在提交问题之前,请确认以下事项:
提交前可参考 [Issue 提交指引](https://github.com/clash-verge-rev/clash-verge-rev/blob/dev/.github/ISSUE_GUIDELINES.md),说明可观察到的问题和证据;不确定的原因请标为猜测。
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 以及 [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似 issue,否则请在已有的 issue 下进行讨论
3. 请 **务必** 给 issue 填写一个简洁明了的标题,以便他人快速检索
@@ -19,6 +21,8 @@ body:
## Before submitting the issue, please make sure of the following checklist:
See the [Issue guidelines](https://github.com/clash-verge-rev/clash-verge-rev/blob/dev/.github/ISSUE_GUIDELINES.md) for how to describe observed behavior and evidence; mark uncertain causes as hypotheses.
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) and [FAQ](https://clash-verge-rev.github.io/faq/windows.html)
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
@@ -9,12 +9,16 @@ body:
attributes:
value: |
## 在提交问题之前,请确认以下事项:
可参考 [Issue 提交指引](https://github.com/clash-verge-rev/clash-verge-rev/blob/dev/.github/ISSUE_GUIDELINES.md),描述用户任务、当前限制和期望结果。
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 确认软件不存在类似的功能
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似 issue,否则请在已有的 issue 下进行讨论
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
4. 请 **务必** 先下载 [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) 版本测试,确保该功能还未实现
5. 请 **务必** 按照模板规范详细描述问题,否则 issue 将会被关闭
## Before submitting the issue, please make sure of the following checklist:
See the [Issue guidelines](https://github.com/clash-verge-rev/clash-verge-rev/blob/dev/.github/ISSUE_GUIDELINES.md) for describing the user task, current limitation, and desired outcome.
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) to confirm that the software does not have similar functions
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
+7 -1
View File
@@ -1,6 +1,12 @@
## Problem
What breaks or what is missing. Link the issue if one exists (`Fixes #123`).
What breaks or what is missing. Product bug fixes and features require a
pre-existing issue; link it here (`Fixes #123` only when this PR fully resolves
it). Maintenance work (such as chore, perf, docs, refactor, test, CI/build,
dependency, style, routine localization, or release changes) does not require
an issue link; link one when it defines the scope. For reverts, link the PR or
commit being reverted. For security-sensitive fixes that cannot be tracked
publicly, follow maintainer-approved private tracking.
## Approach
+5 -5
View File
@@ -51,7 +51,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -185,7 +185,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
cache: 'pnpm'
- name: Pnpm Cache
@@ -282,7 +282,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
cache: 'pnpm'
- name: Pnpm Cache
@@ -426,7 +426,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
cache: 'pnpm'
- name: Pnpm Cache
@@ -524,7 +524,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6.1.0
name: Install pnpm
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
+1 -1
View File
@@ -103,7 +103,7 @@ jobs:
if: github.event.inputs[matrix.input] == 'true'
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
cache: 'pnpm'
- name: Pnpm Cache
+2 -2
View File
@@ -52,7 +52,7 @@ jobs:
- uses: actions/setup-node@v7
if: steps.check_frontend.outputs.frontend == 'true'
with:
node-version: '24.22.0'
node-version: '24.22.1'
cache: 'pnpm'
- name: Restore pnpm cache
@@ -138,7 +138,7 @@ jobs:
- uses: actions/setup-node@v7
if: steps.check_inputs.outputs.contract == 'true'
with:
node-version: '24.22.0'
node-version: '24.22.1'
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
+6 -6
View File
@@ -230,7 +230,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
@@ -331,7 +331,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- name: Install pnpm
uses: pnpm/action-setup@v6
@@ -466,7 +466,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
@@ -547,7 +547,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
@@ -573,7 +573,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
@@ -638,7 +638,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- name: Install pnpm
uses: pnpm/action-setup@v6
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
+2 -2
View File
@@ -15,7 +15,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
@@ -39,7 +39,7 @@ jobs:
- name: Install Node
uses: actions/setup-node@v7
with:
node-version: '24.22.0'
node-version: '24.22.1'
- uses: pnpm/action-setup@v6
name: Install pnpm
+1 -1
View File
@@ -1,3 +1,3 @@
nodejs 24.22.0
nodejs 24.22.1
pnpm 12.14.0
rust 1.99.1
+25 -21
View File
@@ -18,22 +18,25 @@ These rules apply to every change, whether human- or agent-authored. They match
the ownership evidence the AI-slop review evaluates (see
[`pr-ai-slop-review.md`](.github/workflows/pr-ai-slop-review.md)).
1. **Issue first.** Non-trivial changes require a pre-existing issue describing
the problem. If none exists, ask the maintainers to open or approve one
before implementing.
1. **Issue first.** Product bug fixes and features require a pre-existing issue;
self-scoped maintenance work does not. Follow the PR template for linkage and
revert references. If a required issue is missing, ask maintainers to open or
approve one before implementing. For security-sensitive fixes that cannot be
tracked publicly, follow maintainer-approved private tracking.
2. **Scope discipline.** Every changed file must be justifiable from the linked
issue. No drive-by refactors, renames, formatting churn, or dependency bumps
unrelated to the problem being fixed.
issue or the stated PR scope. No drive-by refactors, renames, formatting
churn, or dependency bumps unrelated to the work.
3. **Author accountability.** AI assistance is welcome, but the contributor owns
the result: understand the change, describe the problem and approach in your
own words, and verify the change against the reported behavior before
submitting.
4. **Tests are justified, not default.** Do not add tests, test scaffolding, or
speculative defensive code unless the linked issue demands them. When a test
is genuinely necessary — it reproduces the reported regression or guards
behavior whose breakage would otherwise go unnoticed — keep it minimal and
state in the PR body why it is needed. Bulk test files and defensive
programming for hypothetical failure modes are PR bloat, not rigor.
speculative defensive code unless the linked issue or stated task demands
them. When a test is genuinely necessary — it reproduces the reported
regression or guards behavior whose breakage would otherwise go unnoticed —
keep it minimal and state in the PR body why it is needed. Bulk test files
and defensive programming for hypothetical failure modes are PR bloat, not
rigor.
5. **Comments state constraints, not narration.** Write a comment only for a
non-obvious constraint the code cannot express; never restate what the code
does.
@@ -44,13 +47,12 @@ the ownership evidence the AI-slop review evaluates (see
real evidence instead: reproduction steps, failure output, targeted tests.
8. **Minimal diffs.** Match the surrounding code's style, naming, and comment
density. Do not introduce new dependencies or restructure working code unless
the issue demands it.
9. **Disclose AI automation.** When an agent produces or co-produces a change,
append a footer line to the PR body with the model and effort used (e.g.
`Assisted by: GPT-5.6 High`). The PR template intentionally omits this line —
the agent adds it itself, humans are not asked to declare anything. Effort may
be omitted when the runtime does not report it. Disclosure is transparency
only; it does not substitute for any rule above.
the linked issue or stated task demands it.
9. **Disclose AI automation.** When an agent creates or co-creates a PR or Issue,
append a final body line with the model and effort used (e.g.
`Assisted by: GPT-5.6 High`). Effort may be omitted when the runtime does not
report it. Human contributors are not asked to disclose AI assistance.
Disclosure is transparency only and carries no positive or negative weight.
10. **Compiled workflows.** The AI-slop review policy in
[pr-ai-slop-review.md](.github/workflows/pr-ai-slop-review.md) is compiled:
after editing it, run `gh aw compile` and commit the regenerated
@@ -59,8 +61,10 @@ the ownership evidence the AI-slop review evaluates (see
[`template/Changelog.md`](template/Changelog.md): one line per
user-visible change, no internals.
## Pull Request Shape
## Issue and PR Workflows
Describe three things, briefly: the problem (with issue link), why this approach
solves it, and what changed. See
[`PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md).
When drafting, triaging, splitting, or implementing from a community issue, use
the conditional checklist in [`.github/ISSUE_GUIDELINES.md`](.github/ISSUE_GUIDELINES.md).
Do not make GitHub issue changes without explicit authorization. For PRs, follow
the directly loaded [PR template](.github/PULL_REQUEST_TEMPLATE.md); do not
duplicate its prompts here.
Generated
+73 -160
View File
@@ -1119,7 +1119,7 @@ dependencies = [
"getrandom 0.4.3",
"libc",
"log",
"minisign-verify 0.3.0",
"minisign-verify",
"nanoid",
"network-interface",
"objc2",
@@ -4170,12 +4170,6 @@ dependencies = [
"unicase",
]
[[package]]
name = "minisign-verify"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e"
[[package]]
name = "minisign-verify"
version = "0.3.0"
@@ -5999,12 +5993,13 @@ dependencies = [
[[package]]
name = "rust-ini"
version = "0.21.3"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7"
checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f"
dependencies = [
"cfg-if",
"ordered-multimap",
"trim-in-place",
]
[[package]]
@@ -6625,7 +6620,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7"
dependencies = [
"libc",
"sigchld",
"windows-sys 0.60.2",
]
@@ -6645,17 +6639,6 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "sigchld"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1"
dependencies = [
"libc",
"os_pipe",
"signal-hook 0.3.18",
]
[[package]]
name = "signal-hook"
version = "0.1.17"
@@ -6666,16 +6649,6 @@ dependencies = [
"signal-hook-registry",
]
[[package]]
name = "signal-hook"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
@@ -6881,6 +6854,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "static_vcruntime"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff7589a1859b09232522bb9edf076ca7fcf14ded96685d3fa629db73023ffbb7"
[[package]]
name = "string_cache"
version = "0.9.0"
@@ -6940,9 +6919,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "swift-rs"
version = "1.0.8"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e45c444e496845d3f2a351146bff59aae4975b2280238df1dfaa0c7d1846f38e"
checksum = "cefd87076fd385308ee4aff597256c902f1fbb4d031de1558efc12f8ffefadd9"
dependencies = [
"base64 0.21.7",
"serde",
@@ -7189,9 +7168,9 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
[[package]]
name = "tauri"
version = "2.12.1"
version = "2.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed99ee9694a2deb776d91cae48ac7411ddfc89ecae2f9b5041111d8c88f2ace9"
checksum = "f316751027fc2644221d1a448564d519efb07067fda584879d9cda966391d212"
dependencies = [
"anyhow",
"bytes",
@@ -7237,16 +7216,16 @@ dependencies = [
"tray-icon",
"url",
"webkit2gtk",
"webview2-com 0.39.1",
"webview2-com",
"window-vibrancy",
"windows 0.62.2",
]
[[package]]
name = "tauri-build"
version = "2.7.1"
version = "2.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59563ca5b331fd97f27ee9672ec8d36d33bb3c9e2c9f6710a1a5687256052e45"
checksum = "641dd5fd297c99ab92717b0428cca5b9c6f960b2ac96ca131b3eebc9d70b8ddc"
dependencies = [
"anyhow",
"cargo_toml",
@@ -7258,6 +7237,8 @@ dependencies = [
"semver 1.0.28",
"serde",
"serde_json",
"static_vcruntime",
"strsim",
"tauri-utils",
"tauri-winres",
"walkdir",
@@ -7265,11 +7246,11 @@ dependencies = [
[[package]]
name = "tauri-codegen"
version = "2.7.1"
version = "2.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e50213e463086ecc283d7e9f51c30cc0fd304ad457425158018be26dbf0d0a80"
checksum = "a6585c5b536c00f039d12ce70a9755172d5423bbcfd3969863baa70314c3e02f"
dependencies = [
"base64 0.22.1",
"base64 0.23.1",
"brotli",
"ico",
"json-patch",
@@ -7292,9 +7273,9 @@ dependencies = [
[[package]]
name = "tauri-macros"
version = "2.7.1"
version = "2.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8129fb43bb6e0d6b73ad3315cd172beaab17cd28899c594b1b32c80edbbfd99c"
checksum = "e2e83a0cfa1bae376e8fbbdc0b1692707aed50cd6072ce85cae4789af5d6c19f"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -7350,9 +7331,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-clipboard-manager"
version = "2.4.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "333d3b6beeb1c2c7fc040233d4ea7b6c03a9f8f039592b7400833c43fb5b568a"
checksum = "9be5ed8d94c33afe8377e885119069f6508780659271d0a25cfc54d441f2bc81"
dependencies = [
"arboard",
"log",
@@ -7365,9 +7346,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-deep-link"
version = "2.6.1"
version = "2.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac7a92a46ab5c88f44532ca50906d6e448a948d4ddf8c5376ab125e3260f736"
checksum = "1b3c64e24ebcbc63aaa2d88a9c51e2507084b46620baf39ecb0baa0738a08bb4"
dependencies = [
"dunce",
"plist",
@@ -7413,9 +7394,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-dialog"
version = "2.8.1"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf9a5c92e39bdd84f22f6be9230e39d0c4e140345f71ffe6058dca4f71127cf"
checksum = "b7461aaacf1901915ea7b9f5cd74f8224a351ed96af0a62c07fce934003cb34b"
dependencies = [
"log",
"raw-window-handle",
@@ -7431,9 +7412,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs"
version = "2.6.0"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "466eb32466fe5021b6728b06862f9ff14a9f7e1af890047654e03a96d7c0e1bb"
checksum = "5d58eb1d4984e535f47a642ffec09a2da6f5c18a12b5902d12126cb7626d628b"
dependencies = [
"anyhow",
"dunce",
@@ -7455,9 +7436,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-global-shortcut"
version = "2.4.0"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bd2e1f725891a1613af8f25bf918ba3357654b0fd3f2d794c0ce76cbdd92ed2"
checksum = "93ff17919fe09852d269bd37b1d3d2e993b9dbb514afe7acbf3346c1d3627e2d"
dependencies = [
"global-hotkey",
"log",
@@ -7470,9 +7451,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-http"
version = "2.8.0"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93e9d6b3319e101bc1be27cfa0fb4054d7784a12509c67ead0033b82180e5ed1"
checksum = "2c57e3451553f95a1db3bfed6a358a77ce5080b6399a242c6eadac113f97abd2"
dependencies = [
"bytes",
"cookie_store",
@@ -7489,7 +7470,7 @@ dependencies = [
"thiserror 2.0.20",
"tokio",
"url",
"urlpattern 0.3.0",
"urlpattern",
]
[[package]]
@@ -7519,9 +7500,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-notification"
version = "2.5.1"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "533770889abb60a0407d5a32096182f0e6463f5a3dfaa675be94580aa14070e1"
checksum = "b939d7b19c8af1381a72ef8474b3aba2b56c1ddac2c23f0c8e96abbcf86b198b"
dependencies = [
"log",
"notify-rust",
@@ -7534,13 +7515,14 @@ dependencies = [
"thiserror 2.0.20",
"time",
"url",
"zbus",
]
[[package]]
name = "tauri-plugin-opener"
version = "2.7.0"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39404b2572927e0d3ed30a7ca226037f7508d22e79c96ee6ef0d42b6a4b3345"
checksum = "53810be1b4fed22bb6ac3f4cab5a2b80d9391d1af436bda145607532bc0bb219"
dependencies = [
"dunce",
"glob",
@@ -7570,11 +7552,12 @@ dependencies = [
[[package]]
name = "tauri-plugin-shell"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "094bdbc47e5efe36544ba21b3a53ab5c724150236cf55e6c9be46191deb6eab6"
checksum = "8567d42b2c7264355daa1df415ec77f52aa42e885924c86a969be2e920e05521"
dependencies = [
"encoding_rs",
"libc",
"log",
"open",
"os_pipe",
@@ -7587,13 +7570,14 @@ dependencies = [
"tauri-plugin",
"thiserror 2.0.20",
"tokio",
"windows-sys 0.60.2",
]
[[package]]
name = "tauri-plugin-updater"
version = "2.13.1"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb0b2ea3e85ca287990d3859a29cc5cb18024240fd78f62e027fb7963670f18"
checksum = "7259989d4fe11b2bf51f7d671642249b1837c4ae2da1430dc713ae38f98ceeec"
dependencies = [
"base64 0.22.1",
"dirs 7.0.0",
@@ -7601,8 +7585,9 @@ dependencies = [
"futures-util",
"http",
"infer",
"libc",
"log",
"minisign-verify 0.2.5",
"minisign-verify",
"osakit",
"percent-encoding",
"reqwest 0.13.5",
@@ -7624,9 +7609,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-wdio-webdriver"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52c5e97428174a52b7f4357bbc4535fcce52c6a06c8ee7a379502f7cda1b6045"
checksum = "4f76676d510d271d80abcf8b0552987b5b4f0eae5e3f906e9b5660d43c97c62e"
dependencies = [
"async-trait",
"axum",
@@ -7650,9 +7635,9 @@ dependencies = [
"tracing",
"uuid",
"webkit2gtk",
"webview2-com 0.38.2",
"windows 0.61.3",
"windows-core 0.61.2",
"webview2-com",
"windows 0.62.2",
"windows-core 0.62.2",
]
[[package]]
@@ -7672,9 +7657,9 @@ dependencies = [
[[package]]
name = "tauri-runtime"
version = "2.12.1"
version = "2.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a57a2a9b8c8b7fc00d35b510fe808ded7f9f1b44fc1cdda6aee38632ea5413"
checksum = "7c55766d99cea69055904d1735b93c2049302b2e09effd462120deb5581d78e9"
dependencies = [
"cookie",
"dpi",
@@ -7691,15 +7676,15 @@ dependencies = [
"thiserror 2.0.20",
"url",
"webkit2gtk",
"webview2-com 0.39.1",
"webview2-com",
"windows 0.62.2",
]
[[package]]
name = "tauri-runtime-wry"
version = "2.12.1"
version = "2.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9e7e0c9f80a5130773cfabb6df4dc924518fb1b2c923726966804634b57d22"
checksum = "8d61892587aea2a85245bcaec98c6fe46268874c0a0deae5535fb71ca7b93eae"
dependencies = [
"gtk",
"http",
@@ -7717,7 +7702,7 @@ dependencies = [
"tracing",
"url",
"webkit2gtk",
"webview2-com 0.39.1",
"webview2-com",
"windows 0.62.2",
"wry",
]
@@ -7755,9 +7740,9 @@ dependencies = [
[[package]]
name = "tauri-utils"
version = "2.10.1"
version = "2.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ff55a614843b9a3f010f211df637c94df2607175b8d0f6e0f4a7c19e18621ee"
checksum = "362ab21cd4cc713f2a02b1a9b5688198b1541cfb6907c4281e9190e0f0ef4aa3"
dependencies = [
"anyhow",
"brotli",
@@ -7786,7 +7771,7 @@ dependencies = [
"thiserror 2.0.20",
"toml 1.1.6+spec-1.1.0",
"url",
"urlpattern 0.6.0",
"urlpattern",
"uuid",
"walkdir",
]
@@ -7905,7 +7890,7 @@ dependencies = [
"regex",
"semver 0.11.0",
"sha2 0.9.9",
"signal-hook 0.1.17",
"signal-hook",
"terminfo",
"termios",
"thiserror 1.0.69",
@@ -8503,6 +8488,12 @@ dependencies = [
"petgraph",
]
[[package]]
name = "trim-in-place"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daa60874b45b168f67f3f9ba1ee821ad77144d6fa19cef1cd1874a7450a948da"
[[package]]
name = "triomphe"
version = "0.1.16"
@@ -8595,47 +8586,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-ucd-ident"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicase"
version = "2.9.0"
@@ -8695,18 +8645,6 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "urlpattern"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d"
dependencies = [
"regex",
"serde",
"unic-ucd-ident",
"url",
]
[[package]]
name = "urlpattern"
version = "0.6.0"
@@ -9098,20 +9036,6 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webview2-com"
version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a"
dependencies = [
"webview2-com-macros",
"webview2-com-sys 0.38.2",
"windows 0.61.3",
"windows-core 0.61.2",
"windows-implement",
"windows-interface",
]
[[package]]
name = "webview2-com"
version = "0.39.1"
@@ -9119,7 +9043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f89fca7a704cee10dcb3654c1dbb8941d1783132f1917358af75bec37a7d7e6"
dependencies = [
"webview2-com-macros",
"webview2-com-sys 0.39.1",
"webview2-com-sys",
"windows 0.62.2",
"windows-core 0.62.2",
]
@@ -9135,17 +9059,6 @@ dependencies = [
"syn 2.0.119",
]
[[package]]
name = "webview2-com-sys"
version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c"
dependencies = [
"thiserror 2.0.20",
"windows 0.61.3",
"windows-core 0.61.2",
]
[[package]]
name = "webview2-com-sys"
version = "0.39.1"
@@ -9885,7 +9798,7 @@ dependencies = [
"url",
"webkit2gtk",
"webkit2gtk-sys",
"webview2-com 0.39.1",
"webview2-com",
"windows 0.62.2",
"windows-core 0.62.2",
"windows-version",
+2 -2
View File
@@ -61,8 +61,8 @@ tracing-estuary = { git = "https://github.com/Tunglies/tracing-estuary.git", bra
tauri-plugin-clash-verge-sysinfo = { path = "crates/tauri-plugin-clash-verge-sysinfo" }
tracing = "0.1.44"
tauri = { version = "2.12.1" }
tauri-plugin-clipboard-manager = "2.4.1"
tauri = { version = "2.12.4" }
tauri-plugin-clipboard-manager = "2.5.0"
parking_lot = { version = "0.12.5", features = ["hardware-lock-elision"] }
anyhow = "1.0.104"
chrono = "0.4.45"
+9 -9
View File
@@ -54,13 +54,13 @@
"@mui/icons-material": "^9.4.0",
"@mui/material": "^9.4.0",
"@tanstack/react-virtual": "^3.14.13",
"@tauri-apps/api": "2.12.1",
"@tauri-apps/plugin-clipboard-manager": "2.4.0",
"@tauri-apps/plugin-dialog": "2.8.0",
"@tauri-apps/plugin-fs": "2.6.0",
"@tauri-apps/plugin-http": "2.8.0",
"@tauri-apps/plugin-opener": "2.7.0",
"@tauri-apps/plugin-updater": "2.13.1",
"@tauri-apps/api": "2.12.4",
"@tauri-apps/plugin-clipboard-manager": "2.5.0",
"@tauri-apps/plugin-dialog": "2.8.3",
"@tauri-apps/plugin-fs": "2.7.1",
"@tauri-apps/plugin-http": "2.8.3",
"@tauri-apps/plugin-opener": "2.7.2",
"@tauri-apps/plugin-updater": "2.14.0",
"ahooks": "^3.10.0",
"cidr-block": "^2.3.0",
"compare-versions": "^6.1.1",
@@ -95,7 +95,7 @@
"@biomejs/biome": "^2.5.14",
"@eslint-react/eslint-plugin": "^5.20.5",
"@eslint/js": "^10.0.1",
"@tauri-apps/cli": "2.12.1",
"@tauri-apps/cli": "2.12.3",
"@types/lodash-es": "^4.17.12",
"@types/node": "^24.13.6",
"@types/react": "19.3.0",
@@ -103,7 +103,7 @@
"@types/validator": "^13.15.10",
"@vitejs/plugin-legacy": "^8.2.3",
"@vitejs/plugin-react": "^6.1.1",
"@wdio/tauri-service": "1.4.0",
"@wdio/tauri-service": "1.5.0",
"adm-zip": "^0.6.1",
"axios": "^1.20.0",
"cli-color": "^2.0.4",
+145 -145
View File
@@ -200,26 +200,26 @@ importers:
specifier: ^3.14.13
version: 3.14.13(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
'@tauri-apps/api':
specifier: 2.12.1
version: 2.12.1
specifier: 2.12.4
version: 2.12.4
'@tauri-apps/plugin-clipboard-manager':
specifier: 2.4.0
version: 2.4.0
specifier: 2.5.0
version: 2.5.0
'@tauri-apps/plugin-dialog':
specifier: 2.8.0
version: 2.8.0
specifier: 2.8.3
version: 2.8.3
'@tauri-apps/plugin-fs':
specifier: 2.6.0
version: 2.6.0
specifier: 2.7.1
version: 2.7.1
'@tauri-apps/plugin-http':
specifier: 2.8.0
version: 2.8.0
specifier: 2.8.3
version: 2.8.3
'@tauri-apps/plugin-opener':
specifier: 2.7.0
version: 2.7.0
specifier: 2.7.2
version: 2.7.2
'@tauri-apps/plugin-updater':
specifier: 2.13.1
version: 2.13.1
specifier: 2.14.0
version: 2.14.0
ahooks:
specifier: ^3.10.0
version: 3.10.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
@@ -318,8 +318,8 @@ importers:
specifier: ^10.0.1
version: 10.0.1(eslint@10.11.0(jiti@2.7.0)(supports-color@7.2.0))
'@tauri-apps/cli':
specifier: 2.12.1
version: 2.12.1
specifier: 2.12.3
version: 2.12.3
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
@@ -342,8 +342,8 @@ importers:
specifier: ^6.1.1
version: 6.1.1(vite@8.3.0(@types/node@24.13.6)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.1)(terser@5.51.2)(yaml@2.9.1))
'@wdio/tauri-service':
specifier: 1.4.0
version: 1.4.0(expect-webdriverio@5.7.0)(supports-color@7.2.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
specifier: 1.5.0
version: 1.5.0(expect-webdriverio@6.1.0)(supports-color@7.2.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
adm-zip:
specifier: ^0.6.1
version: 0.6.1
@@ -2129,102 +2129,102 @@ packages:
'@tanstack/virtual-core@3.17.11':
resolution: {integrity: sha512-+ILjvtHup6Y2hzQ6YzwMgX1Q+oQpxEGOXCEsCNaPoIP0VxMbizIBTmYTDtkerkIQS8/CbP1BRuyt8V/8BCsy1g==}
'@tauri-apps/api@2.12.1':
resolution: {integrity: sha512-DeyFHa3wynpyoqTDikDEDGTJIq4LQ5USfolQGRmGIWT6JMADyxZBTDa5cAdT3tDg73rUXufPaCwN7aXBos4OnQ==}
'@tauri-apps/api@2.12.4':
resolution: {integrity: sha512-pVmfis+4zT8H0Qhp3xPZx9Ju7kpzvA6rr/PSJPyuwfvucTQ8sVt61NYU9KMkK703UFlYadFmjKA4HhybOtN0gg==}
'@tauri-apps/cli-darwin-arm64@2.12.1':
resolution: {integrity: sha512-8bMnbpJ2jKO/ufrOPL65EMHC3ptw7fzeraoQkwibyfGLqIl+UCWsC0152kmNbW6r9NvVQduXqAZF5mH1QgTWhw==}
'@tauri-apps/cli-darwin-arm64@2.12.3':
resolution: {integrity: sha512-xmVNoJOOKzKLj7GLHXmXLimRby9M42aBIJa0sB80N7o24eKV5JiVmToKTRLVH9yhL05GZ/B6rSSOmbzNFJwBAA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@tauri-apps/cli-darwin-x64@2.12.1':
resolution: {integrity: sha512-G+2qte8GNqNlEZ9ftd21rbu/APVkl3r/nzNDI7LVxEoqJWVNe9GbEgQUMH1r4PHT20Z2UxR3KjCkltIb0e/Wjg==}
'@tauri-apps/cli-darwin-x64@2.12.3':
resolution: {integrity: sha512-URd+0usfmUQQyb5kNPiKt2OT8gp7oGU7QR+qOppB6e35mpVBFFVNhWc9oWb3p0u71fDJ09DpF4T6m9xYxoIB8g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.1':
resolution: {integrity: sha512-5b3n4DaTW+A1Zntnh4Yn44VyLrlPEpB8kMOBRfWkzNnzolBk+AYhKIfKjCLmoC8Mob3ETodxAEOMkE2YPKEWzQ==}
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.3':
resolution: {integrity: sha512-0kwUVx2LbmOoTRlwF1oDww7th4/NSluv4ZBQ6KRZsFKg4g0TlTcIiJ0VehqkQYUeC9xIT1Mk6XtF52mI155VSQ==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
'@tauri-apps/cli-linux-arm64-gnu@2.12.1':
resolution: {integrity: sha512-APArHhDu+8pXSCkCQmvaz1nD3d8WTmlCoSS/oG475TJ6AATBvyQOAmf5qELgsQ4s2+8MOsop0Zd699RKELF1Cw==}
'@tauri-apps/cli-linux-arm64-gnu@2.12.3':
resolution: {integrity: sha512-gKSGDx6fx+HBLQmG6guChFdisbrCSdx9Yli+j5teOa64gm1CeM+C6NLru5Pj3ZkkEep05BmCFjxvX+cjqAycZQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@tauri-apps/cli-linux-arm64-musl@2.12.1':
resolution: {integrity: sha512-JaCxcLoV0oGtllVkLr4UAHWG/wTfkEunnUqnsEsGYOp0VRxnUwHg63wFBD0jU2ul5eFfSLIDS4RF2gfzsSo5Jg==}
'@tauri-apps/cli-linux-arm64-musl@2.12.3':
resolution: {integrity: sha512-Yr59qMy/gcvAfBuFdCGlAmGiLsYWMFDbsP4bAI6iNBzcJTGrYWZGeiQhGDo29MQwfF/NUBqyM2qljXu5tZ6wjQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@tauri-apps/cli-linux-riscv64-gnu@2.12.1':
resolution: {integrity: sha512-K5+VXM7+SGVDwZleA2+lMgvbTVuA5e1tkiVEawu1Yxj26ZyEfO8h8xTC1rBdRX2xgJDSwCk6vPUBCS6i+Z5slQ==}
'@tauri-apps/cli-linux-riscv64-gnu@2.12.3':
resolution: {integrity: sha512-jKr0/REBMnLKC0OwPQZkyge0mKDaNZ0b/AbfGwVyCgFfwS730EVLfVDo3nt7MUu6jJaytRq08+xSj5qfy+U1+Q==}
engines: {node: '>= 10'}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@tauri-apps/cli-linux-x64-gnu@2.12.1':
resolution: {integrity: sha512-Z1QGPr49HJZMktu+Spu6Q1b/f9ANadXvqZZZt2645ua1x1ev6prOgp85eiGv2jRzohFEMLo6aJyaLjLUX5KIvA==}
'@tauri-apps/cli-linux-x64-gnu@2.12.3':
resolution: {integrity: sha512-gTkEqJAGCMROGanxHnzaJzQ+/rXl39HWVg0/hDODS1wDWBGqoceqGC6Qm1+mQbyT11xnsB8mKu/gyVID/YpFIw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@tauri-apps/cli-linux-x64-musl@2.12.1':
resolution: {integrity: sha512-nHuEhRPOMSJ/8RRhtMRxB9B9lVr7xxpe4DapBz8x1GIau3vdzjHHJ1hAfmw+PyayPLZ6XoaVIHPgI17rX6ii8w==}
'@tauri-apps/cli-linux-x64-musl@2.12.3':
resolution: {integrity: sha512-T2dTxL1svRym71fZtaW4pZYXbthbfFsEJr1NeOUg/p7laWXZbUt/8DMSZf8recu9f7+1F/Lv00HtzsEu6vDO9w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@tauri-apps/cli-win32-arm64-msvc@2.12.1':
resolution: {integrity: sha512-I0oPk2uGh86R8dAs2X5OxSP+/GqSc8jh1Px3l8EqrocSNivsRHDTh2k3PVOqdv163dlV6PIVvmhZAbH/lPfZrA==}
'@tauri-apps/cli-win32-arm64-msvc@2.12.3':
resolution: {integrity: sha512-eoiQwpEZWbpsVHcM9BAzqqe4TCHszvr3rsM7pUQ4ofLK0lF1i1d/jX0Qo5DYMqcrUtwQuDdDuOCbcT0Izf1VwQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@tauri-apps/cli-win32-ia32-msvc@2.12.1':
resolution: {integrity: sha512-baNZRBfepAJ5qNFRMwzgBk94xQmkcmTZrNDjZjnzrq2vAaTC3NAhallb/zo3hyoCGQlMS13sdovktrg46NZz6Q==}
'@tauri-apps/cli-win32-ia32-msvc@2.12.3':
resolution: {integrity: sha512-kE+KUg6Dbbkgvcw0m99wJVIToFQzJqpMBAXah74WqxaLzssNwSTUccrHp6+QVzMhjQP330tvekFmnQF+0NbE6Q==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
'@tauri-apps/cli-win32-x64-msvc@2.12.1':
resolution: {integrity: sha512-dIFaKslrzcbesb+bBh+E1R9km241pHyj32w6D9FPtvQeYpRUFbiCLEa/2S+S0UnIytfxepp4P+X8IerGqnXeYg==}
'@tauri-apps/cli-win32-x64-msvc@2.12.3':
resolution: {integrity: sha512-L7wndWAgX2mLW7alswpL3d1R0P9FN2WYBgHaQkAYEBxHHGkY4vFX9CjcRQ1LAxDAMIJxrY7/aDziFJeChS84NQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@tauri-apps/cli@2.12.1':
resolution: {integrity: sha512-kEDEiGzG+yAc5FeLxtXpES/VN+F2C8H0r4gDVtfRLKxT9np9101d9REG/Kgo2lr0hKi0IpDsODiHnU3+naOmLg==}
'@tauri-apps/cli@2.12.3':
resolution: {integrity: sha512-f7/LsY74SVb1ChmOPw1ajOpxii0GSzDAgmWHRci8JUYuuai04rXsSbFobpmB0sP2DdlvMD/B5ZotEn8GOGMRUg==}
engines: {node: '>= 10'}
hasBin: true
'@tauri-apps/plugin-clipboard-manager@2.4.0':
resolution: {integrity: sha512-yAuTffXc/sm+4oYnrwxbUkaJXQMTesPJ9dim0ADcA31rpboyhAN2TGQqs9VCcPIpb60LFOeePkvhpP2I3xhejg==}
'@tauri-apps/plugin-clipboard-manager@2.5.0':
resolution: {integrity: sha512-dibUy1nKURYDXRMvjNk4deAbTZ5jPQ8wCE4nolt5xniryWgXQ4sK2GkFXoXlHbRdPzfZptZj95BRLfalA7m/2Q==}
'@tauri-apps/plugin-dialog@2.8.0':
resolution: {integrity: sha512-HSSD5C8UFE9ijD1wue84F7jjaIReFmj8AAPtS+xyjYRltJafIc4BiWHY7SJ6vbbew6u+YljEJHfyNfy5VwywXg==}
'@tauri-apps/plugin-dialog@2.8.3':
resolution: {integrity: sha512-Hd/yBfk2R5v2MFrz/0VArSXeh8xKLLXGunqSiTtcHKn1zNZwaKujuA0VSwUvNfwC4hDoF1PveS+gBDNe3nHspw==}
'@tauri-apps/plugin-fs@2.6.0':
resolution: {integrity: sha512-MhBAZ4rryd+h9fijd/GWDfArqiAeGI0ZNduV4wuRyUVI6wDZ+oDBY7atqtoXKDwlTUVSvpvmWJAY0ehQd/v6Uw==}
'@tauri-apps/plugin-fs@2.7.1':
resolution: {integrity: sha512-4TBVjpi/q8PuNzjpkAc2iBGXMTLjOrAyfTiiOL8ORaJCZJRG3tjzmQ4sqs2CMG75FvLyRkOkERfP7AyY4iBNwQ==}
'@tauri-apps/plugin-http@2.8.0':
resolution: {integrity: sha512-cPvZvfUSaBkqGxef/dgbh/iEl6T3jQfSJyypi9OdcWr1VcuTt4ZRlk9DLAHEHF2q2NML+0UOkjyXRPNo6Cky6g==}
'@tauri-apps/plugin-http@2.8.3':
resolution: {integrity: sha512-MrgCnnxSnzxkMX+Tk1XXB8rSI9hfhUHQmtbn0EpflEDcSx04K1BDfrv51tcK27SCuU/B1j8sNHL0UZur/1iqKA==}
'@tauri-apps/plugin-opener@2.7.0':
resolution: {integrity: sha512-mBorYfVKh9Lt7s4ZFtKbMUTxBw+Y/sVmSlKCtkkoBgMTC/DIbt/kaPm67L/2djAUqDI1wbixy5OHHVmipjuGMw==}
'@tauri-apps/plugin-opener@2.7.2':
resolution: {integrity: sha512-LyybP1VSzTMQiaFYcsbAse47KpivlyXdLZMQzGLEnkgQacGESnpjAfFoQ6h5sqWgAdZDH9szYjPzHMpv0Sz+TQ==}
'@tauri-apps/plugin-updater@2.13.1':
resolution: {integrity: sha512-+STDzJ0sdQLImjc63zkv6Nncimqeo6jyCWoTQtbSwgGLNj1qbP9I6LC4p5R5ocBk3gNKAZs6i/AJz0jxysytiw==}
'@tauri-apps/plugin-updater@2.14.0':
resolution: {integrity: sha512-gdylJ9tger4hkyOn24QZd6MNOKVo2Eh53iw5th2Qj1vKTR/+u4PIwJWuiis5hohYvobn6iOvlnALfrqIPSzh7Q==}
'@tybys/wasm-util@0.10.4':
resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==}
@@ -2570,12 +2570,12 @@ packages:
resolution: {integrity: sha512-n6elHE4ItKAtr4lwAaWIh/sAFuEFhyesLM27i5l9IWBJEK6VECdt0Pigj/4vUD2tliOoBtsWxphSW4oiNFXotg==}
engines: {node: '>=22.19.0'}
'@wdio/globals@9.29.1':
resolution: {integrity: sha512-F96BKppx4HGD64v+s57TM4K4zaxqUCg2RXHk6sjB2xrSa7P+d2VYV28ID2ddF7iSodVfPlpa1i2/jy8jMGrU8w==}
'@wdio/globals@9.31.3':
resolution: {integrity: sha512-ZzmRKUlwUBahNoNxHbAzst+9dNInEjLQc7Z3c86OhDRxAf3Ivw8k2rc56UCbyYiZnkd1dOpuA91zFiTrUNNORw==}
engines: {node: '>=18.20.0'}
peerDependencies:
expect-webdriverio: ^5.6.5
webdriverio: ^9.0.0
expect-webdriverio: ^6.0.9
webdriverio: ^9.28.0
'@wdio/logger@10.0.0':
resolution: {integrity: sha512-kUIw0ZzMs1mvXOaLEcjrM1nqNXY1reaJKReKNcjDSnfhnfUIb0Q5pAsxiMeil2uR0WsSUPzn0r3D9v//7vTOkA==}
@@ -2585,21 +2585,21 @@ packages:
resolution: {integrity: sha512-0ZAEIo6PNyMIJPlOGkIgyOJUjcd0pC8/QHlVAAe1c91/IcjZ1X+k0yidXHaboJdN7dq1XPUacmhRdtua0U5EZg==}
engines: {node: '>=18.20.0'}
'@wdio/native-core@1.2.0':
resolution: {integrity: sha512-Z/Qa2xmV/2IMSCsCKyVk79tda8n47FOOOS9XEOWGpHUiFr1z4gGOFxt13Fd9RQu9Kk1IA9fJB1VmJZtrtkXvEw==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.11.0}
'@wdio/native-core@1.3.0':
resolution: {integrity: sha512-wUwc0QTdvhD0LwH4YcRaN9JWLX/yac8sovddUR5/4sqHMNJr3yaN11bpIfYoD/bEk+1nTLjWuDCFpe5l5wUgLQ==}
engines: {node: '>=18.20.0'}
'@wdio/native-spy@1.3.0':
resolution: {integrity: sha512-Kw1/HsOM8CNnlPHozlv0FP+nFnms5efICq5WqpaNdwa0urv/C9K/jhM69OqAbocBfRXkDVuWecNPmCV9S/cXGw==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.11.0}
'@wdio/native-spy@1.4.0':
resolution: {integrity: sha512-unsC2Vgu5T9atD478Zj/p2N+rVSK4i/NibIaaEw4rZF/T5u5bmAHChFntEiBEfyMzd62VwbhKhzwwOSKjzrfJA==}
engines: {node: '>=18.20.0'}
'@wdio/native-types@2.5.0':
resolution: {integrity: sha512-NjaIfcsEKpU9gm0goywEG0A7J4pyEsgORKNrQ1xboSy10BeTk5QpgHWP1bNvqUnZrKoKJRonpSn81ZyYKghO1g==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.11.0}
'@wdio/native-types@2.6.0':
resolution: {integrity: sha512-MVMVpZTH+UY6nUtLClCzY4BQSIs/nCCHo81i4ClLR+b2NehyBvwccttXDAGPgf0icyHUhd+PgIPXaLgRcm4M9A==}
engines: {node: '>=18.20.0'}
'@wdio/native-utils@2.7.0':
resolution: {integrity: sha512-qCzc+5o4YVESApQB5//NxomZ+F+M3Pc02hUNnJ1/w9naMb8mfgaHXBLWVwejEfO36z2MnwGatBNWZAm38G1frA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.11.0}
'@wdio/native-utils@2.8.0':
resolution: {integrity: sha512-TmIkPAd19FkJ747AdFVEtawbakVV3HHCh8zk3Kl/FLc6B2bbea7hn90jtLxqBZgCVqUuJIBcMNFg/nV/hgBFOw==}
engines: {node: '>=18.20.0'}
peerDependencies:
tsx: ^4.22.4
peerDependenciesMeta:
@@ -2614,17 +2614,17 @@ packages:
resolution: {integrity: sha512-wAC9ksdWWv2E3Sj86eNKxB3IUt0gEyw9rgDGAWjk/GWgi6K3e+/n3erGNweI9JMJyC/+RNe0qHgVPQpRJMRVpg==}
engines: {node: '>=22.19.0'}
'@wdio/reporter@9.30.1':
resolution: {integrity: sha512-0whWaLfJtOAy3PzbGUxGrCAGitgaUCMe8qUgAuP2l7ess70AXqvp1wJibw74a/Z2giegJlJiAc4PxS0abs9/tw==}
'@wdio/reporter@9.31.2':
resolution: {integrity: sha512-3cKE6vCOsro/Ep9dGTIbo3FBn3WNvJ++BIn32lFd9m19pFdjuwlVgLtPXHb9jWNCJs740h5AIUcVkcscqUYhAA==}
engines: {node: '>=18.20.0'}
'@wdio/spec-reporter@9.30.1':
resolution: {integrity: sha512-En74iLuj8xjNanSPA05rTCii0qHZQe6Zpwi74vTGO6LtfGxvcNr1Z1zUj8xWwnoclnAne3DtmCAyXTezLX1pEA==}
'@wdio/spec-reporter@9.31.2':
resolution: {integrity: sha512-lNLLPUk4y1Yp5pWwBFF+tjZIy7bOv0TPTk4HDWV4LnnHnkc24abI0nN+kb2y5/JV8ZgwLCCVKUFRdRUxfKsAaQ==}
engines: {node: '>=18.20.0'}
'@wdio/tauri-service@1.4.0':
resolution: {integrity: sha512-EUTS8tfMOXK1yPNEaRd6yiSdPoX19zeV+gtp2m7UuPTWFZGayPuMUoFyttP6Lx3OFvJC3lnbxjr1vcCNAOA7tg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.11.0}
'@wdio/tauri-service@1.5.0':
resolution: {integrity: sha512-S3fs8T+jgNOFi4x/X2z69unS/1K3ZB28+owBouhHtVnrMKeBWAKP46IHnp8c8AZXppn6fiPNC4M1jfRZbLKeKw==}
engines: {node: '>=18.20.0'}
peerDependencies:
webdriverio: ^9.0.0
@@ -2632,8 +2632,8 @@ packages:
resolution: {integrity: sha512-HGP9lAYXCsLAXzugfT4khCh7tYByWOMIxZHCG+tUvgmpwNzi6lfIsxyIlWownXK1wYJUpk6tkDBX/iXwN+q0lg==}
engines: {node: '>=22.19.0'}
'@wdio/types@9.30.1':
resolution: {integrity: sha512-umKQDbSmu3/ucUsIA5UUTK5gCWnClyVpWz3fC39044rCXQ3zCd1a3GoJibbAITKiwnPFf2yU3LvTa+C78sh9Lg==}
'@wdio/types@9.31.2':
resolution: {integrity: sha512-lQKaiQDCJJ6VC1K/cKzaAxCpwB9pL1U0VbmX2uGksMxO4EDbNuLvIxWryuUDJ7OaSYTjxILTKYFErdbT/xEikg==}
engines: {node: '>=18.20.0'}
'@wdio/utils@10.0.1':
@@ -3418,13 +3418,13 @@ packages:
resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==}
engines: {node: '>=12.0.0'}
expect-webdriverio@5.7.0:
resolution: {integrity: sha512-jLOTrJoPBC3Wtd83ryHMbRcEajMGtAnn6OWtSnoJoDLt16nHvxVdjcI4Bc0n+1KAOr8DvQtlJ55f0M48kJtEpw==}
expect-webdriverio@6.1.0:
resolution: {integrity: sha512-RXgaXoH1U8IiAHPelkMhZSnWUT0HfIhkjKK8nBkIpnXRO+zJ8dRafoyZhVy5mu/LtoyIr9juRWRwN284OSNM6Q==}
engines: {node: '>=20'}
peerDependencies:
'@wdio/globals': ^9.0.0
'@wdio/logger': ^9.0.0
webdriverio: ^9.0.0
webdriverio: ^9.28.0
expect@30.5.2:
resolution: {integrity: sha512-0LNuMvs8/5mRYhnCR4k+lGV7fqPMs6Bnksda4S3zsCUmdxBpAn4zU4NNzXdq1pMKe/H4W5t/zVIDSJ/H3e0vDA==}
@@ -6910,78 +6910,78 @@ snapshots:
'@tanstack/virtual-core@3.17.11': {}
'@tauri-apps/api@2.12.1': {}
'@tauri-apps/api@2.12.4': {}
'@tauri-apps/cli-darwin-arm64@2.12.1':
'@tauri-apps/cli-darwin-arm64@2.12.3':
optional: true
'@tauri-apps/cli-darwin-x64@2.12.1':
'@tauri-apps/cli-darwin-x64@2.12.3':
optional: true
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.1':
'@tauri-apps/cli-linux-arm-gnueabihf@2.12.3':
optional: true
'@tauri-apps/cli-linux-arm64-gnu@2.12.1':
'@tauri-apps/cli-linux-arm64-gnu@2.12.3':
optional: true
'@tauri-apps/cli-linux-arm64-musl@2.12.1':
'@tauri-apps/cli-linux-arm64-musl@2.12.3':
optional: true
'@tauri-apps/cli-linux-riscv64-gnu@2.12.1':
'@tauri-apps/cli-linux-riscv64-gnu@2.12.3':
optional: true
'@tauri-apps/cli-linux-x64-gnu@2.12.1':
'@tauri-apps/cli-linux-x64-gnu@2.12.3':
optional: true
'@tauri-apps/cli-linux-x64-musl@2.12.1':
'@tauri-apps/cli-linux-x64-musl@2.12.3':
optional: true
'@tauri-apps/cli-win32-arm64-msvc@2.12.1':
'@tauri-apps/cli-win32-arm64-msvc@2.12.3':
optional: true
'@tauri-apps/cli-win32-ia32-msvc@2.12.1':
'@tauri-apps/cli-win32-ia32-msvc@2.12.3':
optional: true
'@tauri-apps/cli-win32-x64-msvc@2.12.1':
'@tauri-apps/cli-win32-x64-msvc@2.12.3':
optional: true
'@tauri-apps/cli@2.12.1':
'@tauri-apps/cli@2.12.3':
optionalDependencies:
'@tauri-apps/cli-darwin-arm64': 2.12.1
'@tauri-apps/cli-darwin-x64': 2.12.1
'@tauri-apps/cli-linux-arm-gnueabihf': 2.12.1
'@tauri-apps/cli-linux-arm64-gnu': 2.12.1
'@tauri-apps/cli-linux-arm64-musl': 2.12.1
'@tauri-apps/cli-linux-riscv64-gnu': 2.12.1
'@tauri-apps/cli-linux-x64-gnu': 2.12.1
'@tauri-apps/cli-linux-x64-musl': 2.12.1
'@tauri-apps/cli-win32-arm64-msvc': 2.12.1
'@tauri-apps/cli-win32-ia32-msvc': 2.12.1
'@tauri-apps/cli-win32-x64-msvc': 2.12.1
'@tauri-apps/cli-darwin-arm64': 2.12.3
'@tauri-apps/cli-darwin-x64': 2.12.3
'@tauri-apps/cli-linux-arm-gnueabihf': 2.12.3
'@tauri-apps/cli-linux-arm64-gnu': 2.12.3
'@tauri-apps/cli-linux-arm64-musl': 2.12.3
'@tauri-apps/cli-linux-riscv64-gnu': 2.12.3
'@tauri-apps/cli-linux-x64-gnu': 2.12.3
'@tauri-apps/cli-linux-x64-musl': 2.12.3
'@tauri-apps/cli-win32-arm64-msvc': 2.12.3
'@tauri-apps/cli-win32-ia32-msvc': 2.12.3
'@tauri-apps/cli-win32-x64-msvc': 2.12.3
'@tauri-apps/plugin-clipboard-manager@2.4.0':
'@tauri-apps/plugin-clipboard-manager@2.5.0':
dependencies:
'@tauri-apps/api': 2.12.1
'@tauri-apps/api': 2.12.4
'@tauri-apps/plugin-dialog@2.8.0':
'@tauri-apps/plugin-dialog@2.8.3':
dependencies:
'@tauri-apps/api': 2.12.1
'@tauri-apps/api': 2.12.4
'@tauri-apps/plugin-fs@2.6.0':
'@tauri-apps/plugin-fs@2.7.1':
dependencies:
'@tauri-apps/api': 2.12.1
'@tauri-apps/api': 2.12.4
'@tauri-apps/plugin-http@2.8.0':
'@tauri-apps/plugin-http@2.8.3':
dependencies:
'@tauri-apps/api': 2.12.1
'@tauri-apps/api': 2.12.4
'@tauri-apps/plugin-opener@2.7.0':
'@tauri-apps/plugin-opener@2.7.2':
dependencies:
'@tauri-apps/api': 2.12.1
'@tauri-apps/api': 2.12.4
'@tauri-apps/plugin-updater@2.13.1':
'@tauri-apps/plugin-updater@2.14.0':
dependencies:
'@tauri-apps/api': 2.12.1
'@tauri-apps/api': 2.12.4
'@tybys/wasm-util@0.10.4':
dependencies:
@@ -7323,9 +7323,9 @@ snapshots:
- supports-color
- yauzl
'@wdio/globals@9.29.1(expect-webdriverio@5.7.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))':
'@wdio/globals@9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))':
dependencies:
expect-webdriverio: 5.7.0(@wdio/globals@9.29.1)(@wdio/logger@9.29.1)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
expect-webdriverio: 6.1.0(@wdio/globals@9.31.3)(@wdio/logger@9.29.1)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
webdriverio: 10.0.2(supports-color@7.2.0)(yauzl@2.10.0)
'@wdio/logger@10.0.0':
@@ -7344,11 +7344,11 @@ snapshots:
safe-regex2: 5.1.1
strip-ansi: 7.2.0
'@wdio/native-core@1.2.0(supports-color@7.2.0)':
'@wdio/native-core@1.3.0(supports-color@7.2.0)':
dependencies:
'@wdio/logger': 9.29.1
'@wdio/native-types': 2.5.0
'@wdio/native-utils': 2.7.0(supports-color@7.2.0)
'@wdio/native-types': 2.6.0
'@wdio/native-utils': 2.8.0(supports-color@7.2.0)
debug: 4.4.3(supports-color@7.2.0)
get-port: 7.2.0
tslib: 2.8.1
@@ -7356,11 +7356,11 @@ snapshots:
- supports-color
- tsx
'@wdio/native-spy@1.3.0': {}
'@wdio/native-spy@1.4.0': {}
'@wdio/native-types@2.5.0': {}
'@wdio/native-types@2.6.0': {}
'@wdio/native-utils@2.7.0(supports-color@7.2.0)':
'@wdio/native-utils@2.8.0(supports-color@7.2.0)':
dependencies:
'@wdio/logger': 9.29.1
debug: 4.4.3(supports-color@7.2.0)
@@ -7378,32 +7378,32 @@ snapshots:
dependencies:
'@types/node': 22.20.5
'@wdio/reporter@9.30.1':
'@wdio/reporter@9.31.2':
dependencies:
'@types/node': 20.19.43
'@wdio/logger': 9.29.1
'@wdio/types': 9.30.1
'@wdio/types': 9.31.2
diff: 8.0.4
object-inspect: 1.13.4
'@wdio/spec-reporter@9.30.1':
'@wdio/spec-reporter@9.31.2':
dependencies:
'@wdio/reporter': 9.30.1
'@wdio/types': 9.30.1
'@wdio/reporter': 9.31.2
'@wdio/types': 9.31.2
chalk: 5.6.2
easy-table: 1.2.0
pretty-ms: 9.3.1
'@wdio/tauri-service@1.4.0(expect-webdriverio@5.7.0)(supports-color@7.2.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))':
'@wdio/tauri-service@1.5.0(expect-webdriverio@6.1.0)(supports-color@7.2.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))':
dependencies:
'@wdio/globals': 9.29.1(expect-webdriverio@5.7.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
'@wdio/globals': 9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
'@wdio/logger': 9.29.1
'@wdio/native-core': 1.2.0(supports-color@7.2.0)
'@wdio/native-spy': 1.3.0
'@wdio/native-types': 2.5.0
'@wdio/native-utils': 2.7.0(supports-color@7.2.0)
'@wdio/spec-reporter': 9.30.1
'@wdio/types': 9.30.1
'@wdio/native-core': 1.3.0(supports-color@7.2.0)
'@wdio/native-spy': 1.4.0
'@wdio/native-types': 2.6.0
'@wdio/native-utils': 2.8.0(supports-color@7.2.0)
'@wdio/spec-reporter': 9.31.2
'@wdio/types': 9.31.2
debug: 4.4.3(supports-color@7.2.0)
get-port: 7.2.0
tslib: 2.8.1
@@ -7417,7 +7417,7 @@ snapshots:
dependencies:
'@types/node': 22.20.5
'@wdio/types@9.30.1':
'@wdio/types@9.31.2':
dependencies:
'@types/node': 20.19.43
@@ -8331,10 +8331,10 @@ snapshots:
expect-type@1.4.0: {}
expect-webdriverio@5.7.0(@wdio/globals@9.29.1)(@wdio/logger@9.29.1)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0)):
expect-webdriverio@6.1.0(@wdio/globals@9.31.3)(@wdio/logger@9.29.1)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0)):
dependencies:
'@vitest/snapshot': 4.1.11
'@wdio/globals': 9.29.1(expect-webdriverio@5.7.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
'@wdio/globals': 9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.0.2(supports-color@7.2.0)(yauzl@2.10.0))
'@wdio/logger': 9.29.1
deep-eql: 5.0.2
expect: 30.5.2
@@ -10005,7 +10005,7 @@ snapshots:
tauri-plugin-mihomo-api@https://codeload.github.com/clash-verge-rev/tauri-plugin-mihomo/tar.gz/7a03d16f4d39b1bb885b7babe66b9e153e34b615:
dependencies:
'@tauri-apps/api': 2.12.1
'@tauri-apps/api': 2.12.4
teex@1.0.1:
dependencies:
+11 -11
View File
@@ -29,7 +29,7 @@ perf-harness = ["dep:tauri-plugin-wdio-webdriver"]
identifier = "io.github.clash-verge-rev.clash-verge-rev"
[build-dependencies]
tauri-build = { version = "2.7.1", features = [] }
tauri-build = { version = "2.7.3", features = [] }
[dependencies]
clash-verge-draft = { workspace = true }
@@ -72,12 +72,12 @@ sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs.git", branch
"guard",
] }
network-interface = { version = "2.0.5", features = ["serde"] }
tauri-plugin-shell = "2.4.0"
tauri-plugin-opener = "2.7.0"
tauri-plugin-dialog = "2.8.1"
tauri-plugin-fs = "2.6.0"
tauri-plugin-shell = "2.5.0"
tauri-plugin-opener = "2.7.2"
tauri-plugin-dialog = "2.8.3"
tauri-plugin-fs = "2.7.1"
tauri-plugin-process = "2.4.0"
tauri-plugin-deep-link = "2.6.1"
tauri-plugin-deep-link = "2.6.2"
tauri-plugin-window-state = "2.5.0"
zip = "9.0.4"
flate2 = "1.1.10"
@@ -90,10 +90,10 @@ getrandom = "0.4.3"
futures = "0.3.34"
gethostname = "1.1.0"
scopeguard = "1.2.0"
tauri-plugin-notification = "2.5.1"
tauri-plugin-notification = "2.7.0"
tokio-stream = "0.1.19"
backon = { version = "1.6.0", features = ["tokio-sleep"] }
tauri-plugin-http = "2.8.0"
tauri-plugin-http = "2.8.3"
tracing = { workspace = true }
tauri-plugin-devtools = { version = "2.2.2", optional = true }
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo", rev = "7a03d16f4d39b1bb885b7babe66b9e153e34b615" }
@@ -120,7 +120,7 @@ libc = "0.2.191"
clash-verge-signal = { workspace = true }
[target.'cfg(target_os = "macos")'.dependencies]
tauri-plugin-wdio-webdriver = { version = "=1.4.0", optional = true }
tauri-plugin-wdio-webdriver = { version = "=1.5.0", optional = true }
objc2 = "0.6.5"
objc2-foundation = { version = "0.3.2", features = [
"NSString",
@@ -153,8 +153,8 @@ windows-sys.workspace = true
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-autostart = "2.7.0"
tauri-plugin-global-shortcut = "2.4.0"
tauri-plugin-updater = "2.13.1"
tauri-plugin-global-shortcut = "2.4.1"
tauri-plugin-updater = "2.14.0"
[dev-dependencies]
criterion = { workspace = true }
+10 -5
View File
@@ -1,10 +1,9 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows")
&& std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc")
&& std::env::var_os("CARGO_FEATURE_CLIPPY").is_some()
{
// Tauri's resource is linked to the app binary, but not to Rust unit-test harnesses.
// Give mock-context builds their own manifest so tests can resolve TaskDialogIndirect.
// Tauri's resource is linked to the app binary, but not to Rust unit-test harnesses or examples.
// Give non-app targets their own manifest so tests and examples can resolve TaskDialogIndirect.
let out_dir = std::env::var_os("OUT_DIR").ok_or_else(|| std::io::Error::other("OUT_DIR is not set"))?;
let manifest_path = std::path::PathBuf::from(out_dir).join("windows-test-manifest.xml");
std::fs::write(
@@ -25,8 +24,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
</assembly>
"#,
)?;
println!("cargo:rustc-link-arg=/MANIFEST:EMBED");
println!("cargo:rustc-link-arg=/MANIFESTINPUT:{}", manifest_path.display());
let manifest_display = manifest_path.display();
if std::env::var_os("CARGO_FEATURE_CLIPPY").is_some() {
println!("cargo:rustc-link-arg=/MANIFEST:EMBED");
println!("cargo:rustc-link-arg=/MANIFESTINPUT:{manifest_display}");
} else {
println!("cargo:rustc-link-arg-examples=/MANIFEST:EMBED");
println!("cargo:rustc-link-arg-examples=/MANIFESTINPUT:{manifest_display}");
}
}
#[cfg(feature = "clippy")]
-237
View File
@@ -1,237 +0,0 @@
//! Live handles into the attached tray menu and the reconcile decision:
//! state-only changes mutate items in place, a proxy-only structure change
//! swaps the group submenus, anything else rebuilds.
use crate::Type;
use crate::config::{IProfiles, IVerge};
use clash_verge_logging::logging_error;
use parking_lot::Mutex;
use smartstring::alias::String;
use std::collections::HashMap;
use tauri::menu::{CheckMenuItem, IsMenuItem, Submenu};
use tauri::tray::TrayIcon;
use tauri::{AppHandle, Wry};
use tauri_plugin_mihomo::models::Proxies;
use super::{TrayMenuOptions, build_tray_menu, create_subcreate_proxy_menu_item};
pub(super) struct ProxyNodeItem {
pub(super) name: String,
pub(super) item: CheckMenuItem<Wry>,
pub(super) text: String,
pub(super) checked: bool,
}
pub(super) struct ProxyGroupItems {
pub(super) name: String,
pub(super) nodes: Vec<ProxyNodeItem>,
}
pub(super) struct TrayMenuState {
pub(super) mode_items: [CheckMenuItem<Wry>; 3],
pub(super) system_proxy_item: CheckMenuItem<Wry>,
pub(super) tun_item: CheckMenuItem<Wry>,
pub(super) lightweight_item: CheckMenuItem<Wry>,
pub(super) profile_items: Vec<(String, CheckMenuItem<Wry>)>,
pub(super) proxies_submenu: Option<Submenu<Wry>>,
pub(super) proxy_groups: Vec<ProxyGroupItems>,
pub(super) signature: String,
pub(super) proxy_signature: Option<String>,
}
pub(super) fn proxy_delay_text(proxy_nodes_data: &Proxies, proxy_str: &str) -> String {
proxy_nodes_data
.proxies
.get(proxy_str)
.and_then(|h| h.history.last())
.map(|h| match h.delay {
0 => "-ms".into(),
delay if delay >= 10000 => "-ms".into(),
_ => format!("{}ms", h.delay).into(),
})
.unwrap_or_else(|| "-ms".into())
}
/// Topology inputs that a rebuild cannot reconcile by mutating items.
pub(super) fn menu_signature(verge: &IVerge, profiles: &IProfiles, mode: &str) -> String {
let hotkeys = verge.hotkeys.as_ref().map(|h| h.join(",")).unwrap_or_default();
let profiles = profiles
.profiles_preview()
.unwrap_or_default()
.into_iter()
.map(|profile| format!("{}:{}", profile.uid, profile.name))
.collect::<Vec<_>>()
.join(";");
format!(
"{}|{}|{mode}|{}|{hotkeys}|{profiles}",
verge.tray_proxy_groups_display_mode.as_deref().unwrap_or("default"),
verge.tray_inline_outbound_modes.unwrap_or(false),
verge.language.as_deref().unwrap_or(""),
)
.into()
}
/// Group/node identity plus ordering, canonicalized so it is stable across fetches.
pub(super) fn proxy_structure_signature(
proxy_mode: &str,
order_map: Option<&HashMap<String, usize>>,
proxy_nodes_data: &Proxies,
) -> String {
let mut parts: Vec<std::string::String> = proxy_nodes_data
.proxies
.iter()
.filter(|(name, data)| {
let global = name.as_str() == "GLOBAL";
(match proxy_mode {
"global" => global,
_ => !global,
}) && !data.hidden.unwrap_or_default()
})
.filter_map(|(name, data)| {
data.all.as_ref().map(|all| {
let order = order_map
.and_then(|map| map.get(name.as_str()))
.map_or_else(|| "-".to_owned(), |index| index.to_string());
format!(
"{}@{order}:{}",
name,
all.iter().map(|node| node.as_str()).collect::<Vec<_>>().join(",")
)
})
})
.collect();
parts.sort();
parts.join(";").into()
}
pub(super) struct ReconcileContext<'a> {
pub(super) app_handle: &'a AppHandle<Wry>,
pub(super) tray: &'a TrayIcon<Wry>,
pub(super) options: TrayMenuOptions<'a>,
pub(super) verge: &'a IVerge,
pub(super) profiles: &'a IProfiles,
pub(super) fetched_proxies: Option<&'a Proxies>,
pub(super) order_map: Option<&'a HashMap<String, usize>>,
pub(super) menu_signature: &'a str,
pub(super) proxy_signature: Option<&'a str>,
pub(super) fetched: bool,
}
pub(super) fn reconcile(state_store: &Mutex<Option<TrayMenuState>>, ctx: ReconcileContext<'_>) -> anyhow::Result<()> {
let tun_mode_available = crate::core::runstate::RUN_STATE.state().tun_capable();
{
let mut attached = state_store.lock();
if let Some(state) = attached.as_mut().filter(|state| state.signature == ctx.menu_signature) {
let in_place = !ctx.fetched || state.proxy_signature.as_deref() == ctx.proxy_signature;
let swapped = !in_place
&& ctx.fetched_proxies.is_some_and(|data| {
state.swap_proxy_section(
ctx.app_handle,
ctx.options.mode.unwrap_or(""),
ctx.order_map,
data,
ctx.proxy_signature,
)
});
if in_place || swapped {
state.apply_static(&ctx.options, ctx.profiles, tun_mode_available);
if in_place && let Some(data) = ctx.fetched_proxies {
state.apply_proxy(data);
}
return Ok(());
}
}
}
let (menu, mut new_state) = build_tray_menu(
ctx.app_handle,
ctx.options,
ctx.verge,
ctx.profiles,
ctx.order_map,
ctx.fetched_proxies,
)?;
new_state.signature = ctx.menu_signature.into();
new_state.proxy_signature = if ctx.fetched {
ctx.proxy_signature.map(Into::into)
} else {
None
};
logging_error!(Type::Tray, ctx.tray.set_menu(Some(menu)));
*state_store.lock() = Some(new_state);
Ok(())
}
impl TrayMenuState {
fn apply_static(&self, options: &TrayMenuOptions<'_>, profiles: &IProfiles, tun_mode_available: bool) {
let mode = options.mode.unwrap_or("");
for (item, name) in self.mode_items.iter().zip(["rule", "global", "direct"]) {
logging_error!(Type::Tray, item.set_checked(mode == name));
}
logging_error!(
Type::Tray,
self.system_proxy_item.set_checked(options.system_proxy_enabled)
);
logging_error!(Type::Tray, self.tun_item.set_enabled(tun_mode_available));
logging_error!(Type::Tray, self.tun_item.set_checked(options.tun_mode_enabled));
logging_error!(
Type::Tray,
self.lightweight_item.set_checked(options.is_lightweight_mode)
);
let current = profiles.current.as_deref();
for (uid, item) in &self.profile_items {
logging_error!(Type::Tray, item.set_checked(current == Some(uid.as_str())));
}
}
fn apply_proxy(&mut self, proxy_nodes_data: &Proxies) {
for group in self.proxy_groups.iter_mut() {
let Some(group_data) = proxy_nodes_data.proxies.get(group.name.as_str()) else {
continue;
};
let now = group_data.now.as_deref().unwrap_or_default();
for node in group.nodes.iter_mut() {
let text: String = format!(
"{} | {}",
node.name,
proxy_delay_text(proxy_nodes_data, node.name.as_str())
)
.into();
if node.text != text {
logging_error!(Type::Tray, node.item.set_text(&text));
node.text = text;
}
let checked = node.name == now;
if node.checked != checked {
logging_error!(Type::Tray, node.item.set_checked(checked));
node.checked = checked;
}
}
}
}
fn swap_proxy_section(
&mut self,
app_handle: &AppHandle<Wry>,
proxy_mode: &str,
order_map: Option<&HashMap<String, usize>>,
proxy_nodes_data: &Proxies,
proxy_signature: Option<&str>,
) -> bool {
let Some(proxies_submenu) = self.proxies_submenu.clone() else {
return false;
};
let (group_menus, group_state) =
create_subcreate_proxy_menu_item(app_handle, proxy_mode, order_map, proxy_nodes_data);
if group_menus.is_empty() {
return false;
}
while proxies_submenu.remove_at(0).is_ok_and(|item| item.is_some()) {}
let group_menus_refs: Vec<&dyn IsMenuItem<Wry>> =
group_menus.iter().map(|menu| menu as &dyn IsMenuItem<Wry>).collect();
logging_error!(Type::Tray, proxies_submenu.append_items(&group_menus_refs));
self.proxy_groups = group_state;
self.proxy_signature = proxy_signature.map(Into::into);
true
}
}
+166 -214
View File
@@ -1,4 +1,4 @@
use crate::config::{IProfilePreview, IProfiles, IVerge};
use crate::config::{IProfilePreview, IVerge};
use crate::core::lightweight;
use crate::core::tray::menu_def::TrayAction;
use crate::process::AsyncHandler;
@@ -13,7 +13,6 @@ use crate::{
};
use clash_verge_limiter::{Limiter, SystemClock, SystemLimiter};
use clash_verge_logging::logging_error;
use parking_lot::Mutex;
use tauri::tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder, TrayIconEvent};
use tauri_plugin_mihomo::models::Proxies;
use tokio::fs;
@@ -30,14 +29,9 @@ use tauri::{
};
mod menu_def;
mod menu_state;
#[cfg(target_os = "macos")]
mod speed_task;
use menu_def::{MenuIds, MenuTexts};
use menu_state::{
ProxyGroupItems, ProxyNodeItem, ReconcileContext, TrayMenuState, menu_signature, proxy_delay_text,
proxy_structure_signature, reconcile,
};
// TODO: 是否需要将可变菜单抽离存储起来,后续直接更新对应菜单实例,无需重新创建菜单(待考虑)
@@ -47,10 +41,7 @@ const TRAY_CLICK_DEBOUNCE_MS: u64 = 300;
pub const TRAY_ID: &str = "clash-verge-rev-tray";
#[derive(Clone, Copy)]
struct TrayMenuOptions<'a> {
mode: Option<&'a str>,
system_proxy_enabled: bool,
tun_mode_enabled: bool,
struct TrayMenuOptions {
is_lightweight_mode: bool,
include_proxy_groups: bool,
}
@@ -68,7 +59,6 @@ pub struct Tray {
limiter: SystemLimiter,
#[cfg(target_os = "macos")]
speed_controller: speed_task::TraySpeedController,
menu_state: Mutex<Option<TrayMenuState>>,
}
impl TrayState {
@@ -142,7 +132,6 @@ impl Default for Tray {
limiter: Limiter::new(Duration::from_millis(TRAY_CLICK_DEBOUNCE_MS), SystemClock),
#[cfg(target_os = "macos")]
speed_controller: speed_task::TraySpeedController::new(),
menu_state: Mutex::new(None),
}
}
}
@@ -212,8 +201,9 @@ impl Tray {
};
let verge = Config::verge().await.latest_arc();
let system_proxy = verge.enable_system_proxy.unwrap_or(false);
let tun_mode = verge.enable_tun_mode.unwrap_or(false);
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
let tun_mode_available = crate::core::runstate::RUN_STATE.state().tun_capable();
let mode = {
Config::clash()
.await
@@ -224,81 +214,29 @@ impl Tray {
.unwrap_or("rule")
.to_owned()
};
let profiles_config = Config::profiles().await;
let profiles_arc = profiles_config.latest_arc();
let profiles_preview = profiles_arc.profiles_preview().unwrap_or_default();
let is_lightweight_mode = is_in_lightweight_mode();
let fetch_proxy_groups =
include_proxy_groups && verge.tray_proxy_groups_display_mode.as_deref() != Some("disable");
// TODO: should update tray menu again when it was timeout error
let (proxy_nodes_data, runtime_proxy_groups_order) = if fetch_proxy_groups {
let proxy_nodes_data =
tokio::time::timeout(Duration::from_millis(1000), handle::Handle::mihomo().get_proxies())
.await
.map_or(None, |res| res.ok());
let runtime = Config::runtime().await.latest_arc();
let runtime_proxy_groups_order = runtime.config.as_ref().map(|config| {
config
.get("proxy-groups")
.and_then(|groups| groups.as_sequence())
.map(|groups| {
groups
.iter()
.filter_map(|group| group.get("name"))
.filter_map(|name| name.as_str())
.enumerate()
.map(|(index, name)| (name.into(), index))
.collect::<HashMap<String, usize>>()
})
.unwrap_or_default()
});
(proxy_nodes_data, runtime_proxy_groups_order)
} else {
(None, None)
};
let verge = if fetch_proxy_groups {
Config::verge().await.latest_arc()
} else {
verge
};
let profiles = Config::profiles().await.latest_arc();
let menu_signature = menu_signature(&verge, &profiles, &mode);
let proxy_signature = proxy_nodes_data
.as_ref()
.map(|data| proxy_structure_signature(&mode, runtime_proxy_groups_order.as_ref(), data));
let (tx, rx) = tokio::sync::oneshot::channel();
let dispatch_handle = app_handle.clone();
app_handle
.run_on_main_thread(move || {
let _ = tx.send(reconcile(
&Self::global().menu_state,
ReconcileContext {
app_handle: &dispatch_handle,
tray: &tray,
options: TrayMenuOptions {
mode: Some(mode.as_str()),
system_proxy_enabled: system_proxy,
tun_mode_enabled: tun_mode,
is_lightweight_mode,
include_proxy_groups,
},
verge: &verge,
profiles: &profiles,
fetched_proxies: proxy_nodes_data.as_ref(),
order_map: runtime_proxy_groups_order.as_ref(),
menu_signature: &menu_signature,
proxy_signature: proxy_signature.as_deref(),
fetched: fetch_proxy_groups,
logging_error!(
Type::Tray,
tray.set_menu(Some(
create_tray_menu(
app_handle,
Some(mode.as_str()),
*system_proxy,
*tun_mode,
tun_mode_available,
profiles_preview,
TrayMenuOptions {
is_lightweight_mode,
include_proxy_groups,
},
));
})
.map_err(|e| anyhow::anyhow!("Failed to dispatch tray menu update: {e}"))?;
rx.await
.map_err(|_| anyhow::anyhow!("Tray menu update returned no result"))??;
)
.await?,
))
);
logging!(debug, Type::Tray, "托盘菜单更新成功");
Ok(())
@@ -484,12 +422,11 @@ fn create_hotkeys(hotkeys: &Option<Vec<String>>) -> HashMap<&str, &str> {
let mut parts = item.split(',');
match (parts.next(), parts.next()) {
(Some(func), Some(key)) => {
// 托盘菜单中的 `accelerator` 属性,在 Linux/Windows 中都不支持小键盘按键的解析
if key.to_uppercase().contains("NUMPAD") {
None
} else {
Some((func, key))
}
// 托盘菜单的 `accelerator` 在 Linux/Windows 下不支持小键盘按键,Windows 下也不支持 Win 键(前端上报为 `CMD`)
let uppercase_key = key.to_uppercase();
let unsupported =
uppercase_key.contains("NUMPAD") || (cfg!(windows) && uppercase_key.contains("CMD"));
if unsupported { None } else { Some((func, key)) }
}
_ => None,
}
@@ -502,7 +439,7 @@ fn create_hotkeys(hotkeys: &Option<Vec<String>>) -> HashMap<&str, &str> {
fn create_profile_menu_item(
app_handle: &AppHandle,
profiles_preview: Vec<IProfilePreview<'_>>,
) -> Result<Vec<(String, CheckMenuItem<Wry>)>> {
) -> Result<Vec<CheckMenuItem<Wry>>> {
profiles_preview
.into_iter()
.map(|profile| {
@@ -514,7 +451,6 @@ fn create_profile_menu_item(
profile.is_current,
None::<&str>,
)
.map(|item| (profile.uid.clone(), item))
.map_err(|e| e.into())
})
.collect()
@@ -523,96 +459,93 @@ fn create_profile_menu_item(
fn create_subcreate_proxy_menu_item(
app_handle: &AppHandle,
proxy_mode: &str,
proxy_group_order_map: Option<&HashMap<String, usize>>,
proxy_nodes_data: &Proxies,
) -> (Vec<Submenu<Wry>>, Vec<ProxyGroupItems>) {
let mut submenus: Vec<(String, usize, Submenu<Wry>, Vec<ProxyNodeItem>)> = Vec::new();
proxy_group_order_map: Option<HashMap<String, usize>>,
proxy_nodes_data: Option<Proxies>,
) -> Vec<Submenu<Wry>> {
let proxy_submenus: Vec<Submenu<Wry>> = {
let mut submenus: Vec<(String, usize, Submenu<Wry>)> = Vec::new();
// TODO: 应用启动时,内核还未启动完全,无法获取代理节点信息
for (group_name, group_data) in proxy_nodes_data.proxies.iter() {
let should_show = match proxy_mode {
"global" => group_name == "GLOBAL",
_ => group_name != "GLOBAL",
} && !group_data.hidden.unwrap_or_default();
// TODO: 应用启动时,内核还未启动完全,无法获取代理节点信息
if let Some(proxy_nodes_data) = proxy_nodes_data {
for (group_name, group_data) in proxy_nodes_data.proxies.iter() {
let should_show = match proxy_mode {
"global" => group_name == "GLOBAL",
_ => group_name != "GLOBAL",
} && !group_data.hidden.unwrap_or_default();
if !should_show {
continue;
}
let Some(all_proxies) = group_data.all.as_ref() else {
continue;
};
let now_proxy = group_data.now.as_deref().unwrap_or_default();
let mut group_items: Vec<CheckMenuItem<Wry>> = Vec::with_capacity(all_proxies.len());
let mut nodes: Vec<ProxyNodeItem> = Vec::with_capacity(all_proxies.len());
for proxy_str in all_proxies {
let is_selected = proxy_str == now_proxy;
let item_id = format!("proxy_{}_{}", group_name, proxy_str);
let display_text = format!(
"{} | {}",
proxy_str,
proxy_delay_text(proxy_nodes_data, proxy_str.as_str())
);
match CheckMenuItem::with_id(app_handle, item_id, &display_text, true, is_selected, None::<&str>) {
Ok(item) => {
group_items.push(item.clone());
nodes.push(ProxyNodeItem {
name: proxy_str.clone().into(),
item,
text: display_text.as_str().into(),
checked: is_selected,
});
if !should_show {
continue;
}
let Some(all_proxies) = group_data.all.as_ref() else {
continue;
};
let now_proxy = group_data.now.as_deref().unwrap_or_default();
let group_items: Vec<CheckMenuItem<Wry>> = all_proxies
.iter()
.filter_map(|proxy_str| {
let is_selected = *proxy_str == now_proxy;
let item_id = format!("proxy_{}_{}", group_name, proxy_str);
let delay_text = proxy_nodes_data
.proxies
.get(proxy_str)
.and_then(|h| h.history.last())
.map(|h| match h.delay {
0 => "-ms".into(),
delay if delay >= 10000 => "-ms".into(),
_ => format!("{}ms", h.delay),
})
.unwrap_or_else(|| "-ms".into());
let display_text = format!("{} | {}", proxy_str, delay_text);
CheckMenuItem::with_id(app_handle, item_id, display_text, true, is_selected, None::<&str>)
.map_err(|e| logging!(warn, Type::Tray, "Failed to create proxy menu item: {}", e))
.ok()
})
.collect();
if group_items.is_empty() {
continue;
}
let group_display_name = group_name.to_string();
let group_items_refs: Vec<&dyn IsMenuItem<Wry>> =
group_items.iter().map(|item| item as &dyn IsMenuItem<Wry>).collect();
if let Ok(submenu) = Submenu::with_id_and_items(
app_handle,
format!("proxy_group_{}", group_name),
group_display_name,
true,
&group_items_refs,
) {
let insertion_index = submenus.len();
submenus.push((group_name.into(), insertion_index, submenu));
} else {
logging!(warn, Type::Tray, "Failed to create proxy group submenu: {}", group_name);
}
Err(e) => logging!(warn, Type::Tray, "Failed to create proxy menu item: {}", e),
}
}
if group_items.is_empty() {
continue;
if let Some(order_map) = proxy_group_order_map.as_ref() {
submenus.sort_by(|(name_a, original_index_a, _), (name_b, original_index_b, _)| {
match (order_map.get(name_a), order_map.get(name_b)) {
(Some(index_a), Some(index_b)) => index_a.cmp(index_b),
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => original_index_a.cmp(original_index_b),
}
});
}
let group_display_name = group_name.to_string();
let group_items_refs: Vec<&dyn IsMenuItem<Wry>> =
group_items.iter().map(|item| item as &dyn IsMenuItem<Wry>).collect();
if let Ok(submenu) = Submenu::with_id_and_items(
app_handle,
format!("proxy_group_{}", group_name),
group_display_name,
true,
&group_items_refs,
) {
let insertion_index = submenus.len();
submenus.push((group_name.into(), insertion_index, submenu, nodes));
} else {
logging!(warn, Type::Tray, "Failed to create proxy group submenu: {}", group_name);
}
}
if let Some(order_map) = proxy_group_order_map {
submenus.sort_by(|(name_a, original_index_a, _, _), (name_b, original_index_b, _, _)| {
match (order_map.get(name_a), order_map.get(name_b)) {
(Some(index_a), Some(index_b)) => index_a.cmp(index_b),
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => original_index_a.cmp(original_index_b),
}
});
}
let mut groups = Vec::with_capacity(submenus.len());
let group_menus = submenus
.into_iter()
.map(|(name, _, submenu, nodes)| {
groups.push(ProxyGroupItems { name, nodes });
submenu
})
.collect();
(group_menus, groups)
submenus.into_iter().map(|(_, _, submenu)| submenu).collect()
};
proxy_submenus
}
fn create_proxy_menu_item(
@@ -651,16 +584,53 @@ fn create_proxy_menu_item(
Ok((proxies_submenu, inline_proxy_items))
}
fn build_tray_menu(
async fn create_tray_menu(
app_handle: &AppHandle,
options: TrayMenuOptions<'_>,
verge_settings: &IVerge,
profiles_config: &IProfiles,
proxy_group_order_map: Option<&HashMap<String, usize>>,
proxy_nodes_data: Option<&Proxies>,
) -> Result<(tauri::menu::Menu<Wry>, TrayMenuState)> {
let current_proxy_mode = options.mode.unwrap_or("");
let tun_mode_available = crate::core::runstate::RUN_STATE.state().tun_capable();
mode: Option<&str>,
system_proxy_enabled: bool,
tun_mode_enabled: bool,
tun_mode_available: bool,
profiles_preview: Vec<IProfilePreview<'_>>,
options: TrayMenuOptions,
) -> Result<tauri::menu::Menu<Wry>> {
let current_proxy_mode = mode.unwrap_or("");
let mut verge_settings = Config::verge().await.latest_arc();
let fetch_proxy_groups =
options.include_proxy_groups && verge_settings.tray_proxy_groups_display_mode.as_deref() != Some("disable");
// TODO: should update tray menu again when it was timeout error
let (proxy_nodes_data, runtime_proxy_groups_order) = if fetch_proxy_groups {
let proxy_nodes_data =
tokio::time::timeout(Duration::from_millis(1000), handle::Handle::mihomo().get_proxies())
.await
.map_or(None, |res| res.ok());
let runtime = Config::runtime().await.latest_arc();
let runtime_proxy_groups_order = runtime.config.as_ref().map(|config| {
config
.get("proxy-groups")
.and_then(|groups| groups.as_sequence())
.map(|groups| {
groups
.iter()
.filter_map(|group| group.get("name"))
.filter_map(|name| name.as_str())
.enumerate()
.map(|(index, name)| (name.into(), index))
.collect::<HashMap<String, usize>>()
})
.unwrap_or_default()
});
(proxy_nodes_data, runtime_proxy_groups_order)
} else {
(None, None)
};
if fetch_proxy_groups {
verge_settings = Config::verge().await.latest_arc();
}
let tray_proxy_groups_display_mode = verge_settings
.tray_proxy_groups_display_mode
@@ -668,19 +638,20 @@ fn build_tray_menu(
.unwrap_or("default");
let include_proxy_groups = options.include_proxy_groups && tray_proxy_groups_display_mode != "disable";
let proxy_group_order_map = runtime_proxy_groups_order;
let show_outbound_modes_inline = verge_settings.tray_inline_outbound_modes.unwrap_or(false);
let version = env!("CARGO_PKG_VERSION");
let hotkeys = create_hotkeys(&verge_settings.hotkeys);
let profiles_preview = profiles_config.profiles_preview().unwrap_or_default();
let profile_menu_items: Vec<(String, CheckMenuItem<Wry>)> = create_profile_menu_item(app_handle, profiles_preview)?;
let profile_menu_items: Vec<CheckMenuItem<Wry>> = create_profile_menu_item(app_handle, profiles_preview)?;
let texts = MenuTexts::new();
let profile_menu_items_refs: Vec<&dyn IsMenuItem<Wry>> = profile_menu_items
.iter()
.map(|(_, item)| item as &dyn IsMenuItem<Wry>)
.map(|item| item as &dyn IsMenuItem<Wry>)
.collect();
let open_window = &MenuItem::with_id(
@@ -748,20 +719,12 @@ fn build_tray_menu(
&profile_menu_items_refs,
)?;
let mut proxy_groups: Vec<ProxyGroupItems> = Vec::new();
let mut proxies_submenu_handle: Option<Submenu<Wry>> = None;
let (proxies_menu, inline_proxy_items) = if include_proxy_groups && let Some(proxy_nodes_data) = proxy_nodes_data {
let (proxy_sub_menus, groups) =
let (proxies_menu, inline_proxy_items) = if include_proxy_groups {
let proxy_sub_menus =
create_subcreate_proxy_menu_item(app_handle, current_proxy_mode, proxy_group_order_map, proxy_nodes_data);
proxy_groups = groups;
match tray_proxy_groups_display_mode {
"default" => {
let (submenu, inline_items) =
create_proxy_menu_item(app_handle, false, proxy_sub_menus, &texts.proxies)?;
proxies_submenu_handle = submenu.clone();
(submenu, inline_items)
}
"default" => create_proxy_menu_item(app_handle, false, proxy_sub_menus, &texts.proxies)?,
"inline" => create_proxy_menu_item(app_handle, true, proxy_sub_menus, &texts.proxies)?,
_ => (None, Vec::new()),
}
@@ -774,7 +737,7 @@ fn build_tray_menu(
MenuIds::SYSTEM_PROXY,
&texts.system_proxy,
true,
options.system_proxy_enabled,
system_proxy_enabled,
hotkeys.get("toggle_system_proxy").copied(),
)?;
@@ -783,7 +746,7 @@ fn build_tray_menu(
MenuIds::TUN_MODE,
&texts.tun_mode,
tun_mode_available,
options.tun_mode_enabled,
tun_mode_enabled,
hotkeys.get("toggle_tun_mode").copied(),
)?;
@@ -902,18 +865,7 @@ fn build_tray_menu(
]);
let menu = tauri::menu::MenuBuilder::new(app_handle).items(&menu_items).build()?;
let state = TrayMenuState {
mode_items: [rule_mode.clone(), global_mode.clone(), direct_mode.clone()],
system_proxy_item: system_proxy.clone(),
tun_item: tun_mode.clone(),
lightweight_item: lightweight_mode.clone(),
profile_items: profile_menu_items,
proxies_submenu: proxies_submenu_handle,
proxy_groups,
signature: String::new(),
proxy_signature: None,
};
Ok((menu, state))
Ok(menu)
}
fn on_tray_icon_event(_tray_icon: &TrayIcon, tray_event: TrayIconEvent) {