Compare commits

...

33 commits

Author SHA1 Message Date
2dust
cc4154bb0d Increase UI grid column widths and font size options
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-28 20:31:40 +08:00
2dust
d7f77f220c Improve group text description
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-27 19:55:33 +08:00
JieXu
86f45d103d
Update build-linux.yml to use Red Hat UBI image (#8392)
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-27 15:01:44 +08:00
2dust
0077751f75 Add subscription delete functionality to ProfilesView
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-26 20:11:14 +08:00
dependabot[bot]
fa2b4b3dc9
Bump actions/setup-dotnet from 5.0.0 to 5.0.1 (#8387)
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-26 14:31:34 +08:00
DHR60
23cacb8339
Format imported xhttp extra (#8390) 2025-11-26 14:31:14 +08:00
DHR60
9ffa6a4eb6
Remove formatted spaces from extra JSON before URL encoding (#8385)
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-25 17:40:41 +08:00
2dust
386209b835 Fix
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-24 19:12:49 +08:00
jiuqianyuan
830dc89c32
Fix: tcping high latency and speedtest displayed 0 (#8374)
* Fix: High latency in tcping test due to thread blocking

* Fix: download to fast, speed displayed as 0.

---------

Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
2025-11-24 19:01:04 +08:00
2dust
693afe3560 up 7.16.4
Some checks failed
release Linux / build (Release) (push) Has been cancelled
release macOS / build (Release) (push) Has been cancelled
release Windows desktop (Avalonia UI) / build (Release) (push) Has been cancelled
release Windows / build (Release) (push) Has been cancelled
release Linux / rpm (push) Has been cancelled
2025-11-23 14:33:01 +08:00
2dust
95361e8b65 Simplify configuration-related resource strings 2025-11-23 14:31:29 +08:00
2dust
3ff7299aca Refactor update result handling and model 2025-11-23 14:06:34 +08:00
DHR60
34fc4de0c2
Avoid xray warning (#8369)
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-22 19:17:18 +08:00
DHR60
91536d3923
Fix sing-box ws (#8367)
* Fix sing-box ws

* Parse eh
2025-11-22 16:40:07 +08:00
2dust
6b87c09a96 Add confirmation before removing duplicate servers
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
https://github.com/2dust/v2rayN/issues/8365
2025-11-22 10:20:16 +08:00
2dust
ecaac2ac61 Fix
https://github.com/2dust/v2rayN/discussions/8366
2025-11-22 10:16:53 +08:00
2dust
ad74b1584d Refactor dialog layouts
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-21 20:30:41 +08:00
dependabot[bot]
514d76953a
Bump actions/checkout from 5.0.1 to 6.0.0 (#8359)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.1 to 6.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5.0.1...v6.0.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-21 15:57:37 +08:00
DHR60
5b82f17995
Fix (#8363)
* Fix

* AI-optimized code
2025-11-21 15:56:42 +08:00
2dust
20ce35bc30 Update dotnet publish syntax in build workflows
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-20 20:04:14 +08:00
2dust
c0fca0dddd Update build script and remove global.json 2025-11-20 19:56:14 +08:00
2dust
2ba896e17e Update Directory.Packages.props 2025-11-20 19:39:29 +08:00
DHR60
f61e6d8c63
perf: Shadowsocks (#8352)
* perf: Shadowsocks

* stricter plugin name fix for SIP002 URI

* Fix
2025-11-20 19:35:57 +08:00
2dust
d3e2e55ecf Add global.json for SDK configuration
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
Introduces a global.json file specifying the .NET SDK version (8.0.416) and disables rollForward to ensure consistent SDK usage across environments.
2025-11-20 10:12:44 +08:00
2dust
30e663cd4f up 7.16.3
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-11-19 17:15:35 +08:00
JieXu
054efeb32c
[PR]改进Emoji字体兼容性 (#8346)
* Update AppBuilderExtension.cs

* Update package-rhel.sh

* Update package-debian.sh

* Update AppBuilderExtension.cs

* Update AppBuilderExtension.cs

* Update AppBuilderExtension.cs

* Withdraw

* Update AppBuilderExtension.cs
2025-11-19 16:47:00 +08:00
2dust
2ebd2b28a8 Support Backspace for remove actions in UI lists
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
Changed key handling and menu input gestures to allow Backspace (in addition to Delete) for removing items in server, profile, and routing rule lists. This improves usability and consistency across both Avalonia and WPF views.
2025-11-18 16:54:42 +08:00
dependabot[bot]
84f812c8ee
Bump actions/checkout from 5.0.0 to 5.0.1 (#8341)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-18 16:15:59 +08:00
2dust
b6ee40ab8d Update Directory.Packages.props 2025-11-18 16:15:19 +08:00
2dust
7f24f4a15f Remove shortcut hints from menu translations
Shortcut key hints (e.g., '(Ctrl+C)', '(Delete)') were removed from various menu item translations in resource files for all supported languages. This improves consistency and clarity in UI text across the application.
2025-11-18 16:00:02 +08:00
2dust
0d307671d1 Bug fix
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
https://github.com/2dust/v2rayN/issues/8267
2025-11-17 17:44:39 +08:00
Harry Huang
8ea5a57988
Optimize speedtest (#8325)
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
* Optimize stop-speedtest tip display

* Fix speedtest termination latency
2025-11-16 14:58:55 +08:00
Harry Huang
4fb41aeca1
Remove redundant string operation (#8324) 2025-11-16 14:21:34 +08:00
64 changed files with 1266 additions and 726 deletions

View file

@ -31,23 +31,23 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5.0.0 uses: actions/checkout@v6.0.0
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v5.0.0 uses: actions/setup-dotnet@v5.0.1
with: with:
dotnet-version: '8.0.x' dotnet-version: '8.0.x'
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained=true -o "$OutputPath64" dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 -p:SelfContained=true -o "$OutputPath64"
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained=true -o "$OutputPathArm64" dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 -p:SelfContained=true -o "$OutputPathArm64"
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained=true -p:PublishTrimmed=true -o "$OutputPath64" dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 -p:SelfContained=true -p:PublishTrimmed=true -o "$OutputPath64"
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o "$OutputPathArm64" dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 -p:SelfContained=true -p:PublishTrimmed=true -o "$OutputPathArm64"
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v5.0.0 uses: actions/upload-artifact@v5.0.0
@ -97,20 +97,20 @@ jobs:
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
container: container:
image: quay.io/almalinuxorg/10-base:latest image: registry.access.redhat.com/ubi10/ubi
options: --platform=linux/amd64/v2
env: env:
RELEASE_TAG: ${{ github.event.inputs.release_tag != '' && github.event.inputs.release_tag || github.ref_name }} RELEASE_TAG: ${{ github.event.inputs.release_tag != '' && github.event.inputs.release_tag || github.ref_name }}
steps: steps:
- name: Prepare tools (Red Hat) - name: Prepare tools (Red Hat)
run: | run: |
dnf repolist all
dnf -y makecache dnf -y makecache
dnf -y install epel-release dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm
dnf -y install sudo git rpm-build rpmdevtools dnf-plugins-core rsync findutils tar gzip unzip which dnf -y install sudo git rpm-build rpmdevtools dnf-plugins-core rsync findutils tar gzip unzip which
- name: Checkout repo (for scripts) - name: Checkout repo (for scripts)
uses: actions/checkout@v5.0.0 uses: actions/checkout@v6.0.0
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'

View file

@ -26,23 +26,23 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5.0.0 uses: actions/checkout@v6.0.0
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'
- name: Setup - name: Setup
uses: actions/setup-dotnet@v5.0.0 uses: actions/setup-dotnet@v5.0.1
with: with:
dotnet-version: '8.0.x' dotnet-version: '8.0.x'
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained=true -o $OutputPath64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 -p:SelfContained=true -o $OutputPath64
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained=true -o $OutputPathArm64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 -p:SelfContained=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 -p:SelfContained=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 -p:SelfContained=true -p:PublishTrimmed=true -o $OutputPathArm64
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v5.0.0 uses: actions/upload-artifact@v5.0.0

View file

@ -26,23 +26,23 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5.0.0 uses: actions/checkout@v6.0.0
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'
- name: Setup - name: Setup
uses: actions/setup-dotnet@v5.0.0 uses: actions/setup-dotnet@v5.0.1
with: with:
dotnet-version: '8.0.x' dotnet-version: '8.0.x'
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v5.0.0 uses: actions/upload-artifact@v5.0.0

View file

@ -27,22 +27,22 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5.0.0 uses: actions/checkout@v6.0.0
- name: Setup - name: Setup
uses: actions/setup-dotnet@v5.0.0 uses: actions/setup-dotnet@v5.0.1
with: with:
dotnet-version: '8.0.x' dotnet-version: '8.0.x'
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc
- name: Upload build artifacts - name: Upload build artifacts

View file

@ -28,7 +28,7 @@ Package: v2rayN
Version: $Version Version: $Version
Architecture: $Arch2 Architecture: $Arch2
Maintainer: https://github.com/2dust/v2rayN Maintainer: https://github.com/2dust/v2rayN
Depends: libc6 (>= 2.34), fontconfig (>= 2.13.1), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 8.32), bash (>= 5.1) Depends: libc6 (>= 2.34), fontconfig (>= 2.13.1), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 8.32), bash (>= 5.1), libfreetype6 (>= 2.11)
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
EOF EOF

View file

@ -631,13 +631,14 @@ ExclusiveArch: aarch64 x86_64
Source0: __PKGROOT__.tar.gz Source0: __PKGROOT__.tar.gz
# Runtime dependencies (Avalonia / X11 / Fonts / GL) # Runtime dependencies (Avalonia / X11 / Fonts / GL)
Requires: freetype, cairo, pango, openssl, mesa-libEGL, mesa-libGL Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
Requires: glibc >= 2.34 Requires: glibc >= 2.34
Requires: fontconfig >= 2.13.1 Requires: fontconfig >= 2.13.1
Requires: desktop-file-utils >= 0.26 Requires: desktop-file-utils >= 0.26
Requires: xdg-utils >= 1.1.3 Requires: xdg-utils >= 1.1.3
Requires: coreutils >= 8.32 Requires: coreutils >= 8.32
Requires: bash >= 5.1 Requires: bash >= 5.1
Requires: freetype >= 2.10
%description %description
v2rayN Linux for Red Hat Enterprise Linux v2rayN Linux for Red Hat Enterprise Linux

View file

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.16.2</Version> <Version>7.16.4</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -6,11 +6,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.3.0" /> <PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.3.0" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.8" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.9" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.8" /> <PackageVersion Include="Avalonia.Desktop" Version="11.3.9" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.8" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.3.9" />
<PackageVersion Include="ReactiveUI.Avalonia" Version="11.3.8" /> <PackageVersion Include="ReactiveUI.Avalonia" Version="11.3.8" />
<PackageVersion Include="CliWrap" Version="3.9.0" /> <PackageVersion Include="CliWrap" Version="3.10.0" />
<PackageVersion Include="Downloader" Version="4.0.3" /> <PackageVersion Include="Downloader" Version="4.0.3" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.2" /> <PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.2" />
<PackageVersion Include="MaterialDesignThemes" Version="5.3.0" /> <PackageVersion Include="MaterialDesignThemes" Version="5.3.0" />
@ -19,9 +19,9 @@
<PackageVersion Include="ReactiveUI" Version="22.2.1" /> <PackageVersion Include="ReactiveUI" Version="22.2.1" />
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" /> <PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageVersion Include="ReactiveUI.WPF" Version="22.2.1" /> <PackageVersion Include="ReactiveUI.WPF" Version="22.2.1" />
<PackageVersion Include="Semi.Avalonia" Version="11.3.7" /> <PackageVersion Include="Semi.Avalonia" Version="11.3.7.1" />
<PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" /> <PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7" /> <PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.1" />
<PackageVersion Include="NLog" Version="6.0.6" /> <PackageVersion Include="NLog" Version="6.0.6" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" /> <PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.2" /> <PackageVersion Include="TaskScheduler" Version="2.12.2" />

View file

@ -425,7 +425,7 @@ public class Utils
var domain = authority; var domain = authority;
// Handle IPv6 addresses, e.g., "[2001:db8::1]:443" // Handle IPv6 addresses, e.g., "[2001:db8::1]:443"
if (authority.StartsWith("[") && authority.Contains("]")) if (authority.StartsWith('[') && authority.Contains(']'))
{ {
var closingBracketIndex = authority.LastIndexOf(']'); var closingBracketIndex = authority.LastIndexOf(']');
if (closingBracketIndex < authority.Length - 1 && authority[closingBracketIndex + 1] == ':') if (closingBracketIndex < authority.Length - 1 && authority[closingBracketIndex + 1] == ':')

View file

@ -73,6 +73,7 @@ public class Global
public const string GrpcMultiMode = "multi"; public const string GrpcMultiMode = "multi";
public const int MaxPort = 65536; public const int MaxPort = 65536;
public const int MinFontSize = 8; public const int MinFontSize = 8;
public const int MinFontSizeCount = 13;
public const string RebootAs = "rebootas"; public const string RebootAs = "rebootas";
public const string AvaAssets = "avares://v2rayN/Assets/"; public const string AvaAssets = "avares://v2rayN/Assets/";
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2"; public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2";

View file

@ -4,7 +4,7 @@ namespace ServiceLib.Handler.Fmt;
public class BaseFmt public class BaseFmt
{ {
private static readonly string[] _allowInsecureArray = new[] { "insecure", "allowInsecure", "allow_insecure", "verify" }; private static readonly string[] _allowInsecureArray = new[] { "insecure", "allowInsecure", "allow_insecure" };
protected static string GetIpv6(string address) protected static string GetIpv6(string address)
{ {
@ -118,7 +118,16 @@ public class BaseFmt
} }
if (item.Extra.IsNotEmpty()) if (item.Extra.IsNotEmpty())
{ {
dicQuery.Add("extra", Utils.UrlEncode(item.Extra)); var node = JsonUtils.ParseJson(item.Extra);
var extra = node != null
? JsonUtils.Serialize(node, new JsonSerializerOptions
{
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
})
: item.Extra;
dicQuery.Add("extra", Utils.UrlEncode(extra));
} }
break; break;
@ -237,7 +246,21 @@ public class BaseFmt
item.RequestHost = GetQueryDecoded(query, "host"); item.RequestHost = GetQueryDecoded(query, "host");
item.Path = GetQueryDecoded(query, "path", "/"); item.Path = GetQueryDecoded(query, "path", "/");
item.HeaderType = GetQueryDecoded(query, "mode"); item.HeaderType = GetQueryDecoded(query, "mode");
item.Extra = GetQueryDecoded(query, "extra"); var extraDecoded = GetQueryDecoded(query, "extra");
if (extraDecoded.IsNotEmpty())
{
var node = JsonUtils.ParseJson(extraDecoded);
if (node != null)
{
extraDecoded = JsonUtils.Serialize(node, new JsonSerializerOptions
{
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
}
}
item.Extra = extraDecoded;
break; break;
case nameof(ETransport.http): case nameof(ETransport.http):

View file

@ -41,7 +41,66 @@ public class ShadowsocksFmt : BaseFmt
//url = Utile.Base64Encode(url); //url = Utile.Base64Encode(url);
//new Sip002 //new Sip002
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}", true); var pw = Utils.Base64Encode($"{item.Security}:{item.Id}", true);
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, null, remark);
// plugin
var plugin = string.Empty;
var pluginArgs = string.Empty;
if (item.Network == nameof(ETransport.tcp) && item.HeaderType == Global.TcpHeaderHttp)
{
plugin = "obfs-local";
pluginArgs = $"obfs=http;obfs-host={item.RequestHost};";
}
else
{
if (item.Network == nameof(ETransport.ws))
{
pluginArgs += "mode=websocket;";
pluginArgs += $"host={item.RequestHost};";
pluginArgs += $"path={item.Path};";
}
else if (item.Network == nameof(ETransport.quic))
{
pluginArgs += "mode=quic;";
}
if (item.StreamSecurity == Global.StreamSecurity)
{
pluginArgs += "tls;";
var certs = CertPemManager.ParsePemChain(item.Cert);
if (certs.Count > 0)
{
var cert = certs.First();
const string beginMarker = "-----BEGIN CERTIFICATE-----\n";
const string endMarker = "\n-----END CERTIFICATE-----";
var base64Content = cert.Replace(beginMarker, "").Replace(endMarker, "").Trim();
// https://github.com/shadowsocks/v2ray-plugin/blob/e9af1cdd2549d528deb20a4ab8d61c5fbe51f306/args.go#L172
// Equal signs and commas [and backslashes] must be escaped with a backslash.
base64Content = base64Content.Replace("=", "\\=");
pluginArgs += $"certRaw={base64Content};";
}
}
if (pluginArgs.Length > 0)
{
plugin = "v2ray-plugin";
}
}
var dicQuery = new Dictionary<string, string>();
if (plugin.IsNotEmpty())
{
var pluginStr = plugin + ";" + pluginArgs;
// pluginStr remove last ';' and url encode
if (pluginStr.EndsWith(';'))
{
pluginStr = pluginStr[..^1];
}
dicQuery["plugin"] = Utils.UrlEncode(pluginStr);
}
return ToUri(EConfigType.Shadowsocks, item.Address, item.Port, pw, dicQuery, remark);
} }
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
@ -124,19 +183,81 @@ public class ShadowsocksFmt : BaseFmt
var queryParameters = Utils.ParseQueryString(parsedUrl.Query); var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
if (queryParameters["plugin"] != null) if (queryParameters["plugin"] != null)
{ {
//obfs-host exists var pluginStr = queryParameters["plugin"];
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host")); var pluginParts = pluginStr.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
if (queryParameters["plugin"].Contains("obfs=http") && obfsHost.IsNotEmpty())
{ if (pluginParts.Length == 0)
obfsHost = obfsHost?.Replace("obfs-host=", "");
item.Network = Global.DefaultNetwork;
item.HeaderType = Global.TcpHeaderHttp;
item.RequestHost = obfsHost ?? "";
}
else
{ {
return null; return null;
} }
var pluginName = pluginParts[0];
// A typo in https://github.com/shadowsocks/shadowsocks-org/blob/6b1c064db4129de99c516294960e731934841c94/docs/doc/sip002.md?plain=1#L15
// "simple-obfs" should be "obfs-local"
if (pluginName == "simple-obfs")
{
pluginName = "obfs-local";
}
// Parse obfs-local plugin
if (pluginName == "obfs-local")
{
var obfsMode = pluginParts.FirstOrDefault(t => t.StartsWith("obfs="));
var obfsHost = pluginParts.FirstOrDefault(t => t.StartsWith("obfs-host="));
if ((!obfsMode.IsNullOrEmpty()) && obfsMode.Contains("obfs=http") && obfsHost.IsNotEmpty())
{
obfsHost = obfsHost.Replace("obfs-host=", "");
item.Network = Global.DefaultNetwork;
item.HeaderType = Global.TcpHeaderHttp;
item.RequestHost = obfsHost;
}
}
// Parse v2ray-plugin
else if (pluginName == "v2ray-plugin")
{
var mode = pluginParts.FirstOrDefault(t => t.StartsWith("mode="), "websocket");
var host = pluginParts.FirstOrDefault(t => t.StartsWith("host="));
var path = pluginParts.FirstOrDefault(t => t.StartsWith("path="));
var hasTls = pluginParts.Any(t => t == "tls");
var certRaw = pluginParts.FirstOrDefault(t => t.StartsWith("certRaw="));
var modeValue = mode.Replace("mode=", "");
if (modeValue == "websocket")
{
item.Network = nameof(ETransport.ws);
if (!host.IsNullOrEmpty())
{
item.RequestHost = host.Replace("host=", "");
}
if (!path.IsNullOrEmpty())
{
item.Path = path.Replace("path=", "");
}
}
else if (modeValue == "quic")
{
item.Network = nameof(ETransport.quic);
}
if (hasTls)
{
item.StreamSecurity = Global.StreamSecurity;
if (!certRaw.IsNullOrEmpty())
{
var certBase64 = certRaw.Replace("certRaw=", "");
certBase64 = certBase64.Replace("\\=", "=");
const string beginMarker = "-----BEGIN CERTIFICATE-----\n";
const string endMarker = "\n-----END CERTIFICATE-----";
var certPem = beginMarker + certBase64 + endMarker;
item.Cert = certPem;
}
}
}
} }
return item; return item;

View file

@ -45,18 +45,18 @@ public class SocksFmt : BaseFmt
}; };
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..]; result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
//remark //remark
var indexRemark = result.IndexOf("#"); var indexRemark = result.IndexOf('#');
if (indexRemark > 0) if (indexRemark > 0)
{ {
try try
{ {
item.Remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); item.Remarks = Utils.UrlDecode(result.Substring(indexRemark + 1));
} }
catch { } catch { }
result = result[..indexRemark]; result = result[..indexRemark];
} }
//part decode //part decode
var indexS = result.IndexOf("@"); var indexS = result.IndexOf('@');
if (indexS > 0) if (indexS > 0)
{ {
} }

View file

@ -71,28 +71,25 @@ public class DownloaderHelper
} }
}; };
var totalDatetime = DateTime.Now; var lastUpdateTime = DateTime.Now;
var totalSecond = 0;
var hasValue = false; var hasValue = false;
double maxSpeed = 0; double maxSpeed = 0;
await using var downloader = new Downloader.DownloadService(downloadOpt); await using var downloader = new Downloader.DownloadService(downloadOpt);
//downloader.DownloadStarted += (sender, value) =>
//{
// if (progress != null)
// {
// progress.Report("Start download data...");
// }
//};
downloader.DownloadProgressChanged += (sender, value) => downloader.DownloadProgressChanged += (sender, value) =>
{ {
var ts = DateTime.Now - totalDatetime; if (progress != null && value.BytesPerSecondSpeed > 0)
if (progress != null && ts.Seconds > totalSecond)
{ {
hasValue = true; hasValue = true;
totalSecond = ts.Seconds;
if (value.BytesPerSecondSpeed > maxSpeed) if (value.BytesPerSecondSpeed > maxSpeed)
{ {
maxSpeed = value.BytesPerSecondSpeed; maxSpeed = value.BytesPerSecondSpeed;
}
var ts = DateTime.Now - lastUpdateTime;
if (ts.TotalMilliseconds >= 1000)
{
lastUpdateTime = DateTime.Now;
var speed = (maxSpeed / 1000 / 1000).ToString("#0.0"); var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
progress.Report(speed); progress.Report(speed);
} }
@ -102,10 +99,19 @@ public class DownloaderHelper
{ {
if (progress != null) if (progress != null)
{ {
if (!hasValue && value.Error != null) if (hasValue && maxSpeed > 0)
{
var finalSpeed = (maxSpeed / 1000 / 1000).ToString("#0.0");
progress.Report(finalSpeed);
}
else if (value.Error != null)
{ {
progress.Report(value.Error?.Message); progress.Report(value.Error?.Message);
} }
else
{
progress.Report("0");
}
} }
}; };
//progress.Report("......"); //progress.Report("......");

View file

@ -10,6 +10,13 @@ public class ActionPrecheckManager(Config config)
private readonly Config _config = config; private readonly Config _config = config;
// sing-box supported transports for different protocol types
private static readonly HashSet<string> SingboxUnsupportedTransports = [nameof(ETransport.kcp), nameof(ETransport.xhttp)];
private static readonly HashSet<EConfigType> SingboxTransportSupportedProtocols =
[EConfigType.VMess, EConfigType.VLESS, EConfigType.Trojan, EConfigType.Shadowsocks];
private static readonly HashSet<string> SingboxShadowsocksAllowedTransports =
[nameof(ETransport.tcp), nameof(ETransport.ws), nameof(ETransport.quic)];
public async Task<List<string>> Check(string? indexId) public async Task<List<string>> Check(string? indexId)
{ {
if (indexId.IsNullOrEmpty()) if (indexId.IsNullOrEmpty())
@ -174,26 +181,16 @@ public class ActionPrecheckManager(Config config)
return errors; return errors;
} }
var net = item.GetNetwork() ?? item.Network; var net = item.GetNetwork();
if (coreType == ECoreType.sing_box) if (coreType == ECoreType.sing_box)
{ {
// sing-box does not support xhttp / kcp var transportError = ValidateSingboxTransport(item.ConfigType, net);
// sing-box does not support transports like ws/http/httpupgrade/etc. when the node is not vmess/trojan/vless if (transportError != null)
if (net is nameof(ETransport.kcp) or nameof(ETransport.xhttp))
{ {
errors.Add(string.Format(ResUI.CoreNotSupportNetwork, nameof(ECoreType.sing_box), net)); errors.Add(transportError);
return errors; return errors;
} }
if (item.ConfigType is not (EConfigType.VMess or EConfigType.VLESS or EConfigType.Trojan))
{
if (net is nameof(ETransport.ws) or nameof(ETransport.http) or nameof(ETransport.h2) or nameof(ETransport.quic) or nameof(ETransport.httpupgrade))
{
errors.Add(string.Format(ResUI.CoreNotSupportProtocolTransport, nameof(ECoreType.sing_box), item.ConfigType.ToString(), net));
return errors;
}
}
} }
else if (coreType is ECoreType.Xray) else if (coreType is ECoreType.Xray)
{ {
@ -209,6 +206,31 @@ public class ActionPrecheckManager(Config config)
return errors; return errors;
} }
private static string? ValidateSingboxTransport(EConfigType configType, string net)
{
// sing-box does not support xhttp / kcp transports
if (SingboxUnsupportedTransports.Contains(net))
{
return string.Format(ResUI.CoreNotSupportNetwork, nameof(ECoreType.sing_box), net);
}
// sing-box does not support non-tcp transports for protocols other than vmess/trojan/vless/shadowsocks
if (!SingboxTransportSupportedProtocols.Contains(configType) && net != nameof(ETransport.tcp))
{
return string.Format(ResUI.CoreNotSupportProtocolTransport,
nameof(ECoreType.sing_box), configType.ToString(), net);
}
// sing-box shadowsocks only supports tcp/ws/quic transports
if (configType == EConfigType.Shadowsocks && !SingboxShadowsocksAllowedTransports.Contains(net))
{
return string.Format(ResUI.CoreNotSupportProtocolTransport,
nameof(ECoreType.sing_box), configType.ToString(), net);
}
return null;
}
private async Task<List<string>> ValidateRelatedNodesExistAndValid(ProfileItem? item) private async Task<List<string>> ValidateRelatedNodesExistAndValid(ProfileItem? item)
{ {
var errors = new List<string>(); var errors = new List<string>();

View file

@ -216,6 +216,8 @@ public class Transport4Sbox
public string? idle_timeout { get; set; } public string? idle_timeout { get; set; }
public string? ping_timeout { get; set; } public string? ping_timeout { get; set; }
public bool? permit_without_stream { get; set; } public bool? permit_without_stream { get; set; }
public int? max_early_data { get; set; }
public string? early_data_header_name { get; set; }
} }
public class Headers4Sbox public class Headers4Sbox

View file

@ -0,0 +1,21 @@
namespace ServiceLib.Models;
public class UpdateResult
{
public bool Success { get; set; }
public string? Msg { get; set; }
public SemanticVersion? Version { get; set; }
public string? Url { get; set; }
public UpdateResult(bool success, string? msg)
{
Success = success;
Msg = msg;
}
public UpdateResult(bool success, SemanticVersion? version)
{
Success = success;
Version = version;
}
}

View file

@ -411,8 +411,6 @@ public class WsSettings4Ray
public class Headers4Ray public class Headers4Ray
{ {
public string Host { get; set; }
[JsonPropertyName("User-Agent")] [JsonPropertyName("User-Agent")]
public string UserAgent { get; set; } public string UserAgent { get; set; }
} }

View file

@ -529,7 +529,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Next proxy Configuration remarks 的本地化字符串。 /// 查找类似 Next proxy remarks 的本地化字符串。
/// </summary> /// </summary>
public static string LvNextProfile { public static string LvNextProfile {
get { get {
@ -547,7 +547,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Previous proxy Configuration remarks 的本地化字符串。 /// 查找类似 Previous proxy remarks 的本地化字符串。
/// </summary> /// </summary>
public static string LvPrevProfile { public static string LvPrevProfile {
get { get {
@ -736,7 +736,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [Anytls] Configuration 的本地化字符串。 /// 查找类似 Add [Anytls] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddAnytlsServer { public static string menuAddAnytlsServer {
get { get {
@ -745,7 +745,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add Child Configuration 的本地化字符串。 /// 查找类似 Add Child 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddChildServer { public static string menuAddChildServer {
get { get {
@ -754,7 +754,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add a custom configuration Configuration 的本地化字符串。 /// 查找类似 Add a custom configuration 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddCustomServer { public static string menuAddCustomServer {
get { get {
@ -763,7 +763,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [HTTP] Configuration 的本地化字符串。 /// 查找类似 Add [HTTP] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddHttpServer { public static string menuAddHttpServer {
get { get {
@ -772,7 +772,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [Hysteria2] Configuration 的本地化字符串。 /// 查找类似 Add [Hysteria2] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddHysteria2Server { public static string menuAddHysteria2Server {
get { get {
@ -781,7 +781,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add Policy Group Configuration 的本地化字符串。 /// 查找类似 Add Policy Group 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddPolicyGroupServer { public static string menuAddPolicyGroupServer {
get { get {
@ -790,7 +790,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add Proxy Chain Configuration 的本地化字符串。 /// 查找类似 Add Proxy Chain 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddProxyChainServer { public static string menuAddProxyChainServer {
get { get {
@ -799,7 +799,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Import Share Links from clipboard (Ctrl+V) 的本地化字符串。 /// 查找类似 Import Share Links from clipboard 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddServerViaClipboard { public static string menuAddServerViaClipboard {
get { get {
@ -817,7 +817,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Scan QR code on the screen (Ctrl+S) 的本地化字符串。 /// 查找类似 Scan QR code on the screen 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddServerViaScan { public static string menuAddServerViaScan {
get { get {
@ -826,7 +826,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [Shadowsocks] Configuration 的本地化字符串。 /// 查找类似 Add [Shadowsocks] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddShadowsocksServer { public static string menuAddShadowsocksServer {
get { get {
@ -835,7 +835,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [SOCKS] Configuration 的本地化字符串。 /// 查找类似 Add [SOCKS] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddSocksServer { public static string menuAddSocksServer {
get { get {
@ -844,7 +844,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [Trojan] Configuration 的本地化字符串。 /// 查找类似 Add [Trojan] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddTrojanServer { public static string menuAddTrojanServer {
get { get {
@ -853,7 +853,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [TUIC] Configuration 的本地化字符串。 /// 查找类似 Add [TUIC] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddTuicServer { public static string menuAddTuicServer {
get { get {
@ -862,7 +862,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [VLESS] Configuration 的本地化字符串。 /// 查找类似 Add [VLESS] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddVlessServer { public static string menuAddVlessServer {
get { get {
@ -871,7 +871,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [VMess] Configuration 的本地化字符串。 /// 查找类似 Add [VMess] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddVmessServer { public static string menuAddVmessServer {
get { get {
@ -880,7 +880,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Add [WireGuard] Configuration 的本地化字符串。 /// 查找类似 Add [WireGuard] 的本地化字符串。
/// </summary> /// </summary>
public static string menuAddWireguardServer { public static string menuAddWireguardServer {
get { get {
@ -952,7 +952,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Clone selected Configuration 的本地化字符串。 /// 查找类似 Clone selected 的本地化字符串。
/// </summary> /// </summary>
public static string menuCopyServer { public static string menuCopyServer {
get { get {
@ -970,7 +970,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Edit Configuration (Ctrl+D) 的本地化字符串。 /// 查找类似 Edit 的本地化字符串。
/// </summary> /// </summary>
public static string menuEditServer { public static string menuEditServer {
get { get {
@ -997,7 +997,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Export selected Configuration for complete configuration 的本地化字符串。 /// 查找类似 Export selected for complete configuration 的本地化字符串。
/// </summary> /// </summary>
public static string menuExport2ClientConfig { public static string menuExport2ClientConfig {
get { get {
@ -1006,7 +1006,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Export selected Configuration for complete configuration to clipboard 的本地化字符串。 /// 查找类似 Export selected for complete configuration to clipboard 的本地化字符串。
/// </summary> /// </summary>
public static string menuExport2ClientConfigClipboard { public static string menuExport2ClientConfigClipboard {
get { get {
@ -1015,7 +1015,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Export Share Link to Clipboard (Ctrl+C) 的本地化字符串。 /// 查找类似 Export Share Link to Clipboard 的本地化字符串。
/// </summary> /// </summary>
public static string menuExport2ShareUrl { public static string menuExport2ShareUrl {
get { get {
@ -1033,7 +1033,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Export Configuration 的本地化字符串。 /// 查找类似 Export 的本地化字符串。
/// </summary> /// </summary>
public static string menuExportConfig { public static string menuExportConfig {
get { get {
@ -1069,7 +1069,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Multi-Configuration Fallback by sing-box 的本地化字符串。 /// 查找类似 Fallback by sing-box 的本地化字符串。
/// </summary> /// </summary>
public static string menuGenGroupMultipleServerSingBoxFallback { public static string menuGenGroupMultipleServerSingBoxFallback {
get { get {
@ -1078,7 +1078,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Multi-Configuration LeastPing by sing-box 的本地化字符串。 /// 查找类似 LeastPing by sing-box 的本地化字符串。
/// </summary> /// </summary>
public static string menuGenGroupMultipleServerSingBoxLeastPing { public static string menuGenGroupMultipleServerSingBoxLeastPing {
get { get {
@ -1087,7 +1087,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Multi-Configuration Fallback by Xray 的本地化字符串。 /// 查找类似 Fallback by Xray 的本地化字符串。
/// </summary> /// </summary>
public static string menuGenGroupMultipleServerXrayFallback { public static string menuGenGroupMultipleServerXrayFallback {
get { get {
@ -1096,7 +1096,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Multi-Configuration LeastLoad by Xray 的本地化字符串。 /// 查找类似 LeastLoad by Xray 的本地化字符串。
/// </summary> /// </summary>
public static string menuGenGroupMultipleServerXrayLeastLoad { public static string menuGenGroupMultipleServerXrayLeastLoad {
get { get {
@ -1105,7 +1105,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Multi-Configuration LeastPing by Xray 的本地化字符串。 /// 查找类似 LeastPing by Xray 的本地化字符串。
/// </summary> /// </summary>
public static string menuGenGroupMultipleServerXrayLeastPing { public static string menuGenGroupMultipleServerXrayLeastPing {
get { get {
@ -1114,7 +1114,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Multi-Configuration Random by Xray 的本地化字符串。 /// 查找类似 Random by Xray 的本地化字符串。
/// </summary> /// </summary>
public static string menuGenGroupMultipleServerXrayRandom { public static string menuGenGroupMultipleServerXrayRandom {
get { get {
@ -1123,7 +1123,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Multi-Configuration RoundRobin by Xray 的本地化字符串。 /// 查找类似 RoundRobin by Xray 的本地化字符串。
/// </summary> /// </summary>
public static string menuGenGroupMultipleServerXrayRoundRobin { public static string menuGenGroupMultipleServerXrayRoundRobin {
get { get {
@ -1249,7 +1249,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Move to bottom (B) 的本地化字符串。 /// 查找类似 Move to bottom 的本地化字符串。
/// </summary> /// </summary>
public static string menuMoveBottom { public static string menuMoveBottom {
get { get {
@ -1258,7 +1258,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Down (D) 的本地化字符串。 /// 查找类似 Down 的本地化字符串。
/// </summary> /// </summary>
public static string menuMoveDown { public static string menuMoveDown {
get { get {
@ -1285,7 +1285,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Move to top (T) 的本地化字符串。 /// 查找类似 Move to top 的本地化字符串。
/// </summary> /// </summary>
public static string menuMoveTop { public static string menuMoveTop {
get { get {
@ -1294,7 +1294,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Up (U) 的本地化字符串。 /// 查找类似 Up 的本地化字符串。
/// </summary> /// </summary>
public static string menuMoveUp { public static string menuMoveUp {
get { get {
@ -1312,7 +1312,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Copy (Ctrl+C) 的本地化字符串。 /// 查找类似 Copy 的本地化字符串。
/// </summary> /// </summary>
public static string menuMsgViewCopy { public static string menuMsgViewCopy {
get { get {
@ -1330,7 +1330,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Select all (Ctrl+A) 的本地化字符串。 /// 查找类似 Select all 的本地化字符串。
/// </summary> /// </summary>
public static string menuMsgViewSelectAll { public static string menuMsgViewSelectAll {
get { get {
@ -1402,7 +1402,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Select active node (Enter) 的本地化字符串。 /// 查找类似 Select active node 的本地化字符串。
/// </summary> /// </summary>
public static string menuProxiesSelectActivity { public static string menuProxiesSelectActivity {
get { get {
@ -1411,7 +1411,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Test Configurations real delay (Ctrl+R) 的本地化字符串。 /// 查找类似 Test real delay 的本地化字符串。
/// </summary> /// </summary>
public static string menuRealPingServer { public static string menuRealPingServer {
get { get {
@ -1501,7 +1501,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Remove Child Configuration 的本地化字符串。 /// 查找类似 Remove Child 的本地化字符串。
/// </summary> /// </summary>
public static string menuRemoveChildServer { public static string menuRemoveChildServer {
get { get {
@ -1510,7 +1510,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Remove duplicate Configurations 的本地化字符串。 /// 查找类似 Remove duplicate 的本地化字符串。
/// </summary> /// </summary>
public static string menuRemoveDuplicateServer { public static string menuRemoveDuplicateServer {
get { get {
@ -1528,7 +1528,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Remove selected Configurations (Delete) 的本地化字符串。 /// 查找类似 Remove selected 的本地化字符串。
/// </summary> /// </summary>
public static string menuRemoveServer { public static string menuRemoveServer {
get { get {
@ -1564,7 +1564,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Remove selected (Delete) 的本地化字符串。 /// 查找类似 Remove selected 的本地化字符串。
/// </summary> /// </summary>
public static string menuRoutingAdvancedRemove { public static string menuRoutingAdvancedRemove {
get { get {
@ -1573,7 +1573,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Set as active rule (Enter) 的本地化字符串。 /// 查找类似 Set as active rule 的本地化字符串。
/// </summary> /// </summary>
public static string menuRoutingAdvancedSetDefault { public static string menuRoutingAdvancedSetDefault {
get { get {
@ -1645,7 +1645,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Remove Rule (Delete) 的本地化字符串。 /// 查找类似 Remove Rule 的本地化字符串。
/// </summary> /// </summary>
public static string menuRuleRemove { public static string menuRuleRemove {
get { get {
@ -1654,7 +1654,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Select all (Ctrl+A) 的本地化字符串。 /// 查找类似 Select all 的本地化字符串。
/// </summary> /// </summary>
public static string menuSelectAll { public static string menuSelectAll {
get { get {
@ -1663,7 +1663,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Configuration List 的本地化字符串。 /// 查找类似 Configuration item 1, Auto add from subscription group 的本地化字符串。
/// </summary> /// </summary>
public static string menuServerList { public static string menuServerList {
get { get {
@ -1672,7 +1672,16 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Configurations 的本地化字符串。 /// 查找类似 Configuration Item 2, Select and add from self-built 的本地化字符串。
/// </summary>
public static string menuServerList2 {
get {
return ResourceManager.GetString("menuServerList2", resourceCulture);
}
}
/// <summary>
/// 查找类似 Configuration 的本地化字符串。
/// </summary> /// </summary>
public static string menuServers { public static string menuServers {
get { get {
@ -1681,7 +1690,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Set as active Configuration (Enter) 的本地化字符串。 /// 查找类似 Set as active 的本地化字符串。
/// </summary> /// </summary>
public static string menuSetDefaultServer { public static string menuSetDefaultServer {
get { get {
@ -1699,7 +1708,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Share Configuration (Ctrl+F) 的本地化字符串。 /// 查找类似 Share 的本地化字符串。
/// </summary> /// </summary>
public static string menuShareServer { public static string menuShareServer {
get { get {
@ -1726,7 +1735,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Test Configurations download speed (Ctrl+T) 的本地化字符串。 /// 查找类似 Test download speed 的本地化字符串。
/// </summary> /// </summary>
public static string menuSpeedServer { public static string menuSpeedServer {
get { get {
@ -1870,7 +1879,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Test Configurations with tcping (Ctrl+O) 的本地化字符串。 /// 查找类似 Test tcping 的本地化字符串。
/// </summary> /// </summary>
public static string menuTcpingServer { public static string menuTcpingServer {
get { get {
@ -1978,7 +1987,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Configuration filter, press Enter to execute 的本地化字符串。 /// 查找类似 Filter, press Enter to execute 的本地化字符串。
/// </summary> /// </summary>
public static string MsgServerTitle { public static string MsgServerTitle {
get { get {
@ -2275,7 +2284,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Are you sure you want to remove the Configuration? 的本地化字符串。 /// 查找类似 Are you sure you want to remove? 的本地化字符串。
/// </summary> /// </summary>
public static string RemoveServer { public static string RemoveServer {
get { get {
@ -2355,6 +2364,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Press ESC to terminate the test 的本地化字符串。
/// </summary>
public static string SpeedtestingPressEscToExit {
get {
return ResourceManager.GetString("SpeedtestingPressEscToExit", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Skip test 的本地化字符串。 /// 查找类似 Skip test 的本地化字符串。
/// </summary> /// </summary>
@ -2383,7 +2401,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Waiting for testing (press ESC to terminate)... 的本地化字符串。 /// 查找类似 Waiting... 的本地化字符串。
/// </summary> /// </summary>
public static string SpeedtestingWait { public static string SpeedtestingWait {
get { get {
@ -4096,7 +4114,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Tray right-click menu Configurations display limit 的本地化字符串。 /// 查找类似 Tray right-click menu display limit 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsTrayMenuServersLimit { public static string TbSettingsTrayMenuServersLimit {
get { get {

View file

@ -472,10 +472,10 @@
<value>زبان</value> <value>زبان</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>وارد کردن URL انبوه از کلیپ بورد (Ctrl+V)</value> <value>وارد کردن URL انبوه از کلیپ بورد</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>اسکن کد QR روی صفحه (Ctrl+S)</value> <value>اسکن کد QR روی صفحه</value>
</data> </data>
<data name="menuCopyServer" xml:space="preserve"> <data name="menuCopyServer" xml:space="preserve">
<value>سرور انتخاب شده را شبیه سازی کنید</value> <value>سرور انتخاب شده را شبیه سازی کنید</value>
@ -484,31 +484,31 @@
<value>سرورهای تکراری را حذف کنید</value> <value>سرورهای تکراری را حذف کنید</value>
</data> </data>
<data name="menuRemoveServer" xml:space="preserve"> <data name="menuRemoveServer" xml:space="preserve">
<value>حذف سرورهای انتخابی (Delete)</value> <value>حذف سرورهای انتخابی</value>
</data> </data>
<data name="menuSetDefaultServer" xml:space="preserve"> <data name="menuSetDefaultServer" xml:space="preserve">
<value>به عنوان سرور فعال تنظیم کنید (Enter)</value> <value>به عنوان سرور فعال تنظیم کنید</value>
</data> </data>
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>تمام آمار خدمات را پاک کنید</value> <value>تمام آمار خدمات را پاک کنید</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>آزمایش سرورها با تاخیر واقعی (Ctrl+R)</value> <value>آزمایش سرورها با تاخیر واقعی</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>مرتب سازی بر اساس نتیجه تست</value> <value>مرتب سازی بر اساس نتیجه تست</value>
</data> </data>
<data name="menuSpeedServer" xml:space="preserve"> <data name="menuSpeedServer" xml:space="preserve">
<value>تست سرعت دانلود سرورها (Ctrl+T)</value> <value>تست سرعت دانلود سرورها</value>
</data> </data>
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>تست سرورها با tcping (Ctrl+O)</value> <value>تست سرورها با tcping</value>
</data> </data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value> <value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value> <value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>یک سرور پیکربندی سفارشی اضافه شود</value> <value>یک سرور پیکربندی سفارشی اضافه شود</value>
@ -529,19 +529,19 @@
<value>سرور [VMess] را اضافه کنید</value> <value>سرور [VMess] را اضافه کنید</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>انتخاب همه (Ctrl+A)</value> <value>انتخاب همه</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>همه را پاک کن</value> <value>همه را پاک کن</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>کپی (Ctrl+C)</value> <value>کپی</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>کپی همه</value> <value>کپی همه</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>انتخاب همه (Ctrl+A)</value> <value>انتخاب همه</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>اضافه کردن</value> <value>اضافه کردن</value>
@ -796,13 +796,13 @@
<value>به پایین حرکت شود(B)</value> <value>به پایین حرکت شود(B)</value>
</data> </data>
<data name="menuMoveDown" xml:space="preserve"> <data name="menuMoveDown" xml:space="preserve">
<value>پایین (D)</value> <value>پایین</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>حرکت به بالا (T)</value> <value>حرکت به بالا</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>بالا (U)</value> <value>بالا</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>فیلتر، از عبارات منظم پشتیبانی می کند</value> <value>فیلتر، از عبارات منظم پشتیبانی می کند</value>
@ -922,7 +922,7 @@
<value>رد شدن از آزمون</value> <value>رد شدن از آزمون</value>
</data> </data>
<data name="menuEditServer" xml:space="preserve"> <data name="menuEditServer" xml:space="preserve">
<value>ویرایش سرور (Ctrl+D)</value> <value>ویرایش سرور</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>دوبار کلیک کردن سرور باعث فعال شدن آن می شود</value> <value>دوبار کلیک کردن سرور باعث فعال شدن آن می شود</value>
@ -976,7 +976,10 @@
<value>فعال‌ سازی شتاب‌ دهنده سخت‌ افزاری (نیاز به راه‌اندازی مجدد)</value> <value>فعال‌ سازی شتاب‌ دهنده سخت‌ افزاری (نیاز به راه‌اندازی مجدد)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>در انتظار آزمایش (برای پایان دادن به ESC فشار دهید)...</value> <value>در انتظار آزمایش...</value>
</data>
<data name="SpeedtestingPressEscToExit" xml:space="preserve">
<value>برای پایان دادن به ESC فشار دهید</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>لطفاً در صورت قطع غیرعادی آن را خاموش کنید</value> <value>لطفاً در صورت قطع غیرعادی آن را خاموش کنید</value>
@ -1204,7 +1207,7 @@
<value>تازه سازی پروکسی ها</value> <value>تازه سازی پروکسی ها</value>
</data> </data>
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>انتخاب گره فعال (Enter)</value> <value>انتخاب گره فعال</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>استراتژی دامنه پیش فرض برای خروجی</value> <value>استراتژی دامنه پیش فرض برای خروجی</value>
@ -1537,7 +1540,7 @@
<value>Remove Child Configuration</value> <value>Remove Child Configuration</value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>Configuration List</value> <value>Configuration item 1, Auto add from subscription group</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>Fallback</value> <value>Fallback</value>
@ -1635,4 +1638,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>macOS displays this in the Dock (requires restart)</value> <value>macOS displays this in the Dock (requires restart)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value>
</data>
</root> </root>

View file

@ -472,10 +472,10 @@
<value>Langue (redémarrage requis)</value> <value>Langue (redémarrage requis)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>Importer liens depuis le presse-papiers (Ctrl+V)</value> <value>Importer liens depuis le presse-papiers</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>Scanner le QR code à lécran (Ctrl+S)</value> <value>Scanner le QR code à lécran</value>
</data> </data>
<data name="menuCopyServer" xml:space="preserve"> <data name="menuCopyServer" xml:space="preserve">
<value>Cloner la sélection</value> <value>Cloner la sélection</value>
@ -484,7 +484,7 @@
<value>Supprimer les doublons</value> <value>Supprimer les doublons</value>
</data> </data>
<data name="menuRemoveServer" xml:space="preserve"> <data name="menuRemoveServer" xml:space="preserve">
<value>Supprimer la sélection (multi-sélection) (Delete)</value> <value>Supprimer la sélection (multi-sélection)</value>
</data> </data>
<data name="menuSetDefaultServer" xml:space="preserve"> <data name="menuSetDefaultServer" xml:space="preserve">
<value>Définir comme actif (Entrée)</value> <value>Définir comme actif (Entrée)</value>
@ -493,22 +493,22 @@
<value>Effacer toutes les statistiques de service</value> <value>Effacer toutes les statistiques de service</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>Tester la latence de connexion réelle (multi-sélect) (Ctrl+R)</value> <value>Tester la latence de connexion réelle (multi-sélect)</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>Trier selon les résultats de test</value> <value>Trier selon les résultats de test</value>
</data> </data>
<data name="menuSpeedServer" xml:space="preserve"> <data name="menuSpeedServer" xml:space="preserve">
<value>Tester la vitesse (multi-sélection) (Ctrl+T)</value> <value>Tester la vitesse (multi-sélection)</value>
</data> </data>
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>Tester la latence Tcping (multi-sélection) (Ctrl+O)</value> <value>Tester la latence Tcping (multi-sélection)</value>
</data> </data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>Exporter la configuration complète sélectionnée</value> <value>Exporter la configuration complète sélectionnée</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>Exporter les liens de partage vers le presse-papiers (multi-sélection) (Ctrl+C)</value> <value>Exporter les liens de partage vers le presse-papiers (multi-sélection)</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>Ajouter une configuration personnalisée</value> <value>Ajouter une configuration personnalisée</value>
@ -529,19 +529,19 @@
<value>Ajouter [VMess]</value> <value>Ajouter [VMess]</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>Tout sélectionner (Ctrl+A)</value> <value>Tout sélectionner</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>Tout effacer</value> <value>Tout effacer</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>Copier (Ctrl+C)</value> <value>Copier</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Tout copier</value> <value>Tout copier</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Tout sélect (Ctrl+A)</value> <value>Tout sélect</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>Ajouter</value> <value>Ajouter</value>
@ -781,7 +781,7 @@
<value>Mode PAC</value> <value>Mode PAC</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>Partager (Ctrl+F)</value> <value>Partager</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>Routage</value> <value>Routage</value>
@ -793,16 +793,16 @@
<value>Exécuter en tant quadministrateur</value> <value>Exécuter en tant quadministrateur</value>
</data> </data>
<data name="menuMoveBottom" xml:space="preserve"> <data name="menuMoveBottom" xml:space="preserve">
<value>Déplacer tout en bas (B)</value> <value>Déplacer tout en bas</value>
</data> </data>
<data name="menuMoveDown" xml:space="preserve"> <data name="menuMoveDown" xml:space="preserve">
<value>Descendre (D)</value> <value>Descendre</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>Déplacer tout en haut (T)</value> <value>Déplacer tout en haut</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>Monter (U)</value> <value>Monter</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>Filtre (regex pris en charge)</value> <value>Filtre (regex pris en charge)</value>
@ -817,7 +817,7 @@
<value>Importer 1-clic du jeu de règles</value> <value>Importer 1-clic du jeu de règles</value>
</data> </data>
<data name="menuRoutingAdvancedRemove" xml:space="preserve"> <data name="menuRoutingAdvancedRemove" xml:space="preserve">
<value>Suppr. règles sélectionnées (Delete)</value> <value>Suppr. règles sélectionnées</value>
</data> </data>
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Définir comme règles actives (Entrée)</value> <value>Définir comme règles actives (Entrée)</value>
@ -853,7 +853,7 @@
<value>Liste des règles</value> <value>Liste des règles</value>
</data> </data>
<data name="menuRuleRemove" xml:space="preserve"> <data name="menuRuleRemove" xml:space="preserve">
<value>Supprimer les règles sélectionnées (Delete)</value> <value>Supprimer les règles sélectionnées</value>
</data> </data>
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve"> <data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
<value>Paramètres détaillés des règles de routage</value> <value>Paramètres détaillés des règles de routage</value>
@ -922,7 +922,7 @@
<value>Ignorer le test</value> <value>Ignorer le test</value>
</data> </data>
<data name="menuEditServer" xml:space="preserve"> <data name="menuEditServer" xml:space="preserve">
<value>Éditer (Ctrl+D)</value> <value>Éditer</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Double-cliquer sur linterface principale pour activer</value> <value>Double-cliquer sur linterface principale pour activer</value>
@ -976,7 +976,10 @@
<value>Activer laccélération matérielle (redémarrage requis)</value> <value>Activer laccélération matérielle (redémarrage requis)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>En attente du test (appuyer sur Échap pour arrêter)...</value> <value>En attente du test...</value>
</data>
<data name="SpeedtestingPressEscToExit" xml:space="preserve">
<value>Appuyer sur Échap pour arrêter</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>Désactiver cette option si coupure anormale</value> <value>Désactiver cette option si coupure anormale</value>
@ -1534,7 +1537,7 @@
<value>Supprimer une sous-configuration</value> <value>Supprimer une sous-configuration</value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>Liste des configurations</value> <value>Configuration item 1, Auto add from subscription group</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>Basculement (failover)</value> <value>Basculement (failover)</value>
@ -1632,4 +1635,7 @@ Si un certificat auto-signé est utilisé ou si le système contient une CA non
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>Afficher dans le Dock de macOS (redém. requis)</value> <value>Afficher dans le Dock de macOS (redém. requis)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value>
</data>
</root> </root>

View file

@ -472,10 +472,10 @@
<value>Nyelv (Újraindítás)</value> <value>Nyelv (Újraindítás)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>Megosztási linkek importálása vágólapról (Ctrl+V)</value> <value>Megosztási linkek importálása vágólapról</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>QR kód beolvasása a képernyőről (Ctrl+S)</value> <value>QR kód beolvasása a képernyőről</value>
</data> </data>
<data name="menuCopyServer" xml:space="preserve"> <data name="menuCopyServer" xml:space="preserve">
<value>Kijelölt konfiguráció klónozása</value> <value>Kijelölt konfiguráció klónozása</value>
@ -484,31 +484,31 @@
<value>Ismétlődő konfigurációk eltávolítása</value> <value>Ismétlődő konfigurációk eltávolítása</value>
</data> </data>
<data name="menuRemoveServer" xml:space="preserve"> <data name="menuRemoveServer" xml:space="preserve">
<value>Kijelölt konfigurációk eltávolítása (Delete)</value> <value>Kijelölt konfigurációk eltávolítása</value>
</data> </data>
<data name="menuSetDefaultServer" xml:space="preserve"> <data name="menuSetDefaultServer" xml:space="preserve">
<value>Beállítás aktív konfigurációként (Enter)</value> <value>Beállítás aktív konfigurációként</value>
</data> </data>
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>Összes szolgáltatás statisztika törlése</value> <value>Összes szolgáltatás statisztika törlése</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>Konfigurációk valós késleltetésének tesztelése (Ctrl+R)</value> <value>Konfigurációk valós késleltetésének tesztelése</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>Rendezés teszteredmény szerint</value> <value>Rendezés teszteredmény szerint</value>
</data> </data>
<data name="menuSpeedServer" xml:space="preserve"> <data name="menuSpeedServer" xml:space="preserve">
<value>Konfigurációk letöltési sebességének tesztelése (Ctrl+T)</value> <value>Konfigurációk letöltési sebességének tesztelése</value>
</data> </data>
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>Konfigurációk tesztelése tcpinggel (Ctrl+O)</value> <value>Konfigurációk tesztelése tcpinggel</value>
</data> </data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>Kijelölt konfiguráció exportálása teljes konfigurációként</value> <value>Kijelölt konfiguráció exportálása teljes konfigurációként</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>Megosztási link exportálása vágólapra (Ctrl+C)</value> <value>Megosztási link exportálása vágólapra</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>Egyéni konfiguráció hozzáadása</value> <value>Egyéni konfiguráció hozzáadása</value>
@ -529,19 +529,19 @@
<value>[VMess] konfiguráció hozzáadása</value> <value>[VMess] konfiguráció hozzáadása</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>Összes kijelölése (Ctrl+A)</value> <value>Összes kijelölése</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>Összes törlése</value> <value>Összes törlése</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>Másolás (Ctrl+C)</value> <value>Másolás</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Összes másolása</value> <value>Összes másolása</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Összes kijelölése (Ctrl+A)</value> <value>Összes kijelölése</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>Hozzáadás</value> <value>Hozzáadás</value>
@ -781,7 +781,7 @@
<value>PAC mód</value> <value>PAC mód</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>Konfiguráció megosztása (Ctrl+F)</value> <value>Konfiguráció megosztása</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>Útválasztás</value> <value>Útválasztás</value>
@ -793,16 +793,16 @@
<value>Futtatás rendszergazdaként</value> <value>Futtatás rendszergazdaként</value>
</data> </data>
<data name="menuMoveBottom" xml:space="preserve"> <data name="menuMoveBottom" xml:space="preserve">
<value>Mozgatás alulra (B)</value> <value>Mozgatás alulra</value>
</data> </data>
<data name="menuMoveDown" xml:space="preserve"> <data name="menuMoveDown" xml:space="preserve">
<value>Le (D)</value> <value>Le</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>Mozgatás felülre (T)</value> <value>Mozgatás felülre</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>Fel (U)</value> <value>Fel</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>Szűrő, támogatja a reguláris kifejezéseket</value> <value>Szűrő, támogatja a reguláris kifejezéseket</value>
@ -817,10 +817,10 @@
<value>Szabályok importálása</value> <value>Szabályok importálása</value>
</data> </data>
<data name="menuRoutingAdvancedRemove" xml:space="preserve"> <data name="menuRoutingAdvancedRemove" xml:space="preserve">
<value>Kijelölt eltávolítása (Delete)</value> <value>Kijelölt eltávolítása</value>
</data> </data>
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Beállítás aktív szabályként (Enter)</value> <value>Beállítás aktív szabályként</value>
</data> </data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>Tartomány stratégia</value> <value>Tartomány stratégia</value>
@ -853,7 +853,7 @@
<value>Szabálylista</value> <value>Szabálylista</value>
</data> </data>
<data name="menuRuleRemove" xml:space="preserve"> <data name="menuRuleRemove" xml:space="preserve">
<value>Szabály eltávolítása (Delete)</value> <value>Szabály eltávolítása</value>
</data> </data>
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve"> <data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
<value>Útválasztási szabály részleteinek beállítása</value> <value>Útválasztási szabály részleteinek beállítása</value>
@ -922,7 +922,7 @@
<value>Teszt kihagyása</value> <value>Teszt kihagyása</value>
</data> </data>
<data name="menuEditServer" xml:space="preserve"> <data name="menuEditServer" xml:space="preserve">
<value>Konfiguráció szerkesztése (Ctrl+D)</value> <value>Konfiguráció szerkesztése</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Dupla kattintás a konfigurációra aktiválja</value> <value>Dupla kattintás a konfigurációra aktiválja</value>
@ -976,7 +976,10 @@
<value>Hardveres gyorsítás engedélyezése (újraindítást igényel)</value> <value>Hardveres gyorsítás engedélyezése (újraindítást igényel)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>Tesztelésre vár (ESC megnyomásával megszakítható)...</value> <value>Tesztelésre vár...</value>
</data>
<data name="SpeedtestingPressEscToExit" xml:space="preserve">
<value>ESC megnyomásával megszakítható</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>Kérjük, kapcsolja ki rendellenes megszakadás esetén</value> <value>Kérjük, kapcsolja ki rendellenes megszakadás esetén</value>
@ -1204,7 +1207,7 @@
<value>Proxyk frissítése</value> <value>Proxyk frissítése</value>
</data> </data>
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Aktív csomópont kiválasztása (Enter)</value> <value>Aktív csomópont kiválasztása</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Alapértelmezett tartomány stratégia kimenő forgalomhoz</value> <value>Alapértelmezett tartomány stratégia kimenő forgalomhoz</value>
@ -1537,7 +1540,7 @@
<value>Remove Child Configuration</value> <value>Remove Child Configuration</value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>Configuration List</value> <value>Configuration item 1, Auto add from subscription group</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>Fallback</value> <value>Fallback</value>
@ -1635,4 +1638,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>macOS displays this in the Dock (requires restart)</value> <value>macOS displays this in the Dock (requires restart)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value>
</data>
</root> </root>

View file

@ -271,7 +271,7 @@
<value>Configurations deduplication completed. Old: {0}, New: {1}.</value> <value>Configurations deduplication completed. Old: {0}, New: {1}.</value>
</data> </data>
<data name="RemoveServer" xml:space="preserve"> <data name="RemoveServer" xml:space="preserve">
<value>Are you sure you want to remove the Configuration?</value> <value>Are you sure you want to remove?</value>
</data> </data>
<data name="SaveClientConfigurationIn" xml:space="preserve"> <data name="SaveClientConfigurationIn" xml:space="preserve">
<value>The client configuration file is saved at: {0}</value> <value>The client configuration file is saved at: {0}</value>
@ -397,7 +397,7 @@
<value>Local</value> <value>Local</value>
</data> </data>
<data name="MsgServerTitle" xml:space="preserve"> <data name="MsgServerTitle" xml:space="preserve">
<value>Configuration filter, press Enter to execute</value> <value>Filter, press Enter to execute</value>
</data> </data>
<data name="menuCheckUpdate" xml:space="preserve"> <data name="menuCheckUpdate" xml:space="preserve">
<value>Check Update</value> <value>Check Update</value>
@ -427,7 +427,7 @@
<value>Routing Setting</value> <value>Routing Setting</value>
</data> </data>
<data name="menuServers" xml:space="preserve"> <data name="menuServers" xml:space="preserve">
<value>Configurations</value> <value>Configuration</value>
</data> </data>
<data name="menuSetting" xml:space="preserve"> <data name="menuSetting" xml:space="preserve">
<value>Settings</value> <value>Settings</value>
@ -472,76 +472,76 @@
<value>Language (Restart)</value> <value>Language (Restart)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>Import Share Links from clipboard (Ctrl+V)</value> <value>Import Share Links from clipboard</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>Scan QR code on the screen (Ctrl+S)</value> <value>Scan QR code on the screen</value>
</data> </data>
<data name="menuCopyServer" xml:space="preserve"> <data name="menuCopyServer" xml:space="preserve">
<value>Clone selected Configuration</value> <value>Clone selected</value>
</data> </data>
<data name="menuRemoveDuplicateServer" xml:space="preserve"> <data name="menuRemoveDuplicateServer" xml:space="preserve">
<value>Remove duplicate Configurations</value> <value>Remove duplicate</value>
</data> </data>
<data name="menuRemoveServer" xml:space="preserve"> <data name="menuRemoveServer" xml:space="preserve">
<value>Remove selected Configurations (Delete)</value> <value>Remove selected</value>
</data> </data>
<data name="menuSetDefaultServer" xml:space="preserve"> <data name="menuSetDefaultServer" xml:space="preserve">
<value>Set as active Configuration (Enter)</value> <value>Set as active</value>
</data> </data>
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>Clear all service statistics</value> <value>Clear all service statistics</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>Test Configurations real delay (Ctrl+R)</value> <value>Test real delay</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>Sort by test result</value> <value>Sort by test result</value>
</data> </data>
<data name="menuSpeedServer" xml:space="preserve"> <data name="menuSpeedServer" xml:space="preserve">
<value>Test Configurations download speed (Ctrl+T)</value> <value>Test download speed</value>
</data> </data>
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>Test Configurations with tcping (Ctrl+O)</value> <value>Test tcping</value>
</data> </data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>Export selected Configuration for complete configuration</value> <value>Export selected for complete configuration</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>Export Share Link to Clipboard (Ctrl+C)</value> <value>Export Share Link to Clipboard</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>Add a custom configuration Configuration</value> <value>Add a custom configuration</value>
</data> </data>
<data name="menuAddShadowsocksServer" xml:space="preserve"> <data name="menuAddShadowsocksServer" xml:space="preserve">
<value>Add [Shadowsocks] Configuration</value> <value>Add [Shadowsocks] </value>
</data> </data>
<data name="menuAddSocksServer" xml:space="preserve"> <data name="menuAddSocksServer" xml:space="preserve">
<value>Add [SOCKS] Configuration</value> <value>Add [SOCKS] </value>
</data> </data>
<data name="menuAddTrojanServer" xml:space="preserve"> <data name="menuAddTrojanServer" xml:space="preserve">
<value>Add [Trojan] Configuration</value> <value>Add [Trojan] </value>
</data> </data>
<data name="menuAddVlessServer" xml:space="preserve"> <data name="menuAddVlessServer" xml:space="preserve">
<value>Add [VLESS] Configuration</value> <value>Add [VLESS] </value>
</data> </data>
<data name="menuAddVmessServer" xml:space="preserve"> <data name="menuAddVmessServer" xml:space="preserve">
<value>Add [VMess] Configuration</value> <value>Add [VMess] </value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>Select all (Ctrl+A)</value> <value>Select all</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>Clear all</value> <value>Clear all</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>Copy (Ctrl+C)</value> <value>Copy</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Copy all</value> <value>Copy all</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Select all (Ctrl+A)</value> <value>Select all</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>Add</value> <value>Add</value>
@ -748,7 +748,7 @@
<value>System proxy settings</value> <value>System proxy settings</value>
</data> </data>
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve"> <data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
<value>Tray right-click menu Configurations display limit</value> <value>Tray right-click menu display limit</value>
</data> </data>
<data name="TbSettingsUdpEnabled" xml:space="preserve"> <data name="TbSettingsUdpEnabled" xml:space="preserve">
<value>Enable UDP</value> <value>Enable UDP</value>
@ -781,7 +781,7 @@
<value>PAC mode</value> <value>PAC mode</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>Share Configuration (Ctrl+F)</value> <value>Share</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>Routing</value> <value>Routing</value>
@ -793,16 +793,16 @@
<value>Run as Admin</value> <value>Run as Admin</value>
</data> </data>
<data name="menuMoveBottom" xml:space="preserve"> <data name="menuMoveBottom" xml:space="preserve">
<value>Move to bottom (B)</value> <value>Move to bottom</value>
</data> </data>
<data name="menuMoveDown" xml:space="preserve"> <data name="menuMoveDown" xml:space="preserve">
<value>Down (D)</value> <value>Down</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>Move to top (T)</value> <value>Move to top</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>Up (U)</value> <value>Up</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>Filter, supports regular expressions</value> <value>Filter, supports regular expressions</value>
@ -817,10 +817,10 @@
<value>Import Rules</value> <value>Import Rules</value>
</data> </data>
<data name="menuRoutingAdvancedRemove" xml:space="preserve"> <data name="menuRoutingAdvancedRemove" xml:space="preserve">
<value>Remove selected (Delete)</value> <value>Remove selected</value>
</data> </data>
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule (Enter)</value> <value>Set as active rule</value>
</data> </data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>Domain strategy</value> <value>Domain strategy</value>
@ -853,7 +853,7 @@
<value>Rule List</value> <value>Rule List</value>
</data> </data>
<data name="menuRuleRemove" xml:space="preserve"> <data name="menuRuleRemove" xml:space="preserve">
<value>Remove Rule (Delete)</value> <value>Remove Rule</value>
</data> </data>
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve"> <data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
<value>Routing Rule Details Setting</value> <value>Routing Rule Details Setting</value>
@ -922,7 +922,7 @@
<value>Skip test</value> <value>Skip test</value>
</data> </data>
<data name="menuEditServer" xml:space="preserve"> <data name="menuEditServer" xml:space="preserve">
<value>Edit Configuration (Ctrl+D)</value> <value>Edit </value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Double-clicking Configuration makes it active</value> <value>Double-clicking Configuration makes it active</value>
@ -976,7 +976,10 @@
<value>Enable hardware acceleration (requires restart)</value> <value>Enable hardware acceleration (requires restart)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing (press ESC to terminate)...</value> <value>Waiting...</value>
</data>
<data name="SpeedtestingPressEscToExit" xml:space="preserve">
<value>Press ESC to terminate the test</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value> <value>Please turn off when there is an abnormal disconnection</value>
@ -1033,7 +1036,7 @@
<value>Domain</value> <value>Domain</value>
</data> </data>
<data name="menuAddHysteria2Server" xml:space="preserve"> <data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] Configuration</value> <value>Add [Hysteria2] </value>
</data> </data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve"> <data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Down)</value> <value>Hysteria Max bandwidth (Up/Down)</value>
@ -1042,16 +1045,16 @@
<value>Use System Hosts</value> <value>Use System Hosts</value>
</data> </data>
<data name="menuAddTuicServer" xml:space="preserve"> <data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] Configuration</value> <value>Add [TUIC] </value>
</data> </data>
<data name="TbHeaderType8" xml:space="preserve"> <data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value> <value>Congestion control</value>
</data> </data>
<data name="LvPrevProfile" xml:space="preserve"> <data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy Configuration remarks</value> <value>Previous proxy remarks</value>
</data> </data>
<data name="LvNextProfile" xml:space="preserve"> <data name="LvNextProfile" xml:space="preserve">
<value>Next proxy Configuration remarks</value> <value>Next proxy remarks</value>
</data> </data>
<data name="LvPrevProfileTip" xml:space="preserve"> <data name="LvPrevProfileTip" xml:space="preserve">
<value>Please make sure the Configuration remarks exist and are unique</value> <value>Please make sure the Configuration remarks exist and are unique</value>
@ -1075,7 +1078,7 @@
<value>Enable IPv6 Address</value> <value>Enable IPv6 Address</value>
</data> </data>
<data name="menuAddWireguardServer" xml:space="preserve"> <data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [WireGuard] Configuration</value> <value>Add [WireGuard] </value>
</data> </data>
<data name="TbPrivateKey" xml:space="preserve"> <data name="TbPrivateKey" xml:space="preserve">
<value>Private Key</value> <value>Private Key</value>
@ -1108,7 +1111,7 @@
<value>*grpc Authority</value> <value>*grpc Authority</value>
</data> </data>
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP] Configuration</value> <value>Add [HTTP]</value>
</data> </data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve"> <data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>which conflicts with the group previous proxy</value> <value>which conflicts with the group previous proxy</value>
@ -1204,7 +1207,7 @@
<value>Refresh Proxies</value> <value>Refresh Proxies</value>
</data> </data>
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value> <value>Select active node</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Default domain strategy for outbound</value> <value>Default domain strategy for outbound</value>
@ -1222,7 +1225,7 @@
<value>Export Base64-encoded Share Links to Clipboard</value> <value>Export Base64-encoded Share Links to Clipboard</value>
</data> </data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve"> <data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected Configuration for complete configuration to clipboard</value> <value>Export selected for complete configuration to clipboard</value>
</data> </data>
<data name="menuShowOrHideMainWindow" xml:space="preserve"> <data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value> <value>Show or hide the main window</value>
@ -1378,22 +1381,22 @@
<value>Generate Policy Group from Multiple Profiles</value> <value>Generate Policy Group from Multiple Profiles</value>
</data> </data>
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve"> <data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
<value>Multi-Configuration Random by Xray</value> <value>Random by Xray</value>
</data> </data>
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve"> <data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
<value>Multi-Configuration RoundRobin by Xray</value> <value>RoundRobin by Xray</value>
</data> </data>
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve"> <data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
<value>Multi-Configuration LeastPing by Xray</value> <value>LeastPing by Xray</value>
</data> </data>
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve"> <data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
<value>Multi-Configuration LeastLoad by Xray</value> <value>LeastLoad by Xray</value>
</data> </data>
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve"> <data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
<value>Multi-Configuration LeastPing by sing-box</value> <value>LeastPing by sing-box</value>
</data> </data>
<data name="menuExportConfig" xml:space="preserve"> <data name="menuExportConfig" xml:space="preserve">
<value>Export Configuration</value> <value>Export</value>
</data> </data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve"> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value> <value>Current connection info test URL</value>
@ -1408,7 +1411,7 @@
<value>Mldsa65Verify</value> <value>Mldsa65Verify</value>
</data> </data>
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value> <value>Add [Anytls]</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve"> <data name="TbRemoteDNS" xml:space="preserve">
<value>Remote DNS</value> <value>Remote DNS</value>
@ -1525,28 +1528,28 @@
<value>Policy Group Type</value> <value>Policy Group Type</value>
</data> </data>
<data name="menuAddPolicyGroupServer" xml:space="preserve"> <data name="menuAddPolicyGroupServer" xml:space="preserve">
<value>Add Policy Group Configuration</value> <value>Add Policy Group </value>
</data> </data>
<data name="menuAddProxyChainServer" xml:space="preserve"> <data name="menuAddProxyChainServer" xml:space="preserve">
<value>Add Proxy Chain Configuration</value> <value>Add Proxy Chain</value>
</data> </data>
<data name="menuAddChildServer" xml:space="preserve"> <data name="menuAddChildServer" xml:space="preserve">
<value>Add Child Configuration</value> <value>Add Child </value>
</data> </data>
<data name="menuRemoveChildServer" xml:space="preserve"> <data name="menuRemoveChildServer" xml:space="preserve">
<value>Remove Child Configuration</value> <value>Remove Child </value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>Configuration List</value> <value>Configuration item 1, Auto add from subscription group</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>Fallback</value> <value>Fallback</value>
</data> </data>
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve"> <data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
<value>Multi-Configuration Fallback by sing-box</value> <value>Fallback by sing-box</value>
</data> </data>
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve"> <data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
<value>Multi-Configuration Fallback by Xray</value> <value>Fallback by Xray</value>
</data> </data>
<data name="CoreNotSupportNetwork" xml:space="preserve"> <data name="CoreNotSupportNetwork" xml:space="preserve">
<value>Core '{0}' does not support network type '{1}'.</value> <value>Core '{0}' does not support network type '{1}'.</value>
@ -1635,4 +1638,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>macOS displays this in the Dock (requires restart)</value> <value>macOS displays this in the Dock (requires restart)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value>
</data>
</root> </root>

View file

@ -472,10 +472,10 @@
<value>Язык (требуется перезапуск)</value> <value>Язык (требуется перезапуск)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>Импорт массива URL из буфера обмена (Ctrl+V)</value> <value>Импорт массива URL из буфера обмена</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>Сканировать QR-код с экрана (Ctrl+S)</value> <value>Сканировать QR-код с экрана</value>
</data> </data>
<data name="menuCopyServer" xml:space="preserve"> <data name="menuCopyServer" xml:space="preserve">
<value>Клонировать выбранный сервер</value> <value>Клонировать выбранный сервер</value>
@ -484,31 +484,31 @@
<value>Удалить дубликаты серверов</value> <value>Удалить дубликаты серверов</value>
</data> </data>
<data name="menuRemoveServer" xml:space="preserve"> <data name="menuRemoveServer" xml:space="preserve">
<value>Удалить выбранные серверы (Delete)</value> <value>Удалить выбранные серверы</value>
</data> </data>
<data name="menuSetDefaultServer" xml:space="preserve"> <data name="menuSetDefaultServer" xml:space="preserve">
<value>Установить как активный сервер (Enter)</value> <value>Установить как активный сервер</value>
</data> </data>
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>Очистить всю статистику</value> <value>Очистить всю статистику</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>Тест на реальную задержку сервера (Ctrl+R)</value> <value>Тест на реальную задержку сервера</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>Сортировать по результату теста</value> <value>Сортировать по результату теста</value>
</data> </data>
<data name="menuSpeedServer" xml:space="preserve"> <data name="menuSpeedServer" xml:space="preserve">
<value>Тест на скорость загрузки сервера (Ctrl+T)</value> <value>Тест на скорость загрузки сервера</value>
</data> </data>
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>Тест задержки с tcping (Ctrl+O)</value> <value>Тест задержки с tcping</value>
</data> </data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>Экспортировать выбранный сервер для клиента</value> <value>Экспортировать выбранный сервер для клиента</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value> <value>Экспорт URL-адресов общего доступа в буфер обмена</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>Добавить сервер пользовательской конфигурации</value> <value>Добавить сервер пользовательской конфигурации</value>
@ -529,19 +529,19 @@
<value>Добавить сервер [VMess]</value> <value>Добавить сервер [VMess]</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>Выбрать все (Ctrl+A)</value> <value>Выбрать все</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>Очистить все</value> <value>Очистить все</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>Скопировать (Ctrl+C)</value> <value>Скопировать</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Скопировать все</value> <value>Скопировать все</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Выбрать все (Ctrl+A)</value> <value>Выбрать все</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>Добавить</value> <value>Добавить</value>
@ -781,7 +781,7 @@
<value>Режим PAC</value> <value>Режим PAC</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>Поделиться сервером (Ctrl+F)</value> <value>Поделиться сервером</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>Маршрутизация</value> <value>Маршрутизация</value>
@ -793,16 +793,16 @@
<value>Администратор</value> <value>Администратор</value>
</data> </data>
<data name="menuMoveBottom" xml:space="preserve"> <data name="menuMoveBottom" xml:space="preserve">
<value>Спуститься вниз (B)</value> <value>Спуститься вниз</value>
</data> </data>
<data name="menuMoveDown" xml:space="preserve"> <data name="menuMoveDown" xml:space="preserve">
<value>Вниз (D)</value> <value>Вниз</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>Подняться наверх (T)</value> <value>Подняться наверх</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>Вверх (U)</value> <value>Вверх</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>Фильтр, поддерживает regex</value> <value>Фильтр, поддерживает regex</value>
@ -853,7 +853,7 @@
<value>Список правил</value> <value>Список правил</value>
</data> </data>
<data name="menuRuleRemove" xml:space="preserve"> <data name="menuRuleRemove" xml:space="preserve">
<value>Удалить правила (Delete)</value> <value>Удалить правила</value>
</data> </data>
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve"> <data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
<value>Детальные настройки правил маршрутизации</value> <value>Детальные настройки правил маршрутизации</value>
@ -922,7 +922,7 @@
<value>Пропустить тест</value> <value>Пропустить тест</value>
</data> </data>
<data name="menuEditServer" xml:space="preserve"> <data name="menuEditServer" xml:space="preserve">
<value>Редактировать сервер (Ctrl+D)</value> <value>Редактировать сервер</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Двойной клик чтобы сделать сервер активным</value> <value>Двойной клик чтобы сделать сервер активным</value>
@ -976,7 +976,10 @@
<value>Включить аппаратное ускорение (требуется перезагрузка)</value> <value>Включить аппаратное ускорение (требуется перезагрузка)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>Ожидание тестирования (нажмите ESC для отмены)…</value> <value>Ожидание тестирования…</value>
</data>
<data name="SpeedtestingPressEscToExit" xml:space="preserve">
<value>нажмите ESC для отмены</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>Отключите при аномальном разрыве соединения</value> <value>Отключите при аномальном разрыве соединения</value>
@ -1204,7 +1207,7 @@
<value>Обновить прокси</value> <value>Обновить прокси</value>
</data> </data>
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Сделать узел активным (Enter)</value> <value>Сделать узел активным</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Стратегия домена по умолчанию для исходящих</value> <value>Стратегия домена по умолчанию для исходящих</value>
@ -1537,7 +1540,7 @@
<value>Remove Child Configuration</value> <value>Remove Child Configuration</value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>Configuration List</value> <value>Configuration item 1, Auto add from subscription group</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>Fallback</value> <value>Fallback</value>
@ -1635,4 +1638,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>macOS displays this in the Dock (requires restart)</value> <value>macOS displays this in the Dock (requires restart)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve">
<value>Configuration Item 2, Select and add from self-built</value>
</data>
</root> </root>

View file

@ -472,10 +472,10 @@
<value>语言 (需重启)</value> <value>语言 (需重启)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>从剪贴板导入分享链接 (Ctrl+V)</value> <value>从剪贴板导入分享链接</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>扫描屏幕上的二维码 (Ctrl+S)</value> <value>扫描屏幕上的二维码</value>
</data> </data>
<data name="menuCopyServer" xml:space="preserve"> <data name="menuCopyServer" xml:space="preserve">
<value>克隆所选</value> <value>克隆所选</value>
@ -484,31 +484,31 @@
<value>移除重复</value> <value>移除重复</value>
</data> </data>
<data name="menuRemoveServer" xml:space="preserve"> <data name="menuRemoveServer" xml:space="preserve">
<value>移除所选 (多选) (Delete)</value> <value>移除所选 (多选)</value>
</data> </data>
<data name="menuSetDefaultServer" xml:space="preserve"> <data name="menuSetDefaultServer" xml:space="preserve">
<value>设为活动 (Enter)</value> <value>设为活动</value>
</data> </data>
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>清除所有服务统计数据</value> <value>清除所有服务统计数据</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>测试真连接延迟 (多选) (Ctrl+R)</value> <value>测试真连接延迟 (多选)</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>按测试结果排序</value> <value>按测试结果排序</value>
</data> </data>
<data name="menuSpeedServer" xml:space="preserve"> <data name="menuSpeedServer" xml:space="preserve">
<value>测试速度 (多选) (Ctrl+T)</value> <value>测试速度 (多选)</value>
</data> </data>
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>测试延迟 Tcping (多选) (Ctrl+O)</value> <value>测试延迟 Tcping (多选)</value>
</data> </data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>导出所选完整配置</value> <value>导出所选完整配置</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>导出分享链接至剪贴板 (多选) (Ctrl+C)</value> <value>导出分享链接至剪贴板 (多选)</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>添加自定义配置</value> <value>添加自定义配置</value>
@ -529,19 +529,19 @@
<value>添加 [VMess] </value> <value>添加 [VMess] </value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>全选 (Ctrl+A)</value> <value>全选</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>清除所有</value> <value>清除所有</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>复制 (Ctrl+C)</value> <value>复制</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>复制所有</value> <value>复制所有</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>全选 (Ctrl+A)</value> <value>全选</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>添加</value> <value>添加</value>
@ -781,7 +781,7 @@
<value>Pac 模式</value> <value>Pac 模式</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>分享 (Ctrl+F)</value> <value>分享</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>路由</value> <value>路由</value>
@ -793,16 +793,16 @@
<value>以管理员身份运行</value> <value>以管理员身份运行</value>
</data> </data>
<data name="menuMoveBottom" xml:space="preserve"> <data name="menuMoveBottom" xml:space="preserve">
<value>下移至底 (B)</value> <value>下移至底</value>
</data> </data>
<data name="menuMoveDown" xml:space="preserve"> <data name="menuMoveDown" xml:space="preserve">
<value>下移 (D)</value> <value>下移</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>上移至顶 (T)</value> <value>上移至顶</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>上移 (U)</value> <value>上移</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>过滤器 (支持正则)</value> <value>过滤器 (支持正则)</value>
@ -817,10 +817,10 @@
<value>一键导入规则集</value> <value>一键导入规则集</value>
</data> </data>
<data name="menuRoutingAdvancedRemove" xml:space="preserve"> <data name="menuRoutingAdvancedRemove" xml:space="preserve">
<value>移除所选规则 (Delete)</value> <value>移除所选规则</value>
</data> </data>
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>设为活动规则 (Enter)</value> <value>设为活动规则</value>
</data> </data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value> <value>域名解析策略</value>
@ -853,7 +853,7 @@
<value>规则列表</value> <value>规则列表</value>
</data> </data>
<data name="menuRuleRemove" xml:space="preserve"> <data name="menuRuleRemove" xml:space="preserve">
<value>移除所选规则 (Delete)</value> <value>移除所选规则</value>
</data> </data>
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve"> <data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
<value>路由规则详情设置</value> <value>路由规则详情设置</value>
@ -922,7 +922,7 @@
<value>跳过测试</value> <value>跳过测试</value>
</data> </data>
<data name="menuEditServer" xml:space="preserve"> <data name="menuEditServer" xml:space="preserve">
<value>编辑 (Ctrl+D)</value> <value>编辑</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>主界面双击设为活动</value> <value>主界面双击设为活动</value>
@ -976,7 +976,10 @@
<value>启用硬件加速 (需重启)</value> <value>启用硬件加速 (需重启)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>等待测试中 (按 ESC 终止)...</value> <value>等待测试...</value>
</data>
<data name="SpeedtestingPressEscToExit" xml:space="preserve">
<value>按 ESC 可终止测试</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>当有异常断流时请关闭</value> <value>当有异常断流时请关闭</value>
@ -1201,7 +1204,7 @@
<value>刷新</value> <value>刷新</value>
</data> </data>
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>设为活动 (Enter)</value> <value>设为活动</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Outbound 默认解析策略</value> <value>Outbound 默认解析策略</value>
@ -1534,7 +1537,7 @@
<value>删除子配置</value> <value>删除子配置</value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>子配置项</value> <value>子配置项一,从订阅分组中自动添加</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>故障转移</value> <value>故障转移</value>
@ -1632,4 +1635,7 @@
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>macOS 在 Dock 栏中显示 (需重启)</value> <value>macOS 在 Dock 栏中显示 (需重启)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve">
<value>子配置项二,从自建中选择添加</value>
</data>
</root> </root>

View file

@ -472,10 +472,10 @@
<value>語言 (需重啟)</value> <value>語言 (需重啟)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>從剪貼簿導入分享連結 (Ctrl+V)</value> <value>從剪貼簿導入分享連結</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>掃描螢幕上的二維碼 (Ctrl+S)</value> <value>掃描螢幕上的二維碼</value>
</data> </data>
<data name="menuCopyServer" xml:space="preserve"> <data name="menuCopyServer" xml:space="preserve">
<value>複製所選</value> <value>複製所選</value>
@ -484,31 +484,31 @@
<value>移除重複</value> <value>移除重複</value>
</data> </data>
<data name="menuRemoveServer" xml:space="preserve"> <data name="menuRemoveServer" xml:space="preserve">
<value>移除所選 (多選) (Delete)</value> <value>移除所選 (多選)</value>
</data> </data>
<data name="menuSetDefaultServer" xml:space="preserve"> <data name="menuSetDefaultServer" xml:space="preserve">
<value>設為活動 (Enter)</value> <value>設為活動</value>
</data> </data>
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>清除所有服務統計資料</value> <value>清除所有服務統計資料</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>測試真連線延遲 (多選) (Ctrl+R)</value> <value>測試真連線延遲 (多選)</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>按測試結果排序</value> <value>按測試結果排序</value>
</data> </data>
<data name="menuSpeedServer" xml:space="preserve"> <data name="menuSpeedServer" xml:space="preserve">
<value>測試速度 (多選) (Ctrl+T)</value> <value>測試速度 (多選)</value>
</data> </data>
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>測試延遲 Tcping (多選) (Ctrl+O)</value> <value>測試延遲 Tcping (多選)</value>
</data> </data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>匯出所選完整設定</value> <value>匯出所選完整設定</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>匯出分享連結至剪貼簿 (多選) (Ctrl+C)</value> <value>匯出分享連結至剪貼簿 (多選)</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>新增自訂節點</value> <value>新增自訂節點</value>
@ -529,19 +529,19 @@
<value>新增 [VMess] 節點</value> <value>新增 [VMess] 節點</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>全選 (Ctrl+A)</value> <value>全選</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>清除所有</value> <value>清除所有</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>複製 (Ctrl+C)</value> <value>複製</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>複製所有</value> <value>複製所有</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>全選 (Ctrl+A)</value> <value>全選</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>新增</value> <value>新增</value>
@ -781,7 +781,7 @@
<value>PAC 模式</value> <value>PAC 模式</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>分享 (Ctrl+F)</value> <value>分享</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>路由</value> <value>路由</value>
@ -793,16 +793,16 @@
<value>以管理員身份執行</value> <value>以管理員身份執行</value>
</data> </data>
<data name="menuMoveBottom" xml:space="preserve"> <data name="menuMoveBottom" xml:space="preserve">
<value>下移至底部 (B)</value> <value>下移至底部</value>
</data> </data>
<data name="menuMoveDown" xml:space="preserve"> <data name="menuMoveDown" xml:space="preserve">
<value>下移 (D)</value> <value>下移</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>上移至頂部 (T)</value> <value>上移至頂部</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>上移 (U)</value> <value>上移</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>過濾 (允許正則)</value> <value>過濾 (允許正則)</value>
@ -817,10 +817,10 @@
<value>一鍵匯入規則集</value> <value>一鍵匯入規則集</value>
</data> </data>
<data name="menuRoutingAdvancedRemove" xml:space="preserve"> <data name="menuRoutingAdvancedRemove" xml:space="preserve">
<value>移除所選規則 (Delete)</value> <value>移除所選規則</value>
</data> </data>
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>設為活動規則 (Enter)</value> <value>設為活動規則</value>
</data> </data>
<data name="TbdomainStrategy" xml:space="preserve"> <data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value> <value>域名解析策略</value>
@ -853,7 +853,7 @@
<value>規則列表</value> <value>規則列表</value>
</data> </data>
<data name="menuRuleRemove" xml:space="preserve"> <data name="menuRuleRemove" xml:space="preserve">
<value>移除所選規則 (Delete)</value> <value>移除所選規則</value>
</data> </data>
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve"> <data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
<value>路由規則詳情設定</value> <value>路由規則詳情設定</value>
@ -922,7 +922,7 @@
<value>跳過測試</value> <value>跳過測試</value>
</data> </data>
<data name="menuEditServer" xml:space="preserve"> <data name="menuEditServer" xml:space="preserve">
<value>編輯 (Ctrl+D)</value> <value>編輯</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>主介面輕按兩下設為活動</value> <value>主介面輕按兩下設為活動</value>
@ -976,7 +976,10 @@
<value>啟用硬體加速 (需重啟)</value> <value>啟用硬體加速 (需重啟)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>等待測試中(按 ESC 終止)...</value> <value>等待測試中...</value>
</data>
<data name="SpeedtestingPressEscToExit" xml:space="preserve">
<value>按 ECS 以終止測試</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>當有異常斷流時請關閉</value> <value>當有異常斷流時請關閉</value>
@ -1201,7 +1204,7 @@
<value>重新整理</value> <value>重新整理</value>
</data> </data>
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>設為活動節點 (Enter)</value> <value>設為活動節點</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Outbound 預設解析策略</value> <value>Outbound 預設解析策略</value>
@ -1534,7 +1537,7 @@
<value>刪除子配置</value> <value>刪除子配置</value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>子配置項</value> <value>子配置項目一,從訂閱分組中自動新增</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>容錯移轉</value> <value>容錯移轉</value>
@ -1632,4 +1635,7 @@
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>macOS 在 Dock 欄顯示 (需重啟)</value> <value>macOS 在 Dock 欄顯示 (需重啟)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve">
<value>子配置項二,從自建中選擇新增</value>
</data>
</root> </root>

View file

@ -26,6 +26,7 @@ public partial class CoreConfigSingboxService
} }
await GenOutboundMux(node, outbound); await GenOutboundMux(node, outbound);
await GenOutboundTransport(node, outbound);
break; break;
} }
case EConfigType.Shadowsocks: case EConfigType.Shadowsocks:
@ -33,6 +34,50 @@ public partial class CoreConfigSingboxService
outbound.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(node.Security) ? node.Security : Global.None; outbound.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(node.Security) ? node.Security : Global.None;
outbound.password = node.Id; outbound.password = node.Id;
if (node.Network == nameof(ETransport.tcp) && node.HeaderType == Global.TcpHeaderHttp)
{
outbound.plugin = "obfs-local";
outbound.plugin_opts = $"obfs=http;obfs-host={node.RequestHost};";
}
else
{
var pluginArgs = string.Empty;
if (node.Network == nameof(ETransport.ws))
{
pluginArgs += "mode=websocket;";
pluginArgs += $"host={node.RequestHost};";
pluginArgs += $"path={node.Path};";
}
else if (node.Network == nameof(ETransport.quic))
{
pluginArgs += "mode=quic;";
}
if (node.StreamSecurity == Global.StreamSecurity)
{
pluginArgs += "tls;";
var certs = CertPemManager.ParsePemChain(node.Cert);
if (certs.Count > 0)
{
var cert = certs.First();
const string beginMarker = "-----BEGIN CERTIFICATE-----\n";
const string endMarker = "\n-----END CERTIFICATE-----";
var base64Content = cert.Replace(beginMarker, "").Replace(endMarker, "").Trim();
// https://github.com/shadowsocks/v2ray-plugin/blob/e9af1cdd2549d528deb20a4ab8d61c5fbe51f306/args.go#L172
// Equal signs and commas [and backslashes] must be escaped with a backslash.
base64Content = base64Content.Replace("=", "\\=");
pluginArgs += $"certRaw={base64Content};";
}
}
if (pluginArgs.Length > 0)
{
outbound.plugin = "v2ray-plugin";
outbound.plugin_opts = pluginArgs;
}
}
await GenOutboundMux(node, outbound); await GenOutboundMux(node, outbound);
break; break;
} }
@ -71,6 +116,8 @@ public partial class CoreConfigSingboxService
{ {
outbound.flow = node.Flow; outbound.flow = node.Flow;
} }
await GenOutboundTransport(node, outbound);
break; break;
} }
case EConfigType.Trojan: case EConfigType.Trojan:
@ -78,6 +125,7 @@ public partial class CoreConfigSingboxService
outbound.password = node.Id; outbound.password = node.Id;
await GenOutboundMux(node, outbound); await GenOutboundMux(node, outbound);
await GenOutboundTransport(node, outbound);
break; break;
} }
case EConfigType.Hysteria2: case EConfigType.Hysteria2:
@ -127,8 +175,6 @@ public partial class CoreConfigSingboxService
} }
await GenOutboundTls(node, outbound); await GenOutboundTls(node, outbound);
await GenOutboundTransport(node, outbound);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -232,54 +278,59 @@ public partial class CoreConfigSingboxService
{ {
try try
{ {
if (node.StreamSecurity is Global.StreamSecurityReality or Global.StreamSecurity) if (node.StreamSecurity is not (Global.StreamSecurityReality or Global.StreamSecurity))
{ {
var server_name = string.Empty; return await Task.FromResult(0);
if (node.Sni.IsNotEmpty()) }
{ if (node.ConfigType is EConfigType.Shadowsocks or EConfigType.SOCKS or EConfigType.WireGuard)
server_name = node.Sni; {
} return await Task.FromResult(0);
else if (node.RequestHost.IsNotEmpty()) }
{ var server_name = string.Empty;
server_name = Utils.String2List(node.RequestHost)?.First(); if (node.Sni.IsNotEmpty())
} {
var tls = new Tls4Sbox() server_name = node.Sni;
}
else if (node.RequestHost.IsNotEmpty())
{
server_name = Utils.String2List(node.RequestHost)?.First();
}
var tls = new Tls4Sbox()
{
enabled = true,
record_fragment = _config.CoreBasicItem.EnableFragment ? true : null,
server_name = server_name,
insecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure),
alpn = node.GetAlpn(),
};
if (node.Fingerprint.IsNotEmpty())
{
tls.utls = new Utls4Sbox()
{ {
enabled = true, enabled = true,
record_fragment = _config.CoreBasicItem.EnableFragment ? true : null, fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint
server_name = server_name,
insecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure),
alpn = node.GetAlpn(),
}; };
if (node.Fingerprint.IsNotEmpty()) }
if (node.StreamSecurity == Global.StreamSecurity)
{
var certs = CertPemManager.ParsePemChain(node.Cert);
if (certs.Count > 0)
{ {
tls.utls = new Utls4Sbox() tls.certificate = certs;
{
enabled = true,
fingerprint = node.Fingerprint.IsNullOrEmpty() ? _config.CoreBasicItem.DefFingerprint : node.Fingerprint
};
}
if (node.StreamSecurity == Global.StreamSecurity)
{
var certs = CertPemManager.ParsePemChain(node.Cert);
if (certs.Count > 0)
{
tls.certificate = certs;
tls.insecure = false;
}
}
else if (node.StreamSecurity == Global.StreamSecurityReality)
{
tls.reality = new Reality4Sbox()
{
enabled = true,
public_key = node.PublicKey,
short_id = node.ShortId
};
tls.insecure = false; tls.insecure = false;
} }
outbound.tls = tls;
} }
else if (node.StreamSecurity == Global.StreamSecurityReality)
{
tls.reality = new Reality4Sbox()
{
enabled = true,
public_key = node.PublicKey,
short_id = node.ShortId
};
tls.insecure = false;
}
outbound.tls = tls;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -305,23 +356,43 @@ public partial class CoreConfigSingboxService
case nameof(ETransport.tcp): //http case nameof(ETransport.tcp): //http
if (node.HeaderType == Global.TcpHeaderHttp) if (node.HeaderType == Global.TcpHeaderHttp)
{ {
if (node.ConfigType == EConfigType.Shadowsocks) transport.type = nameof(ETransport.http);
{ transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost);
outbound.plugin = "obfs-local"; transport.path = node.Path.IsNullOrEmpty() ? null : node.Path;
outbound.plugin_opts = $"obfs=http;obfs-host={node.RequestHost};";
}
else
{
transport.type = nameof(ETransport.http);
transport.host = node.RequestHost.IsNullOrEmpty() ? null : Utils.String2List(node.RequestHost);
transport.path = node.Path.IsNullOrEmpty() ? null : node.Path;
}
} }
break; break;
case nameof(ETransport.ws): case nameof(ETransport.ws):
transport.type = nameof(ETransport.ws); transport.type = nameof(ETransport.ws);
transport.path = node.Path.IsNullOrEmpty() ? null : node.Path; var wsPath = node.Path;
// Parse eh and ed parameters from path using regex
if (!wsPath.IsNullOrEmpty())
{
var edRegex = new Regex(@"[?&]ed=(\d+)");
var edMatch = edRegex.Match(wsPath);
if (edMatch.Success && int.TryParse(edMatch.Groups[1].Value, out var edValue))
{
transport.max_early_data = edValue;
transport.early_data_header_name = "Sec-WebSocket-Protocol";
wsPath = edRegex.Replace(wsPath, "");
wsPath = wsPath.Replace("?&", "?");
if (wsPath.EndsWith('?'))
{
wsPath = wsPath.TrimEnd('?');
}
}
var ehRegex = new Regex(@"[?&]eh=([^&]+)");
var ehMatch = ehRegex.Match(wsPath);
if (ehMatch.Success)
{
transport.early_data_header_name = Uri.UnescapeDataString(ehMatch.Groups[1].Value);
}
}
transport.path = wsPath.IsNullOrEmpty() ? null : wsPath;
if (node.RequestHost.IsNotEmpty()) if (node.RequestHost.IsNotEmpty())
{ {
transport.headers = new() transport.headers = new()

View file

@ -300,7 +300,7 @@ public partial class CoreConfigSingboxService
private bool ParseV2Domain(string domain, Rule4Sbox rule) private bool ParseV2Domain(string domain, Rule4Sbox rule)
{ {
if (domain.StartsWith("#") || domain.StartsWith("ext:") || domain.StartsWith("ext-domain:")) if (domain.StartsWith('#') || domain.StartsWith("ext:") || domain.StartsWith("ext-domain:"))
{ {
return false; return false;
} }

View file

@ -351,7 +351,6 @@ public partial class CoreConfigV2rayService
if (host.IsNotEmpty()) if (host.IsNotEmpty())
{ {
wsSettings.host = host; wsSettings.host = host;
wsSettings.headers.Host = host;
} }
if (path.IsNotEmpty()) if (path.IsNotEmpty())
{ {

View file

@ -7,7 +7,7 @@ namespace ServiceLib.Services;
/// </summary> /// </summary>
public class DownloadService public class DownloadService
{ {
public event EventHandler<RetResult>? UpdateCompleted; public event EventHandler<UpdateResult>? UpdateCompleted;
public event ErrorEventHandler? Error; public event ErrorEventHandler? Error;
@ -40,10 +40,10 @@ public class DownloadService
{ {
try try
{ {
UpdateCompleted?.Invoke(this, new RetResult(false, $"{ResUI.Downloading} {url}")); UpdateCompleted?.Invoke(this, new UpdateResult(false, $"{ResUI.Downloading} {url}"));
var progress = new Progress<double>(); var progress = new Progress<double>();
progress.ProgressChanged += (sender, value) => UpdateCompleted?.Invoke(this, new RetResult(value > 100, $"...{value}%")); progress.ProgressChanged += (sender, value) => UpdateCompleted?.Invoke(this, new UpdateResult(value > 100, $"...{value}%"));
var webProxy = await GetWebProxy(blProxy); var webProxy = await GetWebProxy(blProxy);
await DownloaderHelper.Instance.DownloadFileAsync(webProxy, await DownloaderHelper.Instance.DownloadFileAsync(webProxy,

View file

@ -19,7 +19,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
public void ExitLoop() public void ExitLoop()
{ {
if (_lstExitLoop.Count > 0) if (!_lstExitLoop.IsEmpty)
{ {
_ = UpdateFunc("", ResUI.SpeedtestingStop); _ = UpdateFunc("", ResUI.SpeedtestingStop);
@ -27,6 +27,11 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
} }
} }
private static bool ShouldStopTest(string exitLoopKey)
{
return !_lstExitLoop.Any(p => p == exitLoopKey);
}
private async Task RunAsync(ESpeedActionType actionType, List<ProfileItem> selecteds) private async Task RunAsync(ESpeedActionType actionType, List<ProfileItem> selecteds)
{ {
var exitLoopKey = Utils.GetGuid(false); var exitLoopKey = Utils.GetGuid(false);
@ -103,6 +108,11 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
} }
} }
if (lstSelected.Count > 1 && (actionType == ESpeedActionType.Speedtest || actionType == ESpeedActionType.Mixedtest))
{
NoticeManager.Instance.Enqueue(ResUI.SpeedtestingPressEscToExit);
}
return lstSelected; return lstSelected;
} }
@ -152,7 +162,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
var pageSizeNext = pageSize / 2; var pageSizeNext = pageSize / 2;
if (lstFailed.Count > 0 && pageSizeNext > 0) if (lstFailed.Count > 0 && pageSizeNext > 0)
{ {
if (_lstExitLoop.Any(p => p == exitLoopKey) == false) if (ShouldStopTest(exitLoopKey))
{ {
await UpdateFunc("", ResUI.SpeedtestingSkip); await UpdateFunc("", ResUI.SpeedtestingSkip);
return; return;
@ -190,6 +200,12 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
{ {
continue; continue;
} }
if (ShouldStopTest(exitLoopKey))
{
return false;
}
tasks.Add(Task.Run(async () => tasks.Add(Task.Run(async () =>
{ {
await DoRealPing(it); await DoRealPing(it);
@ -218,7 +234,7 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
List<Task> tasks = new(); List<Task> tasks = new();
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
if (_lstExitLoop.Any(p => p == exitLoopKey) == false) if (ShouldStopTest(exitLoopKey))
{ {
await UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip); await UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
continue; continue;
@ -234,21 +250,27 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
if (processService is null) if (processService is null)
{ {
await UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore); await UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
return;
} }
else
await Task.Delay(1000);
var delay = await DoRealPing(it);
if (blSpeedTest)
{ {
await Task.Delay(1000); if (ShouldStopTest(exitLoopKey))
var delay = await DoRealPing(it);
if (blSpeedTest)
{ {
if (delay > 0) await UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
{ return;
await DoSpeedTest(downloadHandle, it); }
}
else if (delay > 0)
{ {
await UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip); await DoSpeedTest(downloadHandle, it);
} }
else
{
await UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
} }
} }
} }
@ -301,31 +323,28 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
{ {
var responseTime = -1; var responseTime = -1;
if (!IPAddress.TryParse(url, out var ipAddress))
{
var ipHostInfo = await Dns.GetHostEntryAsync(url);
ipAddress = ipHostInfo.AddressList.First();
}
IPEndPoint endPoint = new(ipAddress, port);
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
var timer = Stopwatch.StartNew();
try try
{ {
if (!IPAddress.TryParse(url, out var ipAddress)) using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
{ await clientSocket.ConnectAsync(endPoint, cts.Token).ConfigureAwait(false);
var ipHostInfo = await Dns.GetHostEntryAsync(url); responseTime = (int)timer.ElapsedMilliseconds;
ipAddress = ipHostInfo.AddressList.First();
}
IPEndPoint endPoint = new(ipAddress, port);
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
var timer = Stopwatch.StartNew();
var result = clientSocket.BeginConnect(endPoint, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
{
throw new TimeoutException("connect timeout (5s): " + url);
}
timer.Stop();
responseTime = (int)timer.Elapsed.TotalMilliseconds;
clientSocket.EndConnect(result);
} }
catch (Exception ex) catch (OperationCanceledException)
{ {
Logging.SaveLog(_tag, ex); }
finally
{
timer.Stop();
} }
return responseTime; return responseTime;
} }

View file

@ -37,7 +37,7 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
await UpdateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, ECoreType.v2rayN)); await UpdateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, ECoreType.v2rayN));
await UpdateFunc(false, result.Msg); await UpdateFunc(false, result.Msg);
url = result.Data?.ToString(); url = result.Url.ToString();
fileName = Utils.GetTempPath(Utils.GetGuid()); fileName = Utils.GetTempPath(Utils.GetGuid());
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout); await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
} }
@ -86,7 +86,7 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
await UpdateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, type)); await UpdateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, type));
await UpdateFunc(false, result.Msg); await UpdateFunc(false, result.Msg);
url = result.Data?.ToString(); url = result.Url.ToString();
var ext = url.Contains(".tar.gz") ? ".tar.gz" : Path.GetExtension(url); var ext = url.Contains(".tar.gz") ? ".tar.gz" : Path.GetExtension(url);
fileName = Utils.GetTempPath(Utils.GetGuid() + ext); fileName = Utils.GetTempPath(Utils.GetGuid() + ext);
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout); await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
@ -110,26 +110,26 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
#region CheckUpdate private #region CheckUpdate private
private async Task<RetResult> CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease) private async Task<UpdateResult> CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease)
{ {
try try
{ {
var result = await GetRemoteVersion(downloadHandle, type, preRelease); var result = await GetRemoteVersion(downloadHandle, type, preRelease);
if (!result.Success || result.Data is null) if (!result.Success || result.Version is null)
{ {
return result; return result;
} }
return await ParseDownloadUrl(type, (SemanticVersion)result.Data); return await ParseDownloadUrl(type, result);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(_tag, ex); Logging.SaveLog(_tag, ex);
await UpdateFunc(false, ex.Message); await UpdateFunc(false, ex.Message);
return new RetResult(false, ex.Message); return new UpdateResult(false, ex.Message);
} }
} }
private async Task<RetResult> GetRemoteVersion(DownloadService downloadHandle, ECoreType type, bool preRelease) private async Task<UpdateResult> GetRemoteVersion(DownloadService downloadHandle, ECoreType type, bool preRelease)
{ {
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type); var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type);
var tagName = string.Empty; var tagName = string.Empty;
@ -139,7 +139,7 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
var result = await downloadHandle.TryDownloadString(url, true, Global.AppName); var result = await downloadHandle.TryDownloadString(url, true, Global.AppName);
if (result.IsNullOrEmpty()) if (result.IsNullOrEmpty())
{ {
return new RetResult(false, ""); return new UpdateResult(false, "");
} }
var gitHubReleases = JsonUtils.Deserialize<List<GitHubRelease>>(result); var gitHubReleases = JsonUtils.Deserialize<List<GitHubRelease>>(result);
@ -153,12 +153,12 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
var lastUrl = await downloadHandle.UrlRedirectAsync(url, true); var lastUrl = await downloadHandle.UrlRedirectAsync(url, true);
if (lastUrl == null) if (lastUrl == null)
{ {
return new RetResult(false, ""); return new UpdateResult(false, "");
} }
tagName = lastUrl?.Split("/tag/").LastOrDefault(); tagName = lastUrl?.Split("/tag/").LastOrDefault();
} }
return new RetResult(true, "", new SemanticVersion(tagName)); return new UpdateResult(true, new SemanticVersion(tagName));
} }
private async Task<SemanticVersion> GetCoreVersion(ECoreType type) private async Task<SemanticVersion> GetCoreVersion(ECoreType type)
@ -213,10 +213,11 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
} }
} }
private async Task<RetResult> ParseDownloadUrl(ECoreType type, SemanticVersion version) private async Task<UpdateResult> ParseDownloadUrl(ECoreType type, UpdateResult result)
{ {
try try
{ {
var version = result.Version ?? new SemanticVersion(0, 0, 0);
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type); var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type);
var coreUrl = await GetUrlFromCore(coreInfo) ?? string.Empty; var coreUrl = await GetUrlFromCore(coreInfo) ?? string.Empty;
SemanticVersion curVersion; SemanticVersion curVersion;
@ -260,16 +261,17 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
if (curVersion >= version && version != new SemanticVersion(0, 0, 0)) if (curVersion >= version && version != new SemanticVersion(0, 0, 0))
{ {
return new RetResult(false, message); return new UpdateResult(false, message);
} }
return new RetResult(true, "", url); result.Url = url;
return result;
} }
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(_tag, ex); Logging.SaveLog(_tag, ex);
await UpdateFunc(false, ex.Message); await UpdateFunc(false, ex.Message);
return new RetResult(false, ex.Message); return new UpdateResult(false, ex.Message);
} }
} }

View file

@ -77,6 +77,7 @@ public class ProfilesViewModel : MyReactiveObject
public ReactiveCommand<Unit, Unit> AddSubCmd { get; } public ReactiveCommand<Unit, Unit> AddSubCmd { get; }
public ReactiveCommand<Unit, Unit> EditSubCmd { get; } public ReactiveCommand<Unit, Unit> EditSubCmd { get; }
public ReactiveCommand<Unit, Unit> DeleteSubCmd { get; }
#endregion Menu #endregion Menu
@ -235,6 +236,10 @@ public class ProfilesViewModel : MyReactiveObject
{ {
await EditSubAsync(false); await EditSubAsync(false);
}); });
DeleteSubCmd = ReactiveCommand.CreateFromTask(async () =>
{
await DeleteSubAsync();
});
#endregion WhenAnyValue && ReactiveCommand #endregion WhenAnyValue && ReactiveCommand
@ -553,6 +558,11 @@ public class ProfilesViewModel : MyReactiveObject
private async Task RemoveDuplicateServer() private async Task RemoveDuplicateServer()
{ {
if (await _updateView?.Invoke(EViewAction.ShowYesNo, null) == false)
{
return;
}
var tuple = await ConfigHandler.DedupServerList(_config, _config.SubIndexId); var tuple = await ConfigHandler.DedupServerList(_config, _config.SubIndexId);
if (tuple.Item1 > 0 || tuple.Item2 > 0) if (tuple.Item1 > 0 || tuple.Item2 > 0)
{ {
@ -879,5 +889,23 @@ public class ProfilesViewModel : MyReactiveObject
} }
} }
private async Task DeleteSubAsync()
{
var item = await AppManager.Instance.GetSubItem(_config.SubIndexId);
if (item is null)
{
return;
}
if (await _updateView?.Invoke(EViewAction.ShowYesNo, null) == false)
{
return;
}
await ConfigHandler.DeleteSubItem(_config, item.Id);
await RefreshSubscriptions();
await SubSelectedChangedAsync(true);
}
#endregion Subscription #endregion Subscription
} }

View file

@ -1,14 +1,31 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia;
using Avalonia.Media;
namespace v2rayN.Desktop.Common; namespace v2rayN.Desktop.Common;
public static class AppBuilderExtension public static class AppBuilderExtension
{ {
public static AppBuilder WithFontByDefault(this AppBuilder appBuilder) public static AppBuilder WithFontByDefault(this AppBuilder appBuilder)
{ {
var uri = Path.Combine(Global.AvaAssets, "Fonts#Noto Sans SC"); var fallbacks = new List<FontFallback>();
return appBuilder.With(new FontManagerOptions()
var notoSansSc = new FontFamily(Path.Combine(Global.AvaAssets, "Fonts#Noto Sans SC"));
fallbacks.Add(new FontFallback { FontFamily = notoSansSc });
if (OperatingSystem.IsLinux())
{ {
//DefaultFamilyName = uri, fallbacks.Add(new FontFallback
FontFallbacks = new[] { new FontFallback { FontFamily = new FontFamily(uri) } } {
FontFamily = new FontFamily("Noto Color Emoji")
});
}
return appBuilder.With(new FontManagerOptions
{
FontFallbacks = fallbacks.ToArray()
}); });
} }
} }

View file

@ -35,7 +35,7 @@
<Grid <Grid
Grid.Row="0" Grid.Row="0"
ColumnDefinitions="180,Auto,Auto" ColumnDefinitions="300,Auto,Auto"
DockPanel.Dock="Top" DockPanel.Dock="Top"
RowDefinitions="Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
@ -75,7 +75,7 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
ColumnDefinitions="180,Auto,Auto"> ColumnDefinitions="300,Auto,Auto">
<TextBlock <TextBlock
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
@ -93,7 +93,7 @@
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuServerList}"> <TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuServerList}">
<Grid <Grid
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
ColumnDefinitions="180,Auto,Auto" ColumnDefinitions="300,Auto,Auto"
RowDefinitions="Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto">
<TextBlock <TextBlock
@ -134,7 +134,7 @@
</TabControl> </TabControl>
<TabControl> <TabControl>
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuServerList}"> <TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuServerList2}">
<DataGrid <DataGrid
x:Name="lstChild" x:Name="lstChild"
Grid.Row="1" Grid.Row="1"
@ -152,13 +152,31 @@
<DataGrid.ContextMenu> <DataGrid.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem x:Name="menuAddChildServer" Header="{x:Static resx:ResUI.menuAddChildServer}" /> <MenuItem x:Name="menuAddChildServer" Header="{x:Static resx:ResUI.menuAddChildServer}" />
<MenuItem x:Name="menuRemoveChildServer" Header="{x:Static resx:ResUI.menuRemoveChildServer}" /> <MenuItem
<MenuItem x:Name="menuSelectAllChild" Header="{x:Static resx:ResUI.menuSelectAll}" /> x:Name="menuRemoveChildServer"
Header="{x:Static resx:ResUI.menuRemoveChildServer}"
InputGesture="Back" />
<MenuItem
x:Name="menuSelectAllChild"
Header="{x:Static resx:ResUI.menuSelectAll}"
InputGesture="Ctrl+A" />
<Separator /> <Separator />
<MenuItem x:Name="menuMoveTop" Header="{x:Static resx:ResUI.menuMoveTop}" /> <MenuItem
<MenuItem x:Name="menuMoveUp" Header="{x:Static resx:ResUI.menuMoveUp}" /> x:Name="menuMoveTop"
<MenuItem x:Name="menuMoveDown" Header="{x:Static resx:ResUI.menuMoveDown}" /> Header="{x:Static resx:ResUI.menuMoveTop}"
<MenuItem x:Name="menuMoveBottom" Header="{x:Static resx:ResUI.menuMoveBottom}" /> InputGesture="T" />
<MenuItem
x:Name="menuMoveUp"
Header="{x:Static resx:ResUI.menuMoveUp}"
InputGesture="U" />
<MenuItem
x:Name="menuMoveDown"
Header="{x:Static resx:ResUI.menuMoveDown}"
InputGesture="D" />
<MenuItem
x:Name="menuMoveBottom"
Header="{x:Static resx:ResUI.menuMoveBottom}"
InputGesture="B" />
</ContextMenu> </ContextMenu>
</DataGrid.ContextMenu> </DataGrid.ContextMenu>
<DataGrid.Columns> <DataGrid.Columns>

View file

@ -132,6 +132,7 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
break; break;
case Key.Delete: case Key.Delete:
case Key.Back:
ViewModel?.ChildRemoveAsync(); ViewModel?.ChildRemoveAsync();
e.Handled = true; e.Handled = true;
break; break;

View file

@ -36,7 +36,7 @@
<Grid <Grid
Grid.Row="0" Grid.Row="0"
ColumnDefinitions="180,Auto,Auto" ColumnDefinitions="300,Auto,Auto"
RowDefinitions="Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
@ -50,7 +50,7 @@
Orientation="Horizontal"> Orientation="Horizontal">
<ComboBox <ComboBox
x:Name="cmbCoreType" x:Name="cmbCoreType"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
ToolTip.Tip="{x:Static resx:ResUI.TbCoreType}" /> ToolTip.Tip="{x:Static resx:ResUI.TbCoreType}" />
</StackPanel> </StackPanel>
@ -101,7 +101,7 @@
<Grid <Grid
x:Name="gridVMess" x:Name="gridVMess"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto,Auto" ColumnDefinitions="300,Auto,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto">
@ -167,7 +167,7 @@
<Grid <Grid
x:Name="gridSs" x:Name="gridSs"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto">
@ -213,7 +213,7 @@
<Grid <Grid
x:Name="gridSocks" x:Name="gridSocks"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto">
@ -246,7 +246,7 @@
<Grid <Grid
x:Name="gridVLESS" x:Name="gridVLESS"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto,Auto" ColumnDefinitions="300,Auto,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto">
@ -312,7 +312,7 @@
<Grid <Grid
x:Name="gridTrojan" x:Name="gridTrojan"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto">
@ -358,7 +358,7 @@
<Grid <Grid
x:Name="gridHysteria2" x:Name="gridHysteria2"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto,Auto" ColumnDefinitions="300,Auto,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto">
@ -411,7 +411,7 @@
<Grid <Grid
x:Name="gridTuic" x:Name="gridTuic"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto">
@ -457,7 +457,7 @@
<Grid <Grid
x:Name="gridWireguard" x:Name="gridWireguard"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
@ -534,7 +534,7 @@
<Grid <Grid
x:Name="gridAnytls" x:Name="gridAnytls"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto">
@ -560,7 +560,7 @@
<Grid <Grid
x:Name="gridTransport" x:Name="gridTransport"
Grid.Row="4" Grid.Row="4"
ColumnDefinitions="180,Auto,Auto" ColumnDefinitions="300,Auto,Auto"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
@ -692,7 +692,7 @@
<Grid <Grid
x:Name="gridTls" x:Name="gridTls"
Grid.Row="6" Grid.Row="6"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
@ -711,7 +711,7 @@
<Grid <Grid
x:Name="gridTlsMore" x:Name="gridTlsMore"
Grid.Row="7" Grid.Row="7"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
@ -831,7 +831,7 @@
<Grid <Grid
x:Name="gridRealityMore" x:Name="gridRealityMore"
Grid.Row="7" Grid.Row="7"
ColumnDefinitions="180,Auto" ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">

View file

@ -110,7 +110,10 @@
<ItemsControl.ContextMenu> <ItemsControl.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" /> <MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" />
<MenuItem x:Name="menuProxiesSelectActivity" Header="{x:Static resx:ResUI.menuProxiesSelectActivity}" /> <MenuItem
x:Name="menuProxiesSelectActivity"
Header="{x:Static resx:ResUI.menuProxiesSelectActivity}"
InputGesture="Enter" />
</ContextMenu> </ContextMenu>
</ItemsControl.ContextMenu> </ItemsControl.ContextMenu>
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>

View file

@ -9,8 +9,8 @@
xmlns:view="using:v2rayN.Desktop.Views" xmlns:view="using:v2rayN.Desktop.Views"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="v2rayN" Title="v2rayN"
Width="1000" Width="1200"
Height="600" Height="800"
MinWidth="900" MinWidth="900"
x:DataType="vms:MainWindowViewModel" x:DataType="vms:MainWindowViewModel"
Icon="/Assets/NotifyIcon1.ico" Icon="/Assets/NotifyIcon1.ico"
@ -26,8 +26,14 @@
<ContentControl x:Name="conTheme" DockPanel.Dock="Right" /> <ContentControl x:Name="conTheme" DockPanel.Dock="Right" />
<Menu Margin="{StaticResource Margin4}"> <Menu Margin="{StaticResource Margin4}">
<MenuItem Header="{x:Static resx:ResUI.menuServers}"> <MenuItem Header="{x:Static resx:ResUI.menuServers}">
<MenuItem x:Name="menuAddServerViaClipboard" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" /> <MenuItem
<MenuItem x:Name="menuAddServerViaScan" Header="{x:Static resx:ResUI.menuAddServerViaScan}" /> x:Name="menuAddServerViaClipboard"
Header="{x:Static resx:ResUI.menuAddServerViaClipboard}"
InputGesture="Ctrl+V" />
<MenuItem
x:Name="menuAddServerViaScan"
Header="{x:Static resx:ResUI.menuAddServerViaScan}"
InputGesture="Ctrl+S" />
<MenuItem x:Name="menuAddServerViaImage" Header="{x:Static resx:ResUI.menuAddServerViaImage}" /> <MenuItem x:Name="menuAddServerViaImage" Header="{x:Static resx:ResUI.menuAddServerViaImage}" />
<MenuItem x:Name="menuAddCustomServer" Header="{x:Static resx:ResUI.menuAddCustomServer}" /> <MenuItem x:Name="menuAddCustomServer" Header="{x:Static resx:ResUI.menuAddCustomServer}" />
<MenuItem x:Name="menuAddPolicyGroupServer" Header="{x:Static resx:ResUI.menuAddPolicyGroupServer}" /> <MenuItem x:Name="menuAddPolicyGroupServer" Header="{x:Static resx:ResUI.menuAddPolicyGroupServer}" />
@ -84,13 +90,13 @@
<MenuItem x:Name="menuOpenTheFileLocation" Header="{x:Static resx:ResUI.menuOpenTheFileLocation}" /> <MenuItem x:Name="menuOpenTheFileLocation" Header="{x:Static resx:ResUI.menuOpenTheFileLocation}" />
</MenuItem> </MenuItem>
<MenuItem x:Name="menuReload" Header="{x:Static resx:ResUI.menuReload}" />
<MenuItem x:Name="menuHelp" Header="{x:Static resx:ResUI.menuHelp}"> <MenuItem x:Name="menuHelp" Header="{x:Static resx:ResUI.menuHelp}">
<MenuItem x:Name="menuCheckUpdate" Header="{x:Static resx:ResUI.menuCheckUpdate}" /> <MenuItem x:Name="menuCheckUpdate" Header="{x:Static resx:ResUI.menuCheckUpdate}" />
<Separator /> <Separator />
</MenuItem> </MenuItem>
<MenuItem x:Name="menuReload" Header="{x:Static resx:ResUI.menuReload}" />
<MenuItem x:Name="menuPromotion" Header="{x:Static resx:ResUI.menuPromotion}" /> <MenuItem x:Name="menuPromotion" Header="{x:Static resx:ResUI.menuPromotion}" />
<MenuItem x:Name="menuClose" Header="{x:Static resx:ResUI.menuExit}" /> <MenuItem x:Name="menuClose" Header="{x:Static resx:ResUI.menuExit}" />

View file

@ -72,18 +72,20 @@
VerticalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
WordWrap="True"> WordWrap="True">
<avaloniaEdit:TextEditor.Options> <avaloniaEdit:TextEditor.Options>
<avaloniaEdit:TextEditorOptions AllowScrollBelowDocument="False"/> <avaloniaEdit:TextEditorOptions AllowScrollBelowDocument="False" />
</avaloniaEdit:TextEditor.Options> </avaloniaEdit:TextEditor.Options>
<avaloniaEdit:TextEditor.ContextFlyout> <avaloniaEdit:TextEditor.ContextFlyout>
<MenuFlyout> <MenuFlyout>
<MenuItem <MenuItem
x:Name="menuMsgViewSelectAll" x:Name="menuMsgViewSelectAll"
Click="menuMsgViewSelectAll_Click" Click="menuMsgViewSelectAll_Click"
InputGesture="Ctrl+A"
Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" /> Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" />
<MenuItem <MenuItem
x:Name="menuMsgViewCopy" x:Name="menuMsgViewCopy"
Click="menuMsgViewCopy_Click" Click="menuMsgViewCopy_Click"
Header="{x:Static resx:ResUI.menuMsgViewCopy}" /> Header="{x:Static resx:ResUI.menuMsgViewCopy}"
InputGesture="Ctrl+C" />
<MenuItem <MenuItem
x:Name="menuMsgViewCopyAll" x:Name="menuMsgViewCopyAll"
Click="menuMsgViewCopyAll_Click" Click="menuMsgViewCopyAll_Click"

View file

@ -28,6 +28,14 @@
<WrapPanel /> <WrapPanel />
</ItemsPanelTemplate> </ItemsPanelTemplate>
</ListBox.ItemsPanel> </ListBox.ItemsPanel>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuSubEdit" Header="{x:Static resx:ResUI.menuSubEdit}" />
<MenuItem x:Name="menuSubAdd" Header="{x:Static resx:ResUI.menuSubAdd}" />
<MenuItem x:Name="menuSubDelete" Header="{x:Static resx:ResUI.menuSubDelete}" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox> </ListBox>
<Button <Button
@ -103,16 +111,34 @@
</DataGrid.KeyBindings> </DataGrid.KeyBindings>
<DataGrid.ContextMenu> <DataGrid.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem x:Name="menuSetDefaultServer" Header="{x:Static resx:ResUI.menuSetDefaultServer}" /> <MenuItem
<MenuItem x:Name="menuEditServer" Header="{x:Static resx:ResUI.menuEditServer}" /> x:Name="menuSetDefaultServer"
Header="{x:Static resx:ResUI.menuSetDefaultServer}"
InputGesture="Enter" />
<MenuItem
x:Name="menuEditServer"
Header="{x:Static resx:ResUI.menuEditServer}"
InputGesture="Ctrl+D" />
<MenuItem x:Name="menuCopyServer" Header="{x:Static resx:ResUI.menuCopyServer}" /> <MenuItem x:Name="menuCopyServer" Header="{x:Static resx:ResUI.menuCopyServer}" />
<MenuItem x:Name="menuRemoveServer" Header="{x:Static resx:ResUI.menuRemoveServer}" /> <MenuItem
x:Name="menuRemoveServer"
Header="{x:Static resx:ResUI.menuRemoveServer}"
InputGesture="Back" />
<MenuItem x:Name="menuRemoveDuplicateServer" Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" /> <MenuItem x:Name="menuRemoveDuplicateServer" Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
<MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" /> <MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
<Separator /> <Separator />
<MenuItem x:Name="menuTcpingServer" Header="{x:Static resx:ResUI.menuTcpingServer}" /> <MenuItem
<MenuItem x:Name="menuRealPingServer" Header="{x:Static resx:ResUI.menuRealPingServer}" /> x:Name="menuTcpingServer"
<MenuItem x:Name="menuSpeedServer" Header="{x:Static resx:ResUI.menuSpeedServer}" /> Header="{x:Static resx:ResUI.menuTcpingServer}"
InputGesture="Ctrl+O" />
<MenuItem
x:Name="menuRealPingServer"
Header="{x:Static resx:ResUI.menuRealPingServer}"
InputGesture="Ctrl+R" />
<MenuItem
x:Name="menuSpeedServer"
Header="{x:Static resx:ResUI.menuSpeedServer}"
InputGesture="Ctrl+T" />
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" /> <MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
<Separator /> <Separator />
<MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}"> <MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
@ -130,19 +156,40 @@
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}"> <MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
<MenuItem x:Name="menuMoveTop" Header="{x:Static resx:ResUI.menuMoveTop}" /> <MenuItem
<MenuItem x:Name="menuMoveUp" Header="{x:Static resx:ResUI.menuMoveUp}" /> x:Name="menuMoveTop"
<MenuItem x:Name="menuMoveDown" Header="{x:Static resx:ResUI.menuMoveDown}" /> Header="{x:Static resx:ResUI.menuMoveTop}"
<MenuItem x:Name="menuMoveBottom" Header="{x:Static resx:ResUI.menuMoveBottom}" /> InputGesture="T" />
<MenuItem
x:Name="menuMoveUp"
Header="{x:Static resx:ResUI.menuMoveUp}"
InputGesture="U" />
<MenuItem
x:Name="menuMoveDown"
Header="{x:Static resx:ResUI.menuMoveDown}"
InputGesture="D" />
<MenuItem
x:Name="menuMoveBottom"
Header="{x:Static resx:ResUI.menuMoveBottom}"
InputGesture="B" />
</MenuItem> </MenuItem>
<MenuItem x:Name="menuSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" /> <MenuItem
x:Name="menuSelectAll"
Header="{x:Static resx:ResUI.menuSelectAll}"
InputGesture="Ctrl+A" />
<Separator /> <Separator />
<MenuItem x:Name="menuShareServer" Header="{x:Static resx:ResUI.menuShareServer}" /> <MenuItem
x:Name="menuShareServer"
Header="{x:Static resx:ResUI.menuShareServer}"
InputGesture="Ctrl+F" />
<MenuItem Header="{x:Static resx:ResUI.menuExportConfig}"> <MenuItem Header="{x:Static resx:ResUI.menuExportConfig}">
<MenuItem x:Name="menuExport2ClientConfig" Header="{x:Static resx:ResUI.menuExport2ClientConfig}" /> <MenuItem x:Name="menuExport2ClientConfig" Header="{x:Static resx:ResUI.menuExport2ClientConfig}" />
<MenuItem x:Name="menuExport2ClientConfigClipboard" Header="{x:Static resx:ResUI.menuExport2ClientConfigClipboard}" /> <MenuItem x:Name="menuExport2ClientConfigClipboard" Header="{x:Static resx:ResUI.menuExport2ClientConfigClipboard}" />
<Separator /> <Separator />
<MenuItem x:Name="menuExport2ShareUrl" Header="{x:Static resx:ResUI.menuExport2ShareUrl}" /> <MenuItem
x:Name="menuExport2ShareUrl"
Header="{x:Static resx:ResUI.menuExport2ShareUrl}"
InputGesture="Ctrl+C" />
<MenuItem x:Name="menuExport2ShareUrlBase64" Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" /> <MenuItem x:Name="menuExport2ShareUrlBase64" Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" />
</MenuItem> </MenuItem>
<Separator /> <Separator />

View file

@ -49,6 +49,9 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.btnAddSub).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.btnAddSub).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.EditSubCmd, v => v.btnEditSub).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.EditSubCmd, v => v.btnEditSub).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.EditSubCmd, v => v.menuSubEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.menuSubAdd).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.DeleteSubCmd, v => v.menuSubDelete).DisposeWith(disposables);
//servers delete //servers delete
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.menuEditServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.menuEditServer).DisposeWith(disposables);
@ -313,33 +316,37 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
} }
else else
{ {
if (e.Key is Key.Enter or Key.Return) switch (e.Key)
{ {
ViewModel?.SetDefaultServer(); case Key.Enter:
} //case Key.Return:
else if (e.Key == Key.Delete) ViewModel?.SetDefaultServer();
{ break;
ViewModel?.RemoveServerAsync();
} case Key.Delete:
else if (e.Key == Key.T) case Key.Back:
{ ViewModel?.RemoveServerAsync();
ViewModel?.MoveServer(EMove.Top); break;
}
else if (e.Key == Key.U) case Key.T:
{ ViewModel?.MoveServer(EMove.Top);
ViewModel?.MoveServer(EMove.Up); break;
}
else if (e.Key == Key.D) case Key.U:
{ ViewModel?.MoveServer(EMove.Up);
ViewModel?.MoveServer(EMove.Down); break;
}
else if (e.Key == Key.B) case Key.D:
{ ViewModel?.MoveServer(EMove.Down);
ViewModel?.MoveServer(EMove.Bottom); break;
}
else if (e.Key == Key.Escape) case Key.B:
{ ViewModel?.MoveServer(EMove.Bottom);
ViewModel?.ServerSpeedtestStop(); break;
case Key.Escape:
ViewModel?.ServerSpeedtestStop();
break;
} }
} }
} }

View file

@ -184,14 +184,32 @@
<DataGrid.ContextMenu> <DataGrid.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem x:Name="menuRuleAdd2" Header="{x:Static resx:ResUI.menuRuleAdd}" /> <MenuItem x:Name="menuRuleAdd2" Header="{x:Static resx:ResUI.menuRuleAdd}" />
<MenuItem x:Name="menuRuleRemove" Header="{x:Static resx:ResUI.menuRuleRemove}" /> <MenuItem
<MenuItem x:Name="menuRuleSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" /> x:Name="menuRuleRemove"
Header="{x:Static resx:ResUI.menuRuleRemove}"
InputGesture="Back" />
<MenuItem
x:Name="menuRuleSelectAll"
Header="{x:Static resx:ResUI.menuSelectAll}"
InputGesture="Ctrl+A" />
<MenuItem x:Name="menuRuleExportSelected" Header="{x:Static resx:ResUI.menuRuleExportSelected}" /> <MenuItem x:Name="menuRuleExportSelected" Header="{x:Static resx:ResUI.menuRuleExportSelected}" />
<Separator /> <Separator />
<MenuItem x:Name="menuMoveTop" Header="{x:Static resx:ResUI.menuMoveTop}" /> <MenuItem
<MenuItem x:Name="menuMoveUp" Header="{x:Static resx:ResUI.menuMoveUp}" /> x:Name="menuMoveTop"
<MenuItem x:Name="menuMoveDown" Header="{x:Static resx:ResUI.menuMoveDown}" /> Header="{x:Static resx:ResUI.menuMoveTop}"
<MenuItem x:Name="menuMoveBottom" Header="{x:Static resx:ResUI.menuMoveBottom}" /> InputGesture="T" />
<MenuItem
x:Name="menuMoveUp"
Header="{x:Static resx:ResUI.menuMoveUp}"
InputGesture="U" />
<MenuItem
x:Name="menuMoveDown"
Header="{x:Static resx:ResUI.menuMoveDown}"
InputGesture="D" />
<MenuItem
x:Name="menuMoveBottom"
Header="{x:Static resx:ResUI.menuMoveBottom}"
InputGesture="B" />
</ContextMenu> </ContextMenu>
</DataGrid.ContextMenu> </DataGrid.ContextMenu>
<DataGrid.Columns> <DataGrid.Columns>

View file

@ -140,25 +140,28 @@ public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingVie
} }
else else
{ {
if (e.Key == Key.T) switch (e.Key)
{ {
ViewModel?.MoveRule(EMove.Top); case Key.T:
} ViewModel?.MoveRule(EMove.Top);
else if (e.Key == Key.U) break;
{
ViewModel?.MoveRule(EMove.Up); case Key.U:
} ViewModel?.MoveRule(EMove.Up);
else if (e.Key == Key.D) break;
{
ViewModel?.MoveRule(EMove.Down); case Key.D:
} ViewModel?.MoveRule(EMove.Down);
else if (e.Key == Key.B) break;
{
ViewModel?.MoveRule(EMove.Bottom); case Key.B:
} ViewModel?.MoveRule(EMove.Bottom);
else if (e.Key == Key.Delete) break;
{
ViewModel?.RuleRemoveAsync(); case Key.Delete:
case Key.Back:
ViewModel?.RuleRemoveAsync();
break;
} }
} }
} }

View file

@ -99,9 +99,18 @@
<DataGrid.ContextMenu> <DataGrid.ContextMenu>
<ContextMenu> <ContextMenu>
<MenuItem x:Name="menuRoutingAdvancedAdd" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" /> <MenuItem x:Name="menuRoutingAdvancedAdd" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
<MenuItem x:Name="menuRoutingAdvancedRemove" Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" /> <MenuItem
<MenuItem x:Name="menuRoutingAdvancedSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" /> x:Name="menuRoutingAdvancedRemove"
<MenuItem x:Name="menuRoutingAdvancedSetDefault" Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}" /> Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}"
InputGesture="Back" />
<MenuItem
x:Name="menuRoutingAdvancedSelectAll"
Header="{x:Static resx:ResUI.menuSelectAll}"
InputGesture="Ctrl+A" />
<MenuItem
x:Name="menuRoutingAdvancedSetDefault"
Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}"
InputGesture="Enter" />
<Separator /> <Separator />
<MenuItem x:Name="menuRoutingAdvancedImportRules" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" /> <MenuItem x:Name="menuRoutingAdvancedImportRules" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
</ContextMenu> </ContextMenu>

View file

@ -73,18 +73,27 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
{ {
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta) if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
{ {
if (e.Key == Key.A) switch (e.Key)
{ {
lstRoutings.SelectAll(); case Key.A:
lstRoutings.SelectAll();
break;
} }
} }
else if (e.Key is Key.Enter or Key.Return) else
{ {
ViewModel?.RoutingAdvancedSetDefault(); switch (e.Key)
} {
else if (e.Key == Key.Delete) case Key.Enter:
{ //case Key.Return:
ViewModel?.RoutingAdvancedRemoveAsync(); ViewModel?.RoutingAdvancedSetDefault();
break;
case Key.Delete:
case Key.Back:
ViewModel?.RoutingAdvancedRemoveAsync();
break;
}
} }
} }

View file

@ -13,7 +13,7 @@ public partial class ThemeSettingView : ReactiveUserControl<ThemeSettingViewMode
ViewModel = new ThemeSettingViewModel(); ViewModel = new ThemeSettingViewModel();
cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>(); cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>();
cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, 11).ToList(); cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, Global.MinFontSizeCount).ToList();
cmbCurrentLanguage.ItemsSource = Global.Languages; cmbCurrentLanguage.ItemsSource = Global.Languages;
this.WhenActivated(disposables => this.WhenActivated(disposables =>

View file

@ -62,7 +62,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -111,7 +111,7 @@
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3"> Grid.ColumnSpan="3">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -143,7 +143,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -191,7 +191,7 @@
</TabControl> </TabControl>
<TabControl> <TabControl>
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuServerList}"> <TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuServerList2}">
<DataGrid <DataGrid
x:Name="lstChild" x:Name="lstChild"
AutoGenerateColumns="False" AutoGenerateColumns="False"
@ -218,24 +218,29 @@
<MenuItem <MenuItem
x:Name="menuSelectAllChild" x:Name="menuSelectAllChild"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSelectAll}" /> Header="{x:Static resx:ResUI.menuSelectAll}"
InputGestureText="Ctrl+A" />
<Separator /> <Separator />
<MenuItem <MenuItem
x:Name="menuMoveTop" x:Name="menuMoveTop"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveTop}" /> Header="{x:Static resx:ResUI.menuMoveTop}"
InputGestureText="T" />
<MenuItem <MenuItem
x:Name="menuMoveUp" x:Name="menuMoveUp"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveUp}" /> Header="{x:Static resx:ResUI.menuMoveUp}"
InputGestureText="U" />
<MenuItem <MenuItem
x:Name="menuMoveDown" x:Name="menuMoveDown"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveDown}" /> Header="{x:Static resx:ResUI.menuMoveDown}"
InputGestureText="D" />
<MenuItem <MenuItem
x:Name="menuMoveBottom" x:Name="menuMoveBottom"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}" /> Header="{x:Static resx:ResUI.menuMoveBottom}"
InputGestureText="B" />
</ContextMenu> </ContextMenu>
</DataGrid.ContextMenu> </DataGrid.ContextMenu>
<DataGrid.Columns> <DataGrid.Columns>

View file

@ -91,25 +91,28 @@ public partial class AddGroupServerWindow
} }
else else
{ {
if (e.Key == Key.T) switch (e.Key)
{ {
ViewModel?.MoveServer(EMove.Top); case Key.T:
} ViewModel?.MoveServer(EMove.Top);
else if (e.Key == Key.U) break;
{
ViewModel?.MoveServer(EMove.Up); case Key.U:
} ViewModel?.MoveServer(EMove.Up);
else if (e.Key == Key.D) break;
{
ViewModel?.MoveServer(EMove.Down); case Key.D:
} ViewModel?.MoveServer(EMove.Down);
else if (e.Key == Key.B) break;
{
ViewModel?.MoveServer(EMove.Bottom); case Key.B:
} ViewModel?.MoveServer(EMove.Bottom);
else if (e.Key == Key.Delete) break;
{
ViewModel?.ChildRemoveAsync(); case Key.Delete:
case Key.Back:
ViewModel?.ChildRemoveAsync();
break;
} }
} }
} }

View file

@ -70,7 +70,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -87,7 +87,7 @@
Orientation="Horizontal"> Orientation="Horizontal">
<ComboBox <ComboBox
x:Name="cmbCoreType" x:Name="cmbCoreType"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbCoreType}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbCoreType}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
@ -157,7 +157,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -241,7 +241,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -300,7 +300,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -346,7 +346,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -430,7 +430,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -489,7 +489,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -559,7 +559,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -621,7 +621,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -715,7 +715,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -753,7 +753,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -899,7 +899,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -931,7 +931,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@ -1067,7 +1067,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>

View file

@ -1,4 +1,4 @@
<reactiveui:ReactiveUserControl <reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.BackupAndRestoreView" x:Class="v2rayN.Views.BackupAndRestoreView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@ -23,15 +23,6 @@
</UserControl.Resources> </UserControl.Resources>
<DockPanel Margin="{StaticResource Margin8}"> <DockPanel Margin="{StaticResource Margin8}">
<DockPanel Margin="{StaticResource Margin8}" DockPanel.Dock="Bottom"> <DockPanel Margin="{StaticResource Margin8}" DockPanel.Dock="Bottom">
<Button
Width="100"
Margin="{StaticResource Margin8}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
Content="{x:Static resx:ResUI.menuClose}"
DockPanel.Dock="Right"
IsCancel="True"
Style="{StaticResource DefButton}" />
<TextBlock <TextBlock
x:Name="txtMsg" x:Name="txtMsg"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"

View file

@ -1,4 +1,4 @@
<reactiveui:ReactiveUserControl <reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.CheckUpdateView" x:Class="v2rayN.Views.CheckUpdateView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@ -39,15 +39,6 @@
Content="{x:Static resx:ResUI.menuCheckUpdate}" Content="{x:Static resx:ResUI.menuCheckUpdate}"
IsDefault="True" IsDefault="True"
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
<Button
Width="100"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Right"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
Content="{x:Static resx:ResUI.menuClose}"
IsCancel="True"
Style="{StaticResource DefButton}" />
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>

View file

@ -142,7 +142,10 @@
<ListView.ContextMenu> <ListView.ContextMenu>
<ContextMenu Style="{StaticResource DefContextMenu}"> <ContextMenu Style="{StaticResource DefContextMenu}">
<MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" /> <MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" />
<MenuItem x:Name="menuProxiesSelectActivity" Header="{x:Static resx:ResUI.menuProxiesSelectActivity}" /> <MenuItem
x:Name="menuProxiesSelectActivity"
Header="{x:Static resx:ResUI.menuProxiesSelectActivity}"
InputGestureText="Enter" />
</ContextMenu> </ContextMenu>
</ListView.ContextMenu> </ListView.ContextMenu>
<ListView.ItemsPanel> <ListView.ItemsPanel>

View file

@ -11,8 +11,8 @@
xmlns:view="clr-namespace:v2rayN.Views" xmlns:view="clr-namespace:v2rayN.Views"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="v2rayN" Title="v2rayN"
Width="900" Width="1200"
Height="700" Height="800"
MinWidth="900" MinWidth="900"
x:TypeArguments="vms:MainWindowViewModel" x:TypeArguments="vms:MainWindowViewModel"
Icon="/Resources/v2rayN.ico" Icon="/Resources/v2rayN.ico"
@ -32,6 +32,7 @@
<materialDesign:DialogHost <materialDesign:DialogHost
materialDesign:TransitionAssist.DisableTransitions="True" materialDesign:TransitionAssist.DisableTransitions="True"
CloseOnClickAway="True"
Identifier="RootDialog" Identifier="RootDialog"
SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}"
Style="{StaticResource MaterialDesignEmbeddedDialogHost}"> Style="{StaticResource MaterialDesignEmbeddedDialogHost}">
@ -58,11 +59,13 @@
<MenuItem <MenuItem
x:Name="menuAddServerViaClipboard" x:Name="menuAddServerViaClipboard"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" /> Header="{x:Static resx:ResUI.menuAddServerViaClipboard}"
InputGestureText="Ctrl+V" />
<MenuItem <MenuItem
x:Name="menuAddServerViaScan" x:Name="menuAddServerViaScan"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddServerViaScan}" /> Header="{x:Static resx:ResUI.menuAddServerViaScan}"
InputGestureText="Ctrl+S" />
<MenuItem <MenuItem
x:Name="menuAddServerViaImage" x:Name="menuAddServerViaImage"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@ -229,23 +232,6 @@
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem
x:Name="menuReload"
Padding="{StaticResource MarginLeftRight8}"
AutomationProperties.Name="{x:Static resx:ResUI.menuReload}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon
Margin="{StaticResource MarginRight8}"
VerticalAlignment="Center"
Kind="Reload" />
<TextBlock Text="{x:Static resx:ResUI.menuReload}" />
</StackPanel>
</MenuItem.Header>
</MenuItem>
</Menu>
<Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem <MenuItem
x:Name="menuHelp" x:Name="menuHelp"
@ -265,6 +251,23 @@
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem
x:Name="menuReload"
Padding="{StaticResource MarginLeftRight8}"
AutomationProperties.Name="{x:Static resx:ResUI.menuReload}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon
Margin="{StaticResource MarginRight8}"
VerticalAlignment="Center"
Kind="Reload" />
<TextBlock Text="{x:Static resx:ResUI.menuReload}" />
</StackPanel>
</MenuItem.Header>
</MenuItem>
</Menu>
<Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem <MenuItem
x:Name="menuPromotion" x:Name="menuPromotion"

View file

@ -91,11 +91,13 @@
<MenuItem <MenuItem
x:Name="menuMsgViewSelectAll" x:Name="menuMsgViewSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" /> Header="{x:Static resx:ResUI.menuMsgViewSelectAll}"
InputGestureText="Ctrl+A" />
<MenuItem <MenuItem
x:Name="menuMsgViewCopy" x:Name="menuMsgViewCopy"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMsgViewCopy}" /> Header="{x:Static resx:ResUI.menuMsgViewCopy}"
InputGestureText="Ctrl+C" />
<MenuItem <MenuItem
x:Name="menuMsgViewCopyAll" x:Name="menuMsgViewCopyAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"

View file

@ -123,11 +123,13 @@
<MenuItem <MenuItem
x:Name="menuSetDefaultServer" x:Name="menuSetDefaultServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSetDefaultServer}" /> Header="{x:Static resx:ResUI.menuSetDefaultServer}"
InputGestureText="Enter" />
<MenuItem <MenuItem
x:Name="menuEditServer" x:Name="menuEditServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuEditServer}" /> Header="{x:Static resx:ResUI.menuEditServer}"
InputGestureText="Ctrl+D" />
<MenuItem <MenuItem
x:Name="menuCopyServer" x:Name="menuCopyServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@ -135,7 +137,8 @@
<MenuItem <MenuItem
x:Name="menuRemoveServer" x:Name="menuRemoveServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRemoveServer}" /> Header="{x:Static resx:ResUI.menuRemoveServer}"
InputGestureText="Back" />
<MenuItem <MenuItem
x:Name="menuRemoveDuplicateServer" x:Name="menuRemoveDuplicateServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@ -148,15 +151,18 @@
<MenuItem <MenuItem
x:Name="menuTcpingServer" x:Name="menuTcpingServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuTcpingServer}" /> Header="{x:Static resx:ResUI.menuTcpingServer}"
InputGestureText="Ctrl+O" />
<MenuItem <MenuItem
x:Name="menuRealPingServer" x:Name="menuRealPingServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRealPingServer}" /> Header="{x:Static resx:ResUI.menuRealPingServer}"
InputGestureText="Ctrl+R" />
<MenuItem <MenuItem
x:Name="menuSpeedServer" x:Name="menuSpeedServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSpeedServer}" /> Header="{x:Static resx:ResUI.menuSpeedServer}"
InputGestureText="Ctrl+T" />
<MenuItem <MenuItem
x:Name="menuSortServerResult" x:Name="menuSortServerResult"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@ -184,29 +190,35 @@
<MenuItem <MenuItem
x:Name="menuMoveTop" x:Name="menuMoveTop"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveTop}" /> Header="{x:Static resx:ResUI.menuMoveTop}"
InputGestureText="T" />
<MenuItem <MenuItem
x:Name="menuMoveUp" x:Name="menuMoveUp"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveUp}" /> Header="{x:Static resx:ResUI.menuMoveUp}"
InputGestureText="U" />
<MenuItem <MenuItem
x:Name="menuMoveDown" x:Name="menuMoveDown"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveDown}" /> Header="{x:Static resx:ResUI.menuMoveDown}"
InputGestureText="D" />
<MenuItem <MenuItem
x:Name="menuMoveBottom" x:Name="menuMoveBottom"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}" /> Header="{x:Static resx:ResUI.menuMoveBottom}"
InputGestureText="B" />
</MenuItem> </MenuItem>
<MenuItem <MenuItem
x:Name="menuSelectAll" x:Name="menuSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSelectAll}" /> Header="{x:Static resx:ResUI.menuSelectAll}"
InputGestureText="Ctrl+A" />
<Separator /> <Separator />
<MenuItem <MenuItem
x:Name="menuShareServer" x:Name="menuShareServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuShareServer}" /> Header="{x:Static resx:ResUI.menuShareServer}"
InputGestureText="Ctrl+F" />
<MenuItem Header="{x:Static resx:ResUI.menuExportConfig}"> <MenuItem Header="{x:Static resx:ResUI.menuExportConfig}">
<MenuItem <MenuItem
x:Name="menuExport2ClientConfig" x:Name="menuExport2ClientConfig"
@ -220,7 +232,8 @@
<MenuItem <MenuItem
x:Name="menuExport2ShareUrl" x:Name="menuExport2ShareUrl"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuExport2ShareUrl}" /> Header="{x:Static resx:ResUI.menuExport2ShareUrl}"
InputGestureText="Ctrl+C" />
<MenuItem <MenuItem
x:Name="menuExport2ShareUrlBase64" x:Name="menuExport2ShareUrlBase64"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"

View file

@ -292,33 +292,37 @@ public partial class ProfilesView
} }
else else
{ {
if (e.Key is Key.Enter or Key.Return) switch (e.Key)
{ {
ViewModel?.SetDefaultServer(); case Key.Enter:
} //case Key.Return:
else if (e.Key == Key.Delete) ViewModel?.SetDefaultServer();
{ break;
ViewModel?.RemoveServerAsync();
} case Key.Delete:
else if (e.Key == Key.T) case Key.Back:
{ ViewModel?.RemoveServerAsync();
ViewModel?.MoveServer(EMove.Top); break;
}
else if (e.Key == Key.U) case Key.T:
{ ViewModel?.MoveServer(EMove.Top);
ViewModel?.MoveServer(EMove.Up); break;
}
else if (e.Key == Key.D) case Key.U:
{ ViewModel?.MoveServer(EMove.Up);
ViewModel?.MoveServer(EMove.Down); break;
}
else if (e.Key == Key.B) case Key.D:
{ ViewModel?.MoveServer(EMove.Down);
ViewModel?.MoveServer(EMove.Bottom); break;
}
else if (e.Key == Key.Escape) case Key.B:
{ ViewModel?.MoveServer(EMove.Bottom);
ViewModel?.ServerSpeedtestStop(); break;
case Key.Escape:
ViewModel?.ServerSpeedtestStop();
break;
} }
} }
} }

View file

@ -15,18 +15,7 @@
<sys:Double x:Key="QrcodeWidth">400</sys:Double> <sys:Double x:Key="QrcodeWidth">400</sys:Double>
</UserControl.Resources> </UserControl.Resources>
<DockPanel Margin="{StaticResource Margin8}"> <StackPanel Margin="{StaticResource Margin8}">
<StackPanel Margin="{StaticResource Margin8}" DockPanel.Dock="Bottom">
<Button
Width="100"
HorizontalAlignment="Right"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
Content="{x:Static resx:ResUI.menuClose}"
IsCancel="True"
IsDefault="True"
Style="{StaticResource DefButton}" />
</StackPanel>
<Grid Margin="{StaticResource Margin8}"> <Grid Margin="{StaticResource Margin8}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@ -51,5 +40,5 @@
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</Grid> </Grid>
</DockPanel> </StackPanel>
</UserControl> </UserControl>

View file

@ -263,11 +263,13 @@
<MenuItem <MenuItem
x:Name="menuRuleRemove" x:Name="menuRuleRemove"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRuleRemove}" /> Header="{x:Static resx:ResUI.menuRuleRemove}"
InputGestureText="Back" />
<MenuItem <MenuItem
x:Name="menuRuleSelectAll" x:Name="menuRuleSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSelectAll}" /> Header="{x:Static resx:ResUI.menuSelectAll}"
InputGestureText="Ctrl+A" />
<MenuItem <MenuItem
x:Name="menuRuleExportSelected" x:Name="menuRuleExportSelected"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@ -276,19 +278,23 @@
<MenuItem <MenuItem
x:Name="menuMoveTop" x:Name="menuMoveTop"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveTop}" /> Header="{x:Static resx:ResUI.menuMoveTop}"
InputGestureText="T" />
<MenuItem <MenuItem
x:Name="menuMoveUp" x:Name="menuMoveUp"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveUp}" /> Header="{x:Static resx:ResUI.menuMoveUp}"
InputGestureText="U" />
<MenuItem <MenuItem
x:Name="menuMoveDown" x:Name="menuMoveDown"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveDown}" /> Header="{x:Static resx:ResUI.menuMoveDown}"
InputGestureText="D" />
<MenuItem <MenuItem
x:Name="menuMoveBottom" x:Name="menuMoveBottom"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}" /> Header="{x:Static resx:ResUI.menuMoveBottom}"
InputGestureText="B" />
</ContextMenu> </ContextMenu>
</DataGrid.ContextMenu> </DataGrid.ContextMenu>
<DataGrid.Columns> <DataGrid.Columns>

View file

@ -140,25 +140,28 @@ public partial class RoutingRuleSettingWindow
} }
else else
{ {
if (e.Key == Key.T) switch (e.Key)
{ {
ViewModel?.MoveRule(EMove.Top); case Key.T:
} ViewModel?.MoveRule(EMove.Top);
else if (e.Key == Key.U) break;
{
ViewModel?.MoveRule(EMove.Up); case Key.U:
} ViewModel?.MoveRule(EMove.Up);
else if (e.Key == Key.D) break;
{
ViewModel?.MoveRule(EMove.Down); case Key.D:
} ViewModel?.MoveRule(EMove.Down);
else if (e.Key == Key.B) break;
{
ViewModel?.MoveRule(EMove.Bottom); case Key.B:
} ViewModel?.MoveRule(EMove.Bottom);
else if (e.Key == Key.Delete) break;
{
ViewModel?.RuleRemoveAsync(); case Key.Delete:
case Key.Back:
ViewModel?.RuleRemoveAsync();
break;
} }
} }
} }

View file

@ -144,15 +144,18 @@
<MenuItem <MenuItem
x:Name="menuRoutingAdvancedRemove" x:Name="menuRoutingAdvancedRemove"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" /> Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}"
InputGestureText="Back" />
<MenuItem <MenuItem
x:Name="menuRoutingAdvancedSelectAll" x:Name="menuRoutingAdvancedSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSelectAll}" /> Header="{x:Static resx:ResUI.menuSelectAll}"
InputGestureText="Ctrl+A" />
<MenuItem <MenuItem
x:Name="menuRoutingAdvancedSetDefault" x:Name="menuRoutingAdvancedSetDefault"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}" /> Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}"
InputGestureText="Enter" />
<Separator /> <Separator />
<MenuItem <MenuItem
x:Name="menuRoutingAdvancedImportRules" x:Name="menuRoutingAdvancedImportRules"

View file

@ -78,18 +78,27 @@ public partial class RoutingSettingWindow
{ {
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{ {
if (e.Key == Key.A) switch (e.Key)
{ {
lstRoutings.SelectAll(); case Key.A:
lstRoutings.SelectAll();
break;
} }
} }
else if (e.Key is Key.Enter or Key.Return) else
{ {
ViewModel?.RoutingAdvancedSetDefault(); switch (e.Key)
} {
else if (e.Key == Key.Delete) case Key.Enter:
{ //case Key.Return:
ViewModel?.RoutingAdvancedRemoveAsync(); ViewModel?.RoutingAdvancedSetDefault();
break;
case Key.Delete:
case Key.Back:
ViewModel?.RoutingAdvancedRemoveAsync();
break;
}
} }
} }

View file

@ -20,6 +20,7 @@
mc:Ignorable="d"> mc:Ignorable="d">
<materialDesign:DialogHost <materialDesign:DialogHost
materialDesign:TransitionAssist.DisableTransitions="True" materialDesign:TransitionAssist.DisableTransitions="True"
CloseOnClickAway="True"
Identifier="SubDialog" Identifier="SubDialog"
Style="{StaticResource MaterialDesignEmbeddedDialogHost}"> Style="{StaticResource MaterialDesignEmbeddedDialogHost}">
<DockPanel> <DockPanel>

View file

@ -13,7 +13,7 @@ public partial class ThemeSettingView
ViewModel = new ThemeSettingViewModel(); ViewModel = new ThemeSettingViewModel();
cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>().Take(3).ToList(); cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>().Take(3).ToList();
cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, 11).ToList(); cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, Global.MinFontSizeCount).ToList();
cmbCurrentLanguage.ItemsSource = Global.Languages; cmbCurrentLanguage.ItemsSource = Global.Languages;
this.WhenActivated(disposables => this.WhenActivated(disposables =>