Compare commits
28 Commits
7.15.5
...
d727ff40bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d727ff40bb | ||
|
|
1b5069a933 | ||
|
|
18ea6fdc00 | ||
|
|
67494108ad | ||
|
|
38b2a7d2ca | ||
|
|
bf3703bca1 | ||
|
|
554632cc07 | ||
|
|
12fc3e9566 | ||
|
|
c2ef3a4a8c | ||
|
|
86eb8297dd | ||
|
|
c63d4e83f9 | ||
|
|
bf1fb0f92e | ||
|
|
3c4865982b | ||
|
|
22c233f0cd | ||
|
|
b2d6282755 | ||
|
|
c8d89e3dce | ||
|
|
d3b1810eab | ||
|
|
51409a3e28 | ||
|
|
1a0f50a41e | ||
|
|
83d4a9c18e | ||
|
|
b4c20e7b81 | ||
|
|
7c76308c93 | ||
|
|
f28fa31c14 | ||
|
|
bbedc4dbb1 | ||
|
|
ecf42cb85d | ||
|
|
e4701d6703 | ||
|
|
54a47d00a3 | ||
|
|
964572817b |
108
.github/workflows/build-linux.yml
vendored
108
.github/workflows/build-linux.yml
vendored
@@ -9,6 +9,12 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
- 'V*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
env:
|
env:
|
||||||
OutputArch: "linux-64"
|
OutputArch: "linux-64"
|
||||||
@@ -21,7 +27,6 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
configuration: [Release]
|
configuration: [Release]
|
||||||
|
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -31,21 +36,21 @@ jobs:
|
|||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
fetch-depth: '0'
|
fetch-depth: '0'
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v5.0.0
|
uses: actions/setup-dotnet@v5.0.0
|
||||||
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 --self-contained=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 --self-contained=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 --self-contained=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 --self-contained=true -p:PublishTrimmed=true -o "$OutputPathArm64"
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.2
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: v2rayN-linux
|
name: v2rayN-linux
|
||||||
path: |
|
path: |
|
||||||
@@ -56,8 +61,8 @@ jobs:
|
|||||||
if: github.event.inputs.release_tag != ''
|
if: github.event.inputs.release_tag != ''
|
||||||
run: |
|
run: |
|
||||||
chmod 755 package-debian.sh
|
chmod 755 package-debian.sh
|
||||||
./package-debian.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
./package-debian.sh "$OutputArch" "$OutputPath64" "${{ github.event.inputs.release_tag }}"
|
||||||
./package-debian.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
./package-debian.sh "$OutputArchArm" "$OutputPathArm64" "${{ github.event.inputs.release_tag }}"
|
||||||
|
|
||||||
- name: Upload deb to release
|
- name: Upload deb to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
@@ -68,28 +73,13 @@ jobs:
|
|||||||
file_glob: true
|
file_glob: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
||||||
- name: Package AppImage
|
|
||||||
if: github.event.inputs.release_tag != ''
|
|
||||||
run: |
|
|
||||||
chmod a+x package-appimage.sh
|
|
||||||
./package-appimage.sh
|
|
||||||
|
|
||||||
- name: Upload AppImage to release
|
|
||||||
uses: svenstaro/upload-release-action@v2
|
|
||||||
if: github.event.inputs.release_tag != ''
|
|
||||||
with:
|
|
||||||
file: ${{ github.workspace }}/v2rayN*.AppImage
|
|
||||||
tag: ${{ github.event.inputs.release_tag }}
|
|
||||||
file_glob: true
|
|
||||||
prerelease: true
|
|
||||||
|
|
||||||
# release zip archive
|
# release zip archive
|
||||||
- name: Package release zip archive
|
- name: Package release zip archive
|
||||||
if: github.event.inputs.release_tag != ''
|
if: github.event.inputs.release_tag != ''
|
||||||
run: |
|
run: |
|
||||||
chmod 755 package-release-zip.sh
|
chmod 755 package-release-zip.sh
|
||||||
./package-release-zip.sh $OutputArch $OutputPath64
|
./package-release-zip.sh "$OutputArch" "$OutputPath64"
|
||||||
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
./package-release-zip.sh "$OutputArchArm" "$OutputPathArm64"
|
||||||
|
|
||||||
- name: Upload zip archive to release
|
- name: Upload zip archive to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
@@ -100,36 +90,62 @@ jobs:
|
|||||||
file_glob: true
|
file_glob: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
||||||
# release RHEL package
|
rpm:
|
||||||
- name: Package RPM (RHEL-family)
|
needs: build
|
||||||
if: github.event.inputs.release_tag != ''
|
if: |
|
||||||
|
(github.event_name == 'workflow_dispatch' && github.event.inputs.release_tag != '') ||
|
||||||
|
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
container:
|
||||||
|
image: quay.io/almalinuxorg/10-base:latest
|
||||||
|
options: --platform=linux/amd64/v2
|
||||||
|
env:
|
||||||
|
RELEASE_TAG: ${{ github.event.inputs.release_tag != '' && github.event.inputs.release_tag || github.ref_name }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Prepare tools (Red Hat)
|
||||||
run: |
|
run: |
|
||||||
chmod 755 package-rhel.sh
|
dnf -y makecache
|
||||||
# Build for both x86_64 and aarch64 in one go (explicit version passed; no --buildfrom)
|
dnf -y install epel-release
|
||||||
./package-rhel.sh "${{ github.event.inputs.release_tag }}" --arch all
|
dnf -y install sudo git rpm-build rpmdevtools dnf-plugins-core rsync findutils tar gzip unzip which
|
||||||
|
|
||||||
|
- name: Checkout repo (for scripts)
|
||||||
|
uses: actions/checkout@v5.0.0
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
fetch-depth: '0'
|
||||||
|
|
||||||
|
- name: Restore build artifacts
|
||||||
|
uses: actions/download-artifact@v6
|
||||||
|
with:
|
||||||
|
name: v2rayN-linux
|
||||||
|
path: ${{ github.workspace }}/v2rayN/Release
|
||||||
|
|
||||||
|
- name: Ensure script permissions
|
||||||
|
run: chmod 755 package-rhel.sh
|
||||||
|
|
||||||
|
- name: Package RPM (RHEL-family)
|
||||||
|
run: ./package-rhel.sh "${RELEASE_TAG}" --arch all
|
||||||
|
|
||||||
- name: Collect RPMs into workspace
|
- name: Collect RPMs into workspace
|
||||||
if: github.event.inputs.release_tag != ''
|
|
||||||
run: |
|
run: |
|
||||||
mkdir -p "${{ github.workspace }}/dist/rpm"
|
mkdir -p "$GITHUB_WORKSPACE/dist/rpm"
|
||||||
rsync -av "$HOME/rpmbuild/RPMS/" "${{ github.workspace }}/dist/rpm/"
|
rsync -av "$HOME/rpmbuild/RPMS/" "$GITHUB_WORKSPACE/dist/rpm/" || true
|
||||||
# Rename to requested filenames
|
find "$GITHUB_WORKSPACE/dist/rpm" -name "v2rayN-*-1*.x86_64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm/v2rayN-linux-rhel-64.rpm" \; || true
|
||||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.x86_64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-x64.rpm" \; || true
|
find "$GITHUB_WORKSPACE/dist/rpm" -name "v2rayN-*-1*.aarch64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true
|
||||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.aarch64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true
|
echo "==== Dist tree ===="
|
||||||
|
ls -R "$GITHUB_WORKSPACE/dist/rpm" || true
|
||||||
|
|
||||||
- name: Upload RPM artifacts
|
- name: Upload RPM artifacts
|
||||||
if: github.event.inputs.release_tag != ''
|
uses: actions/upload-artifact@v5.0.0
|
||||||
uses: actions/upload-artifact@v4.6.2
|
|
||||||
with:
|
with:
|
||||||
name: v2rayN-rpm
|
name: v2rayN-rpm
|
||||||
path: |
|
path: dist/rpm/**/*.rpm
|
||||||
${{ github.workspace }}/dist/rpm/**/*.rpm
|
|
||||||
|
|
||||||
- name: Upload RPMs to release
|
- name: Upload RPMs to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
if: github.event.inputs.release_tag != ''
|
|
||||||
with:
|
with:
|
||||||
file: ${{ github.workspace }}/dist/rpm/**/*.rpm
|
file: dist/rpm/**/*.rpm
|
||||||
tag: ${{ github.event.inputs.release_tag }}
|
tag: ${{ env.RELEASE_TAG }}
|
||||||
file_glob: true
|
file_glob: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|||||||
2
.github/workflows/build-osx.yml
vendored
2
.github/workflows/build-osx.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
|||||||
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 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.2
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: v2rayN-macos
|
name: v2rayN-macos
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
2
.github/workflows/build-windows-desktop.yml
vendored
2
.github/workflows/build-windows-desktop.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
|||||||
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 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.2
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: v2rayN-windows-desktop
|
name: v2rayN-windows-desktop
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
2
.github/workflows/build-windows.yml
vendored
2
.github/workflows/build-windows.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.2
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: v2rayN-windows
|
name: v2rayN-windows
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Install deps
|
|
||||||
sudo apt update -y
|
|
||||||
sudo apt install -y libfuse2 wget file
|
|
||||||
|
|
||||||
# Get tools
|
|
||||||
wget -qO appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
|
||||||
chmod +x appimagetool
|
|
||||||
|
|
||||||
# x86_64 AppDir
|
|
||||||
APPDIR_X64="AppDir-x86_64"
|
|
||||||
rm -rf "$APPDIR_X64"
|
|
||||||
mkdir -p "$APPDIR_X64/usr/lib/v2rayN" "$APPDIR_X64/usr/bin" "$APPDIR_X64/usr/share/applications" "$APPDIR_X64/usr/share/pixmaps"
|
|
||||||
cp -rf "$OutputPath64"/* "$APPDIR_X64/usr/lib/v2rayN" || true
|
|
||||||
[ -f "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_X64/usr/share/pixmaps/v2rayN.png" || true
|
|
||||||
[ -f "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_X64/v2rayN.png" || true
|
|
||||||
|
|
||||||
printf '%s\n' '#!/bin/sh' 'HERE="$(dirname "$(readlink -f "$0")")"' 'cd "$HERE/usr/lib/v2rayN"' 'exec "$HERE/usr/lib/v2rayN/v2rayN" "$@"' > "$APPDIR_X64/AppRun"
|
|
||||||
chmod +x "$APPDIR_X64/AppRun"
|
|
||||||
ln -sf usr/lib/v2rayN/v2rayN "$APPDIR_X64/usr/bin/v2rayN"
|
|
||||||
cat > "$APPDIR_X64/v2rayN.desktop" <<EOF
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=v2rayN
|
|
||||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
|
||||||
Exec=v2rayN
|
|
||||||
Icon=v2rayN
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=Network;
|
|
||||||
EOF
|
|
||||||
install -Dm644 "$APPDIR_X64/v2rayN.desktop" "$APPDIR_X64/usr/share/applications/v2rayN.desktop"
|
|
||||||
|
|
||||||
ARCH=x86_64 ./appimagetool "$APPDIR_X64" "v2rayN-${OutputArch}.AppImage"
|
|
||||||
file "v2rayN-${OutputArch}.AppImage" | grep -q 'x86-64'
|
|
||||||
|
|
||||||
# aarch64 AppDir
|
|
||||||
APPDIR_ARM64="AppDir-aarch64"
|
|
||||||
rm -rf "$APPDIR_ARM64"
|
|
||||||
mkdir -p "$APPDIR_ARM64/usr/lib/v2rayN" "$APPDIR_ARM64/usr/bin" "$APPDIR_ARM64/usr/share/applications" "$APPDIR_ARM64/usr/share/pixmaps"
|
|
||||||
cp -rf "$OutputPathArm64"/* "$APPDIR_ARM64/usr/lib/v2rayN" || true
|
|
||||||
[ -f "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_ARM64/usr/share/pixmaps/v2rayN.png" || true
|
|
||||||
[ -f "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_ARM64/v2rayN.png" || true
|
|
||||||
|
|
||||||
printf '%s\n' '#!/bin/sh' 'HERE="$(dirname "$(readlink -f "$0")")"' 'cd "$HERE/usr/lib/v2rayN"' 'exec "$HERE/usr/lib/v2rayN/v2rayN" "$@"' > "$APPDIR_ARM64/AppRun"
|
|
||||||
chmod +x "$APPDIR_ARM64/AppRun"
|
|
||||||
ln -sf usr/lib/v2rayN/v2rayN "$APPDIR_ARM64/usr/bin/v2rayN"
|
|
||||||
cat > "$APPDIR_ARM64/v2rayN.desktop" <<EOF
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=v2rayN
|
|
||||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
|
||||||
Exec=v2rayN
|
|
||||||
Icon=v2rayN
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=Network;
|
|
||||||
EOF
|
|
||||||
install -Dm644 "$APPDIR_ARM64/v2rayN.desktop" "$APPDIR_ARM64/usr/share/applications/v2rayN.desktop"
|
|
||||||
|
|
||||||
# aarch64 runtime
|
|
||||||
wget -qO runtime-aarch64 https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-aarch64
|
|
||||||
chmod +x runtime-aarch64
|
|
||||||
|
|
||||||
# build aarch64 AppImage
|
|
||||||
ARCH=aarch64 ./appimagetool --runtime-file ./runtime-aarch64 "$APPDIR_ARM64" "v2rayN-${OutputArchArm}.AppImage"
|
|
||||||
file "v2rayN-${OutputArchArm}.AppImage" | grep -q 'ARM aarch64'
|
|
||||||
@@ -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: desktop-file-utils, xdg-utils
|
Depends: libc6 (>= 2.34), fontconfig (>= 2.13.1), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 8.32), bash (>= 5.1)
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,23 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ======================== Kernel version check (require >= 6.11) =======================
|
||||||
|
MIN_KERNEL_MAJOR=6
|
||||||
|
MIN_KERNEL_MINOR=11
|
||||||
|
KERNEL_FULL=$(uname -r)
|
||||||
|
KERNEL_MAJOR=$(echo "$KERNEL_FULL" | cut -d. -f1)
|
||||||
|
KERNEL_MINOR=$(echo "$KERNEL_FULL" | cut -d. -f2)
|
||||||
|
|
||||||
|
echo "[INFO] Detected kernel version: $KERNEL_FULL"
|
||||||
|
|
||||||
|
if (( KERNEL_MAJOR < MIN_KERNEL_MAJOR )) || { (( KERNEL_MAJOR == MIN_KERNEL_MAJOR )) && (( KERNEL_MINOR < MIN_KERNEL_MINOR )); }; then
|
||||||
|
echo "[ERROR] Kernel $KERNEL_FULL is too old. Requires Linux >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
||||||
|
echo "Please upgrade your system or use a newer container (e.g. Fedora 42+, RHEL 10+, Debian 13+)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[OK] Kernel version >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
||||||
|
|
||||||
# ===== Config & Parse arguments =========================================================
|
# ===== Config & Parse arguments =========================================================
|
||||||
VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty
|
VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty
|
||||||
WITH_CORE="both" # Default: bundle both xray+sing-box
|
WITH_CORE="both" # Default: bundle both xray+sing-box
|
||||||
@@ -614,8 +631,13 @@ 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: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrender, libXfixes, libXinerama, libxkbcommon
|
Requires: freetype, cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
||||||
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL, xdg-utils
|
Requires: glibc >= 2.34
|
||||||
|
Requires: fontconfig >= 2.13.1
|
||||||
|
Requires: desktop-file-utils >= 0.26
|
||||||
|
Requires: xdg-utils >= 1.1.3
|
||||||
|
Requires: coreutils >= 8.32
|
||||||
|
Requires: bash >= 5.1
|
||||||
|
|
||||||
%description
|
%description
|
||||||
v2rayN Linux for Red Hat Enterprise Linux
|
v2rayN Linux for Red Hat Enterprise Linux
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.15.5</Version>
|
<Version>7.15.7</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -6,19 +6,19 @@
|
|||||||
</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.7" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.8" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.7" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.8" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.7" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.8" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.7" />
|
<PackageVersion Include="ReactiveUI.Avalonia" Version="11.3.8" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||||
<PackageVersion Include="Downloader" Version="4.0.3" />
|
<PackageVersion Include="Downloader" Version="4.0.3" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.1" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.2" />
|
||||||
<PackageVersion Include="MaterialDesignThemes" Version="5.3.0" />
|
<PackageVersion Include="MaterialDesignThemes" Version="5.3.0" />
|
||||||
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||||
<PackageVersion Include="QRCoder" Version="1.7.0" />
|
<PackageVersion Include="QRCoder" Version="1.7.0" />
|
||||||
<PackageVersion Include="ReactiveUI" Version="20.4.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="20.4.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" />
|
||||||
<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" />
|
||||||
|
|||||||
@@ -35,9 +35,13 @@ public class JsonUtils
|
|||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static T DeepCopy<T>(T obj)
|
public static T? DeepCopy<T>(T? obj)
|
||||||
{
|
{
|
||||||
return Deserialize<T>(Serialize(obj, false))!;
|
if (obj is null)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
return Deserialize<T>(Serialize(obj, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,7 +71,7 @@ public class JsonUtils
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="strJson"></param>
|
/// <param name="strJson"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static JsonNode? ParseJson(string strJson)
|
public static JsonNode? ParseJson(string? strJson)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -116,7 +120,7 @@ public class JsonUtils
|
|||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string Serialize(object? obj, JsonSerializerOptions options)
|
public static string Serialize(object? obj, JsonSerializerOptions? options)
|
||||||
{
|
{
|
||||||
var result = string.Empty;
|
var result = string.Empty;
|
||||||
try
|
try
|
||||||
@@ -125,7 +129,7 @@ public class JsonUtils
|
|||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result = JsonSerializer.Serialize(obj, options);
|
result = JsonSerializer.Serialize(obj, options ?? _defaultSerializeOptions);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ public class Utils
|
|||||||
// 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("]"))
|
||||||
{
|
{
|
||||||
int closingBracketIndex = authority.LastIndexOf(']');
|
var closingBracketIndex = authority.LastIndexOf(']');
|
||||||
if (closingBracketIndex < authority.Length - 1 && authority[closingBracketIndex + 1] == ':')
|
if (closingBracketIndex < authority.Length - 1 && authority[closingBracketIndex + 1] == ':')
|
||||||
{
|
{
|
||||||
// Port exists
|
// Port exists
|
||||||
@@ -963,13 +963,13 @@ public class Utils
|
|||||||
|
|
||||||
#region Platform
|
#region Platform
|
||||||
|
|
||||||
public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
public static bool IsWindows() => OperatingSystem.IsWindows();
|
||||||
|
|
||||||
public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
public static bool IsLinux() => OperatingSystem.IsLinux();
|
||||||
|
|
||||||
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
public static bool IsOSX() => OperatingSystem.IsMacOS();
|
||||||
|
|
||||||
public static bool IsNonWindows() => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
public static bool IsNonWindows() => !OperatingSystem.IsWindows();
|
||||||
|
|
||||||
public static string GetExeName(string name)
|
public static string GetExeName(string name)
|
||||||
{
|
{
|
||||||
@@ -994,11 +994,6 @@ public class Utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPIMAGE")))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var exePath = GetExePath();
|
var exePath = GetExePath();
|
||||||
var baseDir = string.IsNullOrEmpty(exePath) ? StartupPath() : Path.GetDirectoryName(exePath) ?? "";
|
var baseDir = string.IsNullOrEmpty(exePath) ? StartupPath() : Path.GetDirectoryName(exePath) ?? "";
|
||||||
var p = baseDir.Replace('\\', '/');
|
var p = baseDir.Replace('\\', '/');
|
||||||
@@ -1008,11 +1003,6 @@ public class Utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.Contains("/.mount_", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p.StartsWith("/opt/v2rayN", StringComparison.OrdinalIgnoreCase))
|
if (p.StartsWith("/opt/v2rayN", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace ServiceLib.Common;
|
namespace ServiceLib.Common;
|
||||||
/*
|
/*
|
||||||
* See:
|
* See:
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ public enum ESpeedActionType
|
|||||||
Tcping,
|
Tcping,
|
||||||
Realping,
|
Realping,
|
||||||
Speedtest,
|
Speedtest,
|
||||||
Mixedtest
|
Mixedtest,
|
||||||
|
FastRealping
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ public class Global
|
|||||||
"zh-Hant",
|
"zh-Hant",
|
||||||
"en",
|
"en",
|
||||||
"fa-Ir",
|
"fa-Ir",
|
||||||
|
"fr",
|
||||||
"ru",
|
"ru",
|
||||||
"hu"
|
"hu"
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -447,13 +447,13 @@ public static class ConfigHandler
|
|||||||
/// <returns>0 if successful, -1 if failed</returns>
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> MoveServer(Config config, List<ProfileItem> lstProfile, int index, EMove eMove, int pos = -1)
|
public static async Task<int> MoveServer(Config config, List<ProfileItem> lstProfile, int index, EMove eMove, int pos = -1)
|
||||||
{
|
{
|
||||||
int count = lstProfile.Count;
|
var count = lstProfile.Count;
|
||||||
if (index < 0 || index > lstProfile.Count - 1)
|
if (index < 0 || index > lstProfile.Count - 1)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < lstProfile.Count; i++)
|
for (var i = 0; i < lstProfile.Count; i++)
|
||||||
{
|
{
|
||||||
ProfileExManager.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10);
|
ProfileExManager.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10);
|
||||||
}
|
}
|
||||||
@@ -527,7 +527,7 @@ public static class ConfigHandler
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
var ext = Path.GetExtension(fileName);
|
var ext = Path.GetExtension(fileName);
|
||||||
string newFileName = $"{Utils.GetGuid()}{ext}";
|
var newFileName = $"{Utils.GetGuid()}{ext}";
|
||||||
//newFileName = Path.Combine(Utile.GetTempPath(), newFileName);
|
//newFileName = Path.Combine(Utile.GetTempPath(), newFileName);
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -1221,6 +1221,7 @@ public static class ConfigHandler
|
|||||||
CoreType = coreType,
|
CoreType = coreType,
|
||||||
ConfigType = EConfigType.PolicyGroup,
|
ConfigType = EConfigType.PolicyGroup,
|
||||||
Remarks = remark,
|
Remarks = remark,
|
||||||
|
IsSub = false
|
||||||
};
|
};
|
||||||
if (!subId.IsNullOrEmpty())
|
if (!subId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
@@ -1355,7 +1356,7 @@ public static class ConfigHandler
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var profileItem = FmtHandler.ResolveConfig(str, out string msg);
|
var profileItem = FmtHandler.ResolveConfig(str, out var msg);
|
||||||
if (profileItem is null)
|
if (profileItem is null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -1439,7 +1440,7 @@ public static class ConfigHandler
|
|||||||
{
|
{
|
||||||
await RemoveServersViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
}
|
}
|
||||||
int count = 0;
|
var count = 0;
|
||||||
foreach (var it in lstProfiles)
|
foreach (var it in lstProfiles)
|
||||||
{
|
{
|
||||||
it.Subid = subid;
|
it.Subid = subid;
|
||||||
@@ -1529,7 +1530,7 @@ public static class ConfigHandler
|
|||||||
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
|
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
|
||||||
if (lstSsServer?.Count > 0)
|
if (lstSsServer?.Count > 0)
|
||||||
{
|
{
|
||||||
int counter = 0;
|
var counter = 0;
|
||||||
foreach (var ssItem in lstSsServer)
|
foreach (var ssItem in lstSsServer)
|
||||||
{
|
{
|
||||||
ssItem.Subid = subid;
|
ssItem.Subid = subid;
|
||||||
@@ -1704,7 +1705,7 @@ public static class ConfigHandler
|
|||||||
var maxSort = 0;
|
var maxSort = 0;
|
||||||
if (await SQLiteHelper.Instance.TableAsync<SubItem>().CountAsync() > 0)
|
if (await SQLiteHelper.Instance.TableAsync<SubItem>().CountAsync() > 0)
|
||||||
{
|
{
|
||||||
var lstSubs = (await AppManager.Instance.SubItems());
|
var lstSubs = await AppManager.Instance.SubItems();
|
||||||
maxSort = lstSubs.LastOrDefault()?.Sort ?? 0;
|
maxSort = lstSubs.LastOrDefault()?.Sort ?? 0;
|
||||||
}
|
}
|
||||||
item.Sort = maxSort + 1;
|
item.Sort = maxSort + 1;
|
||||||
@@ -1866,7 +1867,7 @@ public static class ConfigHandler
|
|||||||
/// <returns>0 if successful, -1 if failed</returns>
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> MoveRoutingRule(List<RulesItem> rules, int index, EMove eMove, int pos = -1)
|
public static async Task<int> MoveRoutingRule(List<RulesItem> rules, int index, EMove eMove, int pos = -1)
|
||||||
{
|
{
|
||||||
int count = rules.Count;
|
var count = rules.Count;
|
||||||
if (index < 0 || index > rules.Count - 1)
|
if (index < 0 || index > rules.Count - 1)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public static class CoreConfigHandler
|
|||||||
File.Delete(fileName);
|
File.Delete(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
string addressFileName = node.Address;
|
var addressFileName = node.Address;
|
||||||
if (!File.Exists(addressFileName))
|
if (!File.Exists(addressFileName))
|
||||||
{
|
{
|
||||||
addressFileName = Utils.GetConfigPath(addressFileName);
|
addressFileName = Utils.GetConfigPath(addressFileName);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class FmtHandler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string str = config.TrimEx();
|
var str = config.TrimEx();
|
||||||
if (str.IsNullOrEmpty())
|
if (str.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
msg = ResUI.FailedReadConfiguration;
|
msg = ResUI.FailedReadConfiguration;
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ public class Hysteria2Fmt : BaseFmt
|
|||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
return null;
|
return null;
|
||||||
string url = string.Empty;
|
var url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
var remark = string.Empty;
|
||||||
if (item.Remarks.IsNotEmpty())
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class ActionPrecheckManager(Config config)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.VLESS:
|
case EConfigType.VLESS:
|
||||||
if (item.Id.IsNullOrEmpty() || !Utils.IsGuidByParse(item.Id) && item.Id.Length > 30)
|
if (item.Id.IsNullOrEmpty() || (!Utils.IsGuidByParse(item.Id) && item.Id.Length > 30))
|
||||||
errors.Add(string.Format(ResUI.InvalidProperty, "Id"));
|
errors.Add(string.Format(ResUI.InvalidProperty, "Id"));
|
||||||
if (!Global.Flows.Contains(item.Flow))
|
if (!Global.Flows.Contains(item.Flow))
|
||||||
errors.Add(string.Format(ResUI.InvalidProperty, "Flow"));
|
errors.Add(string.Format(ResUI.InvalidProperty, "Flow"));
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class CoreAdminManager
|
|||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
sb.AppendLine("#!/bin/bash");
|
sb.AppendLine("#!/bin/bash");
|
||||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
||||||
sb.AppendLine($"sudo -S {cmdLine}");
|
sb.AppendLine($"exec sudo -S -- {cmdLine}");
|
||||||
var shFilePath = await FileManager.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
|
var shFilePath = await FileManager.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
|
||||||
|
|
||||||
var procService = new ProcessService(
|
var procService = new ProcessService(
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class ProfileItem : ReactiveObject
|
|||||||
|
|
||||||
public string GetSummary()
|
public string GetSummary()
|
||||||
{
|
{
|
||||||
var summary = $"[{(ConfigType).ToString()}] ";
|
var summary = $"[{ConfigType.ToString()}] ";
|
||||||
if (IsComplex())
|
if (IsComplex())
|
||||||
{
|
{
|
||||||
summary += $"[{CoreType.ToString()}]{Remarks}";
|
summary += $"[{CoreType.ToString()}]{Remarks}";
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ public class Dns4Ray
|
|||||||
public class DnsServer4Ray
|
public class DnsServer4Ray
|
||||||
{
|
{
|
||||||
public string? address { get; set; }
|
public string? address { get; set; }
|
||||||
|
public int? port { get; set; }
|
||||||
public List<string>? domains { get; set; }
|
public List<string>? domains { get; set; }
|
||||||
public bool? skipFallback { get; set; }
|
public bool? skipFallback { get; set; }
|
||||||
public List<string>? expectedIPs { get; set; }
|
public List<string>? expectedIPs { get; set; }
|
||||||
|
|||||||
11
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
11
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -19,7 +19,7 @@ namespace ServiceLib.Resx {
|
|||||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
public class ResUI {
|
public class ResUI {
|
||||||
@@ -1023,6 +1023,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Test real delay 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuFastRealPing {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuFastRealPing", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Full Config Template Setting 的本地化字符串。
|
/// 查找类似 Full Config Template Setting 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1596,4 +1596,7 @@
|
|||||||
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
<value>Resolve DNS server domains, requires IP</value>
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuFastRealPing" xml:space="preserve">
|
||||||
|
<value>Test real delay</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
1599
v2rayN/ServiceLib/Resx/ResUI.fr.resx
Normal file
1599
v2rayN/ServiceLib/Resx/ResUI.fr.resx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1596,4 +1596,7 @@
|
|||||||
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
<value>Resolve DNS server domains, requires IP</value>
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuFastRealPing" xml:space="preserve">
|
||||||
|
<value>Test real delay</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1596,4 +1596,7 @@
|
|||||||
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
<value>Resolve DNS server domains, requires IP</value>
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuFastRealPing" xml:space="preserve">
|
||||||
|
<value>Test real delay</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1596,4 +1596,7 @@
|
|||||||
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
<value>Resolve DNS server domains, requires IP</value>
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuFastRealPing" xml:space="preserve">
|
||||||
|
<value>Test real delay</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -427,7 +427,7 @@
|
|||||||
<value>路由设置</value>
|
<value>路由设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuServers" xml:space="preserve">
|
<data name="menuServers" xml:space="preserve">
|
||||||
<value>配置文件</value>
|
<value>配置项</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetting" xml:space="preserve">
|
<data name="menuSetting" xml:space="preserve">
|
||||||
<value>设置</value>
|
<value>设置</value>
|
||||||
@@ -1593,4 +1593,7 @@
|
|||||||
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
<value>解析 DNS 服务器域名,需指定为 IP</value>
|
<value>解析 DNS 服务器域名,需指定为 IP</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuFastRealPing" xml:space="preserve">
|
||||||
|
<value>一键测试真连接延迟</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
<value>匯出分享連結至剪貼簿成功</value>
|
<value>匯出分享連結至剪貼簿成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CheckServerSettings" xml:space="preserve">
|
<data name="CheckServerSettings" xml:space="preserve">
|
||||||
<value>請先檢查設定檔設定</value>
|
<value>請先檢查設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
||||||
<value>設定格式不正確</value>
|
<value>設定格式不正確</value>
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
<value>下載開始...</value>
|
<value>下載開始...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>轉換設定檔失敗</value>
|
<value>轉換設定失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedGenDefaultConfiguration" xml:space="preserve">
|
<data name="FailedGenDefaultConfiguration" xml:space="preserve">
|
||||||
<value>生成預設設定檔失敗</value>
|
<value>生成預設設定檔失敗</value>
|
||||||
@@ -142,10 +142,10 @@
|
|||||||
<value>獲取預設設定失敗</value>
|
<value>獲取預設設定失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||||
<value>匯入自訂設定設定檔失敗</value>
|
<value>匯入自訂設定失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedReadConfiguration" xml:space="preserve">
|
<data name="FailedReadConfiguration" xml:space="preserve">
|
||||||
<value>讀取設定檔失敗</value>
|
<value>讀取設定失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>請填寫正確格式的埠</value>
|
<value>請填寫正確格式的埠</value>
|
||||||
@@ -265,13 +265,13 @@
|
|||||||
<value>請選擇協定</value>
|
<value>請選擇協定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseSelectServer" xml:space="preserve">
|
<data name="PleaseSelectServer" xml:space="preserve">
|
||||||
<value>請先選擇設定檔</value>
|
<value>請先選擇設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||||
<value>設定檔去重完成。原數量: {0},現數量: {1}。</value>
|
<value>去重完成。原數量: {0},現數量: {1}。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveServer" xml:space="preserve">
|
<data name="RemoveServer" xml:space="preserve">
|
||||||
<value>是否確定移除設定檔?</value>
|
<value>是否確定移除?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>用戶端設定檔儲存在:{0}</value>
|
<value>用戶端設定檔儲存在:{0}</value>
|
||||||
@@ -283,10 +283,10 @@
|
|||||||
<value>設定成功。{0}</value>
|
<value>設定成功。{0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||||
<value>成功匯入自訂設定設定檔</value>
|
<value>成功匯入自訂節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
||||||
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
<value>成功從剪貼簿匯入 {0} 個節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>掃描匯入分享連結成功</value>
|
<value>掃描匯入分享連結成功</value>
|
||||||
@@ -385,7 +385,7 @@
|
|||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>請瀏覽匯入設定檔設定</value>
|
<value>請瀏覽匯入設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>測試中...</value>
|
<value>測試中...</value>
|
||||||
@@ -397,7 +397,7 @@
|
|||||||
<value>本機</value>
|
<value>本機</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgServerTitle" xml:space="preserve">
|
<data name="MsgServerTitle" xml:space="preserve">
|
||||||
<value>設定檔過濾,按 Enter 執行</value>
|
<value>過濾器,按 Enter 執行</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCheckUpdate" xml:space="preserve">
|
<data name="menuCheckUpdate" xml:space="preserve">
|
||||||
<value>檢查更新</value>
|
<value>檢查更新</value>
|
||||||
@@ -478,55 +478,55 @@
|
|||||||
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCopyServer" xml:space="preserve">
|
<data name="menuCopyServer" xml:space="preserve">
|
||||||
<value>複製所選設定檔</value>
|
<value>複製所選</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
||||||
<value>移除重複的設定檔</value>
|
<value>移除重複</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveServer" xml:space="preserve">
|
<data name="menuRemoveServer" xml:space="preserve">
|
||||||
<value>移除所選設定檔 (多選) (Delete)</value>
|
<value>移除所選 (多選) (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultServer" xml:space="preserve">
|
<data name="menuSetDefaultServer" xml:space="preserve">
|
||||||
<value>設為活動設定檔 (Enter)</value>
|
<value>設為活動 (Enter)</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>測試真連線延遲 (多選) (Ctrl+R)</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>測試速度 (多選) (Ctrl+T)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>測試設定檔延遲 Tcping (多選) (Ctrl+O)</value>
|
<value>測試延遲 Tcping (多選) (Ctrl+O)</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>匯出分享連結至剪貼簿 (多選) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>新增自訂設定設定檔</value>
|
<value>新增自訂節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
||||||
<value>新增 [Shadowsocks] 設定檔</value>
|
<value>新增 [Shadowsocks] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>新增 [SOCKS] 設定檔</value>
|
<value>新增 [SOCKS] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>新增 [Trojan] 設定檔</value>
|
<value>新增 [Trojan] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVlessServer" xml:space="preserve">
|
<data name="menuAddVlessServer" xml:space="preserve">
|
||||||
<value>新增 [VLESS] 設定檔</value>
|
<value>新增 [VLESS] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVmessServer" xml:space="preserve">
|
<data name="menuAddVmessServer" xml:space="preserve">
|
||||||
<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>全選 (Ctrl+A)</value>
|
||||||
@@ -676,7 +676,7 @@
|
|||||||
<value>Core: 基礎設定</value>
|
<value>Core: 基礎設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbCustomDnsRay" xml:space="preserve">
|
<data name="TbCustomDnsRay" xml:space="preserve">
|
||||||
<value>V2ray Custom DNS</value>
|
<value>v2ray 自訂 DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||||
<value>Core: KCP 設定</value>
|
<value>Core: KCP 設定</value>
|
||||||
@@ -691,7 +691,7 @@
|
|||||||
<value>Outbound Freedom domainStrategy</value>
|
<value>Outbound Freedom domainStrategy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
||||||
<value>在更新訂閱後自動調整設定檔列寬</value>
|
<value>在更新訂閱後自動調整列寬</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
|
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
|
||||||
<value>檢查 Pre-Release 更新 (請謹慎啟用)</value>
|
<value>檢查 Pre-Release 更新 (請謹慎啟用)</value>
|
||||||
@@ -700,7 +700,7 @@
|
|||||||
<value>例外</value>
|
<value>例外</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>例外:對於下列字元開頭的位址,不使用代理設定檔。使用分號 (;) 分隔。</value>
|
<value>例外:對於下列字元開頭的位址,不使用代理。使用分號 (;) 分隔。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>顯示即時速度(需重啟)</value>
|
<value>顯示即時速度(需重啟)</value>
|
||||||
@@ -748,7 +748,7 @@
|
|||||||
<value>系統代理設定</value>
|
<value>系統代理設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
||||||
<value>工具列右鍵選單設定檔展示數量限制</value>
|
<value>工具列右鍵選單設定展示數量限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
||||||
<value>開啟 UDP</value>
|
<value>開啟 UDP</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>分享 (Ctrl+F)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRouting" xml:space="preserve">
|
<data name="menuRouting" xml:space="preserve">
|
||||||
<value>路由</value>
|
<value>路由</value>
|
||||||
@@ -883,7 +883,7 @@
|
|||||||
<value>請勿將代理伺服器用於本機(Intranet)位址</value>
|
<value>請勿將代理伺服器用於本機(Intranet)位址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>一鍵多執行緒測試延遲和速度 (Ctrl+E)</value>
|
<value>一鍵延遲與速度測試 (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTestDelay" xml:space="preserve">
|
<data name="LvTestDelay" xml:space="preserve">
|
||||||
<value>延遲 (ms)</value>
|
<value>延遲 (ms)</value>
|
||||||
@@ -913,7 +913,7 @@
|
|||||||
<value>移至訂閱分組</value>
|
<value>移至訂閱分組</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>啟動設定檔拖放排序 (需重啟)</value>
|
<value>啟用拖放排序 (需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoRefresh" xml:space="preserve">
|
<data name="TbAutoRefresh" xml:space="preserve">
|
||||||
<value>自動重新整理</value>
|
<value>自動重新整理</value>
|
||||||
@@ -922,10 +922,10 @@
|
|||||||
<value>跳過測試</value>
|
<value>跳過測試</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuEditServer" xml:space="preserve">
|
<data name="menuEditServer" xml:space="preserve">
|
||||||
<value>編輯設定檔 (Ctrl+D)</value>
|
<value>編輯 (Ctrl+D)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
||||||
<value>主介面輕按兩下設為活動設定檔</value>
|
<value>主介面輕按兩下設為活動</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingCompleted" xml:space="preserve">
|
<data name="SpeedtestingCompleted" xml:space="preserve">
|
||||||
<value>測試完成</value>
|
<value>測試完成</value>
|
||||||
@@ -943,7 +943,7 @@
|
|||||||
<value>目前字型 (需重啟)</value>
|
<value>目前字型 (需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>複製字型 TTF/TTC 檔案到目錄 guiFonts,重啟設定</value>
|
<value>複製字型 TTF/TTC 檔案到目錄 guiFonts,重新啟動後生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>Pac 連接埠 = +3;Xray API 連接埠 = +4;mihomo API 連接埠 = +5;</value>
|
<value>Pac 連接埠 = +3;Xray API 連接埠 = +4;mihomo API 連接埠 = +5;</value>
|
||||||
@@ -1003,10 +1003,10 @@
|
|||||||
<value>不需要轉換時請留空</value>
|
<value>不需要轉換時請留空</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuDNSSetting" xml:space="preserve">
|
<data name="menuDNSSetting" xml:space="preserve">
|
||||||
<value>DNS 設定</value>
|
<value>DNS設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbCustomDnsSingbox" xml:space="preserve">
|
<data name="TbCustomDnsSingbox" xml:space="preserve">
|
||||||
<value>sing-box Custom DNS</value>
|
<value>sing-box 自訂 DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
||||||
<value>請填寫 DNS JSON 結構,點擊查看檔案</value>
|
<value>請填寫 DNS JSON 結構,點擊查看檔案</value>
|
||||||
@@ -1030,7 +1030,7 @@
|
|||||||
<value>Domain</value>
|
<value>Domain</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHysteria2Server" xml:space="preserve">
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
<value>添加 [Hysteria2] 設定檔</value>
|
<value>新增 [Hysteria2] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||||
<value>Hysteria 最大頻寬 (Up/Dw)</value>
|
<value>Hysteria 最大頻寬 (Up/Dw)</value>
|
||||||
@@ -1039,19 +1039,19 @@
|
|||||||
<value>使用系統 hosts</value>
|
<value>使用系統 hosts</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>新增 [TUIC] 設定檔</value>
|
<value>新增 [TUIC] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbHeaderType8" xml:space="preserve">
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
<value>擁塞控制算法</value>
|
<value>擁塞控制算法</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfile" xml:space="preserve">
|
<data name="LvPrevProfile" xml:space="preserve">
|
||||||
<value>前置代理設定檔別名</value>
|
<value>前置代理節點別名</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvNextProfile" xml:space="preserve">
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
<value>落地代理設定檔別名</value>
|
<value>落地代理節點別名</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfileTip" xml:space="preserve">
|
<data name="LvPrevProfileTip" xml:space="preserve">
|
||||||
<value>請確保設定檔別名存在並且唯一</value>
|
<value>請確保節點別名存在並且唯一</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunAutoRoute" xml:space="preserve">
|
<data name="TbSettingsTunAutoRoute" xml:space="preserve">
|
||||||
<value>自動路由</value>
|
<value>自動路由</value>
|
||||||
@@ -1072,7 +1072,7 @@
|
|||||||
<value>啟用 IPv6</value>
|
<value>啟用 IPv6</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
<value>添加 [WireGuard] 設定檔</value>
|
<value>新增 [WireGuard] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPrivateKey" xml:space="preserve">
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
<value>PrivateKey</value>
|
<value>PrivateKey</value>
|
||||||
@@ -1105,7 +1105,7 @@
|
|||||||
<value>*grpc Authority</value>
|
<value>*grpc Authority</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHttpServer" xml:space="preserve">
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
<value>新增 [HTTP] 設定檔</value>
|
<value>新增 [HTTP] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>和分組前置代理衝突</value>
|
<value>和分組前置代理衝突</value>
|
||||||
@@ -1219,13 +1219,13 @@
|
|||||||
<value>匯出分享連結至剪貼簿 (多選) Base64 編碼</value>
|
<value>匯出分享連結至剪貼簿 (多選) Base64 編碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>匯出所選設定檔完整設定至剪貼簿</value>
|
<value>匯出所選完整設定至剪貼簿</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>顯示或隱藏主介面</value>
|
<value>顯示或隱藏主介面</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>自訂設定的 Socks 連接埠</value>
|
<value>自訂 Socks 連接埠</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuBackupAndRestore" xml:space="preserve">
|
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||||
<value>備份和還原</value>
|
<value>備份和還原</value>
|
||||||
@@ -1309,7 +1309,7 @@
|
|||||||
<value>請不要使用不安全的 HTTP 協定訂閱位址</value>
|
<value>請不要使用不安全的 HTTP 協定訂閱位址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||||
<value>安裝字體到系統中,選擇或填入字體名稱,重新啟動設定</value>
|
<value>安裝字體到系統中,選擇或填入字體名稱,重新啟動後生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExitTips" xml:space="preserve">
|
<data name="menuExitTips" xml:space="preserve">
|
||||||
<value>是否確定退出?</value>
|
<value>是否確定退出?</value>
|
||||||
@@ -1336,7 +1336,7 @@
|
|||||||
<value>多執行緒測試時的並發數量</value>
|
<value>多執行緒測試時的並發數量</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>例外:對於下列位址不使用代理設定檔,使用逗號 (,) 分隔。</value>
|
<value>例外:對於下列位址不使用代理,使用逗號 (,) 分隔。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||||
<value>流量探測類型</value>
|
<value>流量探測類型</value>
|
||||||
@@ -1372,31 +1372,31 @@
|
|||||||
<value>會覆蓋埠,多組時用逗號 (,) 隔開</value>
|
<value>會覆蓋埠,多組時用逗號 (,) 隔開</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||||
<value>Generate Policy Group from Multiple Profiles</value>
|
<value>多選生成策略組</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||||
<value>多設定檔隨機 Xray</value>
|
<value>多選隨機 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>多設定檔負載平衡 Xray</value>
|
<value>多選負載平衡 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>多設定檔最低延遲 Xray</value>
|
<value>多選最低延遲 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>多設定檔最穩定 Xray</value>
|
<value>多選最穩定 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>多設定檔最低延遲 sing-box</value>
|
<value>多選最低延遲 sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>匯出設定檔</value>
|
<value>匯出</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
<value>目前連接資訊測試地址</value>
|
<value>目前連接資訊測試地址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
<value>可以填寫設定檔別名,請確保存在並唯一</value>
|
<value>可以填寫節點別名,請確保存在並唯一</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
<value>密碼錯誤,請重試。</value>
|
<value>密碼錯誤,請重試。</value>
|
||||||
@@ -1405,192 +1405,195 @@
|
|||||||
<value>Mldsa65Verify</value>
|
<value>Mldsa65Verify</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddAnytlsServer" xml:space="preserve">
|
<data name="menuAddAnytlsServer" xml:space="preserve">
|
||||||
<value>新增 [Anytls] 設定檔</value>
|
<value>新增 [Anytls] 節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRemoteDNS" xml:space="preserve">
|
<data name="TbRemoteDNS" xml:space="preserve">
|
||||||
<value>Remote DNS</value>
|
<value>遠程 DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDomesticDNS" xml:space="preserve">
|
<data name="TbDomesticDNS" xml:space="preserve">
|
||||||
<value>Domestic DNS</value>
|
<value>直連 DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRemoteDNSTips" xml:space="preserve">
|
<data name="TbRemoteDNSTips" xml:space="preserve">
|
||||||
<value>Via proxy — please ensure remote availability</value>
|
<value>通过代理,请确保远程可用</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbXrayFreedomStrategy" xml:space="preserve">
|
<data name="TbXrayFreedomStrategy" xml:space="preserve">
|
||||||
<value>xray Freedom Resolution Strategy</value>
|
<value>xray freedom 解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
|
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
|
||||||
<value>sing-box Direct Resolution Strategy</value>
|
<value>sing-box 直連解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
|
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
|
||||||
<value>sing-box Remote Resolution Strategy</value>
|
<value>sing-box 遠程解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAddCommonDNSHosts" xml:space="preserve">
|
<data name="TbAddCommonDNSHosts" xml:space="preserve">
|
||||||
<value>Add Common DNS Hosts</value>
|
<value>新增常用 DNS Hosts</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIP" xml:space="preserve">
|
<data name="TbFakeIP" xml:space="preserve">
|
||||||
<value>FakeIP</value>
|
<value>FakeIP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
|
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
|
||||||
<value>Block SVCB and HTTPS Queries</value>
|
<value>阻止 SVCB 和 HTTPS 查詢</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDNSHostsConfig" xml:space="preserve">
|
<data name="TbDNSHostsConfig" xml:space="preserve">
|
||||||
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
|
<value>DNS Hosts:(“網域名稱1 ip1 ip2” 一行一個)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ThBasicDNSSettings" xml:space="preserve">
|
<data name="ThBasicDNSSettings" xml:space="preserve">
|
||||||
<value>Basic DNS Settings</value>
|
<value>DNS 基礎設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ThAdvancedDNSSettings" xml:space="preserve">
|
<data name="ThAdvancedDNSSettings" xml:space="preserve">
|
||||||
<value>Advanced DNS Settings</value>
|
<value>DNS 進階設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
<value>Validate Regional Domain IPs</value>
|
<value>校驗相應地區域名 IP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
<value>配置後,會對相應地區域名(如 geosite:cn)的返回 IP 進行校驗,僅返回期望 IP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbCustomDNSEnable" xml:space="preserve">
|
<data name="TbCustomDNSEnable" xml:space="preserve">
|
||||||
<value>Enable Custom DNS</value>
|
<value>啟用自訂 DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
|
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
|
||||||
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
|
<value>自訂 DNS 已啟用,此頁面配置將無效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
|
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
|
||||||
<value>Block ECH and HTTP/3 availability checks when enabled</value>
|
<value>開啟後將阻止 ECH 和 HTTP/3 可用性查詢</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
|
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
|
||||||
<value>Please fill in the correct config template</value>
|
<value>請填寫正確的配置範本</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuFullConfigTemplate" xml:space="preserve">
|
<data name="menuFullConfigTemplate" xml:space="preserve">
|
||||||
<value>Full Config Template Setting</value>
|
<value>完整配置範本設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
|
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
|
||||||
<value>Enable Full Config Template</value>
|
<value>啟用完整配置範本</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRayFullConfigTemplate" xml:space="preserve">
|
<data name="TbRayFullConfigTemplate" xml:space="preserve">
|
||||||
<value>v2ray Full Config Template</value>
|
<value>v2ray 完整配置範本</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
|
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
|
||||||
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag, Click to view the document</value>
|
<value>僅添加出站配置,routing.balancers 和 routing.rules.outboundTag,點擊查看文檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
||||||
<value>Do Not Add Non-Proxy Protocol Outbound</value>
|
<value>不添加非代理協定出站</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
||||||
<value>Set Upstream Proxy Tag</value>
|
<value>設定上游代理 tag</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSBFullConfigTemplate" xml:space="preserve">
|
<data name="TbSBFullConfigTemplate" xml:space="preserve">
|
||||||
<value>sing-box Full Config Template</value>
|
<value>sing-box 完整配置範本</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
|
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
|
||||||
<value>Add Outbound and Endpoint Config Only, Click to view the document</value>
|
<value>僅添加出站和端點配置,點擊查看文檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
||||||
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
|
<value>此功能供高級用戶和有特殊需求的用戶使用。 啟用此功能後,將忽略 Core 的基礎設定,DNS 設定 ,路由設定。你需要保證系統代理的埠和流量統計等功能的配置正確,一切都由你來設定。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
||||||
<value>開始解析和處理訂閱內容</value>
|
<value>開始解析和處理訂閱內容</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSelectProfile" xml:space="preserve">
|
<data name="TbSelectProfile" xml:space="preserve">
|
||||||
<value>Select Profile</value>
|
<value>選擇節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>默認全域生效,內置 FakeIP 過濾,僅在 sing-box 中生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Please Add At Least One Configuration</value>
|
<value>請至少添加一個節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
||||||
<value>Policy Group</value>
|
<value>策略組</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
||||||
<value>Proxy Chain</value>
|
<value>鏈式代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbLeastPing" xml:space="preserve">
|
<data name="TbLeastPing" xml:space="preserve">
|
||||||
<value>Lowest Latency</value>
|
<value>最低延遲</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRandom" xml:space="preserve">
|
<data name="TbRandom" xml:space="preserve">
|
||||||
<value>Random</value>
|
<value>隨機</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoundRobin" xml:space="preserve">
|
<data name="TbRoundRobin" xml:space="preserve">
|
||||||
<value>Round Robin</value>
|
<value>負載均衡</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbLeastLoad" xml:space="preserve">
|
<data name="TbLeastLoad" xml:space="preserve">
|
||||||
<value>Most Stable</value>
|
<value>最穩定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPolicyGroupType" xml:space="preserve">
|
<data name="TbPolicyGroupType" xml:space="preserve">
|
||||||
<value>Policy Group Type</value>
|
<value>策略組類型</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||||
<value>Add Policy Group Configuration</value>
|
<value>添加策略組</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddProxyChainServer" xml:space="preserve">
|
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||||
<value>Add Proxy Chain Configuration</value>
|
<value>添加鏈式代理</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddChildServer" xml:space="preserve">
|
<data name="menuAddChildServer" xml:space="preserve">
|
||||||
<value>Add Child Configuration</value>
|
<value>添加子項</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveChildServer" xml:space="preserve">
|
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||||
<value>Remove Child Configuration</value>
|
<value>刪除子項</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuServerList" xml:space="preserve">
|
<data name="menuServerList" xml:space="preserve">
|
||||||
<value>Server List</value>
|
<value>子項清單</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFallback" xml:space="preserve">
|
<data name="TbFallback" xml:space="preserve">
|
||||||
<value>Fallback</value>
|
<value>容錯移轉</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||||
<value>Multi-Configuration Fallback by sing-box</value>
|
<value>多選容錯移轉 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>多選容錯移轉 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>核心 '{0}' 不支援網路類型 '{1}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
||||||
<value>Core '{0}' does not support protocol '{1}' when using transport '{2}'.</value>
|
<value>核心 '{0}' 在使用傳輸方式 '{2}' 時不支援協定 '{1}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
||||||
<value>Core '{0}' does not support protocol '{1}'.</value>
|
<value>核心 '{0}' 不支援協定 '{1}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ProxyChainedPrefix" xml:space="preserve">
|
<data name="ProxyChainedPrefix" xml:space="preserve">
|
||||||
<value>Proxy chained: </value>
|
<value>代理鏈: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
||||||
<value>Routing rule outbound: </value>
|
<value>路由規則出站: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PolicyGroupPrefix" xml:space="preserve">
|
<data name="PolicyGroupPrefix" xml:space="preserve">
|
||||||
<value>Policy group: </value>
|
<value>策略組: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NodeTagNotExist" xml:space="preserve">
|
<data name="NodeTagNotExist" xml:space="preserve">
|
||||||
<value>Node alias '{0}' does not exist.</value>
|
<value>別名 '{0}' 不存在。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="GroupEmpty" xml:space="preserve">
|
<data name="GroupEmpty" xml:space="preserve">
|
||||||
<value>Group '{0}' is empty. Please add at least one node.</value>
|
<value>組“{0}”為空.請至少添加一個配置。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InvalidProperty" xml:space="preserve">
|
<data name="InvalidProperty" xml:space="preserve">
|
||||||
<value>The {0} property is invalid, please check.</value>
|
<value>{0}屬性無效,請檢查</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="GroupSelfReference" xml:space="preserve">
|
<data name="GroupSelfReference" xml:space="preserve">
|
||||||
<value>{0} 分組不能引用自身或循環引用</value>
|
<value>{0} 分組不能引用自身或循環引用</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NotSupportProtocol" xml:space="preserve">
|
<data name="NotSupportProtocol" xml:space="preserve">
|
||||||
<value>Not support protocol '{0}'.</value>
|
<value>不支援協定 '{0}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
||||||
<value>如果系統沒有托盤功能,請不要開啟</value>
|
<value>如果系統沒有託盤功能,請不要開啟</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleType" xml:space="preserve">
|
<data name="TbRuleType" xml:space="preserve">
|
||||||
<value>规则类型</value>
|
<value>規則類型</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleTypeTips" xml:space="preserve">
|
<data name="TbRuleTypeTips" xml:space="preserve">
|
||||||
<value>可对 Routing 和 DNS 单独设定规则,ALL 则都生效</value>
|
<value>可對 Routing 和 DNS 單獨設定規則,ALL 則都生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBootstrapDNS" xml:space="preserve">
|
<data name="TbBootstrapDNS" xml:space="preserve">
|
||||||
<value>Bootstrap DNS</value>
|
<value>Bootstrap DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
<value>Resolve DNS server domains, requires IP</value>
|
<value>解析 DNS 伺服器網域名稱,需指定為 IP</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuFastRealPing" xml:space="preserve">
|
||||||
|
<value>一鍵測試真連線延遲</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -28,15 +28,15 @@ fi
|
|||||||
kill_children() {
|
kill_children() {
|
||||||
local parent=$1
|
local parent=$1
|
||||||
local children=$(ps -o pid --no-headers --ppid "$parent")
|
local children=$(ps -o pid --no-headers --ppid "$parent")
|
||||||
|
|
||||||
# Output information about processes being terminated
|
# Output information about processes being terminated
|
||||||
echo "Processing children of PID: $parent..."
|
echo "Processing children of PID: $parent..."
|
||||||
|
|
||||||
# Process each child
|
# Process each child
|
||||||
for child in $children; do
|
for child in $children; do
|
||||||
# Recursively find and kill child's children first
|
# Recursively find and kill child's children first
|
||||||
kill_children "$child"
|
kill_children "$child"
|
||||||
|
|
||||||
# Force kill the child process
|
# Force kill the child process
|
||||||
echo "Terminating child process: $child"
|
echo "Terminating child process: $child"
|
||||||
kill -9 "$child" 2>/dev/null || true
|
kill -9 "$child" 2>/dev/null || true
|
||||||
@@ -47,6 +47,18 @@ echo "============================================"
|
|||||||
echo "Starting termination of process $PID and all its children"
|
echo "Starting termination of process $PID and all its children"
|
||||||
echo "============================================"
|
echo "============================================"
|
||||||
|
|
||||||
|
# Try graceful termination first
|
||||||
|
echo "Attempting graceful termination (SIGTERM) of PID: $PID"
|
||||||
|
kill -15 "$PID" 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
# If still running, fall back to kill_children
|
||||||
|
if ps -p $PID > /dev/null; then
|
||||||
|
echo "Process $PID did not exit after SIGTERM; proceeding with forced termination of its children and itself"
|
||||||
|
else
|
||||||
|
echo "Process $PID exited cleanly after SIGTERM"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Find and kill all child processes
|
# Find and kill all child processes
|
||||||
kill_children "$PID"
|
kill_children "$PID"
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,20 @@ echo "============================================"
|
|||||||
echo "Starting termination of process $PID and all its descendants"
|
echo "Starting termination of process $PID and all its descendants"
|
||||||
echo "============================================"
|
echo "============================================"
|
||||||
|
|
||||||
|
# Try graceful termination first
|
||||||
|
echo "Attempting graceful termination (SIGTERM) of PID: $PID"
|
||||||
|
kill -15 "$PID" 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# If still running, fall back to kill_descendants
|
||||||
|
# Use the macOS-native 'kill -0' check
|
||||||
|
if kill -0 $PID 2>/dev/null; then
|
||||||
|
echo "Process $PID did not exit after SIGTERM; proceeding with forced termination of its descendants and itself"
|
||||||
|
else
|
||||||
|
echo "Process $PID exited cleanly after SIGTERM"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Find and kill all descendant processes
|
# Find and kill all descendant processes
|
||||||
kill_descendants "$PID"
|
kill_descendants "$PID"
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,9 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Update="Resx\ResUI.fr.resx">
|
||||||
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Update="Resx\ResUI.hu.resx">
|
<EmbeddedResource Update="Resx\ResUI.hu.resx">
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
@@ -79,4 +82,4 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -470,14 +470,16 @@ public partial class CoreConfigSingboxService
|
|||||||
{
|
{
|
||||||
// udp dns
|
// udp dns
|
||||||
server.type = "udp";
|
server.type = "udp";
|
||||||
server.server = addressFirst;
|
}
|
||||||
return server;
|
else
|
||||||
|
{
|
||||||
|
// server.type = scheme.ToLower();
|
||||||
|
|
||||||
|
// remove "+local" suffix
|
||||||
|
// TODO: "+local" suffix decide server.detour = "direct" ?
|
||||||
|
server.type = scheme.Replace("+local", "", StringComparison.OrdinalIgnoreCase).ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
//server.type = scheme.ToLower();
|
|
||||||
// remove "+local" suffix
|
|
||||||
// TODO: "+local" suffix decide server.detour = "direct" ?
|
|
||||||
server.type = scheme.Replace("+local", "", StringComparison.OrdinalIgnoreCase).ToLower();
|
|
||||||
server.server = domain;
|
server.server = domain;
|
||||||
if (port != 0)
|
if (port != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ public partial class CoreConfigSingboxService
|
|||||||
var tls = new Tls4Sbox()
|
var tls = new Tls4Sbox()
|
||||||
{
|
{
|
||||||
enabled = true,
|
enabled = true,
|
||||||
record_fragment = _config.CoreBasicItem.EnableFragment,
|
record_fragment = _config.CoreBasicItem.EnableFragment ? true : null,
|
||||||
server_name = server_name,
|
server_name = server_name,
|
||||||
insecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure),
|
insecure = Utils.ToBool(node.AllowInsecure.IsNullOrEmpty() ? _config.CoreBasicItem.DefAllowInsecure.ToString().ToLower() : node.AllowInsecure),
|
||||||
alpn = node.GetAlpn(),
|
alpn = node.GetAlpn(),
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ public partial class CoreConfigV2rayService(Config config)
|
|||||||
|
|
||||||
ret.Msg = ResUI.InitialConfiguration;
|
ret.Msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
string result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
|
var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
|
||||||
string txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty())
|
if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGetDefaultConfiguration;
|
ret.Msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
@@ -200,8 +200,8 @@ public partial class CoreConfigV2rayService(Config config)
|
|||||||
|
|
||||||
ret.Msg = ResUI.InitialConfiguration;
|
ret.Msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
string result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
|
var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
|
||||||
string txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty())
|
if (result.IsNullOrEmpty() || txtOutbound.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGetDefaultConfiguration;
|
ret.Msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle outbounds - append instead of override
|
var customOutboundsNode = new JsonArray();
|
||||||
var customOutboundsNode = fullConfigTemplateNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray();
|
|
||||||
foreach (var outbound in v2rayConfig.outbounds)
|
foreach (var outbound in v2rayConfig.outbounds)
|
||||||
{
|
{
|
||||||
if (outbound.protocol.ToLower() is "blackhole" or "dns" or "freedom")
|
if (outbound.protocol.ToLower() is "blackhole" or "dns" or "freedom")
|
||||||
@@ -97,14 +97,30 @@ public partial class CoreConfigV2rayService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() == true) && (!fullConfigTemplate.ProxyDetour.IsNullOrEmpty()) && !(Utils.IsPrivateNetwork(outbound.settings?.servers?.FirstOrDefault()?.address ?? string.Empty) || Utils.IsPrivateNetwork(outbound.settings?.vnext?.FirstOrDefault()?.address ?? string.Empty)))
|
else if ((!fullConfigTemplate.ProxyDetour.IsNullOrEmpty())
|
||||||
|
&& ((outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() ?? true) == true))
|
||||||
{
|
{
|
||||||
outbound.streamSettings ??= new StreamSettings4Ray();
|
var outboundAddress = outbound.settings?.servers?.FirstOrDefault()?.address
|
||||||
outbound.streamSettings.sockopt ??= new Sockopt4Ray();
|
?? outbound.settings?.vnext?.FirstOrDefault()?.address
|
||||||
outbound.streamSettings.sockopt.dialerProxy = fullConfigTemplate.ProxyDetour;
|
?? string.Empty;
|
||||||
|
if (!Utils.IsPrivateNetwork(outboundAddress))
|
||||||
|
{
|
||||||
|
outbound.streamSettings ??= new StreamSettings4Ray();
|
||||||
|
outbound.streamSettings.sockopt ??= new Sockopt4Ray();
|
||||||
|
outbound.streamSettings.sockopt.dialerProxy = fullConfigTemplate.ProxyDetour;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
|
customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fullConfigTemplateNode["outbounds"] is JsonArray templateOutbounds)
|
||||||
|
{
|
||||||
|
foreach (var outbound in templateOutbounds)
|
||||||
|
{
|
||||||
|
customOutboundsNode.Add(outbound?.DeepClone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fullConfigTemplateNode["outbounds"] = customOutboundsNode;
|
fullConfigTemplateNode["outbounds"] = customOutboundsNode;
|
||||||
|
|
||||||
return await Task.FromResult(JsonUtils.Serialize(fullConfigTemplateNode));
|
return await Task.FromResult(JsonUtils.Serialize(fullConfigTemplateNode));
|
||||||
|
|||||||
@@ -79,9 +79,23 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
static object CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
static object CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
||||||
{
|
{
|
||||||
|
var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress);
|
||||||
|
var domainFinal = dnsAddress;
|
||||||
|
int? portFinal = null;
|
||||||
|
if (scheme.IsNullOrEmpty() || scheme.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
domainFinal = domain;
|
||||||
|
portFinal = port > 0 ? port : null;
|
||||||
|
}
|
||||||
|
else if (scheme.StartsWith("tcp", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
domainFinal = scheme + "://" + domain;
|
||||||
|
portFinal = port > 0 ? port : null;
|
||||||
|
}
|
||||||
var dnsServer = new DnsServer4Ray
|
var dnsServer = new DnsServer4Ray
|
||||||
{
|
{
|
||||||
address = dnsAddress,
|
address = domainFinal,
|
||||||
|
port = portFinal,
|
||||||
skipFallback = true,
|
skipFallback = true,
|
||||||
domains = domains.Count > 0 ? domains : null,
|
domains = domains.Count > 0 ? domains : null,
|
||||||
expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null
|
expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null
|
||||||
@@ -333,8 +347,8 @@ public partial class CoreConfigV2rayService
|
|||||||
if (obj is null)
|
if (obj is null)
|
||||||
{
|
{
|
||||||
List<string> servers = [];
|
List<string> servers = [];
|
||||||
string[] arrDNS = normalDNS.Split(',');
|
var arrDNS = normalDNS.Split(',');
|
||||||
foreach (string str in arrDNS)
|
foreach (var str in arrDNS)
|
||||||
{
|
{
|
||||||
servers.Add(str);
|
servers.Add(str);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
private Inbounds4Ray GetInbound(InItem inItem, EInboundProtocol protocol, bool bSocks)
|
private Inbounds4Ray GetInbound(InItem inItem, EInboundProtocol protocol, bool bSocks)
|
||||||
{
|
{
|
||||||
string result = EmbedUtils.GetEmbedText(Global.V2raySampleInbound);
|
var result = EmbedUtils.GetEmbedText(Global.V2raySampleInbound);
|
||||||
if (result.IsNullOrEmpty())
|
if (result.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return new();
|
return new();
|
||||||
|
|||||||
@@ -453,16 +453,16 @@ public partial class CoreConfigV2rayService
|
|||||||
};
|
};
|
||||||
|
|
||||||
//request Host
|
//request Host
|
||||||
string request = EmbedUtils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
|
var request = EmbedUtils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
|
||||||
string[] arrHost = host.Split(',');
|
var arrHost = host.Split(',');
|
||||||
string host2 = string.Join(",".AppendQuotes(), arrHost);
|
var host2 = string.Join(",".AppendQuotes(), arrHost);
|
||||||
request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
|
request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
|
||||||
request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
|
request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
|
||||||
//Path
|
//Path
|
||||||
string pathHttp = @"/";
|
var pathHttp = @"/";
|
||||||
if (path.IsNotEmpty())
|
if (path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
string[] arrPath = path.Split(',');
|
var arrPath = path.Split(',');
|
||||||
pathHttp = string.Join(",".AppendQuotes(), arrPath);
|
pathHttp = string.Join(",".AppendQuotes(), arrPath);
|
||||||
}
|
}
|
||||||
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
|
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
|
||||||
@@ -623,10 +623,10 @@ public partial class CoreConfigV2rayService
|
|||||||
// Cache for chain proxies to avoid duplicate generation
|
// Cache for chain proxies to avoid duplicate generation
|
||||||
var nextProxyCache = new Dictionary<string, Outbounds4Ray?>();
|
var nextProxyCache = new Dictionary<string, Outbounds4Ray?>();
|
||||||
var prevProxyTags = new Dictionary<string, string?>(); // Map from profile name to tag
|
var prevProxyTags = new Dictionary<string, string?>(); // Map from profile name to tag
|
||||||
int prevIndex = 0; // Index for prev outbounds
|
var prevIndex = 0; // Index for prev outbounds
|
||||||
|
|
||||||
// Process nodes
|
// Process nodes
|
||||||
int index = 0;
|
var index = 0;
|
||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ public partial class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
||||||
{
|
{
|
||||||
string tag = EInboundProtocol.api.ToString();
|
var tag = EInboundProtocol.api.ToString();
|
||||||
Metrics4Ray apiObj = new();
|
Metrics4Ray apiObj = new();
|
||||||
Policy4Ray policyObj = new();
|
Policy4Ray policyObj = new();
|
||||||
SystemPolicy4Ray policySystemSetting = new();
|
SystemPolicy4Ray policySystemSetting = new();
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ public class UpdateService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type);
|
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(type);
|
||||||
string filePath = string.Empty;
|
var filePath = string.Empty;
|
||||||
foreach (var name in coreInfo.CoreExes)
|
foreach (var name in coreInfo.CoreExes)
|
||||||
{
|
{
|
||||||
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
|
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
|
||||||
@@ -180,14 +180,14 @@ public class UpdateService
|
|||||||
|
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
{
|
{
|
||||||
string msg = string.Format(ResUI.NotFoundCore, @"", "", "");
|
var msg = string.Format(ResUI.NotFoundCore, @"", "", "");
|
||||||
//ShowMsg(true, msg);
|
//ShowMsg(true, msg);
|
||||||
return new SemanticVersion("");
|
return new SemanticVersion("");
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await Utils.GetCliWrapOutput(filePath, coreInfo.VersionArg);
|
var result = await Utils.GetCliWrapOutput(filePath, coreInfo.VersionArg);
|
||||||
var echo = result ?? "";
|
var echo = result ?? "";
|
||||||
string version = string.Empty;
|
var version = string.Empty;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ECoreType.v2fly:
|
case ECoreType.v2fly:
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ public class ClashProxiesViewModel : MyReactiveObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
//from api
|
//from api
|
||||||
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies)
|
foreach (var kv in _proxies)
|
||||||
{
|
{
|
||||||
if (!Global.allowSelectType.Contains(kv.Value.type.ToLower()))
|
if (!Global.allowSelectType.Contains(kv.Value.type.ToLower()))
|
||||||
{
|
{
|
||||||
@@ -319,7 +319,7 @@ public class ClashProxiesViewModel : MyReactiveObject
|
|||||||
//from providers
|
//from providers
|
||||||
if (_providers != null)
|
if (_providers != null)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<string, ProvidersItem> kv in _providers)
|
foreach (var kv in _providers)
|
||||||
{
|
{
|
||||||
if (Global.proxyVehicleType.Contains(kv.Value.vehicleType.ToLower()))
|
if (Global.proxyVehicleType.Contains(kv.Value.vehicleType.ToLower()))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -273,12 +273,12 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
|
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var needReboot = (EnableStatistics != _config.GuiItem.EnableStatistics
|
var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics
|
||||||
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|
||||||
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
|
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
|
||||||
|| EnableHWA != _config.GuiItem.EnableHWA
|
|| EnableHWA != _config.GuiItem.EnableHWA
|
||||||
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily
|
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily
|
||||||
|| MainGirdOrientation != (int)_config.UiItem.MainGirdOrientation);
|
|| MainGirdOrientation != (int)_config.UiItem.MainGirdOrientation;
|
||||||
|
|
||||||
//if (Utile.IsNullOrEmpty(Kcpmtu.ToString()) || !Utile.IsNumeric(Kcpmtu.ToString())
|
//if (Utile.IsNullOrEmpty(Kcpmtu.ToString()) || !Utile.IsNumeric(Kcpmtu.ToString())
|
||||||
// || Utile.IsNullOrEmpty(Kcptti.ToString()) || !Utile.IsNumeric(Kcptti.ToString())
|
// || Utile.IsNullOrEmpty(Kcptti.ToString()) || !Utile.IsNumeric(Kcptti.ToString())
|
||||||
@@ -375,7 +375,7 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private async Task SaveCoreType()
|
private async Task SaveCoreType()
|
||||||
{
|
{
|
||||||
for (int k = 1; k <= _config.CoreTypeItem.Count; k++)
|
for (var k = 1; k <= _config.CoreTypeItem.Count; k++)
|
||||||
{
|
{
|
||||||
var item = _config.CoreTypeItem[k - 1];
|
var item = _config.CoreTypeItem[k - 1];
|
||||||
var type = string.Empty;
|
var type = string.Empty;
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; }
|
public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> RemoveInvalidServerResultCmd { get; }
|
public ReactiveCommand<Unit, Unit> RemoveInvalidServerResultCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> FastRealPingCmd { get; }
|
||||||
|
|
||||||
//servers export
|
//servers export
|
||||||
public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; }
|
public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; }
|
||||||
@@ -179,6 +180,10 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
}, canEditRemove);
|
}, canEditRemove);
|
||||||
|
|
||||||
//servers ping
|
//servers ping
|
||||||
|
FastRealPingCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await ServerSpeedtest(ESpeedActionType.FastRealping);
|
||||||
|
});
|
||||||
MixedTestServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
MixedTestServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
await ServerSpeedtest(ESpeedActionType.Mixedtest);
|
await ServerSpeedtest(ESpeedActionType.Mixedtest);
|
||||||
@@ -653,7 +658,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
_dicHeaderSort.TryAdd(colName, true);
|
_dicHeaderSort.TryAdd(colName, true);
|
||||||
_dicHeaderSort.TryGetValue(colName, out bool asc);
|
_dicHeaderSort.TryGetValue(colName, out var asc);
|
||||||
if (await ConfigHandler.SortServers(_config, _config.SubIndexId, colName, asc) != 0)
|
if (await ConfigHandler.SortServers(_config, _config.SubIndexId, colName, asc) != 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -729,6 +734,12 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
SelectedProfiles = ProfileItems;
|
SelectedProfiles = ProfileItems;
|
||||||
}
|
}
|
||||||
|
else if (actionType == ESpeedActionType.FastRealping)
|
||||||
|
{
|
||||||
|
SelectedProfiles = ProfileItems;
|
||||||
|
actionType = ESpeedActionType.Realping;
|
||||||
|
}
|
||||||
|
|
||||||
var lstSelected = await GetProfileItems(false);
|
var lstSelected = await GetProfileItems(false);
|
||||||
if (lstSelected == null)
|
if (lstSelected == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ public class RoutingRuleSettingViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private async Task SaveRoutingAsync()
|
private async Task SaveRoutingAsync()
|
||||||
{
|
{
|
||||||
string remarks = SelectedRouting.Remarks;
|
var remarks = SelectedRouting.Remarks;
|
||||||
if (remarks.IsNullOrEmpty())
|
if (remarks.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
NoticeManager.Instance.Enqueue(ResUI.PleaseFillRemarks);
|
NoticeManager.Instance.Enqueue(ResUI.PleaseFillRemarks);
|
||||||
@@ -286,7 +286,7 @@ public class RoutingRuleSettingViewModel : MyReactiveObject
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadService downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
var result = await downloadHandle.TryDownloadString(url, true, "");
|
var result = await downloadHandle.TryDownloadString(url, true, "");
|
||||||
var ret = await AddBatchRoutingRulesAsync(SelectedRouting, result);
|
var ret = await AddBatchRoutingRulesAsync(SelectedRouting, result);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
@@ -298,7 +298,7 @@ public class RoutingRuleSettingViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private async Task<int> AddBatchRoutingRulesAsync(RoutingItem routingItem, string? clipboardData)
|
private async Task<int> AddBatchRoutingRulesAsync(RoutingItem routingItem, string? clipboardData)
|
||||||
{
|
{
|
||||||
bool blReplace = false;
|
var blReplace = false;
|
||||||
if (await _updateView?.Invoke(EViewAction.AddBatchRoutingRulesYesNo, null) == false)
|
if (await _updateView?.Invoke(EViewAction.AddBatchRoutingRulesYesNo, null) == false)
|
||||||
{
|
{
|
||||||
blReplace = true;
|
blReplace = true;
|
||||||
|
|||||||
@@ -313,10 +313,10 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
BlServers = true;
|
BlServers = true;
|
||||||
for (int k = 0; k < lstModel.Count; k++)
|
for (var k = 0; k < lstModel.Count; k++)
|
||||||
{
|
{
|
||||||
ProfileItem it = lstModel[k];
|
ProfileItem it = lstModel[k];
|
||||||
string name = it.GetSummary();
|
var name = it.GetSummary();
|
||||||
|
|
||||||
var item = new ComboItem() { ID = it.IndexId, Text = name };
|
var item = new ComboItem() { ID = it.IndexId, Text = name };
|
||||||
Servers.Add(item);
|
Servers.Add(item);
|
||||||
@@ -394,10 +394,10 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
await SysProxyHandler.UpdateSysProxy(_config, false);
|
await SysProxyHandler.UpdateSysProxy(_config, false);
|
||||||
|
|
||||||
BlSystemProxyClear = (type == ESysProxyType.ForcedClear);
|
BlSystemProxyClear = type == ESysProxyType.ForcedClear;
|
||||||
BlSystemProxySet = (type == ESysProxyType.ForcedChange);
|
BlSystemProxySet = type == ESysProxyType.ForcedChange;
|
||||||
BlSystemProxyNothing = (type == ESysProxyType.Unchanged);
|
BlSystemProxyNothing = type == ESysProxyType.Unchanged;
|
||||||
BlSystemProxyPac = (type == ESysProxyType.Pac);
|
BlSystemProxyPac = type == ESysProxyType.Pac;
|
||||||
|
|
||||||
if (blChange)
|
if (blChange)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,15 +10,17 @@ public partial class App : Application
|
|||||||
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
||||||
|
|
||||||
DataContext = StatusBarViewModel.Instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
public override void OnFrameworkInitializationCompleted()
|
||||||
{
|
{
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
AppManager.Instance.InitComponents();
|
if (!Design.IsDesignMode)
|
||||||
|
{
|
||||||
|
AppManager.Instance.InitComponents();
|
||||||
|
DataContext = StatusBarViewModel.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
desktop.Exit += OnExit;
|
desktop.Exit += OnExit;
|
||||||
desktop.MainWindow = new MainWindow();
|
desktop.MainWindow = new MainWindow();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ global using System.Collections.Generic;
|
|||||||
global using System.Globalization;
|
global using System.Globalization;
|
||||||
global using System.IO;
|
global using System.IO;
|
||||||
global using System.Linq;
|
global using System.Linq;
|
||||||
global using System.Reactive.Disposables;
|
global using System.Reactive.Disposables.Fluent;
|
||||||
global using System.Reactive.Linq;
|
global using System.Reactive.Linq;
|
||||||
global using System.Text;
|
global using System.Text;
|
||||||
global using System.Threading;
|
global using System.Threading;
|
||||||
@@ -17,13 +17,13 @@ global using Avalonia.Markup.Xaml;
|
|||||||
global using Avalonia.Media;
|
global using Avalonia.Media;
|
||||||
global using Avalonia.Media.Imaging;
|
global using Avalonia.Media.Imaging;
|
||||||
global using Avalonia.Platform;
|
global using Avalonia.Platform;
|
||||||
global using Avalonia.ReactiveUI;
|
|
||||||
global using Avalonia.Styling;
|
global using Avalonia.Styling;
|
||||||
global using Avalonia.Threading;
|
global using Avalonia.Threading;
|
||||||
global using ReactiveUI;
|
|
||||||
global using ReactiveUI.Fody.Helpers;
|
|
||||||
global using DynamicData;
|
global using DynamicData;
|
||||||
global using MsBox.Avalonia.Enums;
|
global using MsBox.Avalonia.Enums;
|
||||||
|
global using ReactiveUI;
|
||||||
|
global using ReactiveUI.Avalonia;
|
||||||
|
global using ReactiveUI.Fody.Helpers;
|
||||||
global using ServiceLib;
|
global using ServiceLib;
|
||||||
global using ServiceLib.Base;
|
global using ServiceLib.Base;
|
||||||
global using ServiceLib.Common;
|
global using ServiceLib.Common;
|
||||||
|
|||||||
@@ -54,12 +54,19 @@ internal class Program
|
|||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
{
|
{
|
||||||
return AppBuilder.Configure<App>()
|
var builder = AppBuilder.Configure<App>()
|
||||||
.UsePlatformDetect()
|
.UsePlatformDetect()
|
||||||
//.WithInterFont()
|
//.WithInterFont()
|
||||||
.WithFontByDefault()
|
.WithFontByDefault()
|
||||||
.LogToTrace()
|
.LogToTrace()
|
||||||
.UseReactiveUI()
|
.UseReactiveUI();
|
||||||
.With(new MacOSPlatformOptions { ShowInDock = AppManager.Instance.Config.UiItem.MacOSShowInDock });
|
|
||||||
|
if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
var showInDock = Design.IsDesignMode || AppManager.Instance.Config.UiItem.MacOSShowInDock;
|
||||||
|
builder = builder.With(new MacOSPlatformOptions { ShowInDock = showInDock });
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
lstChild.SelectionChanged += LstChild_SelectionChanged;
|
lstChild.SelectionChanged += LstChild_SelectionChanged;
|
||||||
|
|
||||||
ViewModel = new AddGroupServerViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddGroupServerViewModel(profileItem, UpdateViewHandler);
|
||||||
@@ -32,11 +32,11 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
switch (profileItem.ConfigType)
|
switch (profileItem.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.PolicyGroup:
|
case EConfigType.PolicyGroup:
|
||||||
this.Title = ResUI.TbConfigTypePolicyGroup;
|
Title = ResUI.TbConfigTypePolicyGroup;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.ProxyChain:
|
case EConfigType.ProxyChain:
|
||||||
this.Title = ResUI.TbConfigTypeProxyChain;
|
Title = ResUI.TbConfigTypeProxyChain;
|
||||||
gridPolicyGroup.IsVisible = false;
|
gridPolicyGroup.IsVisible = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
menuSelectAllChild.Click += (s, e) => lstChild.SelectAll();
|
menuSelectAllChild.Click += (s, e) => lstChild.SelectAll();
|
||||||
|
|
||||||
// Keyboard shortcuts when focus is within grid
|
// Keyboard shortcuts when focus is within grid
|
||||||
this.AddHandler(KeyDownEvent, AddGroupServerWindow_KeyDown, RoutingStrategies.Tunnel);
|
AddHandler(KeyDownEvent, AddGroupServerWindow_KeyDown, RoutingStrategies.Tunnel);
|
||||||
lstChild.LoadingRow += LstChild_LoadingRow;
|
lstChild.LoadingRow += LstChild_LoadingRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ public partial class AddServer2Window : WindowBase<AddServer2ViewModel>
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
|
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
|
||||||
@@ -39,7 +39,7 @@ public partial class AddServer2Window : WindowBase<AddServer2ViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.BrowseServer:
|
case EViewAction.BrowseServer:
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
||||||
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
|
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
|
||||||
btnGUID.Click += btnGUID_Click;
|
btnGUID.Click += btnGUID_Click;
|
||||||
@@ -196,7 +196,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Title = $"{profileItem.ConfigType}";
|
Title = $"{profileItem.ConfigType}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
@@ -204,7 +204,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ public partial class ClashProxiesView : ReactiveUserControl<ClashProxiesViewMode
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
ViewModel = new ClashProxiesViewModel(UpdateViewHandler);
|
ViewModel = new ClashProxiesViewModel(UpdateViewHandler);
|
||||||
lstProxyDetails.DoubleTapped += LstProxyDetails_DoubleTapped;
|
lstProxyDetails.DoubleTapped += LstProxyDetails_DoubleTapped;
|
||||||
this.KeyDown += ClashProxiesView_KeyDown;
|
KeyDown += ClashProxiesView_KeyDown;
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
|||||||
|
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms;
|
cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms;
|
||||||
@@ -77,7 +77,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public partial class FullConfigTemplateWindow : WindowBase<FullConfigTemplateVie
|
|||||||
|
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
|
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
@@ -36,7 +36,7 @@ public partial class FullConfigTemplateWindow : WindowBase<FullConfigTemplateVie
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingV
|
|||||||
|
|
||||||
HotkeyManager.Instance.IsPause = true;
|
HotkeyManager.Instance.IsPause = true;
|
||||||
Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
this.Closing += (s, e) => HotkeyManager.Instance.IsPause = false;
|
Closing += (s, e) => HotkeyManager.Instance.IsPause = false;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
@@ -34,7 +34,7 @@ public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingV
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
|||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
|
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
|
||||||
|
|
||||||
this.KeyDown += MainWindow_KeyDown;
|
KeyDown += MainWindow_KeyDown;
|
||||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||||
menuPromotion.Click += menuPromotion_Click;
|
menuPromotion.Click += menuPromotion_Click;
|
||||||
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
||||||
@@ -153,14 +153,14 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
|||||||
|
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||||
|
|
||||||
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||||
HotkeyManager.Instance.Init(_config, OnHotkeyHandler);
|
HotkeyManager.Instance.Init(_config, OnHotkeyHandler);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.Title = $"{Utils.GetVersion()}";
|
Title = $"{Utils.GetVersion()}";
|
||||||
|
|
||||||
menuRebootAsAdmin.IsVisible = false;
|
menuRebootAsAdmin.IsVisible = false;
|
||||||
menuSettingsSetUWP.IsVisible = false;
|
menuSettingsSetUWP.IsVisible = false;
|
||||||
@@ -168,9 +168,9 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
|||||||
}
|
}
|
||||||
menuAddServerViaScan.IsVisible = false;
|
menuAddServerViaScan.IsVisible = false;
|
||||||
|
|
||||||
if (_config.UiItem.AutoHideStartup)
|
if (_config.UiItem.AutoHideStartup && Utils.IsWindows())
|
||||||
{
|
{
|
||||||
this.WindowState = WindowState.Minimized;
|
WindowState = WindowState.Minimized;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
@@ -402,32 +402,32 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
|||||||
public void ShowHideWindow(bool? blShow)
|
public void ShowHideWindow(bool? blShow)
|
||||||
{
|
{
|
||||||
var bl = blShow ??
|
var bl = blShow ??
|
||||||
Utils.IsLinux()
|
(Utils.IsLinux()
|
||||||
? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized))
|
? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized))
|
||||||
: !_config.UiItem.ShowInTaskbar;
|
: !_config.UiItem.ShowInTaskbar);
|
||||||
if (bl)
|
if (bl)
|
||||||
{
|
{
|
||||||
this.Show();
|
Show();
|
||||||
if (this.WindowState == WindowState.Minimized)
|
if (WindowState == WindowState.Minimized)
|
||||||
{
|
{
|
||||||
this.WindowState = WindowState.Normal;
|
WindowState = WindowState.Normal;
|
||||||
}
|
}
|
||||||
this.Activate();
|
Activate();
|
||||||
this.Focus();
|
Focus();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Utils.IsLinux() && _config.UiItem.Hide2TrayWhenClose == false)
|
if (Utils.IsLinux() && _config.UiItem.Hide2TrayWhenClose == false)
|
||||||
{
|
{
|
||||||
this.WindowState = WindowState.Minimized;
|
WindowState = WindowState.Minimized;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var ownedWindow in this.OwnedWindows)
|
foreach (var ownedWindow in OwnedWindows)
|
||||||
{
|
{
|
||||||
ownedWindow.Close();
|
ownedWindow.Close();
|
||||||
}
|
}
|
||||||
this.Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
_config.UiItem.ShowInTaskbar = bl;
|
_config.UiItem.ShowInTaskbar = bl;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
|
|
||||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||||
@@ -153,7 +153,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.InitSettingFont:
|
case EViewAction.InitSettingFont:
|
||||||
|
|||||||
@@ -49,6 +49,13 @@
|
|||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtServerFilter"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource MarginLr4}"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Watermark="{x:Static resx:ResUI.MsgServerTitle}" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAutofitColumnWidth"
|
x:Name="btnAutofitColumnWidth"
|
||||||
Margin="{StaticResource MarginLr4}"
|
Margin="{StaticResource MarginLr4}"
|
||||||
@@ -59,12 +66,25 @@
|
|||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<TextBox
|
<Button
|
||||||
x:Name="txtServerFilter"
|
x:Name="btnFastRealPing"
|
||||||
Width="200"
|
|
||||||
Margin="{StaticResource MarginLr4}"
|
Margin="{StaticResource MarginLr4}"
|
||||||
VerticalContentAlignment="Center"
|
Classes="IconButton Success"
|
||||||
Watermark="{x:Static resx:ResUI.MsgServerTitle}" />
|
ToolTip.Tip="{x:Static resx:ResUI.menuFastRealPing}">
|
||||||
|
<Button.Content>
|
||||||
|
<PathIcon Data="{StaticResource SemiIconBolt}" />
|
||||||
|
</Button.Content>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
x:Name="menuMixedTestServer"
|
||||||
|
Margin="{StaticResource MarginLr4}"
|
||||||
|
Classes="IconButton Success"
|
||||||
|
ToolTip.Tip="{x:Static resx:ResUI.menuMixedTestServer}">
|
||||||
|
<Button.Content>
|
||||||
|
<PathIcon Data="{StaticResource building_ping}" />
|
||||||
|
</Button.Content>
|
||||||
|
</Button>
|
||||||
|
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstProfiles"
|
x:Name="lstProfiles"
|
||||||
@@ -88,15 +108,12 @@
|
|||||||
<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}" />
|
||||||
<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}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem x:Name="menuMixedTestServer" Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
|
||||||
<MenuItem x:Name="menuTcpingServer" Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
<MenuItem x:Name="menuTcpingServer" Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
||||||
<MenuItem x:Name="menuRealPingServer" Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
<MenuItem x:Name="menuRealPingServer" Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
||||||
<MenuItem x:Name="menuSpeedServer" Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
<MenuItem x:Name="menuSpeedServer" Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||||
<MenuItem Header="{x:Static resx:ResUI.menuTestServerResult}">
|
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||||
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
|
||||||
<MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
|
||||||
</MenuItem>
|
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
<MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
@@ -127,7 +144,8 @@
|
|||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem x:Name="menuExport2ShareUrl" Header="{x:Static resx:ResUI.menuExport2ShareUrl}" />
|
<MenuItem x:Name="menuExport2ShareUrl" Header="{x:Static resx:ResUI.menuExport2ShareUrl}" />
|
||||||
<MenuItem x:Name="menuExport2ShareUrlBase64" Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" />
|
<MenuItem x:Name="menuExport2ShareUrlBase64" Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" />
|
||||||
</MenuItem><Separator />
|
</MenuItem>
|
||||||
|
<Separator />
|
||||||
<MenuItem Header="{x:Static resx:ResUI.menuGenGroupMultipleServer}">
|
<MenuItem Header="{x:Static resx:ResUI.menuGenGroupMultipleServer}">
|
||||||
<MenuItem x:Name="menuGenGroupMultipleServerXrayRandom" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRandom}" />
|
<MenuItem x:Name="menuGenGroupMultipleServerXrayRandom" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRandom}" />
|
||||||
<MenuItem x:Name="menuGenGroupMultipleServerXrayRoundRobin" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRoundRobin}" />
|
<MenuItem x:Name="menuGenGroupMultipleServerXrayRoundRobin" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRoundRobin}" />
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
|||||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.FastRealPingCmd, v => v.btnFastRealPing).DisposeWith(disposables);
|
||||||
|
|
||||||
//servers export
|
//servers export
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
||||||
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingVie
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
this.KeyDown += RoutingRuleSettingWindow_KeyDown;
|
KeyDown += RoutingRuleSettingWindow_KeyDown;
|
||||||
lstRules.SelectionChanged += lstRules_SelectionChanged;
|
lstRules.SelectionChanged += lstRules_SelectionChanged;
|
||||||
lstRules.DoubleTapped += LstRules_DoubleTapped;
|
lstRules.DoubleTapped += LstRules_DoubleTapped;
|
||||||
menuRuleSelectAll.Click += menuRuleSelectAll_Click;
|
menuRuleSelectAll.Click += menuRuleSelectAll_Click;
|
||||||
@@ -64,7 +64,7 @@ public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingVie
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
this.Closing += RoutingSettingWindow_Closing;
|
Closing += RoutingSettingWindow_Closing;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
this.KeyDown += RoutingSettingWindow_KeyDown;
|
KeyDown += RoutingSettingWindow_KeyDown;
|
||||||
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;
|
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;
|
||||||
lstRoutings.DoubleTapped += LstRoutings_DoubleTapped;
|
lstRoutings.DoubleTapped += LstRoutings_DoubleTapped;
|
||||||
menuRoutingAdvancedSelectAll.Click += menuRoutingAdvancedSelectAll_Click;
|
menuRoutingAdvancedSelectAll.Click += menuRoutingAdvancedSelectAll_Click;
|
||||||
@@ -48,7 +48,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
@@ -116,7 +116,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
|||||||
private void btnCancel_Click(object? sender, RoutedEventArgs e)
|
private void btnCancel_Click(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_manualClose = true;
|
_manualClose = true;
|
||||||
this.Close(ViewModel?.IsModified);
|
Close(ViewModel?.IsModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RoutingSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
|
private void RoutingSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public partial class SubEditWindow : WindowBase<SubEditViewModel>
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => Close();
|
||||||
|
|
||||||
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ public partial class SubEditWindow : WindowBase<SubEditViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close(true);
|
Close(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
|||||||
|
|
||||||
menuClose.Click += menuClose_Click;
|
menuClose.Click += menuClose_Click;
|
||||||
Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
this.Closing += SubSettingWindow_Closing;
|
Closing += SubSettingWindow_Closing;
|
||||||
this.KeyDown += SubSettingWindow_KeyDown;
|
KeyDown += SubSettingWindow_KeyDown;
|
||||||
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
||||||
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
||||||
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
||||||
@@ -37,7 +37,7 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.Close();
|
Close();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
@@ -89,7 +89,7 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
|||||||
private void menuClose_Click(object? sender, RoutedEventArgs e)
|
private void menuClose_Click(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_manualClose = true;
|
_manualClose = true;
|
||||||
this.Close(ViewModel?.IsModified);
|
Close(ViewModel?.IsModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SubSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
|
private void SubSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public partial class SudoPasswordInputView : UserControl
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Loaded += (s, e) => txtPassword.Focus();
|
Loaded += (s, e) => txtPassword.Focus();
|
||||||
|
|
||||||
btnSave.Click += async (_, _) => await SavePasswordAsync();
|
btnSave.Click += async (_, _) => await SavePasswordAsync();
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Avalonia.Desktop" />
|
<PackageReference Include="Avalonia.Desktop" />
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" />
|
<PackageReference Include="ReactiveUI.Avalonia" />
|
||||||
<PackageReference Include="MessageBox.Avalonia" />
|
<PackageReference Include="MessageBox.Avalonia" />
|
||||||
<PackageReference Include="Semi.Avalonia" />
|
<PackageReference Include="Semi.Avalonia" />
|
||||||
<PackageReference Include="Semi.Avalonia.AvaloniaEdit" />
|
<PackageReference Include="Semi.Avalonia.AvaloniaEdit" />
|
||||||
|
|||||||
@@ -26,11 +26,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Action", "GitHub Act
|
|||||||
..\.github\workflows\build-osx.yml = ..\.github\workflows\build-osx.yml
|
..\.github\workflows\build-osx.yml = ..\.github\workflows\build-osx.yml
|
||||||
..\.github\workflows\build-windows-desktop.yml = ..\.github\workflows\build-windows-desktop.yml
|
..\.github\workflows\build-windows-desktop.yml = ..\.github\workflows\build-windows-desktop.yml
|
||||||
..\.github\workflows\build-windows.yml = ..\.github\workflows\build-windows.yml
|
..\.github\workflows\build-windows.yml = ..\.github\workflows\build-windows.yml
|
||||||
..\package-appimage.sh = ..\package-appimage.sh
|
|
||||||
..\package-debian.sh = ..\package-debian.sh
|
..\package-debian.sh = ..\package-debian.sh
|
||||||
..\package-osx.sh = ..\package-osx.sh
|
..\package-osx.sh = ..\package-osx.sh
|
||||||
..\package-release-zip.sh = ..\package-release-zip.sh
|
..\package-release-zip.sh = ..\package-release-zip.sh
|
||||||
..\pkg2appimage.yml = ..\pkg2appimage.yml
|
|
||||||
..\.github\workflows\winget-publish.yml = ..\.github\workflows\winget-publish.yml
|
..\.github\workflows\winget-publish.yml = ..\.github\workflows\winget-publish.yml
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
<File Path="../.github/workflows/build-windows-desktop.yml" />
|
<File Path="../.github/workflows/build-windows-desktop.yml" />
|
||||||
<File Path="../.github/workflows/build-windows.yml" />
|
<File Path="../.github/workflows/build-windows.yml" />
|
||||||
<File Path="../.github/workflows/winget-publish.yml" />
|
<File Path="../.github/workflows/winget-publish.yml" />
|
||||||
<File Path="../package-appimage.sh" />
|
|
||||||
<File Path="../package-debian.sh" />
|
<File Path="../package-debian.sh" />
|
||||||
<File Path="../package-osx.sh" />
|
<File Path="../package-osx.sh" />
|
||||||
<File Path="../package-release-zip.sh" />
|
<File Path="../package-release-zip.sh" />
|
||||||
<File Path="../pkg2appimage.yml" />
|
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/Solution Files/">
|
<Folder Name="/Solution Files/">
|
||||||
<File Path="Directory.Build.props" />
|
<File Path="Directory.Build.props" />
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public partial class App : Application
|
|||||||
|
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
|
DispatcherUnhandledException += App_DispatcherUnhandledException;
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ public partial class App : Application
|
|||||||
var exePathKey = Utils.GetMd5(Utils.GetExePath());
|
var exePathKey = Utils.GetMd5(Utils.GetExePath());
|
||||||
|
|
||||||
var rebootas = (e.Args ?? Array.Empty<string>()).Any(t => t == Global.RebootAs);
|
var rebootas = (e.Args ?? Array.Empty<string>()).Any(t => t == Global.RebootAs);
|
||||||
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
|
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out var bCreatedNew);
|
||||||
if (!rebootas && !bCreatedNew)
|
if (!rebootas && !bCreatedNew)
|
||||||
{
|
{
|
||||||
ProgramStarted.Set();
|
ProgramStarted.Set();
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ using System.Drawing;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace v2rayN;
|
namespace v2rayN.Common;
|
||||||
|
|
||||||
public class QRCodeUtils
|
public class QRCodeWindowsUtils
|
||||||
{
|
{
|
||||||
public static ImageSource? GetQRCode(string? strContent)
|
public static ImageSource? GetQRCode(string? strContent)
|
||||||
{
|
{
|
||||||
@@ -14,7 +14,7 @@ public class QRCodeUtils
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var qrCodeImage = ServiceLib.Common.QRCodeUtils.GenQRCode(strContent);
|
var qrCodeImage = QRCodeUtils.GenQRCode(strContent);
|
||||||
return qrCodeImage is null ? null : ByteToImage(qrCodeImage);
|
return qrCodeImage is null ? null : ByteToImage(qrCodeImage);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace v2rayN;
|
namespace v2rayN.Common;
|
||||||
|
|
||||||
internal class UI
|
internal class UI
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Windows.Media;
|
|||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace v2rayN;
|
namespace v2rayN.Common;
|
||||||
|
|
||||||
internal static class WindowsUtils
|
internal static class WindowsUtils
|
||||||
{
|
{
|
||||||
@@ -40,13 +40,13 @@ internal static class WindowsUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("dwmapi.dll")]
|
[DllImport("dwmapi.dll")]
|
||||||
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
|
public static extern int DwmSetWindowAttribute(nint hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
|
||||||
|
|
||||||
public static ImageSource IconToImageSource(Icon icon)
|
public static ImageSource IconToImageSource(Icon icon)
|
||||||
{
|
{
|
||||||
return Imaging.CreateBitmapSourceFromHIcon(
|
return Imaging.CreateBitmapSourceFromHIcon(
|
||||||
icon.Handle,
|
icon.Handle,
|
||||||
new System.Windows.Int32Rect(0, 0, icon.Width, icon.Height),
|
new Int32Rect(0, 0, icon.Width, icon.Height),
|
||||||
BitmapSizeOptions.FromEmptyOptions());
|
BitmapSizeOptions.FromEmptyOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,9 +65,9 @@ internal static class WindowsUtils
|
|||||||
private static void SetDarkBorder(Window window, bool dark)
|
private static void SetDarkBorder(Window window, bool dark)
|
||||||
{
|
{
|
||||||
// Make sure the handle is created before the window is shown
|
// Make sure the handle is created before the window is shown
|
||||||
IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle();
|
var hWnd = new WindowInteropHelper(window).EnsureHandle();
|
||||||
int attribute = dark ? 1 : 0;
|
var attribute = dark ? 1 : 0;
|
||||||
uint attributeSize = (uint)Marshal.SizeOf(attribute);
|
var attributeSize = (uint)Marshal.SizeOf(attribute);
|
||||||
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize);
|
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize);
|
||||||
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize);
|
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ global using System.Diagnostics;
|
|||||||
global using System.Globalization;
|
global using System.Globalization;
|
||||||
global using System.IO;
|
global using System.IO;
|
||||||
global using System.Linq;
|
global using System.Linq;
|
||||||
global using System.Reactive.Disposables;
|
global using System.Reactive.Disposables.Fluent;
|
||||||
global using System.Reactive.Linq;
|
global using System.Reactive.Linq;
|
||||||
global using System.Runtime.InteropServices;
|
global using System.Runtime.InteropServices;
|
||||||
global using System.Text;
|
global using System.Text;
|
||||||
@@ -31,3 +31,4 @@ global using ServiceLib.Manager;
|
|||||||
global using ServiceLib.Models;
|
global using ServiceLib.Models;
|
||||||
global using ServiceLib.Resx;
|
global using ServiceLib.Resx;
|
||||||
global using ServiceLib.ViewModels;
|
global using ServiceLib.ViewModels;
|
||||||
|
global using v2rayN.Common;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public sealed class HotkeyManager
|
|||||||
modifiers |= KeyModifiers.Alt;
|
modifiers |= KeyModifiers.Alt;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = key << 16 | (int)modifiers;
|
key = (key << 16) | (int)modifiers;
|
||||||
if (!_hotkeyTriggerDic.ContainsKey(key))
|
if (!_hotkeyTriggerDic.ContainsKey(key))
|
||||||
{
|
{
|
||||||
_hotkeyTriggerDic.Add(key, new() { item.EGlobalHotkey });
|
_hotkeyTriggerDic.Add(key, new() { item.EGlobalHotkey });
|
||||||
@@ -103,7 +103,7 @@ public sealed class HotkeyManager
|
|||||||
private (int fsModifiers, int vKey, string hotkeyStr, List<string> Names) GetHotkeyInfo(int hotkeyCode)
|
private (int fsModifiers, int vKey, string hotkeyStr, List<string> Names) GetHotkeyInfo(int hotkeyCode)
|
||||||
{
|
{
|
||||||
var fsModifiers = hotkeyCode & 0xffff;
|
var fsModifiers = hotkeyCode & 0xffff;
|
||||||
var vKey = hotkeyCode >> 16 & 0xffff;
|
var vKey = (hotkeyCode >> 16) & 0xffff;
|
||||||
var hotkeyStr = new StringBuilder();
|
var hotkeyStr = new StringBuilder();
|
||||||
var names = new List<string>();
|
var names = new List<string>();
|
||||||
|
|
||||||
|
|||||||
@@ -60,18 +60,18 @@ public sealed class WindowsManager
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color color = ColorTranslator.FromHtml("#3399CC");
|
var color = ColorTranslator.FromHtml("#3399CC");
|
||||||
int index = (int)config.SystemProxyItem.SysProxyType;
|
var index = (int)config.SystemProxyItem.SysProxyType;
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
{
|
{
|
||||||
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
|
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = 128;
|
var width = 128;
|
||||||
int height = 128;
|
var height = 128;
|
||||||
|
|
||||||
Bitmap bitmap = new(width, height);
|
Bitmap bitmap = new(width, height);
|
||||||
Graphics graphics = Graphics.FromImage(bitmap);
|
var graphics = Graphics.FromImage(bitmap);
|
||||||
SolidBrush drawBrush = new(color);
|
SolidBrush drawBrush = new(color);
|
||||||
|
|
||||||
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
||||||
@@ -79,7 +79,7 @@ public sealed class WindowsManager
|
|||||||
graphics.DrawImage(new Bitmap(item.CustomIcon), 0, 0, width, height);
|
graphics.DrawImage(new Bitmap(item.CustomIcon), 0, 0, width, height);
|
||||||
graphics.FillEllipse(drawBrush, width / 2, width / 2, width / 2, width / 2);
|
graphics.FillEllipse(drawBrush, width / 2, width / 2, width / 2, width / 2);
|
||||||
|
|
||||||
Icon createdIcon = Icon.FromHandle(bitmap.GetHicon());
|
var createdIcon = Icon.FromHandle(bitmap.GetHicon());
|
||||||
|
|
||||||
drawBrush.Dispose();
|
drawBrush.Dispose();
|
||||||
graphics.Dispose();
|
graphics.Dispose();
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ public partial class AddGroupServerWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
this.PreviewKeyDown += AddGroupServerWindow_PreviewKeyDown;
|
PreviewKeyDown += AddGroupServerWindow_PreviewKeyDown;
|
||||||
lstChild.SelectionChanged += LstChild_SelectionChanged;
|
lstChild.SelectionChanged += LstChild_SelectionChanged;
|
||||||
menuSelectAllChild.Click += MenuSelectAllChild_Click;
|
menuSelectAllChild.Click += MenuSelectAllChild_Click;
|
||||||
|
|
||||||
@@ -27,11 +27,11 @@ public partial class AddGroupServerWindow
|
|||||||
switch (profileItem.ConfigType)
|
switch (profileItem.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.PolicyGroup:
|
case EConfigType.PolicyGroup:
|
||||||
this.Title = ResUI.TbConfigTypePolicyGroup;
|
Title = ResUI.TbConfigTypePolicyGroup;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.ProxyChain:
|
case EConfigType.ProxyChain:
|
||||||
this.Title = ResUI.TbConfigTypeProxyChain;
|
Title = ResUI.TbConfigTypeProxyChain;
|
||||||
gridPolicyGroup.Visibility = Visibility.Collapsed;
|
gridPolicyGroup.Visibility = Visibility.Collapsed;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ public partial class AddGroupServerWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ public partial class AddServer2Window
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
|
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
|
||||||
@@ -32,11 +32,11 @@ public partial class AddServer2Window
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.BrowseServer:
|
case EViewAction.BrowseServer:
|
||||||
if (UI.OpenFileDialog(out string fileName, "Config|*.json|YAML|*.yaml;*.yml|All|*.*") != true)
|
if (UI.OpenFileDialog(out var fileName, "Config|*.json|YAML|*.yaml;*.yml|All|*.*") != true)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ public partial class AddServerWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
||||||
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
|
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
|
||||||
btnGUID.Click += btnGUID_Click;
|
btnGUID.Click += btnGUID_Click;
|
||||||
@@ -191,7 +191,7 @@ public partial class AddServerWindow
|
|||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Title = $"{profileItem.ConfigType}";
|
Title = $"{profileItem.ConfigType}";
|
||||||
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ public partial class AddServerWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public partial class BackupAndRestoreView
|
|||||||
|
|
||||||
private void MenuLocalBackup_Click(object sender, RoutedEventArgs e)
|
private void MenuLocalBackup_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (UI.SaveFileDialog(out string fileName, "Zip|*.zip") != true)
|
if (UI.SaveFileDialog(out var fileName, "Zip|*.zip") != true)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ public partial class BackupAndRestoreView
|
|||||||
|
|
||||||
private void MenuLocalRestore_Click(object sender, RoutedEventArgs e)
|
private void MenuLocalRestore_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (UI.OpenFileDialog(out string fileName, "Zip|*.zip|All|*.*") != true)
|
if (UI.OpenFileDialog(out var fileName, "Zip|*.zip|All|*.*") != true)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ public partial class DNSSettingWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
|
|
||||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||||
@@ -78,7 +78,7 @@ public partial class DNSSettingWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ public partial class FullConfigTemplateWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
|
|
||||||
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
|
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
|
||||||
@@ -35,7 +35,7 @@ public partial class FullConfigTemplateWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ public partial class GlobalHotkeySettingWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
|
|
||||||
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
btnReset.Click += btnReset_Click;
|
btnReset.Click += btnReset_Click;
|
||||||
|
|
||||||
HotkeyManager.Instance.IsPause = true;
|
HotkeyManager.Instance.IsPause = true;
|
||||||
this.Closing += (s, e) => HotkeyManager.Instance.IsPause = false;
|
Closing += (s, e) => HotkeyManager.Instance.IsPause = false;
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
@@ -35,7 +35,7 @@ public partial class GlobalHotkeySettingWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ public partial class MainWindow
|
|||||||
ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
|
ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||||
|
|
||||||
App.Current.SessionEnding += Current_SessionEnding;
|
App.Current.SessionEnding += Current_SessionEnding;
|
||||||
this.Closing += MainWindow_Closing;
|
Closing += MainWindow_Closing;
|
||||||
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
|
PreviewKeyDown += MainWindow_PreviewKeyDown;
|
||||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||||
menuPromotion.Click += menuPromotion_Click;
|
menuPromotion.Click += menuPromotion_Click;
|
||||||
menuClose.Click += menuClose_Click;
|
menuClose.Click += menuClose_Click;
|
||||||
@@ -150,10 +150,10 @@ public partial class MainWindow
|
|||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||||
if (_config.UiItem.AutoHideStartup)
|
if (_config.UiItem.AutoHideStartup)
|
||||||
{
|
{
|
||||||
this.WindowState = WindowState.Minimized;
|
WindowState = WindowState.Minimized;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_config.GuiItem.EnableHWA)
|
if (!_config.GuiItem.EnableHWA)
|
||||||
@@ -187,35 +187,35 @@ public partial class MainWindow
|
|||||||
case EViewAction.AddServerWindow:
|
case EViewAction.AddServerWindow:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
|
return new AddServerWindow((ProfileItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.AddServer2Window:
|
case EViewAction.AddServer2Window:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
|
return new AddServer2Window((ProfileItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.AddGroupServerWindow:
|
case EViewAction.AddGroupServerWindow:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new AddGroupServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
|
return new AddGroupServerWindow((ProfileItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.DNSSettingWindow:
|
case EViewAction.DNSSettingWindow:
|
||||||
return (new DNSSettingWindow().ShowDialog() ?? false);
|
return new DNSSettingWindow().ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.RoutingSettingWindow:
|
case EViewAction.RoutingSettingWindow:
|
||||||
return (new RoutingSettingWindow().ShowDialog() ?? false);
|
return new RoutingSettingWindow().ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.OptionSettingWindow:
|
case EViewAction.OptionSettingWindow:
|
||||||
return (new OptionSettingWindow().ShowDialog() ?? false);
|
return new OptionSettingWindow().ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.FullConfigTemplateWindow:
|
case EViewAction.FullConfigTemplateWindow:
|
||||||
return (new FullConfigTemplateWindow().ShowDialog() ?? false);
|
return new FullConfigTemplateWindow().ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.GlobalHotkeySettingWindow:
|
case EViewAction.GlobalHotkeySettingWindow:
|
||||||
return (new GlobalHotkeySettingWindow().ShowDialog() ?? false);
|
return new GlobalHotkeySettingWindow().ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.SubSettingWindow:
|
case EViewAction.SubSettingWindow:
|
||||||
return (new SubSettingWindow().ShowDialog() ?? false);
|
return new SubSettingWindow().ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.ScanScreenTask:
|
case EViewAction.ScanScreenTask:
|
||||||
await ScanScreenTaskAsync();
|
await ScanScreenTaskAsync();
|
||||||
@@ -328,7 +328,7 @@ public partial class MainWindow
|
|||||||
|
|
||||||
if (Application.Current?.MainWindow is Window window)
|
if (Application.Current?.MainWindow is Window window)
|
||||||
{
|
{
|
||||||
var bytes = QRCodeUtils.CaptureScreen(window);
|
var bytes = QRCodeWindowsUtils.CaptureScreen(window);
|
||||||
await ViewModel?.ScanScreenResult(bytes);
|
await ViewModel?.ScanScreenResult(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +372,7 @@ public partial class MainWindow
|
|||||||
this?.Show();
|
this?.Show();
|
||||||
if (this?.WindowState == WindowState.Minimized)
|
if (this?.WindowState == WindowState.Minimized)
|
||||||
{
|
{
|
||||||
this.WindowState = WindowState.Normal;
|
WindowState = WindowState.Normal;
|
||||||
}
|
}
|
||||||
this?.Activate();
|
this?.Activate();
|
||||||
this?.Focus();
|
this?.Focus();
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ public partial class MsgView
|
|||||||
case EViewAction.DispatcherShowMsg:
|
case EViewAction.DispatcherShowMsg:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
Application.Current?.Dispatcher.Invoke((() =>
|
Application.Current?.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
ShowMsg(obj);
|
ShowMsg(obj);
|
||||||
}), DispatcherPriority.ApplicationIdle);
|
}, DispatcherPriority.ApplicationIdle);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public partial class OptionSettingWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
|
|
||||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||||
@@ -136,7 +136,7 @@ public partial class OptionSettingWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.InitSettingFont:
|
case EViewAction.InitSettingFont:
|
||||||
@@ -168,12 +168,12 @@ public partial class OptionSettingWindow
|
|||||||
foreach (var ttf in files)
|
foreach (var ttf in files)
|
||||||
{
|
{
|
||||||
var families = Fonts.GetFontFamilies(Utils.GetFontsPath(ttf));
|
var families = Fonts.GetFontFamilies(Utils.GetFontsPath(ttf));
|
||||||
foreach (FontFamily family in families)
|
foreach (var family in families)
|
||||||
{
|
{
|
||||||
var typefaces = family.GetTypefaces();
|
var typefaces = family.GetTypefaces();
|
||||||
foreach (Typeface typeface in typefaces)
|
foreach (var typeface in typefaces)
|
||||||
{
|
{
|
||||||
typeface.TryGetGlyphTypeface(out GlyphTypeface glyph);
|
typeface.TryGetGlyphTypeface(out var glyph);
|
||||||
//var fontFace = glyph.Win32FaceNames[new CultureInfo("en-us")];
|
//var fontFace = glyph.Win32FaceNames[new CultureInfo("en-us")];
|
||||||
//if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal"))
|
//if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal"))
|
||||||
//{
|
//{
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public partial class ProfilesSelectWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -57,16 +57,6 @@
|
|||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
|
||||||
x:Name="btnAutofitColumnWidth"
|
|
||||||
Width="30"
|
|
||||||
Height="30"
|
|
||||||
Margin="{StaticResource MarginLeftRight8}"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
|
||||||
ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
|
|
||||||
</Button>
|
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtServerFilter"
|
x:Name="txtServerFilter"
|
||||||
Width="200"
|
Width="200"
|
||||||
@@ -76,6 +66,36 @@
|
|||||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.MsgServerTitle}"
|
AutomationProperties.Name="{x:Static resx:ResUI.MsgServerTitle}"
|
||||||
Style="{StaticResource DefTextBox}" />
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
x:Name="btnAutofitColumnWidth"
|
||||||
|
Width="30"
|
||||||
|
Height="30"
|
||||||
|
Margin="{StaticResource MarginLeftRight4}"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
||||||
|
ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
x:Name="btnFastRealPing"
|
||||||
|
Width="30"
|
||||||
|
Height="30"
|
||||||
|
Margin="{StaticResource MarginLeftRight4}"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
||||||
|
ToolTip="{x:Static resx:ResUI.menuFastRealPing}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="LightningBolt" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
x:Name="menuMixedTestServer"
|
||||||
|
Width="30"
|
||||||
|
Height="30"
|
||||||
|
Margin="{StaticResource MarginLeftRight4}"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
||||||
|
ToolTip="{x:Static resx:ResUI.menuMixedTestServer}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Speedometer" />
|
||||||
|
</Button>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstProfiles"
|
x:Name="lstProfiles"
|
||||||
@@ -120,11 +140,11 @@
|
|||||||
x:Name="menuRemoveDuplicateServer"
|
x:Name="menuRemoveDuplicateServer"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
||||||
<Separator />
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuMixedTestServer"
|
x:Name="menuRemoveInvalidServerResult"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
||||||
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuTcpingServer"
|
x:Name="menuTcpingServer"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
@@ -137,16 +157,10 @@
|
|||||||
x:Name="menuSpeedServer"
|
x:Name="menuSpeedServer"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||||
<MenuItem Header="{x:Static resx:ResUI.menuTestServerResult}">
|
<MenuItem
|
||||||
<MenuItem
|
x:Name="menuSortServerResult"
|
||||||
x:Name="menuSortServerResult"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||||
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuRemoveInvalidServerResult"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
|
||||||
</MenuItem>
|
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuMoveToGroup"
|
x:Name="menuMoveToGroup"
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public partial class ProfilesView
|
|||||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.FastRealPingCmd, v => v.btnFastRealPing).DisposeWith(disposables);
|
||||||
|
|
||||||
//servers export
|
//servers export
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||||
@@ -126,7 +127,7 @@ public partial class ProfilesView
|
|||||||
case EViewAction.SaveFileDialog:
|
case EViewAction.SaveFileDialog:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
if (UI.SaveFileDialog(out string fileName, "Config|*.json") != true)
|
if (UI.SaveFileDialog(out var fileName, "Config|*.json") != true)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -136,17 +137,17 @@ public partial class ProfilesView
|
|||||||
case EViewAction.AddServerWindow:
|
case EViewAction.AddServerWindow:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
|
return new AddServerWindow((ProfileItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.AddServer2Window:
|
case EViewAction.AddServer2Window:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
|
return new AddServer2Window((ProfileItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.AddGroupServerWindow:
|
case EViewAction.AddGroupServerWindow:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new AddGroupServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
|
return new AddGroupServerWindow((ProfileItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.ShareServer:
|
case EViewAction.ShareServer:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
@@ -157,7 +158,7 @@ public partial class ProfilesView
|
|||||||
case EViewAction.SubEditWindow:
|
case EViewAction.SubEditWindow:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new SubEditWindow((SubItem)obj)).ShowDialog() ?? false;
|
return new SubEditWindow((SubItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.DispatcherRefreshServersBiz:
|
case EViewAction.DispatcherRefreshServersBiz:
|
||||||
Application.Current?.Dispatcher.Invoke(RefreshServersBiz, DispatcherPriority.Normal);
|
Application.Current?.Dispatcher.Invoke(RefreshServersBiz, DispatcherPriority.Normal);
|
||||||
@@ -169,7 +170,7 @@ public partial class ProfilesView
|
|||||||
|
|
||||||
public async void ShareServer(string url)
|
public async void ShareServer(string url)
|
||||||
{
|
{
|
||||||
var img = QRCodeUtils.GetQRCode(url);
|
var img = QRCodeWindowsUtils.GetQRCode(url);
|
||||||
var dialog = new QrcodeView()
|
var dialog = new QrcodeView()
|
||||||
{
|
{
|
||||||
imgQrcode = { Source = img },
|
imgQrcode = { Source = img },
|
||||||
@@ -414,8 +415,8 @@ public partial class ProfilesView
|
|||||||
private void LstProfiles_MouseMove(object sender, MouseEventArgs e)
|
private void LstProfiles_MouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
// Get the current mouse position
|
// Get the current mouse position
|
||||||
Point mousePos = e.GetPosition(null);
|
var mousePos = e.GetPosition(null);
|
||||||
Vector diff = startPoint - mousePos;
|
var diff = startPoint - mousePos;
|
||||||
|
|
||||||
if (e.LeftButton == MouseButtonState.Pressed &&
|
if (e.LeftButton == MouseButtonState.Pressed &&
|
||||||
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
||||||
@@ -428,7 +429,7 @@ public partial class ProfilesView
|
|||||||
if (listViewItem == null)
|
if (listViewItem == null)
|
||||||
return; // Abort
|
return; // Abort
|
||||||
// Find the data behind the ListViewItem
|
// Find the data behind the ListViewItem
|
||||||
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
var item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||||
if (item == null)
|
if (item == null)
|
||||||
return; // Abort
|
return; // Abort
|
||||||
// Initialize the drag & drop operation
|
// Initialize the drag & drop operation
|
||||||
@@ -461,7 +462,7 @@ public partial class ProfilesView
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Find the data behind the Item
|
// Find the data behind the Item
|
||||||
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
var item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||||
if (item == null)
|
if (item == null)
|
||||||
return;
|
return;
|
||||||
// Move item into observable collection
|
// Move item into observable collection
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ public partial class RoutingRuleDetailsWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
||||||
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ public partial class RoutingRuleDetailsWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ public partial class RoutingRuleSettingWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
|
PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
|
||||||
lstRules.SelectionChanged += lstRules_SelectionChanged;
|
lstRules.SelectionChanged += lstRules_SelectionChanged;
|
||||||
lstRules.MouseDoubleClick += LstRules_MouseDoubleClick;
|
lstRules.MouseDoubleClick += LstRules_MouseDoubleClick;
|
||||||
menuRuleSelectAll.Click += menuRuleSelectAll_Click;
|
menuRuleSelectAll.Click += menuRuleSelectAll_Click;
|
||||||
@@ -57,7 +57,7 @@ public partial class RoutingRuleSettingWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
@@ -80,11 +80,11 @@ public partial class RoutingRuleSettingWindow
|
|||||||
|
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new RoutingRuleDetailsWindow((RulesItem)obj)).ShowDialog() ?? false;
|
return new RoutingRuleDetailsWindow((RulesItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.ImportRulesFromFile:
|
case EViewAction.ImportRulesFromFile:
|
||||||
|
|
||||||
if (UI.OpenFileDialog(out string fileName, "Rules|*.json|All|*.*") != true)
|
if (UI.OpenFileDialog(out var fileName, "Rules|*.json|All|*.*") != true)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ public partial class RoutingRuleSettingWindow
|
|||||||
|
|
||||||
private void btnBrowseCustomIcon_Click(object sender, System.Windows.RoutedEventArgs e)
|
private void btnBrowseCustomIcon_Click(object sender, System.Windows.RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (UI.OpenFileDialog(out string fileName,
|
if (UI.OpenFileDialog(out var fileName,
|
||||||
"PNG,ICO|*.png;*.ico") != true)
|
"PNG,ICO|*.png;*.ico") != true)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -185,7 +185,7 @@ public partial class RoutingRuleSettingWindow
|
|||||||
|
|
||||||
private void btnBrowseCustomRulesetPath4Singbox_Click(object sender, RoutedEventArgs e)
|
private void btnBrowseCustomRulesetPath4Singbox_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (UI.OpenFileDialog(out string fileName,
|
if (UI.OpenFileDialog(out var fileName,
|
||||||
"Config|*.json|All|*.*") != true)
|
"Config|*.json|All|*.*") != true)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ public partial class RoutingSettingWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
this.Closing += RoutingSettingWindow_Closing;
|
Closing += RoutingSettingWindow_Closing;
|
||||||
this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown;
|
PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown;
|
||||||
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;
|
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;
|
||||||
lstRoutings.MouseDoubleClick += LstRoutings_MouseDoubleClick;
|
lstRoutings.MouseDoubleClick += LstRoutings_MouseDoubleClick;
|
||||||
menuRoutingAdvancedSelectAll.Click += menuRoutingAdvancedSelectAll_Click;
|
menuRoutingAdvancedSelectAll.Click += menuRoutingAdvancedSelectAll_Click;
|
||||||
@@ -44,7 +44,7 @@ public partial class RoutingSettingWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
@@ -58,7 +58,7 @@ public partial class RoutingSettingWindow
|
|||||||
|
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new RoutingRuleSettingWindow((RoutingItem)obj)).ShowDialog() ?? false;
|
return new RoutingRuleSettingWindow((RoutingItem)obj).ShowDialog() ?? false;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ public partial class RoutingSettingWindow
|
|||||||
{
|
{
|
||||||
if (ViewModel?.IsModified == true)
|
if (ViewModel?.IsModified == true)
|
||||||
{
|
{
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,11 +122,11 @@ public partial class RoutingSettingWindow
|
|||||||
{
|
{
|
||||||
if (ViewModel?.IsModified == true)
|
if (ViewModel?.IsModified == true)
|
||||||
{
|
{
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,11 +71,11 @@ public partial class StatusBarView
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.DispatcherRefreshIcon:
|
case EViewAction.DispatcherRefreshIcon:
|
||||||
Application.Current?.Dispatcher.Invoke((async () =>
|
Application.Current?.Dispatcher.Invoke(async () =>
|
||||||
{
|
{
|
||||||
tbNotify.Icon = await WindowsManager.Instance.GetNotifyIcon(_config);
|
tbNotify.Icon = await WindowsManager.Instance.GetNotifyIcon(_config);
|
||||||
Application.Current.MainWindow.Icon = WindowsManager.Instance.GetAppIcon(_config);
|
Application.Current.MainWindow.Icon = WindowsManager.Instance.GetAppIcon(_config);
|
||||||
}), DispatcherPriority.Normal);
|
}, DispatcherPriority.Normal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.SetClipboardData:
|
case EViewAction.SetClipboardData:
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ public partial class SubEditWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
Loaded += Window_Loaded;
|
||||||
|
|
||||||
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ public partial class SubEditWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ public partial class SubSettingWindow
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
Owner = Application.Current.MainWindow;
|
||||||
|
|
||||||
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
||||||
this.Closing += SubSettingWindow_Closing;
|
Closing += SubSettingWindow_Closing;
|
||||||
lstSubscription.MouseDoubleClick += LstSubscription_MouseDoubleClick;
|
lstSubscription.MouseDoubleClick += LstSubscription_MouseDoubleClick;
|
||||||
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
||||||
menuClose.Click += menuClose_Click;
|
menuClose.Click += menuClose_Click;
|
||||||
@@ -34,7 +34,7 @@ public partial class SubSettingWindow
|
|||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case EViewAction.CloseWindow:
|
case EViewAction.CloseWindow:
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
@@ -47,7 +47,7 @@ public partial class SubSettingWindow
|
|||||||
case EViewAction.SubEditWindow:
|
case EViewAction.SubEditWindow:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
return (new SubEditWindow((SubItem)obj)).ShowDialog() ?? false;
|
return new SubEditWindow((SubItem)obj).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.ShareSub:
|
case EViewAction.ShareSub:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
@@ -64,7 +64,7 @@ public partial class SubSettingWindow
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var img = QRCodeUtils.GetQRCode(url);
|
var img = QRCodeWindowsUtils.GetQRCode(url);
|
||||||
var dialog = new QrcodeView()
|
var dialog = new QrcodeView()
|
||||||
{
|
{
|
||||||
imgQrcode = { Source = img },
|
imgQrcode = { Source = img },
|
||||||
@@ -78,7 +78,7 @@ public partial class SubSettingWindow
|
|||||||
{
|
{
|
||||||
if (ViewModel?.IsModified == true)
|
if (ViewModel?.IsModified == true)
|
||||||
{
|
{
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +99,11 @@ public partial class SubSettingWindow
|
|||||||
{
|
{
|
||||||
if (ViewModel?.IsModified == true)
|
if (ViewModel?.IsModified == true)
|
||||||
{
|
{
|
||||||
this.DialogResult = true;
|
DialogResult = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user