diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index d5f9b1c5..b67527a1 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -9,6 +9,12 @@ on: push: branches: - master + tags: + - 'v*' + - 'V*' + +permissions: + contents: write env: OutputArch: "linux-64" @@ -21,7 +27,6 @@ jobs: strategy: matrix: configuration: [Release] - runs-on: ubuntu-24.04 steps: @@ -31,21 +36,21 @@ jobs: submodules: 'recursive' fetch-depth: '0' - - name: Setup + - name: Setup .NET uses: actions/setup-dotnet@v5.0.0 with: dotnet-version: '8.0.x' - name: Build run: | - 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-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-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64 + 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-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-arm64 --self-contained=true -p:PublishTrimmed=true -o "$OutputPathArm64" - name: Upload build artifacts - uses: actions/upload-artifact@v4.6.2 + uses: actions/upload-artifact@v5.0.0 with: name: v2rayN-linux path: | @@ -56,8 +61,8 @@ jobs: if: github.event.inputs.release_tag != '' run: | chmod 755 package-debian.sh - ./package-debian.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }} - ./package-debian.sh $OutputArchArm $OutputPathArm64 ${{ 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 }}" - name: Upload deb to release uses: svenstaro/upload-release-action@v2 @@ -68,28 +73,13 @@ jobs: file_glob: 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 - name: Package release zip archive if: github.event.inputs.release_tag != '' run: | chmod 755 package-release-zip.sh - ./package-release-zip.sh $OutputArch $OutputPath64 - ./package-release-zip.sh $OutputArchArm $OutputPathArm64 + ./package-release-zip.sh "$OutputArch" "$OutputPath64" + ./package-release-zip.sh "$OutputArchArm" "$OutputPathArm64" - name: Upload zip archive to release uses: svenstaro/upload-release-action@v2 @@ -100,36 +90,62 @@ jobs: file_glob: true prerelease: true - # release RHEL package - - name: Package RPM (RHEL-family) - if: github.event.inputs.release_tag != '' + rpm: + needs: build + 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: | - chmod 755 package-rhel.sh - # Build for both x86_64 and aarch64 in one go (explicit version passed; no --buildfrom) - ./package-rhel.sh "${{ github.event.inputs.release_tag }}" --arch all + dnf -y makecache + dnf -y install epel-release + 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 - if: github.event.inputs.release_tag != '' run: | - mkdir -p "${{ github.workspace }}/dist/rpm" - rsync -av "$HOME/rpmbuild/RPMS/" "${{ github.workspace }}/dist/rpm/" - # Rename to requested filenames - 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 + mkdir -p "$GITHUB_WORKSPACE/dist/rpm" + rsync -av "$HOME/rpmbuild/RPMS/" "$GITHUB_WORKSPACE/dist/rpm/" || true + 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*.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 - if: github.event.inputs.release_tag != '' - uses: actions/upload-artifact@v4.6.2 + uses: actions/upload-artifact@v5.0.0 with: name: v2rayN-rpm - path: | - ${{ github.workspace }}/dist/rpm/**/*.rpm + path: dist/rpm/**/*.rpm - name: Upload RPMs to release uses: svenstaro/upload-release-action@v2 - if: github.event.inputs.release_tag != '' with: - file: ${{ github.workspace }}/dist/rpm/**/*.rpm - tag: ${{ github.event.inputs.release_tag }} + file: dist/rpm/**/*.rpm + tag: ${{ env.RELEASE_TAG }} file_glob: true prerelease: true diff --git a/.github/workflows/build-osx.yml b/.github/workflows/build-osx.yml index 97c002c7..5825ac9d 100644 --- a/.github/workflows/build-osx.yml +++ b/.github/workflows/build-osx.yml @@ -45,7 +45,7 @@ jobs: dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64 - name: Upload build artifacts - uses: actions/upload-artifact@v4.6.2 + uses: actions/upload-artifact@v5.0.0 with: name: v2rayN-macos path: | diff --git a/.github/workflows/build-windows-desktop.yml b/.github/workflows/build-windows-desktop.yml index 3b28599d..65b86126 100644 --- a/.github/workflows/build-windows-desktop.yml +++ b/.github/workflows/build-windows-desktop.yml @@ -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 - name: Upload build artifacts - uses: actions/upload-artifact@v4.6.2 + uses: actions/upload-artifact@v5.0.0 with: name: v2rayN-windows-desktop path: | diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index fea3aa70..31b5a90c 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -46,7 +46,7 @@ jobs: - name: Upload build artifacts - uses: actions/upload-artifact@v4.6.2 + uses: actions/upload-artifact@v5.0.0 with: name: v2rayN-windows path: | diff --git a/package-appimage.sh b/package-appimage.sh deleted file mode 100755 index 6c3ae311..00000000 --- a/package-appimage.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env 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" <"$APPDIR_ARM64/AppRun" -chmod +x "$APPDIR_ARM64/AppRun" -ln -sf usr/lib/v2rayN/v2rayN "$APPDIR_ARM64/usr/bin/v2rayN" -cat >"$APPDIR_ARM64/v2rayN.desktop" < Homepage: https://git.vlyaii.ru/voronin9032/v2rayN Architecture: $Arch2 Replaces: v2rayn -Depends: libc6 (>= 2.35), 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) Breaks: v2rayn Conflicts: v2rayn Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others diff --git a/package-rhel.sh b/package-rhel.sh index 3894a932..86c75665 100755 --- a/package-rhel.sh +++ b/package-rhel.sh @@ -19,6 +19,23 @@ else exit 1 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 ========================================================= VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty WITH_CORE="both" # Default: bundle both xray+sing-box @@ -264,8 +281,13 @@ ExclusiveArch: aarch64 x86_64 Source0: __PKGROOT__.tar.gz # Runtime dependencies (Avalonia / X11 / Fonts / GL) -Requires: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrender, libXfixes, libXinerama, libxkbcommon -Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL, xdg-utils +Requires: freetype, cairo, pango, openssl, mesa-libEGL, mesa-libGL +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 Conflicts: v2rayN Obsoletes: v2rayN diff --git a/v2rayN/Directory.Build.props b/v2rayN/Directory.Build.props index bea02572..d97ccb93 100644 --- a/v2rayN/Directory.Build.props +++ b/v2rayN/Directory.Build.props @@ -1,7 +1,7 @@ - 7.15.6 + 7.15.7 diff --git a/v2rayN/Directory.Packages.props b/v2rayN/Directory.Packages.props index a339af4c..b9caf59f 100644 --- a/v2rayN/Directory.Packages.props +++ b/v2rayN/Directory.Packages.props @@ -9,16 +9,16 @@ - + - + - + diff --git a/v2rayN/ServiceLib/Common/JsonUtils.cs b/v2rayN/ServiceLib/Common/JsonUtils.cs index b5bcc7fe..7e2b7f78 100644 --- a/v2rayN/ServiceLib/Common/JsonUtils.cs +++ b/v2rayN/ServiceLib/Common/JsonUtils.cs @@ -35,9 +35,13 @@ public class JsonUtils /// /// /// - public static T DeepCopy(T obj) + public static T? DeepCopy(T? obj) { - return Deserialize(Serialize(obj, false))!; + if (obj is null) + { + return default; + } + return Deserialize(Serialize(obj, false)); } /// @@ -67,7 +71,7 @@ public class JsonUtils /// /// /// - public static JsonNode? ParseJson(string strJson) + public static JsonNode? ParseJson(string? strJson) { try { @@ -116,7 +120,7 @@ public class JsonUtils /// /// /// - public static string Serialize(object? obj, JsonSerializerOptions options) + public static string Serialize(object? obj, JsonSerializerOptions? options) { var result = string.Empty; try @@ -125,7 +129,7 @@ public class JsonUtils { return result; } - result = JsonSerializer.Serialize(obj, options); + result = JsonSerializer.Serialize(obj, options ?? _defaultSerializeOptions); } catch (Exception ex) { diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index 5ca96a88..7f842ddf 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -963,13 +963,13 @@ public class Utils #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) { @@ -994,11 +994,6 @@ public class Utils return false; } - if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPIMAGE"))) - { - return true; - } - var exePath = GetExePath(); var baseDir = string.IsNullOrEmpty(exePath) ? StartupPath() : Path.GetDirectoryName(exePath) ?? ""; var p = baseDir.Replace('\\', '/'); @@ -1008,11 +1003,6 @@ public class Utils return false; } - if (p.Contains("/.mount_", StringComparison.Ordinal)) - { - return true; - } - if (p.StartsWith("/opt/v2rayN", StringComparison.OrdinalIgnoreCase)) { return true; diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 2327de48..492aa124 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -427,6 +427,7 @@ public class Global "zh-Hant", "en", "fa-Ir", + "fr", "ru", "hu" ]; diff --git a/v2rayN/ServiceLib/Manager/CoreAdminManager.cs b/v2rayN/ServiceLib/Manager/CoreAdminManager.cs index 0d52f1c7..dbd19d38 100644 --- a/v2rayN/ServiceLib/Manager/CoreAdminManager.cs +++ b/v2rayN/ServiceLib/Manager/CoreAdminManager.cs @@ -34,7 +34,7 @@ public class CoreAdminManager StringBuilder sb = new(); sb.AppendLine("#!/bin/bash"); 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 procService = new ProcessService( diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx new file mode 100644 index 00000000..a56802e3 --- /dev/null +++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx @@ -0,0 +1,1599 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Lien de partage exporté vers le presse-papiers avec succès + + + Veuillez vérifier d’abord la config + + + Format de configuration incorrect + + + Attention : la configuration personnalisée dépend entièrement de vos paramètres et peut ne pas activer toutes les fonctions. Pour utiliser le proxy système, changez le port d’écoute manuellement. + + + Téléchargement commencé... + + + Échec de la conversion de la configuration + + + Échec de la génération du fichier de configuration par défaut + + + Échec de l’obtention de la configuration par défaut + + + Échec de l’importation de la configuration personnalisée + + + Échec de la lecture de la configuration + + + Veuillez saisir un port au format correct + + + Veuillez saisir le port d’écoute local + + + Veuillez saisir le mot de passe + + + Veuillez saisir l’adresse + + + Veuillez saisir l’ID utilisateur + + + Configuration incorrecte, veuillez vérifier + + + Initialiser la configuration + + + {0} {1} est déjà à jour. + + + {0} {1} est déjà à jour. + + + Adresse + + + Méthode de chiffrement + + + Port + + + Type + + + Grp abonn. + + + Téléchargement du jour + + + Téléversement du jour + + + Total téléchargé + + + Total téléversé + + + Protoc. Transp. + + + Téléchargement du Core réussi + + + Échec de l’importation du contenu d’abonnement + + + Contenu d’abonnement récupéré avec succès + + + Aucun abonnement valide défini + + + Analyse de {0} réussie + + + Début de la récupération du contenu d’abonnement + + + Début de la mise à jour de {0}... + + + Contenu d’abonnement invalide + + + Décompression en cours...... + + + Fin de la mise à jour des abonnements + + + Début de la mise à jour des abonnements + + + Mise à jour du Core réussie + + + Mise à jour du Core réussie ! Redémarrage du service... + + + Protocole non VMess ni SS + + + Fichier Core introuvable dans le dossier ({0}) (nom de fichier : {1}). Veuillez le télécharger puis le placer dans le dossier. Adresse de téléchargement : {2} + + + Analyse terminée, aucun QR code valide trouvé + + + Échec de l’opération, veuillez vérifier et réessayer + + + Veuillez saisir un alias + + + Veuillez sélectionner une méthode de chiffrement + + + Veuillez sélectionner un protocole + + + Sélectionnez d’abord une configuration + + + Déduplication des configurations terminée. Quantité initiale : {0}, quantité actuelle : {1}. + + + Confirmer la suppression ? + + + Le fichier de configuration client est enregistré dans : {0} + + + Démarrage du service ({0})... + + + Configuration réussie. {0} + + + Configuration personnalisée importée avec succès + + + {0} configurations importées depuis le presse-papiers + + + Lien de partage importé par analyse avec succès + + + Latence actuelle : {0} ms, {1} + + + Opération réussie + + + Veuillez d’abord sélectionner une règle + + + Confirmer la suppression de la règle ? + + + {0}, au moins un champ est obligatoire. + + + Alias + + + Adresse optionnelle (URL) + + + Quantité + + + Veuillez saisir l’URL + + + Ajouter les règles ? Choisir "Oui" pour ajouter, "Non" pour tout remplacer. + + + Téléchargement du fichier Geo : {0} réussi + + + Information + + + Icône personnalisée + + + Veuillez saisir un DNS personnalisé valide + + + *chemin ws/httpupgrade/xhttp + + + *chemin h2 + + + *clé de chiffrement QUIC + + + *nom de service gRPC + + + *hôte http, séparés par des virgules (,) + + + *hôte ws/httpupgrade/xhttp + + + *hôte h2, séparés par des virgules (,) + + + *méthode de chiffrement QUIC + + + *type de camouflage tcp + + + *type de camouflage kcp + + + *type de camouflage QUIC + + + *mode gRPC + + + TLS + + + *graine Kcp + + + Échec de l’enregistrement du raccourci global {0}, raison : {1} + + + Raccourci global {0} enregistré avec succès + + + Tous + + + Parcourir pour importer la configuration + + + Test en cours... + + + Réseau local + + + Local + + + Filtre : Entrée pour exécuter + + + Rechercher mises à jour + + + Fermer + + + Quitter + + + Paramètres des raccourcis globaux + + + Aide + + + Paramètres config + + + Promotion + + + Redémarrer + + + Paramètres de routage + + + Fichiers de config + + + Paramètres + + + Mettre à jour l’abonnement actuel (sans proxy) + + + Mettre à jour l’abonnement actuel (via le proxy) + + + Groupe abonnements + + + Paramètres des groupes d’abonnement + + + Mettre à jour tous les abonnements (sans proxy) + + + Mettre à jour tous les abonnements (via le proxy) + + + Proxy système + + + Effacer le proxy système + + + Ne pas modifier le proxy système + + + Mode PAC + + + Configuration auto proxy système + + + Couleur + + + Langue (redémarrage requis) + + + Importer liens depuis le presse-papiers (Ctrl+V) + + + Scanner le QR code à l’écran (Ctrl+S) + + + Cloner la sélection + + + Supprimer les doublons + + + Supprimer la sélection (multi-sélection) (Delete) + + + Définir comme actif (Entrée) + + + Effacer toutes les statistiques de service + + + Tester la latence de connexion réelle (multi-sélect) (Ctrl+R) + + + Trier selon les résultats de test + + + Tester la vitesse (multi-sélection) (Ctrl+T) + + + Tester la latence Tcping (multi-sélection) (Ctrl+O) + + + Exporter la configuration complète sélectionnée + + + Exporter les liens de partage vers le presse-papiers (multi-sélection) (Ctrl+C) + + + Ajouter une configuration personnalisée + + + Ajouter [Shadowsocks] + + + Ajouter [SOCKS] + + + Ajouter [Trojan] + + + Ajouter [VLESS] + + + Ajouter [VMess] + + + Tout sélectionner (Ctrl+A) + + + Tout effacer + + + Copier (Ctrl+C) + + + Tout copier + + + Tout sélect (Ctrl+A) + + + Ajouter + + + Supprimer + + + Éditer + + + Partager + + + Activer MAJ + + + Tri + + + User-Agent (optionnel) + + + Annuler + + + OK + + + Méthode de transport sous-jacente (transport) + + + Adresse (address) + + + Ignorer la vérification du certificat (allowInsecure) + + + ALPN + + + ID supplémentaire (alterId) + + + Empreinte + + + Type de camouflage (type) + + + ID utilisateur (id) + + + Protocole (network) + + + Chemin (path) + + + Port (port) + + + Alias (remarks) + + + Domaine de camouflage (host) + + + Méthode de chiffrement (security) + + + SNI + + + Sécurité couche transport (TLS) + + + *tcp par défaut ; un mauvais choix bloque la connexion + + + Type de Core + + + Contrôle de flux (flow) + + + Générer + + + Mot de passe (password) + + + Mot de passe (optionnel) + + + ID utilisateur (id) + + + Mode chiffrement (encryption) + + + Nom d’utilisateur (optionnel) + + + Mode chiffrement (encryption) + + + Port Socks + + + *Valeur du port Socks (config perso, optionnelle). Si défini, Xray/sing-box (Tun) démarre un service Socks en amont supplémentaire pour fournir le routage sélectif et l’affichage de la vitesse. + + + Parcourir + + + Éditer + + + Paramètres avancés du proxy, choix du protocole (optionnel) + + + Autoriser les connexions depuis le LAN + + + Masquer la fenêtre au démarrage + + + Intervalle de mise à jour auto des fichiers Geo (heures) + + + Core : paramètres de base + + + DNS personnalisé v2ray + + + Core : paramètres KCP + + + Paramètres du type de Core + + + Ignorer la vérif. du certificat (Dangereux) + + + domainStrategy de Freedom (sortant) + + + Auto-ajuster la largeur des colonnes après maj. abonnements + + + Vérifier les mises à jour pré-version (à activer avec prudence) + + + Exceptions + + + Exceptions : pour les adresses commençant par les caractères ci-dessous, ne pas utiliser le proxy. Séparez par des points-virgules (;). + + + Afficher la vitesse en temps réel (redémarrage requis) + + + À la déduplication, garder l’élément au plus petit numéro + + + Activer les journaux + + + Niveau de journalisation + + + Activer Mux multiplex + + + Paramètres v2rayN + + + Mot de passe d’authentification + + + DNS perso (plusieurs configurables, séparés par virgules) + + + Lever la restriction de proxy en boucle locale pour les applications Win10 UWP + + + Activer le sniffing de trafic + + + Port d’écoute mixte local + + + Lancer au démarrage (peut échouer) + + + Activer les statistiques de trafic (redémarrage requis) + + + URL de conversion d’abonnement (optionnel) + + + Paramètres du proxy système + + + Limite du nombre de configurations affichées dans le menu du plateau + + + Activer l’UDP + + + Nom d’utilisateur d’authentification + + + Effacer le proxy système + + + Afficher l’interface principale + + + Paramètres des raccourcis globaux + + + Appuyez directement sur les touches pour définir ; prendra effet après redémarrage + + + Ne pas modifier le proxy système + + + Réinitialiser + + + Configurer automatiquement le proxy système + + + Mode PAC + + + Partager (Ctrl+F) + + + Routage + + + Exécuter sans droits administrateur + + + Exécuter en tant qu’administrateur + + + Déplacer tout en bas (B) + + + Descendre (D) + + + Déplacer tout en haut (T) + + + Monter (U) + + + Filtre (regex pris en charge) + + + Site officiel de {0} + + + Ajouter un jeu de règles + + + Importer 1-clic du jeu de règles + + + Suppr. règles sélectionnées (Delete) + + + Définir comme règles actives (Entrée) + + + Stratégie résolution domaine + + + Liste des jeux de règles prédef. + + + *Règles de routage définies, séparées par des virgules (,); remplacez la virgule dans les expressions régulières par <COMMA> + + + Importer règles du presse-papiers + + + Importer règles depuis fichier + + + Importer depuis URL d’abonnement + + + Paramètres du jeu de règles + + + Ajouter une règle + + + Exporter les règles sélectionnées vers le presse-papiers + + + Liste des règles + + + Supprimer les règles sélectionnées (Delete) + + + Paramètres détaillés des règles de routage + + + Tri automatique par domaine, IP et nom de processus lors de l’enregistrement + + + Documentation détaillée des règles + + + Saisie DnsObject prise en charge (format JSON), cliquer pour doc + + + Laissez vide pour les groupes ordinaires + + + Paramètres de routage modifiés + + + Paramètres du proxy système modifiés + + + Routage uniquement (routeOnly) + + + Ne pas utiliser le proxy pour les adresses locales (Intranet) + + + Tester latence et vitesse multithread en un clic (Ctrl+E) + + + Latence (ms) + + + Vitesse (Mo/s) + + + Échec d’exécution du Core, veuillez consulter les messages + + + Filtrage par alias (regex) + + + Afficher les logs + + + Activer Tun + + + Ouvrir un nouveau port pour le LAN + + + Paramètres du mode Tun + + + Déplacer vers un groupe d’abonnement + + + Activer le tri par glisser-déposer des configurations (redémarrage requis) + + + Actualisation automatique + + + Ignorer le test + + + Éditer (Ctrl+D) + + + Double-cliquer sur l’interface principale pour activer + + + Test terminé + + + Empreinte TLS par défaut (fingerprint) + + + Agent utilisateur (User-Agent) + + + Valable uniquement pour les protocoles tcp/http et ws + + + Police actuelle (redémarrage requis) + + + Copiez les fichiers de police TTF/TTC dans le dossier guiFonts, effet après redémarrage + + + Port PAC = +3 ; port API Xray = +4 ; port API mihomo = +5 ; + + + Définir cette option avec des privilèges administrateur pour obtenir les droits admin au démarrage + + + Taille de police + + + Valeur délai d'expiration test vitesse unique + + + URL du fichier de test de vitesse + + + Déplacer vers haut/bas + + + PublicKey + + + ShortId + + + SpiderX + + + Activer l’accélération matérielle (redémarrage requis) + + + En attente du test (appuyer sur Échap pour arrêter)... + + + Désactiver cette option si coupure anormale + + + Mise à jour désactivée, abonnement ignoré + + + Redémarrer en tant qu’administrateur + + + Adresses suppl. (URL), séparées par des virgules ; la conversion d’abonnement sera désactivée + + + Intervalle maj. auto (min) + + + Activer l’enregistrement des journaux dans un fichier + + + Type cible conv. d’abonnement + + + Laisser vide si aucune conversion n’est nécessaire + + + Paramètres DNS + + + DNS personnalisé sing-box + + + Saisissez la structure JSON DNS ; cliquez pour voir la doc. + + + Cliquez pour importer la config DNS par défaut + + + Stratégie résolution domaine (sing-box) + + + Protocole de multiplexage Mux (sing-box) + + + Nom complet du processus (mode Tun) + + + IP ou IP CIDR + + + Domaine + + + Ajouter [Hysteria2] + + + Bande passante maximale Hysteria (Up/Down) + + + Utiliser les hosts du système + + + Ajouter [TUIC] + + + Algo contrôle congestion + + + Alias de config du proxy amont + + + Alias de config du proxy aval + + + Assurez-vous que l’alias config existe et est unique + + + Routage automatique + + + Routage strict + + + Pile de protocoles + + + MTU + + + Activer un port d’écoute supplémentaire + + + Activer IPv6 + + + Ajouter [WireGuard] + + + PrivateKey + + + Reserved (2,3,4) + + + Address (IPv4,IPv6) + + + Mot de passe d’obfuscation (obfs password) + + + (Domaine ou IP ou nom de processus) avec Port et Protocole et InboundTag => OutboundTag + + + Défilement automatique vers la fin + + + Adresse de test de connexion réelle + + + Ne vérifier l’existence de l’alias qu’à la maj. des abonnements + + + Arrêt du test en cours... + + + *Autorité gRPC + + + Ajouter [HTTP] + + + En conflit avec le proxy amont de groupe + + + Activer le fragmentation (Fragment) + + + Activer le fichier de cache de sing-box (fichiers règles) + + + Set de règles sing-box perso + + + Opération réussie. Veuillez redémarrer l’app via le menu Paramètres. + + + Ouvrir l’emplacement du fichier + + + Tri + + + Chaîne de routage + + + Par défaut + + + Latence + + + Vitesse de téléchargement + + + Trafic téléchargé + + + Hôte + + + Nom + + + Réseau + + + Heure + + + Type + + + Vitesse d’envoi + + + Trafic envoyé + + + Connexions en cours + + + Fermer la connexion + + + Fermer toutes les connexions + + + Proxies actuels + + + Mode règle + + + Direct + + + Global + + + Suivre la configuration d’origine + + + Règle + + + Test de latence + + + Test de latence partiel actuel + + + Actualiser + + + Définir comme actif (Entrée) + + + Stratégie de résolution par défaut des sortants + + + Orientation mise en page principale (redémarrage requis) + + + Adresse de résolution de domaine pour sortants + + + Ajuster auto. la largeur des colonnes + + + Exporter les liens de partage en Base64 vers le presse-papiers (multi-sélection) + + + Exporter la configuration complète sélectionnée vers le presse-papiers + + + Afficher ou masquer l’interface principale + + + Port Socks config personnalisée + + + Sauvegarder et restaurer + + + Sauvegarder localement + + + Restaurer localement + + + Sauvegarder à distance (WebDAV) + + + Restaurer à distance (WebDAV) + + + Local + + + Distant (WebDAV) + + + Adresse du serveur WebDAV + + + Compte WebDAV + + + Mot de passe WebDAV + + + Vérification de disponibilité WebDAV + + + Nom du dossier distant (optionnel) + + + Fichier de sauvegarde invalide + + + Filtre d’hôte + + + Actif + + + Source des fichiers Geo (optionnel) + + + Source des fichiers de jeux de règles sing-box (optionnel) + + + L’application d’outil de mise à niveau est introuvable + + + Source des jeux de règles de routage (optionnel) + + + Réglages régionaux prédéfinis + + + Région par défaut + + + Russie + + + Iran + + + Les utilisateurs de Chine peuvent ignorer + + + Scanner le QR code dans l’image + + + Adresse (URL) invalide + + + N’utilisez pas d’adresse d’abonnement HTTP non sécurisée + + + Installer la police sur le système, choisir ou saisir son nom, effet après redémarrage + + + Voulez-vous vraiment quitter ? + + + Mémo + + + Mot de passe sudo système + + + Le mot de passe sera vérifié en ligne de commande. En cas d’échec ou de dysfonctionnement, redémarrez l’application. Il n’est pas stocké et doit être saisi à chaque redémarrage. + + + *Mode XHTTP + + + JSON brut XHTTP Extra, format : { XHTTPObject } + + + Masquer dans la barre d’état à la fermeture de la fenêtre + + + Niveau de concurrence lors des tests multithread + + + Exceptions : ne pas utiliser le proxy pour ces adresses, séparées par des virgules (,). + + + Type de détection de trafic + + + Activer un second port d’écoute local + + + Socks : port local ; Socks2 : deuxième port local ; Socks3 : port LAN + + + Thème + + + Copier la cmd proxy terminal dans le presse-papiers + + + Recommencer le test des éléments échoués, {0} restants. Appuyez sur Échap pour arrêter... + + + Selon le résultat des tests + + + Supprimer les éléments invalides selon résultats tests + + + {0} résultats de test invalides supprimés. + + + Plage de ports sautés + + + Écrase le port ; pour plusieurs groupes, séparer par virgules (,) + + + Générer un groupe de stratégie depuis plusieurs profils + + + Xray aléatoire (multi-sélection) + + + Xray équilibrage (tourniquet) multi-sélection + + + Xray latence minimale (multi-sélection) + + + Xray le plus stable (multi-sélection) + + + sing-box latence minimale (multi-sélection) + + + Exporter + + + Adresse de test d’informations de connexion actuelles + + + Vous pouvez saisir un alias de configuration ; assurez-vous qu’il existe et qu’il est unique + + + Mot de passe incorrect, veuillez réessayer. + + + Mldsa65Verify + + + Ajouter [Anytls] + + + DNS distant + + + DNS direct + + + Via le proxy ; assurez-vous que le serveur distant est disponible + + + Stratégie de résolution xray freedom + + + Stratégie de résolution directe sing-box + + + Stratégie de résolution distante sing-box + + + Ajouter des hôtes DNS courants + + + FakeIP + + + Bloquer les requêtes SVCB et HTTPS + + + Hôtes DNS : (« domaine1 ip1 ip2 » une ligne par entrée) + + + Paramètres DNS de base + + + Paramètres DNS avancés + + + Valider les IP des domaines de la région concernée + + + Après config, les IP renvoyées des domaines régionaux (ex. geosite:cn) seront vérifiées ; seules les IP attendues seront retournées. + + + Activer le DNS personnalisé + + + DNS personnalisé activé ; la configuration de cette page sera ignorée + + + Une fois activé, bloque les requêtes ECH et de disponibilité HTTP/3 + + + Veuillez saisir un modèle de configuration valide + + + Paramètres du modèle de config complet + + + Activer le modèle de config. complet + + + Modèle de configuration complet v2ray + + + Ajoute seulement la config sortante, routing.balancers et routing.rules.outboundTag. Voir la doc. + + + N’ajoutez pas de sorties pour protocoles non-proxy. + + + Définir le tag de proxy amont + + + Modèle de configuration complet sing-box + + + Ajoute uniquement la configuration des sortants et des endpoints ; cliquer pour voir la documentation + + + Cette fonction s’adresse aux utilisateurs avancés et aux besoins spécifiques. Une fois activée, les paramètres de base du Core, du DNS et du routage sont ignorés. Vous devez vous assurer que la configuration des ports du proxy système, des statistiques de trafic, etc., est correcte — tout est à votre charge. + + + Début de l’analyse et du traitement du contenu d’abonnement + + + Choisir une config. + + + Actif globalement par défaut, avec filtre FakeIP intégré ; ne fonctionne que dans sing-box + + + Veuillez ajouter au moins une configuration + + + Groupe de stratégie + + + Chaîne de proxy + + + Latence minimale + + + Aléatoire + + + Round Robin + + + Le plus stable + + + Type de groupe de stratégie + + + Ajouter un groupe de stratégie + + + Ajouter une chaîne de proxy + + + Ajouter un enfant + + + Supprimer l’enfant + + + Liste des enfants + + + Basculement (failover) + + + sing-box basculement (multi-sélection) + + + Xray basculement (multi-sélection) + + + Le cœur « {0} » ne prend pas en charge le type de réseau « {1} ». + + + Le cœur « {0} » ne prend pas en charge le protocole « {1} » avec le mode de transport « {2} ». + + + Le cœur « {0} » ne prend pas en charge le protocole « {1} ». + + + Chaîne de proxy : + + + Règle de routage sortante : + + + Groupe de stratégie : + + + L’alias « {0} » n’existe pas. + + + Le groupe « {0} » est vide. Veuillez ajouter au moins une configuration. + + + La propriété {0} est invalide, veuillez vérifier + + + Le groupe {0} ne peut pas se référencer lui-même ni créer de référence circulaire + + + Protocole « {0} » non pris en charge. + + + Si le système n’a pas de zone de notif., n’activez pas cette option + + + Type de règle + + + Des règles peuvent être définies séparément pour Routing et DNS ; ALL les applique aux deux + + + DNS d’amorçage + + + Résoudre le nom du serveur DNS ; doit être spécifié en IP + + + Test 1-clic de latence réelle + + diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index 095d8594..96c470c6 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -427,7 +427,7 @@ 路由设置 - 配置文件 + 配置项 设置 diff --git a/v2rayN/ServiceLib/Sample/kill_as_sudo_linux_sh b/v2rayN/ServiceLib/Sample/kill_as_sudo_linux_sh index 7f62a532..21e17408 100644 --- a/v2rayN/ServiceLib/Sample/kill_as_sudo_linux_sh +++ b/v2rayN/ServiceLib/Sample/kill_as_sudo_linux_sh @@ -28,15 +28,15 @@ fi kill_children() { local parent=$1 local children=$(ps -o pid --no-headers --ppid "$parent") - + # Output information about processes being terminated echo "Processing children of PID: $parent..." - + # Process each child for child in $children; do # Recursively find and kill child's children first kill_children "$child" - + # Force kill the child process echo "Terminating child process: $child" kill -9 "$child" 2>/dev/null || true @@ -47,6 +47,18 @@ echo "============================================" echo "Starting termination of process $PID and all its children" 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 kill_children "$PID" diff --git a/v2rayN/ServiceLib/Sample/kill_as_sudo_osx_sh b/v2rayN/ServiceLib/Sample/kill_as_sudo_osx_sh index 94011d6f..61160fa2 100644 --- a/v2rayN/ServiceLib/Sample/kill_as_sudo_osx_sh +++ b/v2rayN/ServiceLib/Sample/kill_as_sudo_osx_sh @@ -42,6 +42,20 @@ echo "============================================" echo "Starting termination of process $PID and all its descendants" 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 kill_descendants "$PID" diff --git a/v2rayN/ServiceLib/ServiceLib.csproj b/v2rayN/ServiceLib/ServiceLib.csproj index 457b065d..8cfbf8ca 100644 --- a/v2rayN/ServiceLib/ServiceLib.csproj +++ b/v2rayN/ServiceLib/ServiceLib.csproj @@ -57,6 +57,9 @@ Designer PublicResXFileCodeGenerator + + PublicResXFileCodeGenerator + PublicResXFileCodeGenerator @@ -79,4 +82,4 @@ - \ No newline at end of file + diff --git a/v2rayN/v2rayN.Desktop/App.axaml.cs b/v2rayN/v2rayN.Desktop/App.axaml.cs index 5da86c6e..35371f0f 100644 --- a/v2rayN/v2rayN.Desktop/App.axaml.cs +++ b/v2rayN/v2rayN.Desktop/App.axaml.cs @@ -10,15 +10,17 @@ public partial class App : Application AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; - - DataContext = StatusBarViewModel.Instance; } public override void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - AppManager.Instance.InitComponents(); + if (!Design.IsDesignMode) + { + AppManager.Instance.InitComponents(); + DataContext = StatusBarViewModel.Instance; + } desktop.Exit += OnExit; desktop.MainWindow = new MainWindow(); diff --git a/v2rayN/v2rayN.Desktop/GlobalUsings.cs b/v2rayN/v2rayN.Desktop/GlobalUsings.cs index c9a2bc45..6a2f1d3b 100644 --- a/v2rayN/v2rayN.Desktop/GlobalUsings.cs +++ b/v2rayN/v2rayN.Desktop/GlobalUsings.cs @@ -3,7 +3,7 @@ global using System.Collections.Generic; global using System.Globalization; global using System.IO; global using System.Linq; -global using System.Reactive.Disposables; +global using System.Reactive.Disposables.Fluent; global using System.Reactive.Linq; global using System.Text; global using System.Threading; @@ -17,7 +17,7 @@ global using Avalonia.Markup.Xaml; global using Avalonia.Media; global using Avalonia.Media.Imaging; global using Avalonia.Platform; -global using Avalonia.ReactiveUI; +global using ReactiveUI.Avalonia; global using Avalonia.Styling; global using Avalonia.Threading; global using ReactiveUI; diff --git a/v2rayN/v2rayN.Desktop/Program.cs b/v2rayN/v2rayN.Desktop/Program.cs index 1a0ce38e..70c43130 100644 --- a/v2rayN/v2rayN.Desktop/Program.cs +++ b/v2rayN/v2rayN.Desktop/Program.cs @@ -54,12 +54,19 @@ internal class Program // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() { - return AppBuilder.Configure() - .UsePlatformDetect() - //.WithInterFont() - .WithFontByDefault() - .LogToTrace() - .UseReactiveUI() - .With(new MacOSPlatformOptions { ShowInDock = AppManager.Instance.Config.UiItem.MacOSShowInDock }); + var builder = AppBuilder.Configure() + .UsePlatformDetect() + //.WithInterFont() + .WithFontByDefault() + .LogToTrace() + .UseReactiveUI(); + + if (OperatingSystem.IsMacOS()) + { + var showInDock = Design.IsDesignMode || AppManager.Instance.Config.UiItem.MacOSShowInDock; + builder = builder.With(new MacOSPlatformOptions { ShowInDock = showInDock }); + } + + return builder; } } diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index c3bba363..e88db5d1 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -168,7 +168,7 @@ public partial class MainWindow : WindowBase } menuAddServerViaScan.IsVisible = false; - if (_config.UiItem.AutoHideStartup) + if (_config.UiItem.AutoHideStartup && Utils.IsWindows()) { this.WindowState = WindowState.Minimized; } @@ -402,9 +402,9 @@ public partial class MainWindow : WindowBase public void ShowHideWindow(bool? blShow) { var bl = blShow ?? - Utils.IsLinux() + (Utils.IsLinux() ? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized)) - : !_config.UiItem.ShowInTaskbar; + : !_config.UiItem.ShowInTaskbar); if (bl) { this.Show(); diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml index 14a2d174..6dc18155 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml @@ -75,6 +75,15 @@ + + - - - - - + diff --git a/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj b/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj index f6ff5735..6212ce12 100644 --- a/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj +++ b/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj @@ -15,7 +15,7 @@ - + diff --git a/v2rayN/v2rayN.sln b/v2rayN/v2rayN.sln index 85f985fe..4e9ee76e 100644 --- a/v2rayN/v2rayN.sln +++ b/v2rayN/v2rayN.sln @@ -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-windows-desktop.yml = ..\.github\workflows\build-windows-desktop.yml ..\.github\workflows\build-windows.yml = ..\.github\workflows\build-windows.yml - ..\package-appimage.sh = ..\package-appimage.sh ..\package-debian.sh = ..\package-debian.sh ..\package-osx.sh = ..\package-osx.sh ..\package-release-zip.sh = ..\package-release-zip.sh - ..\pkg2appimage.yml = ..\pkg2appimage.yml ..\.github\workflows\winget-publish.yml = ..\.github\workflows\winget-publish.yml EndProjectSection EndProject diff --git a/v2rayN/v2rayN.slnx b/v2rayN/v2rayN.slnx index 05c0ea96..1550478b 100644 --- a/v2rayN/v2rayN.slnx +++ b/v2rayN/v2rayN.slnx @@ -6,11 +6,9 @@ - - diff --git a/v2rayN/v2rayN/Common/QRCodeUtils.cs b/v2rayN/v2rayN/Common/QRCodeWindowsUtils.cs similarity index 93% rename from v2rayN/v2rayN/Common/QRCodeUtils.cs rename to v2rayN/v2rayN/Common/QRCodeWindowsUtils.cs index 6b0bc38d..9e001a1d 100644 --- a/v2rayN/v2rayN/Common/QRCodeUtils.cs +++ b/v2rayN/v2rayN/Common/QRCodeWindowsUtils.cs @@ -2,9 +2,9 @@ using System.Drawing; using System.Windows.Media; using System.Windows.Media.Imaging; -namespace v2rayN; +namespace v2rayN.Common; -public class QRCodeUtils +public class QRCodeWindowsUtils { public static ImageSource? GetQRCode(string? strContent) { @@ -14,7 +14,7 @@ public class QRCodeUtils } try { - var qrCodeImage = ServiceLib.Common.QRCodeUtils.GenQRCode(strContent); + var qrCodeImage = QRCodeUtils.GenQRCode(strContent); return qrCodeImage is null ? null : ByteToImage(qrCodeImage); } catch (Exception ex) diff --git a/v2rayN/v2rayN/GlobalUsings.cs b/v2rayN/v2rayN/GlobalUsings.cs index 21d8dbab..1f2d1936 100644 --- a/v2rayN/v2rayN/GlobalUsings.cs +++ b/v2rayN/v2rayN/GlobalUsings.cs @@ -6,7 +6,7 @@ global using System.Diagnostics; global using System.Globalization; global using System.IO; global using System.Linq; -global using System.Reactive.Disposables; +global using System.Reactive.Disposables.Fluent; global using System.Reactive.Linq; global using System.Runtime.InteropServices; global using System.Text; @@ -31,3 +31,4 @@ global using ServiceLib.Manager; global using ServiceLib.Models; global using ServiceLib.Resx; global using ServiceLib.ViewModels; +global using v2rayN.Common; diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index 9dc818ee..a9114813 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -328,7 +328,7 @@ public partial class MainWindow if (Application.Current?.MainWindow is Window window) { - var bytes = QRCodeUtils.CaptureScreen(window); + var bytes = QRCodeWindowsUtils.CaptureScreen(window); await ViewModel?.ScanScreenResult(bytes); } diff --git a/v2rayN/v2rayN/Views/ProfilesView.xaml b/v2rayN/v2rayN/Views/ProfilesView.xaml index 1a33966b..f66db569 100644 --- a/v2rayN/v2rayN/Views/ProfilesView.xaml +++ b/v2rayN/v2rayN/Views/ProfilesView.xaml @@ -87,6 +87,15 @@ ToolTip="{x:Static resx:ResUI.menuFastRealPing}"> + - + Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" /> + - - - - +