Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dffc6d9a9b | ||
|
|
c9989108bd | ||
|
|
386c86bfa6 | ||
|
|
925cf16c50 | ||
|
|
c561916b67 | ||
|
|
d41a73b44b | ||
|
|
7995bdd4df | ||
|
|
df95cc6af7 | ||
|
|
c669e72189 | ||
|
|
46db5efef3 | ||
|
|
610418b42b | ||
|
|
508eb24fc3 | ||
|
|
6973272dd0 | ||
|
|
d820c4367e | ||
|
|
96e1f85d6f | ||
|
|
6fa5ca5aa9 | ||
|
|
1d1f5641eb | ||
|
|
3f79df21d9 | ||
|
|
ac1231ad54 | ||
|
|
8662d94ab6 | ||
|
|
3d23f3e3a2 | ||
|
|
6715d7dce6 | ||
|
|
dad35f57d0 | ||
|
|
f779e311ed | ||
|
|
ce7c41e3ff | ||
|
|
74bb01d044 | ||
|
|
82f9698c0d | ||
|
|
6911883995 | ||
|
|
47c509faf6 | ||
|
|
8704942209 | ||
|
|
e8cdc29bb5 | ||
|
|
191a7a6574 | ||
|
|
ad5d21db5a | ||
|
|
569e939492 | ||
|
|
6a17c539d1 | ||
|
|
f8a4f946e4 | ||
|
|
0715fa85ce | ||
|
|
1360051f0c | ||
|
|
42c4f9a6c6 | ||
|
|
11691d0128 | ||
|
|
26fe9c63a3 | ||
|
|
30cd033b42 | ||
|
|
e21c0b4d62 | ||
|
|
916055d8bd | ||
|
|
683ca8af14 | ||
|
|
70151db91b | ||
|
|
da3d4c36a9 | ||
|
|
1d01476523 | ||
|
|
75ceba1b08 | ||
|
|
493c37e7d5 | ||
|
|
6d686b284d | ||
|
|
60fcf6174e | ||
|
|
4141f451b7 | ||
|
|
7a9ee6e9e2 | ||
|
|
cb28c31519 | ||
|
|
84f93f2ae6 | ||
|
|
30c09a7b54 | ||
|
|
b3874a78b9 | ||
|
|
3e71965cd4 | ||
|
|
3df57f74ba | ||
|
|
7972cb8e1f | ||
|
|
0d74452c6c | ||
|
|
f947f63e6d | ||
|
|
fefa7ded5a | ||
|
|
a46a4ad7c1 | ||
|
|
e46f680651 | ||
|
|
93a20852f5 | ||
|
|
298bb64e66 | ||
|
|
0e5ac65f55 | ||
|
|
cb6122f872 | ||
|
|
06500e0218 | ||
|
|
9ddf0b42e7 | ||
|
|
2056377f55 | ||
|
|
7065dabc94 | ||
|
|
9e2336a71e | ||
|
|
d239c627f3 | ||
|
|
984b36d34e | ||
|
|
c81bc2f536 | ||
|
|
87f7e65076 | ||
|
|
9985b68b6b | ||
|
|
fb4b8b2789 | ||
|
|
3812ccc780 | ||
|
|
608a6c387a | ||
|
|
4875b37f70 | ||
|
|
2f3fba73de | ||
|
|
2ab1b9068f | ||
|
|
b9613875ce | ||
|
|
5d2aea6b4f | ||
|
|
5824e18ed6 | ||
|
|
4f8648cbc9 | ||
|
|
01b021b2c3 | ||
|
|
331e8ce960 | ||
|
|
a2cfe6fa51 | ||
|
|
8381fefb78 | ||
|
|
d3b95d781a | ||
|
|
3a4a96f87a | ||
|
|
3d462c4be3 | ||
|
|
82b366cd9b | ||
|
|
897a4e5635 | ||
|
|
8ea76fd318 | ||
|
|
693a96fff2 | ||
|
|
8b4e2f8f23 | ||
|
|
13b164acac | ||
|
|
e590547b30 | ||
|
|
5a0fdd971a | ||
|
|
514dce960a | ||
|
|
6ee6fb1706 | ||
|
|
6985328653 | ||
|
|
41c406b84d | ||
|
|
30f7f2c563 | ||
|
|
be3dbfb8e3 | ||
|
|
9b92259e80 | ||
|
|
1c04144573 | ||
|
|
adf3b955d6 | ||
|
|
0032a3d27a | ||
|
|
c6d347d49a | ||
|
|
ea42246d1b | ||
|
|
3f19958c75 | ||
|
|
35788158bc | ||
|
|
4fd494ded4 | ||
|
|
23eeb8ff55 | ||
|
|
456ffb200a | ||
|
|
18e0bb194e | ||
|
|
392f6111dd | ||
|
|
ce6572af3d | ||
|
|
cf59137481 | ||
|
|
519e588124 | ||
|
|
666c874998 | ||
|
|
5f9f677467 |
14
.github/workflows/winget-publish.yml
vendored
14
.github/workflows/winget-publish.yml
vendored
@@ -22,10 +22,18 @@ jobs:
|
|||||||
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
|
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
|
||||||
|
|
||||||
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
|
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
|
||||||
$installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip*' | Select -ExpandProperty browser_download_url
|
|
||||||
|
$x64InstallerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip' | Select -ExpandProperty browser_download_url
|
||||||
|
$arm64InstallerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-arm64\.zip' | Select -ExpandProperty browser_download_url
|
||||||
|
|
||||||
$ver = $targetRelease.tag_name
|
$ver = $targetRelease.tag_name
|
||||||
|
|
||||||
# getting latest wingetcreate file
|
# getting latest wingetcreate file
|
||||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||||
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$installerUrl|x64" -t $gitToken
|
|
||||||
|
Write-Host "Updating with both x64 and arm64 installers"
|
||||||
|
Write-Host "Version: $ver"
|
||||||
|
Write-Host "x64 URL: $x64InstallerUrl"
|
||||||
|
Write-Host "arm64 URL: $arm64InstallerUrl"
|
||||||
|
|
||||||
|
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$x64InstallerUrl|x64" "$arm64InstallerUrl|arm64" -t $gitToken
|
||||||
|
|||||||
4
LICENSE
4
LICENSE
@@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
|
|||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) 2019-Present 2dust
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
|||||||
If the program does terminal interaction, make it output a short
|
If the program does terminal interaction, make it output a short
|
||||||
notice like this when it starts in an interactive mode:
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
v2rayN Copyright (C) 2019-Present 2dust
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
# v2rayN
|
# v2rayN
|
||||||
A GUI client for Windows, Linux and macOS, support [Xray](https://github.com/XTLS/Xray-core) and [sing-box](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
|
||||||
|
|
||||||
|
A GUI client for Windows, Linux and macOS, support [Xray](https://github.com/XTLS/Xray-core)
|
||||||
|
and [sing-box](https://github.com/SagerNet/sing-box)
|
||||||
|
and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
||||||
|
|
||||||
[](https://github.com/2dust/v2rayN/commits/master)
|
[](https://github.com/2dust/v2rayN/commits/master)
|
||||||
[](https://www.codefactor.io/repository/github/2dust/v2rayn)
|
[](https://www.codefactor.io/repository/github/2dust/v2rayn)
|
||||||
[](https://github.com/2dust/v2rayN/releases)
|
[](https://github.com/2dust/v2rayN/releases)
|
||||||
[](https://t.me/v2rayn)
|
[](https://t.me/v2rayn)
|
||||||
|
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
Read the [Wiki](https://github.com/2dust/v2rayN/wiki) for details.
|
Read the [Wiki](https://github.com/2dust/v2rayN/wiki) for details.
|
||||||
|
|
||||||
## Telegram Channel
|
## Telegram Channel
|
||||||
|
|
||||||
[github_2dust](https://t.me/github_2dust)
|
[github_2dust](https://t.me/github_2dust)
|
||||||
|
|||||||
@@ -5,21 +5,83 @@ internal static class Program
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length == 0)
|
try
|
||||||
{
|
{
|
||||||
Console.WriteLine(Resx.Resource.Guidelines);
|
// If no arguments are provided, display usage guidelines and exit
|
||||||
Thread.Sleep(5000);
|
if (args.Length == 0)
|
||||||
return;
|
{
|
||||||
}
|
ShowHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
// Log all arguments for debugging purposes
|
||||||
if (argData.Equals("rebootas"))
|
foreach (var arg in args)
|
||||||
|
{
|
||||||
|
Console.WriteLine(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse command based on first argument
|
||||||
|
switch (args[0].ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "rebootas":
|
||||||
|
// Handle application restart
|
||||||
|
HandleRebootAsync();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "help":
|
||||||
|
case "--help":
|
||||||
|
case "-h":
|
||||||
|
case "/?":
|
||||||
|
// Display help information
|
||||||
|
ShowHelp();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Default behavior: handle as upgrade data
|
||||||
|
// Maintain backward compatibility with existing usage pattern
|
||||||
|
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
||||||
|
HandleUpgrade(argData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Thread.Sleep(1000);
|
// Global exception handling
|
||||||
Utils.StartV2RayN();
|
Console.WriteLine($"An error occurred: {ex.Message}");
|
||||||
return;
|
Console.WriteLine("Press any key to exit...");
|
||||||
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpgradeApp.Upgrade(argData);
|
/// <summary>
|
||||||
|
/// Display help information and usage guidelines
|
||||||
|
/// </summary>
|
||||||
|
private static void ShowHelp()
|
||||||
|
{
|
||||||
|
Console.WriteLine(Resx.Resource.Guidelines);
|
||||||
|
Console.WriteLine("Available commands:");
|
||||||
|
Console.WriteLine(" rebootas - Restart the application");
|
||||||
|
Console.WriteLine(" help - Display this help information");
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle application restart
|
||||||
|
/// </summary>
|
||||||
|
private static void HandleRebootAsync()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Restarting application...");
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
Utils.StartV2RayN();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle application upgrade with the provided data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="upgradeData">Data for the upgrade process</param>
|
||||||
|
private static void HandleUpgrade(string upgradeData)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Upgrading application...");
|
||||||
|
UpgradeApp.Upgrade(upgradeData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.11.1</Version>
|
<Version>7.13.7</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -5,24 +5,24 @@
|
|||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.6" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.3" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.6" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.3" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.6" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.3" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.6" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.3" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.8.2" />
|
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||||
<PackageVersion Include="Downloader" Version="3.3.4" />
|
<PackageVersion Include="Downloader" Version="4.0.2" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
||||||
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||||
<PackageVersion Include="QRCoder" Version="1.6.0" />
|
<PackageVersion Include="QRCoder" Version="1.6.0" />
|
||||||
<PackageVersion Include="ReactiveUI" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI" Version="20.4.1" />
|
||||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
|
||||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.6" />
|
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.9" />
|
||||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.6" />
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.9" />
|
||||||
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
<PackageVersion Include="Splat.NLog" Version="15.4.1" />
|
||||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
|
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
||||||
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
||||||
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
||||||
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace ServiceLib.Common;
|
|
||||||
|
|
||||||
public class AesUtils
|
|
||||||
{
|
|
||||||
private const int KeySize = 256; // AES-256
|
|
||||||
private const int IvSize = 16; // AES block size
|
|
||||||
private const int Iterations = 10000;
|
|
||||||
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' '));
|
|
||||||
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">Plain text</param>
|
|
||||||
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
|
||||||
/// <returns>Base64 encoded cipher text with IV</returns>
|
|
||||||
public static string Encrypt(string text, string? password = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(text))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var plaintext = Encoding.UTF8.GetBytes(text);
|
|
||||||
var key = GetKey(password);
|
|
||||||
var iv = GenerateIv();
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
|
||||||
aes.Key = key;
|
|
||||||
aes.IV = iv;
|
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
ms.Write(iv, 0, iv.Length);
|
|
||||||
|
|
||||||
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cs.Write(plaintext, 0, plaintext.Length);
|
|
||||||
cs.FlushFinalBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
var cipherTextWithIv = ms.ToArray();
|
|
||||||
return Convert.ToBase64String(cipherTextWithIv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
|
|
||||||
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
|
||||||
/// <returns>Plain text</returns>
|
|
||||||
public static string Decrypt(string cipherTextWithIv, string? password = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(cipherTextWithIv))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
|
|
||||||
var key = GetKey(password);
|
|
||||||
|
|
||||||
var iv = new byte[IvSize];
|
|
||||||
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
|
|
||||||
|
|
||||||
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
|
|
||||||
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
|
||||||
aes.Key = key;
|
|
||||||
aes.IV = iv;
|
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cs.Write(cipherText, 0, cipherText.Length);
|
|
||||||
cs.FlushFinalBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
var plainText = ms.ToArray();
|
|
||||||
return Encoding.UTF8.GetString(plainText);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] GetKey(string? password)
|
|
||||||
{
|
|
||||||
if (password.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
password = DefaultPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
|
|
||||||
return pbkdf2.GetBytes(KeySize / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] GenerateIv()
|
|
||||||
{
|
|
||||||
var randomNumber = new byte[IvSize];
|
|
||||||
|
|
||||||
using var rng = RandomNumberGenerator.Create();
|
|
||||||
rng.GetBytes(randomNumber);
|
|
||||||
return randomNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace ServiceLib.Common;
|
|
||||||
|
|
||||||
public class DesUtils
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text"></param>
|
|
||||||
/// /// <param name="key"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Encrypt(string? text, string? key = null)
|
|
||||||
{
|
|
||||||
if (text.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
|
||||||
var dsp = DES.Create();
|
|
||||||
using var memStream = new MemoryStream();
|
|
||||||
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
|
||||||
using var sWriter = new StreamWriter(cryStream);
|
|
||||||
sWriter.Write(text);
|
|
||||||
sWriter.Flush();
|
|
||||||
cryStream.FlushFinalBlock();
|
|
||||||
memStream.Flush();
|
|
||||||
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptText"></param>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Decrypt(string? encryptText, string? key = null)
|
|
||||||
{
|
|
||||||
if (encryptText.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
|
||||||
var dsp = DES.Create();
|
|
||||||
var buffer = Convert.FromBase64String(encryptText);
|
|
||||||
|
|
||||||
using var memStream = new MemoryStream();
|
|
||||||
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
|
||||||
cryStream.Write(buffer, 0, buffer.Length);
|
|
||||||
cryStream.FlushFinalBlock();
|
|
||||||
return Encoding.UTF8.GetString(memStream.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
|
|
||||||
{
|
|
||||||
if (key.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("The key cannot be null");
|
|
||||||
}
|
|
||||||
if (key.Length <= 8)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
|
|
||||||
}
|
|
||||||
|
|
||||||
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
|
|
||||||
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetDefaultKey()
|
|
||||||
{
|
|
||||||
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@ public class DownloaderHelper
|
|||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
MaxTryAgainOnFailover = 2,
|
MaxTryAgainOnFailure = 2,
|
||||||
RequestConfiguration =
|
RequestConfiguration =
|
||||||
{
|
{
|
||||||
Headers = headers,
|
Headers = headers,
|
||||||
@@ -64,7 +64,7 @@ public class DownloaderHelper
|
|||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
MaxTryAgainOnFailover = 2,
|
MaxTryAgainOnFailure = 2,
|
||||||
RequestConfiguration =
|
RequestConfiguration =
|
||||||
{
|
{
|
||||||
Timeout= timeout * 1000,
|
Timeout= timeout * 1000,
|
||||||
@@ -135,7 +135,7 @@ public class DownloaderHelper
|
|||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
MaxTryAgainOnFailover = 2,
|
MaxTryAgainOnFailure = 2,
|
||||||
RequestConfiguration =
|
RequestConfiguration =
|
||||||
{
|
{
|
||||||
Timeout= timeout * 1000,
|
Timeout= timeout * 1000,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
|
|
||||||
namespace ServiceLib.Common;
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
public static class StringEx
|
public static class Extension
|
||||||
{
|
{
|
||||||
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
||||||
{
|
{
|
||||||
@@ -79,4 +79,9 @@ public static class StringEx
|
|||||||
{
|
{
|
||||||
return int.TryParse(value, out var result) ? result : defaultValue;
|
return int.TryParse(value, out var result) ? result : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<string> AppendEmpty(this IEnumerable<string> source)
|
||||||
|
{
|
||||||
|
return source.Concat(new[] { string.Empty }).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -223,4 +223,28 @@ public static class FileManager
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a Linux shell file with the specified contents.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName"></param>
|
||||||
|
/// <param name="contents"></param>
|
||||||
|
/// <param name="overwrite"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> CreateLinuxShellFile(string fileName, string contents, bool overwrite)
|
||||||
|
{
|
||||||
|
var shFilePath = Utils.GetBinConfigPath(fileName);
|
||||||
|
|
||||||
|
// Check if the file already exists and if we should overwrite it
|
||||||
|
if (!overwrite && File.Exists(shFilePath))
|
||||||
|
{
|
||||||
|
return shFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Delete(shFilePath);
|
||||||
|
await File.WriteAllTextAsync(shFilePath, contents);
|
||||||
|
await Utils.SetLinuxChmod(shFilePath);
|
||||||
|
|
||||||
|
return shFilePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,5 +128,8 @@ public class JsonUtils
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
|
public static JsonNode? SerializeToNode(object? obj, JsonSerializerOptions? options = null)
|
||||||
|
{
|
||||||
|
return JsonSerializer.SerializeToNode(obj, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,6 +323,14 @@ public class Utils
|
|||||||
return text.Replace(",", ",").Replace(Environment.NewLine, ",");
|
return text.Replace(",", ",").Replace(Environment.NewLine, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<string> GetEnumNames<TEnum>() where TEnum : Enum
|
||||||
|
{
|
||||||
|
return Enum.GetValues(typeof(TEnum))
|
||||||
|
.Cast<TEnum>()
|
||||||
|
.Select(e => e.ToString())
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion 转换函数
|
#endregion 转换函数
|
||||||
|
|
||||||
#region 数据检查
|
#region 数据检查
|
||||||
@@ -382,13 +390,44 @@ public class Utils
|
|||||||
{
|
{
|
||||||
if (IPAddress.TryParse(ip, out var address))
|
if (IPAddress.TryParse(ip, out var address))
|
||||||
{
|
{
|
||||||
|
// Loopback address check (127.0.0.1 for IPv4, ::1 for IPv6)
|
||||||
|
if (IPAddress.IsLoopback(address))
|
||||||
|
return true;
|
||||||
|
|
||||||
var ipBytes = address.GetAddressBytes();
|
var ipBytes = address.GetAddressBytes();
|
||||||
if (ipBytes[0] == 10)
|
if (address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
return true;
|
{
|
||||||
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31)
|
// IPv4 private address check
|
||||||
return true;
|
if (ipBytes[0] == 10)
|
||||||
if (ipBytes[0] == 192 && ipBytes[1] == 168)
|
return true;
|
||||||
return true;
|
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31)
|
||||||
|
return true;
|
||||||
|
if (ipBytes[0] == 192 && ipBytes[1] == 168)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (address.AddressFamily == AddressFamily.InterNetworkV6)
|
||||||
|
{
|
||||||
|
// IPv6 private address check
|
||||||
|
// Link-local address fe80::/10
|
||||||
|
if (ipBytes[0] == 0xfe && (ipBytes[1] & 0xc0) == 0x80)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Unique local address fc00::/7 (typically fd00::/8)
|
||||||
|
if ((ipBytes[0] & 0xfe) == 0xfc)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Private portion in IPv4-mapped addresses ::ffff:0:0/96
|
||||||
|
if (address.IsIPv4MappedToIPv6)
|
||||||
|
{
|
||||||
|
var ipv4Bytes = ipBytes.Skip(12).ToArray();
|
||||||
|
if (ipv4Bytes[0] == 10)
|
||||||
|
return true;
|
||||||
|
if (ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31)
|
||||||
|
return true;
|
||||||
|
if (ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -427,11 +466,11 @@ public class Utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetFreePort(int defaultPort = 9090)
|
public static int GetFreePort(int defaultPort = 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!Utils.PortInUse(defaultPort))
|
if (!(defaultPort == 0 || Utils.PortInUse(defaultPort)))
|
||||||
{
|
{
|
||||||
return defaultPort;
|
return defaultPort;
|
||||||
}
|
}
|
||||||
@@ -582,7 +621,7 @@ public class Utils
|
|||||||
var result = await cmd.ExecuteBufferedAsync();
|
var result = await cmd.ExecuteBufferedAsync();
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
{
|
{
|
||||||
return result.StandardOutput.ToString();
|
return result.StandardOutput ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.SaveLog(result.ToString() ?? "");
|
Logging.SaveLog(result.ToString() ?? "");
|
||||||
@@ -816,18 +855,6 @@ public class Utils
|
|||||||
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
|
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// var id = GetLinuxUserId().Result ?? "1000";
|
|
||||||
// if (int.TryParse(id, out var userId))
|
|
||||||
// {
|
|
||||||
// return userId == 0;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string?> GetLinuxUserId()
|
private static async Task<string?> GetLinuxUserId()
|
||||||
@@ -839,14 +866,46 @@ public class Utils
|
|||||||
public static async Task<string?> SetLinuxChmod(string? fileName)
|
public static async Task<string?> SetLinuxChmod(string? fileName)
|
||||||
{
|
{
|
||||||
if (fileName.IsNullOrEmpty())
|
if (fileName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
if (SetUnixFileMode(fileName))
|
||||||
|
{
|
||||||
|
Logging.SaveLog($"Successfully set the file execution permission, {fileName}");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
if (fileName.Contains(' '))
|
if (fileName.Contains(' '))
|
||||||
|
{
|
||||||
fileName = fileName.AppendQuotes();
|
fileName = fileName.AppendQuotes();
|
||||||
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
|
}
|
||||||
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
||||||
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool SetUnixFileMode(string? fileName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (fileName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
var currentMode = File.GetUnixFileMode(fileName);
|
||||||
|
File.SetUnixFileMode(fileName, currentMode | UnixFileMode.UserExecute | UnixFileMode.GroupExecute | UnixFileMode.OtherExecute);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("SetUnixFileMode", ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<string?> GetLinuxFontFamily(string lang)
|
public static async Task<string?> GetLinuxFontFamily(string lang)
|
||||||
{
|
{
|
||||||
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ public enum EConfigType
|
|||||||
Hysteria2 = 7,
|
Hysteria2 = 7,
|
||||||
TUIC = 8,
|
TUIC = 8,
|
||||||
WireGuard = 9,
|
WireGuard = 9,
|
||||||
HTTP = 10
|
HTTP = 10,
|
||||||
|
Anytls = 11
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ public enum ECoreType
|
|||||||
hysteria2 = 26,
|
hysteria2 = 26,
|
||||||
brook = 27,
|
brook = 27,
|
||||||
overtls = 28,
|
overtls = 28,
|
||||||
|
shadowquic = 29,
|
||||||
v2rayN = 99
|
v2rayN = 99
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public enum EViewAction
|
|||||||
BrowseServer,
|
BrowseServer,
|
||||||
ImportRulesFromFile,
|
ImportRulesFromFile,
|
||||||
InitSettingFont,
|
InitSettingFont,
|
||||||
|
PasswordInput,
|
||||||
SubEditWindow,
|
SubEditWindow,
|
||||||
RoutingRuleSettingWindow,
|
RoutingRuleSettingWindow,
|
||||||
RoutingRuleDetailsWindow,
|
RoutingRuleDetailsWindow,
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ public class Global
|
|||||||
public const string GithubUrl = "https://github.com";
|
public const string GithubUrl = "https://github.com";
|
||||||
public const string GithubApiUrl = "https://api.github.com/repos";
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
||||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
|
||||||
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||||
public const string IPAPIUrl = "https://api.ip.sb/geoip";
|
|
||||||
|
|
||||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
@@ -40,6 +38,8 @@ public class Global
|
|||||||
public const string PacFileName = NamespaceSample + "pac";
|
public const string PacFileName = NamespaceSample + "pac";
|
||||||
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
|
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
|
||||||
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
|
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
|
||||||
|
public const string KillAsSudoOSXShellFileName = NamespaceSample + "kill_as_sudo_osx_sh";
|
||||||
|
public const string KillAsSudoLinuxShellFileName = NamespaceSample + "kill_as_sudo_linux_sh";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
@@ -76,6 +76,13 @@ public class Global
|
|||||||
public const int SpeedTestPageSize = 1000;
|
public const int SpeedTestPageSize = 1000;
|
||||||
public const string LinuxBash = "/bin/bash";
|
public const string LinuxBash = "/bin/bash";
|
||||||
|
|
||||||
|
public const string SingboxDirectDNSTag = "direct_dns";
|
||||||
|
public const string SingboxRemoteDNSTag = "remote_dns";
|
||||||
|
public const string SingboxOutboundResolverTag = "outbound_resolver";
|
||||||
|
public const string SingboxFinalResolverTag = "final_resolver";
|
||||||
|
public const string SingboxHostsDNSTag = "hosts_dns";
|
||||||
|
public const string SingboxFakeDNSTag = "fake_dns";
|
||||||
|
|
||||||
public static readonly List<string> IEProxyProtocols =
|
public static readonly List<string> IEProxyProtocols =
|
||||||
[
|
[
|
||||||
"{ip}:{http_port}",
|
"{ip}:{http_port}",
|
||||||
@@ -129,24 +136,24 @@ public class Global
|
|||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxRulesetSources =
|
public static readonly List<string> SingboxRulesetSources =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
|
@"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/release/sing-box/rule-set-{0}/{1}.srs",
|
||||||
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs"
|
@"https://raw.githubusercontent.com/chocolate4u/Iran-sing-box-rules/rule-set/{1}.srs"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> RoutingRulesSources =
|
public static readonly List<string> RoutingRulesSources =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
|
@"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-custom-routing-list/main/v2rayN/template.json",
|
||||||
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json"
|
@"https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/main/v2rayN/template.json"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DNSTemplateSources =
|
public static readonly List<string> DNSTemplateSources =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
|
@"https://raw.githubusercontent.com/runetfreedom/russia-v2ray-custom-routing-list/main/v2rayN/",
|
||||||
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/"
|
@"https://raw.githubusercontent.com/Chocolate4U/Iran-v2ray-rules/main/v2rayN/"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
||||||
@@ -169,7 +176,8 @@ public class Global
|
|||||||
{ EConfigType.Trojan, "trojan://" },
|
{ EConfigType.Trojan, "trojan://" },
|
||||||
{ EConfigType.Hysteria2, "hysteria2://" },
|
{ EConfigType.Hysteria2, "hysteria2://" },
|
||||||
{ EConfigType.TUIC, "tuic://" },
|
{ EConfigType.TUIC, "tuic://" },
|
||||||
{ EConfigType.WireGuard, "wireguard://" }
|
{ EConfigType.WireGuard, "wireguard://" },
|
||||||
|
{ EConfigType.Anytls, "anytls://" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
||||||
@@ -182,7 +190,8 @@ public class Global
|
|||||||
{ EConfigType.Trojan, "trojan" },
|
{ EConfigType.Trojan, "trojan" },
|
||||||
{ EConfigType.Hysteria2, "hysteria2" },
|
{ EConfigType.Hysteria2, "hysteria2" },
|
||||||
{ EConfigType.TUIC, "tuic" },
|
{ EConfigType.TUIC, "tuic" },
|
||||||
{ EConfigType.WireGuard, "wireguard" }
|
{ EConfigType.WireGuard, "wireguard" },
|
||||||
|
{ EConfigType.Anytls, "anytls" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> VmessSecurities =
|
public static readonly List<string> VmessSecurities =
|
||||||
@@ -349,25 +358,42 @@ public class Global
|
|||||||
|
|
||||||
public static readonly List<string> SingboxDomainStrategy4Out =
|
public static readonly List<string> SingboxDomainStrategy4Out =
|
||||||
[
|
[
|
||||||
"ipv4_only",
|
"",
|
||||||
|
"ipv4_only",
|
||||||
"prefer_ipv4",
|
"prefer_ipv4",
|
||||||
"prefer_ipv6",
|
"prefer_ipv6",
|
||||||
"ipv6_only",
|
"ipv6_only"
|
||||||
""
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> DomainDNSAddress =
|
public static readonly List<string> DomainDirectDNSAddress =
|
||||||
[
|
[
|
||||||
"223.5.5.5",
|
"https://dns.alidns.com/dns-query",
|
||||||
"223.6.6.6",
|
"https://doh.pub/dns-query",
|
||||||
|
"223.5.5.5",
|
||||||
|
"119.29.29.29",
|
||||||
"localhost"
|
"localhost"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxDomainDNSAddress =
|
public static readonly List<string> DomainRemoteDNSAddress =
|
||||||
|
[
|
||||||
|
"https://cloudflare-dns.com/dns-query",
|
||||||
|
"https://dns.cloudflare.com/dns-query",
|
||||||
|
"https://dns.google/dns-query",
|
||||||
|
"https://doh.dns.sb/dns-query",
|
||||||
|
"https://doh.opendns.com/dns-query",
|
||||||
|
"https://common.dot.dns.yandex.net",
|
||||||
|
"8.8.8.8",
|
||||||
|
"1.1.1.1",
|
||||||
|
"185.222.222.222",
|
||||||
|
"208.67.222.222",
|
||||||
|
"77.88.8.8"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> DomainPureIPDNSAddress =
|
||||||
[
|
[
|
||||||
"223.5.5.5",
|
"223.5.5.5",
|
||||||
"223.6.6.6",
|
"119.29.29.29",
|
||||||
"dhcp://auto"
|
"localhost"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> Languages =
|
public static readonly List<string> Languages =
|
||||||
@@ -509,6 +535,7 @@ public class Global
|
|||||||
{ ECoreType.juicity, "juicity/juicity" },
|
{ ECoreType.juicity, "juicity/juicity" },
|
||||||
{ ECoreType.brook, "txthinking/brook" },
|
{ ECoreType.brook, "txthinking/brook" },
|
||||||
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" },
|
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" },
|
||||||
|
{ ECoreType.shadowquic, "spongebob888/shadowquic" },
|
||||||
{ ECoreType.v2rayN, "2dust/v2rayN" },
|
{ ECoreType.v2rayN, "2dust/v2rayN" },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -519,5 +546,47 @@ public class Global
|
|||||||
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
|
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> IPAPIUrls =
|
||||||
|
[
|
||||||
|
@"https://speed.cloudflare.com/meta",
|
||||||
|
@"https://api.ip.sb/geoip",
|
||||||
|
@"https://api-ipv4.ip.sb/geoip",
|
||||||
|
@"https://api-ipv6.ip.sb/geoip",
|
||||||
|
@"https://api.ipapi.is",
|
||||||
|
@""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> OutboundTags =
|
||||||
|
[
|
||||||
|
ProxyTag,
|
||||||
|
DirectTag,
|
||||||
|
BlockTag
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly Dictionary<string, List<string>> PredefinedHosts = new()
|
||||||
|
{
|
||||||
|
{ "dns.google", new List<string> { "8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844" } },
|
||||||
|
{ "dns.alidns.com", new List<string> { "223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1" } },
|
||||||
|
{ "one.one.one.one", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
|
||||||
|
{ "1dot1dot1dot1.cloudflare-dns.com", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
|
||||||
|
{ "cloudflare-dns.com", new List<string> { "104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9" } },
|
||||||
|
{ "dns.cloudflare.com", new List<string> { "104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5" } },
|
||||||
|
{ "dot.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
|
||||||
|
{ "dns.quad9.net", new List<string> { "9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9" } },
|
||||||
|
{ "dns.yandex.net", new List<string> { "77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff" } },
|
||||||
|
{ "dns.sb", new List<string> { "185.222.222.222", "2a09::" } },
|
||||||
|
{ "dns.umbrella.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
|
||||||
|
{ "dns.sse.cisco.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
|
||||||
|
{ "engage.cloudflareclient.com", new List<string> { "162.159.192.1", "2606:4700:d0::a29f:c001" } }
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> ExpectedIPs =
|
||||||
|
[
|
||||||
|
"geoip:cn",
|
||||||
|
"geoip:ir",
|
||||||
|
"geoip:ru",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ public sealed class AppHandler
|
|||||||
private int? _statePort;
|
private int? _statePort;
|
||||||
private int? _statePort2;
|
private int? _statePort2;
|
||||||
private Job? _processJob;
|
private Job? _processJob;
|
||||||
private bool? _isAdministrator;
|
|
||||||
public static AppHandler Instance => _instance.Value;
|
public static AppHandler Instance => _instance.Value;
|
||||||
public Config Config => _config;
|
public Config Config => _config;
|
||||||
|
|
||||||
@@ -31,14 +30,7 @@ public sealed class AppHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsAdministrator
|
public string LinuxSudoPwd { get; set; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
_isAdministrator ??= Utils.IsAdministrator();
|
|
||||||
return _isAdministrator.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Property
|
#endregion Property
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ public class ConfigHandler
|
|||||||
EnableAutoAdjustMainLvColWidth = true
|
EnableAutoAdjustMainLvColWidth = true
|
||||||
};
|
};
|
||||||
config.UiItem.MainColumnItem ??= new();
|
config.UiItem.MainColumnItem ??= new();
|
||||||
|
config.UiItem.WindowSizeItem ??= new();
|
||||||
|
|
||||||
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
@@ -111,6 +112,8 @@ public class ConfigHandler
|
|||||||
|
|
||||||
config.ConstItem ??= new ConstItem();
|
config.ConstItem ??= new ConstItem();
|
||||||
|
|
||||||
|
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
||||||
|
|
||||||
config.SpeedTestItem ??= new();
|
config.SpeedTestItem ??= new();
|
||||||
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
||||||
{
|
{
|
||||||
@@ -122,7 +125,7 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
|
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
|
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrls.First();
|
||||||
}
|
}
|
||||||
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
|
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
|
||||||
{
|
{
|
||||||
@@ -245,7 +248,9 @@ public class ConfigHandler
|
|||||||
item.PublicKey = profileItem.PublicKey;
|
item.PublicKey = profileItem.PublicKey;
|
||||||
item.ShortId = profileItem.ShortId;
|
item.ShortId = profileItem.ShortId;
|
||||||
item.SpiderX = profileItem.SpiderX;
|
item.SpiderX = profileItem.SpiderX;
|
||||||
|
item.Mldsa65Verify = profileItem.Mldsa65Verify;
|
||||||
item.Extra = profileItem.Extra;
|
item.Extra = profileItem.Extra;
|
||||||
|
item.MuxEnabled = profileItem.MuxEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = item.ConfigType switch
|
var ret = item.ConfigType switch
|
||||||
@@ -259,6 +264,7 @@ public class ConfigHandler
|
|||||||
EConfigType.Hysteria2 => await AddHysteria2Server(config, item),
|
EConfigType.Hysteria2 => await AddHysteria2Server(config, item),
|
||||||
EConfigType.TUIC => await AddTuicServer(config, item),
|
EConfigType.TUIC => await AddTuicServer(config, item),
|
||||||
EConfigType.WireGuard => await AddWireguardServer(config, item),
|
EConfigType.WireGuard => await AddWireguardServer(config, item),
|
||||||
|
EConfigType.Anytls => await AddAnytlsServer(config, item),
|
||||||
_ => -1,
|
_ => -1,
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
@@ -783,6 +789,35 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add or edit a Anytls server
|
||||||
|
/// Validates and processes Anytls-specific settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="profileItem">Anytls profile to add</param>
|
||||||
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
|
public static async Task<int> AddAnytlsServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
|
{
|
||||||
|
profileItem.ConfigType = EConfigType.Anytls;
|
||||||
|
profileItem.CoreType = ECoreType.sing_box;
|
||||||
|
|
||||||
|
profileItem.Address = profileItem.Address.TrimEx();
|
||||||
|
profileItem.Id = profileItem.Id.TrimEx();
|
||||||
|
profileItem.Security = profileItem.Security.TrimEx();
|
||||||
|
profileItem.Network = string.Empty;
|
||||||
|
if (profileItem.StreamSecurity.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
profileItem.StreamSecurity = Global.StreamSecurity;
|
||||||
|
}
|
||||||
|
if (profileItem.Id.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
await AddServerCommon(config, profileItem, toFile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sort the server list by the specified column
|
/// Sort the server list by the specified column
|
||||||
/// Updates the sort order in the profile extension data
|
/// Updates the sort order in the profile extension data
|
||||||
@@ -799,8 +834,11 @@ public class ConfigHandler
|
|||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
var lstServerStat = (config.GuiItem.EnableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
||||||
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
||||||
var lstProfile = (from t in lstModel
|
var lstProfile = (from t in lstModel
|
||||||
|
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
|
||||||
|
from t22 in t2b.DefaultIfEmpty()
|
||||||
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
||||||
from t33 in t3b.DefaultIfEmpty()
|
from t33 in t3b.DefaultIfEmpty()
|
||||||
select new ProfileItemModel
|
select new ProfileItemModel
|
||||||
@@ -815,7 +853,11 @@ public class ConfigHandler
|
|||||||
StreamSecurity = t.StreamSecurity,
|
StreamSecurity = t.StreamSecurity,
|
||||||
Delay = t33?.Delay ?? 0,
|
Delay = t33?.Delay ?? 0,
|
||||||
Speed = t33?.Speed ?? 0,
|
Speed = t33?.Speed ?? 0,
|
||||||
Sort = t33?.Sort ?? 0
|
Sort = t33?.Sort ?? 0,
|
||||||
|
TodayDown = (t22?.TodayDown ?? 0).ToString("D16"),
|
||||||
|
TodayUp = (t22?.TodayUp ?? 0).ToString("D16"),
|
||||||
|
TotalDown = (t22?.TotalDown ?? 0).ToString("D16"),
|
||||||
|
TotalUp = (t22?.TotalUp ?? 0).ToString("D16"),
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
Enum.TryParse(colName, true, out EServerColName name);
|
Enum.TryParse(colName, true, out EServerColName name);
|
||||||
@@ -833,6 +875,10 @@ public class ConfigHandler
|
|||||||
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
|
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
|
||||||
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
|
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
|
||||||
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
|
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
|
||||||
|
EServerColName.TodayDown => lstProfile.OrderBy(t => t.TodayDown).ToList(),
|
||||||
|
EServerColName.TodayUp => lstProfile.OrderBy(t => t.TodayUp).ToList(),
|
||||||
|
EServerColName.TotalDown => lstProfile.OrderBy(t => t.TotalDown).ToList(),
|
||||||
|
EServerColName.TotalUp => lstProfile.OrderBy(t => t.TotalUp).ToList(),
|
||||||
_ => lstProfile
|
_ => lstProfile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -849,6 +895,10 @@ public class ConfigHandler
|
|||||||
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
|
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
|
||||||
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
|
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
|
||||||
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
|
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
|
||||||
|
EServerColName.TodayDown => lstProfile.OrderByDescending(t => t.TodayDown).ToList(),
|
||||||
|
EServerColName.TodayUp => lstProfile.OrderByDescending(t => t.TodayUp).ToList(),
|
||||||
|
EServerColName.TotalDown => lstProfile.OrderByDescending(t => t.TotalDown).ToList(),
|
||||||
|
EServerColName.TotalUp => lstProfile.OrderByDescending(t => t.TotalUp).ToList(),
|
||||||
_ => lstProfile
|
_ => lstProfile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1277,6 +1327,7 @@ public class ConfigHandler
|
|||||||
EConfigType.Hysteria2 => await AddHysteria2Server(config, profileItem, false),
|
EConfigType.Hysteria2 => await AddHysteria2Server(config, profileItem, false),
|
||||||
EConfigType.TUIC => await AddTuicServer(config, profileItem, false),
|
EConfigType.TUIC => await AddTuicServer(config, profileItem, false),
|
||||||
EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false),
|
EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false),
|
||||||
|
EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false),
|
||||||
_ => -1,
|
_ => -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1840,12 +1891,25 @@ public class ConfigHandler
|
|||||||
/// <returns>0 if successful</returns>
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
||||||
{
|
{
|
||||||
if (await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(t => t.Id == routingItem.Id).CountAsync() > 0)
|
var items = await AppHandler.Instance.RoutingItems();
|
||||||
|
if (items.Any(t => t.Id == routingItem.Id && t.IsActive == true))
|
||||||
{
|
{
|
||||||
config.RoutingBasicItem.RoutingIndexId = routingItem.Id;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
await SaveConfig(config);
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
if (item.Id == routingItem.Id)
|
||||||
|
{
|
||||||
|
item.IsActive = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.IsActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await SQLiteHelper.Instance.UpdateAllAsync(items);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1858,7 +1922,7 @@ public class ConfigHandler
|
|||||||
/// <returns>The default routing item</returns>
|
/// <returns>The default routing item</returns>
|
||||||
public static async Task<RoutingItem> GetDefaultRouting(Config config)
|
public static async Task<RoutingItem> GetDefaultRouting(Config config)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
|
var item = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.IsActive == true);
|
||||||
if (item is null)
|
if (item is null)
|
||||||
{
|
{
|
||||||
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
|
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
|
||||||
@@ -1964,8 +2028,20 @@ public class ConfigHandler
|
|||||||
items = await AppHandler.Instance.RoutingItems();
|
items = await AppHandler.Instance.RoutingItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0)
|
if (!blImportAdvancedRules && items.Count > 0)
|
||||||
{
|
{
|
||||||
|
//migrate
|
||||||
|
//TODO Temporary code to be removed later
|
||||||
|
if (config.RoutingBasicItem.RoutingIndexId.IsNotEmpty())
|
||||||
|
{
|
||||||
|
var item = items.FirstOrDefault(t => t.Id == config.RoutingBasicItem.RoutingIndexId);
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
await SetDefaultRouting(config, item);
|
||||||
|
}
|
||||||
|
config.RoutingBasicItem.RoutingIndexId = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2020,18 +2096,38 @@ public class ConfigHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize built-in DNS configurations
|
/// Initialize built-in DNS configurations
|
||||||
/// Creates default DNS items for V2Ray and sing-box
|
/// Creates default DNS items for V2Ray and sing-box
|
||||||
|
/// Also checks existing DNS items and disables those with empty NormalDNS
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config">Current configuration</param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <returns>0 if successful</returns>
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> InitBuiltinDNS(Config config)
|
public static async Task<int> InitBuiltinDNS(Config config)
|
||||||
{
|
{
|
||||||
var items = await AppHandler.Instance.DNSItems();
|
var items = await AppHandler.Instance.DNSItems();
|
||||||
|
|
||||||
|
// Check existing DNS items and disable those with empty NormalDNS
|
||||||
|
var needsUpdate = false;
|
||||||
|
foreach (var existingItem in items)
|
||||||
|
{
|
||||||
|
if (existingItem.NormalDNS.IsNullOrEmpty() && existingItem.Enabled)
|
||||||
|
{
|
||||||
|
existingItem.Enabled = false;
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update items if any changes were made
|
||||||
|
if (needsUpdate)
|
||||||
|
{
|
||||||
|
await SQLiteHelper.Instance.UpdateAllAsync(items);
|
||||||
|
}
|
||||||
|
|
||||||
if (items.Count <= 0)
|
if (items.Count <= 0)
|
||||||
{
|
{
|
||||||
var item = new DNSItem()
|
var item = new DNSItem()
|
||||||
{
|
{
|
||||||
Remarks = "V2ray",
|
Remarks = "V2ray",
|
||||||
CoreType = ECoreType.Xray,
|
CoreType = ECoreType.Xray,
|
||||||
|
Enabled = false,
|
||||||
};
|
};
|
||||||
await SaveDNSItems(config, item);
|
await SaveDNSItems(config, item);
|
||||||
|
|
||||||
@@ -2039,6 +2135,7 @@ public class ConfigHandler
|
|||||||
{
|
{
|
||||||
Remarks = "sing-box",
|
Remarks = "sing-box",
|
||||||
CoreType = ECoreType.sing_box,
|
CoreType = ECoreType.sing_box,
|
||||||
|
Enabled = false,
|
||||||
};
|
};
|
||||||
await SaveDNSItems(config, item2);
|
await SaveDNSItems(config, item2);
|
||||||
}
|
}
|
||||||
@@ -2110,6 +2207,37 @@ public class ConfigHandler
|
|||||||
|
|
||||||
#endregion DNS
|
#endregion DNS
|
||||||
|
|
||||||
|
#region Simple DNS
|
||||||
|
|
||||||
|
public static SimpleDNSItem InitBuiltinSimpleDNS()
|
||||||
|
{
|
||||||
|
return new SimpleDNSItem()
|
||||||
|
{
|
||||||
|
UseSystemHosts = false,
|
||||||
|
AddCommonHosts = true,
|
||||||
|
FakeIP = false,
|
||||||
|
BlockBindingQuery = true,
|
||||||
|
DirectDNS = Global.DomainDirectDNSAddress.FirstOrDefault(),
|
||||||
|
RemoteDNS = Global.DomainRemoteDNSAddress.FirstOrDefault(),
|
||||||
|
SingboxOutboundsResolveDNS = Global.DomainDirectDNSAddress.FirstOrDefault(),
|
||||||
|
SingboxFinalResolveDNS = Global.DomainPureIPDNSAddress.FirstOrDefault()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<SimpleDNSItem> GetExternalSimpleDNSItem(string url)
|
||||||
|
{
|
||||||
|
var downloadHandle = new DownloadService();
|
||||||
|
var templateContent = await downloadHandle.TryDownloadString(url, true, "");
|
||||||
|
if (templateContent.IsNullOrEmpty())
|
||||||
|
return null;
|
||||||
|
var template = JsonUtils.Deserialize<SimpleDNSItem>(templateContent);
|
||||||
|
if (template == null)
|
||||||
|
return null;
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Simple DNS
|
||||||
|
|
||||||
#region Regional Presets
|
#region Regional Presets
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -2131,7 +2259,8 @@ public class ConfigHandler
|
|||||||
await SQLiteHelper.Instance.DeleteAllAsync<DNSItem>();
|
await SQLiteHelper.Instance.DeleteAllAsync<DNSItem>();
|
||||||
await InitBuiltinDNS(config);
|
await InitBuiltinDNS(config);
|
||||||
|
|
||||||
return true;
|
config.SimpleDNSItem = InitBuiltinSimpleDNS();
|
||||||
|
break;
|
||||||
|
|
||||||
case EPresetType.Russia:
|
case EPresetType.Russia:
|
||||||
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[1];
|
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[1];
|
||||||
@@ -2141,7 +2270,8 @@ public class ConfigHandler
|
|||||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json"));
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json"));
|
||||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
|
||||||
|
|
||||||
return true;
|
config.SimpleDNSItem = await GetExternalSimpleDNSItem(Global.DNSTemplateSources[1] + "simple_dns.json") ?? InitBuiltinSimpleDNS();
|
||||||
|
break;
|
||||||
|
|
||||||
case EPresetType.Iran:
|
case EPresetType.Iran:
|
||||||
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[2];
|
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[2];
|
||||||
@@ -2151,11 +2281,52 @@ public class ConfigHandler
|
|||||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json"));
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json"));
|
||||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json"));
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json"));
|
||||||
|
|
||||||
return true;
|
config.SimpleDNSItem = await GetExternalSimpleDNSItem(Global.DNSTemplateSources[2] + "simple_dns.json") ?? InitBuiltinSimpleDNS();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Regional Presets
|
#endregion Regional Presets
|
||||||
|
|
||||||
|
#region UIItem
|
||||||
|
|
||||||
|
public static WindowSizeItem? GetWindowSizeItem(Config config, string typeName)
|
||||||
|
{
|
||||||
|
var sizeItem = config?.UiItem?.WindowSizeItem?.FirstOrDefault(t => t.TypeName == typeName);
|
||||||
|
if (sizeItem == null || sizeItem.Width <= 0 || sizeItem.Height <= 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sizeItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int SaveWindowSizeItem(Config config, string typeName, double width, double height)
|
||||||
|
{
|
||||||
|
var sizeItem = config?.UiItem?.WindowSizeItem?.FirstOrDefault(t => t.TypeName == typeName);
|
||||||
|
if (sizeItem == null)
|
||||||
|
{
|
||||||
|
sizeItem = new WindowSizeItem { TypeName = typeName };
|
||||||
|
config.UiItem.WindowSizeItem.Add(sizeItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
sizeItem.Width = (int)width;
|
||||||
|
sizeItem.Height = (int)height;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int SaveMainGirdHeight(Config config, double height1, double height2)
|
||||||
|
{
|
||||||
|
var uiItem = config.UiItem ?? new();
|
||||||
|
|
||||||
|
uiItem.MainGirdHeight1 = (int)(height1 + 0.1);
|
||||||
|
uiItem.MainGirdHeight2 = (int)(height2 + 0.1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion UIItem
|
||||||
}
|
}
|
||||||
|
|||||||
42
v2rayN/ServiceLib/Handler/ConnectionHandler.cs
Normal file
42
v2rayN/ServiceLib/Handler/ConnectionHandler.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
namespace ServiceLib.Handler;
|
||||||
|
|
||||||
|
public class ConnectionHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<ConnectionHandler> _instance = new(() => new());
|
||||||
|
public static ConnectionHandler Instance => _instance.Value;
|
||||||
|
|
||||||
|
public async Task<string> RunAvailabilityCheck()
|
||||||
|
{
|
||||||
|
var downloadHandle = new DownloadService();
|
||||||
|
var time = await downloadHandle.RunAvailabilityCheck(null);
|
||||||
|
var ip = time > 0 ? await GetIPInfo(downloadHandle) ?? Global.None : Global.None;
|
||||||
|
|
||||||
|
return string.Format(ResUI.TestMeOutput, time, ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string?> GetIPInfo(DownloadService downloadHandle)
|
||||||
|
{
|
||||||
|
var url = AppHandler.Instance.Config.SpeedTestItem.IPAPIUrl;
|
||||||
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await downloadHandle.TryDownloadString(url, true, "");
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
|
||||||
|
if (ipInfo == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ip = ipInfo.ip ?? ipInfo.clientIp ?? ipInfo.ip_addr ?? ipInfo.query;
|
||||||
|
var country = ipInfo.country_code ?? ipInfo.country ?? ipInfo.countryCode ?? ipInfo.location?.country_code;
|
||||||
|
|
||||||
|
return $"({country ?? "unknown"}) {ip}";
|
||||||
|
}
|
||||||
|
}
|
||||||
118
v2rayN/ServiceLib/Handler/CoreAdminHandler.cs
Normal file
118
v2rayN/ServiceLib/Handler/CoreAdminHandler.cs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
using CliWrap;
|
||||||
|
using CliWrap.Buffered;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler;
|
||||||
|
|
||||||
|
public class CoreAdminHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<CoreAdminHandler> _instance = new(() => new());
|
||||||
|
public static CoreAdminHandler Instance => _instance.Value;
|
||||||
|
private Config _config;
|
||||||
|
private Action<bool, string>? _updateFunc;
|
||||||
|
private int _linuxSudoPid = -1;
|
||||||
|
private const string _tag = "CoreAdminHandler";
|
||||||
|
|
||||||
|
public async Task Init(Config config, Action<bool, string> updateFunc)
|
||||||
|
{
|
||||||
|
if (_config != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_config = config;
|
||||||
|
_updateFunc = updateFunc;
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFunc(bool notify, string msg)
|
||||||
|
{
|
||||||
|
_updateFunc?.Invoke(notify, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Process?> RunProcessAsLinuxSudo(string fileName, CoreInfo coreInfo, string configPath)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new();
|
||||||
|
sb.AppendLine("#!/bin/bash");
|
||||||
|
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
||||||
|
sb.AppendLine($"sudo -S {cmdLine}");
|
||||||
|
var shFilePath = await FileManager.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
|
||||||
|
|
||||||
|
Process proc = new()
|
||||||
|
{
|
||||||
|
StartInfo = new()
|
||||||
|
{
|
||||||
|
FileName = shFilePath,
|
||||||
|
Arguments = "",
|
||||||
|
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardInput = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
StandardOutputEncoding = Encoding.UTF8,
|
||||||
|
StandardErrorEncoding = Encoding.UTF8,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void dataHandler(object sender, DataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Data.IsNotEmpty())
|
||||||
|
{
|
||||||
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.OutputDataReceived += dataHandler;
|
||||||
|
proc.ErrorDataReceived += dataHandler;
|
||||||
|
|
||||||
|
proc.Start();
|
||||||
|
proc.BeginOutputReadLine();
|
||||||
|
proc.BeginErrorReadLine();
|
||||||
|
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
|
||||||
|
|
||||||
|
await Task.Delay(100);
|
||||||
|
if (proc is null or { HasExited: true })
|
||||||
|
{
|
||||||
|
throw new Exception(ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
|
|
||||||
|
_linuxSudoPid = proc.Id;
|
||||||
|
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task KillProcessAsLinuxSudo()
|
||||||
|
{
|
||||||
|
if (_linuxSudoPid < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var shellFileName = Utils.IsOSX() ? Global.KillAsSudoOSXShellFileName : Global.KillAsSudoLinuxShellFileName;
|
||||||
|
var shFilePath = await FileManager.CreateLinuxShellFile("kill_as_sudo.sh", EmbedUtils.GetEmbedText(shellFileName), true);
|
||||||
|
if (shFilePath.Contains(' '))
|
||||||
|
{
|
||||||
|
shFilePath = shFilePath.AppendQuotes();
|
||||||
|
}
|
||||||
|
var arg = new List<string>() { "-c", $"sudo -S {shFilePath} {_linuxSudoPid}" };
|
||||||
|
var result = await Cli.Wrap(Global.LinuxBash)
|
||||||
|
.WithArguments(arg)
|
||||||
|
.WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd))
|
||||||
|
.ExecuteBufferedAsync();
|
||||||
|
|
||||||
|
UpdateFunc(false, result.StandardOutput.ToString());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_linuxSudoPid = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ public class CoreHandler
|
|||||||
private Config _config;
|
private Config _config;
|
||||||
private Process? _process;
|
private Process? _process;
|
||||||
private Process? _processPre;
|
private Process? _processPre;
|
||||||
private int _linuxSudoPid = -1;
|
private bool _linuxSudo = false;
|
||||||
private Action<bool, string>? _updateFunc;
|
private Action<bool, string>? _updateFunc;
|
||||||
private const string _tag = "CoreHandler";
|
private const string _tag = "CoreHandler";
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ public class CoreHandler
|
|||||||
|
|
||||||
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC) ? ECoreType.sing_box : ECoreType.Xray;
|
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
||||||
var configPath = Utils.GetBinConfigPath(fileName);
|
var configPath = Utils.GetBinConfigPath(fileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||||
@@ -155,23 +155,23 @@ public class CoreHandler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (_linuxSudo)
|
||||||
|
{
|
||||||
|
await CoreAdminHandler.Instance.KillProcessAsLinuxSudo();
|
||||||
|
_linuxSudo = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_process != null)
|
if (_process != null)
|
||||||
{
|
{
|
||||||
await ProcUtils.ProcessKill(_process, true);
|
await ProcUtils.ProcessKill(_process, Utils.IsWindows());
|
||||||
_process = null;
|
_process = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_processPre != null)
|
if (_processPre != null)
|
||||||
{
|
{
|
||||||
await ProcUtils.ProcessKill(_processPre, true);
|
await ProcUtils.ProcessKill(_processPre, Utils.IsWindows());
|
||||||
_processPre = null;
|
_processPre = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_linuxSudoPid > 0)
|
|
||||||
{
|
|
||||||
await KillProcessAsLinuxSudo();
|
|
||||||
}
|
|
||||||
_linuxSudoPid = -1;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -225,15 +225,6 @@ public class CoreHandler
|
|||||||
_updateFunc?.Invoke(notify, msg);
|
_updateFunc?.Invoke(notify, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsNeedSudo(ECoreType eCoreType)
|
|
||||||
{
|
|
||||||
return _config.TunModeItem.EnableTun
|
|
||||||
&& eCoreType == ECoreType.sing_box
|
|
||||||
&& (Utils.IsNonWindows())
|
|
||||||
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Private
|
#endregion Private
|
||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
@@ -249,69 +240,17 @@ public class CoreHandler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Process proc = new()
|
if (mayNeedSudo
|
||||||
|
&& _config.TunModeItem.EnableTun
|
||||||
|
&& coreInfo.CoreType == ECoreType.sing_box
|
||||||
|
&& Utils.IsNonWindows())
|
||||||
{
|
{
|
||||||
StartInfo = new()
|
_linuxSudo = true;
|
||||||
{
|
await CoreAdminHandler.Instance.Init(_config, _updateFunc);
|
||||||
FileName = fileName,
|
return await CoreAdminHandler.Instance.RunProcessAsLinuxSudo(fileName, coreInfo, configPath);
|
||||||
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
|
||||||
WorkingDirectory = Utils.GetBinConfigPath(),
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardOutput = displayLog,
|
|
||||||
RedirectStandardError = displayLog,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
|
|
||||||
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
|
||||||
if (isNeedSudo)
|
|
||||||
{
|
|
||||||
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayLog)
|
return await RunProcessNormal(fileName, coreInfo, configPath, displayLog);
|
||||||
{
|
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data.IsNullOrEmpty())
|
|
||||||
return;
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
};
|
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data.IsNullOrEmpty())
|
|
||||||
return;
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
proc.Start();
|
|
||||||
|
|
||||||
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
|
||||||
{
|
|
||||||
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
|
||||||
await Task.Delay(10);
|
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
|
||||||
await Task.Delay(10);
|
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
|
||||||
}
|
|
||||||
if (isNeedSudo)
|
|
||||||
_linuxSudoPid = proc.Id;
|
|
||||||
|
|
||||||
if (displayLog)
|
|
||||||
{
|
|
||||||
proc.BeginOutputReadLine();
|
|
||||||
proc.BeginErrorReadLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(500);
|
|
||||||
AppHandler.Instance.AddProcess(proc.Handle);
|
|
||||||
if (proc is null or { HasExited: true })
|
|
||||||
{
|
|
||||||
throw new Exception(ResUI.FailedToRunCore);
|
|
||||||
}
|
|
||||||
return proc;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -321,89 +260,52 @@ public class CoreHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Process
|
private async Task<Process?> RunProcessNormal(string fileName, CoreInfo? coreInfo, string configPath, bool displayLog)
|
||||||
|
|
||||||
#region Linux
|
|
||||||
|
|
||||||
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
|
||||||
{
|
{
|
||||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
|
||||||
|
|
||||||
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
|
|
||||||
proc.StartInfo.FileName = shFilePath;
|
|
||||||
proc.StartInfo.Arguments = "";
|
|
||||||
proc.StartInfo.WorkingDirectory = "";
|
|
||||||
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
|
||||||
{
|
|
||||||
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
|
||||||
proc.StartInfo.RedirectStandardInput = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task KillProcessAsLinuxSudo()
|
|
||||||
{
|
|
||||||
var cmdLine = $"kill {_linuxSudoPid}";
|
|
||||||
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
|
|
||||||
Process proc = new()
|
Process proc = new()
|
||||||
{
|
{
|
||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = shFilePath,
|
FileName = fileName,
|
||||||
|
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
||||||
|
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = displayLog,
|
||||||
|
RedirectStandardError = displayLog,
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
StandardInputEncoding = Encoding.UTF8,
|
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
RedirectStandardInput = true
|
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (displayLog)
|
||||||
|
{
|
||||||
|
void dataHandler(object sender, DataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Data.IsNotEmpty())
|
||||||
|
{
|
||||||
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proc.OutputDataReceived += dataHandler;
|
||||||
|
proc.ErrorDataReceived += dataHandler;
|
||||||
|
}
|
||||||
proc.Start();
|
proc.Start();
|
||||||
|
|
||||||
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
if (displayLog)
|
||||||
{
|
{
|
||||||
try
|
proc.BeginOutputReadLine();
|
||||||
{
|
proc.BeginErrorReadLine();
|
||||||
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
|
||||||
await Task.Delay(10);
|
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
|
||||||
await Task.Delay(10);
|
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
await Task.Delay(100);
|
||||||
await proc.WaitForExitAsync(timeout.Token);
|
AppHandler.Instance.AddProcess(proc.Handle);
|
||||||
await Task.Delay(3000);
|
if (proc is null or { HasExited: true })
|
||||||
|
{
|
||||||
|
throw new Exception(ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
#endregion Process
|
||||||
{
|
|
||||||
//Shell scripts
|
|
||||||
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
|
||||||
File.Delete(shFilePath);
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine("#!/bin/sh");
|
|
||||||
if (AppHandler.Instance.IsAdministrator)
|
|
||||||
{
|
|
||||||
sb.AppendLine($"{cmdLine}");
|
|
||||||
}
|
|
||||||
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
sb.AppendLine($"pkexec {cmdLine}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.AppendLine($"sudo -S {cmdLine}");
|
|
||||||
}
|
|
||||||
|
|
||||||
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
|
||||||
await Utils.SetLinuxChmod(shFilePath);
|
|
||||||
Logging.SaveLog(shFilePath);
|
|
||||||
|
|
||||||
return shFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Linux
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,6 +200,15 @@ public sealed class CoreInfoHandler
|
|||||||
Arguments = "-r client -c {0}",
|
Arguments = "-r client -c {0}",
|
||||||
Url = GetCoreUrl(ECoreType.overtls),
|
Url = GetCoreUrl(ECoreType.overtls),
|
||||||
AbsolutePath = false,
|
AbsolutePath = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.shadowquic,
|
||||||
|
CoreExes = [ "shadowquic", "shadowquic"],
|
||||||
|
Arguments = "-c {0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.shadowquic),
|
||||||
|
AbsolutePath = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
48
v2rayN/ServiceLib/Handler/Fmt/AnytlsFmt.cs
Normal file
48
v2rayN/ServiceLib/Handler/Fmt/AnytlsFmt.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt;
|
||||||
|
|
||||||
|
public class AnytlsFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
var parsedUrl = Utils.TryUri(str);
|
||||||
|
if (parsedUrl == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
ConfigType = EConfigType.Anytls,
|
||||||
|
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
|
Address = parsedUrl.IdnHost,
|
||||||
|
Port = parsedUrl.Port,
|
||||||
|
};
|
||||||
|
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
||||||
|
item.Id = rawUserInfo;
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(parsedUrl.Query);
|
||||||
|
_ = ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var remark = string.Empty;
|
||||||
|
if (item.Remarks.IsNotEmpty())
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
|
}
|
||||||
|
var pw = item.Id;
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
_ = GetStdTransport(item, Global.None, ref dicQuery);
|
||||||
|
|
||||||
|
return ToUri(EConfigType.Anytls, item.Address, item.Port, pw, dicQuery, remark);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,6 +59,10 @@ public class BaseFmt
|
|||||||
{
|
{
|
||||||
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
|
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
|
||||||
}
|
}
|
||||||
|
if (item.Mldsa65Verify.IsNotEmpty())
|
||||||
|
{
|
||||||
|
dicQuery.Add("pqv", Utils.UrlEncode(item.Mldsa65Verify));
|
||||||
|
}
|
||||||
if (item.AllowInsecure.Equals("true"))
|
if (item.AllowInsecure.Equals("true"))
|
||||||
{
|
{
|
||||||
dicQuery.Add("allowInsecure", "1");
|
dicQuery.Add("allowInsecure", "1");
|
||||||
@@ -159,6 +163,7 @@ public class BaseFmt
|
|||||||
item.PublicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
item.PublicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
||||||
item.ShortId = Utils.UrlDecode(query["sid"] ?? "");
|
item.ShortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||||
item.SpiderX = Utils.UrlDecode(query["spx"] ?? "");
|
item.SpiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||||
|
item.Mldsa65Verify = Utils.UrlDecode(query["pqv"] ?? "");
|
||||||
item.AllowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
item.AllowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
||||||
|
|
||||||
item.Network = query["type"] ?? nameof(ETransport.tcp);
|
item.Network = query["type"] ?? nameof(ETransport.tcp);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public class FmtHandler
|
|||||||
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
||||||
EConfigType.TUIC => TuicFmt.ToUri(item),
|
EConfigType.TUIC => TuicFmt.ToUri(item),
|
||||||
EConfigType.WireGuard => WireguardFmt.ToUri(item),
|
EConfigType.WireGuard => WireguardFmt.ToUri(item),
|
||||||
|
EConfigType.Anytls => AnytlsFmt.ToUri(item),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,6 +76,10 @@ public class FmtHandler
|
|||||||
{
|
{
|
||||||
return WireguardFmt.Resolve(str, out msg);
|
return WireguardFmt.Resolve(str, out msg);
|
||||||
}
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Anytls]))
|
||||||
|
{
|
||||||
|
return AnytlsFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = ResUI.NonvmessOrssProtocol;
|
msg = ResUI.NonvmessOrssProtocol;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class Hysteria2Fmt : BaseFmt
|
|||||||
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
||||||
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
||||||
|
|
||||||
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
|
item.Ports = Utils.UrlDecode(query["mport"] ?? "");
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ public class VmessFmt : BaseFmt
|
|||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
ProfileItem? item;
|
ProfileItem? item;
|
||||||
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
if (str.IndexOf('@') > 0)
|
||||||
{
|
{
|
||||||
item = ResolveStdVmess(str);
|
item = ResolveStdVmess(str) ?? ResolveVmess(str, out msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,14 +18,7 @@ public class ProxySettingLinux
|
|||||||
|
|
||||||
private static async Task ExecCmd(List<string> args)
|
private static async Task ExecCmd(List<string> args)
|
||||||
{
|
{
|
||||||
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName), false);
|
||||||
if (!File.Exists(fileName))
|
|
||||||
{
|
|
||||||
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
|
|
||||||
await File.AppendAllTextAsync(fileName, contents);
|
|
||||||
|
|
||||||
await Utils.SetLinuxChmod(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Utils.GetCliWrapOutput(fileName, args);
|
await Utils.GetCliWrapOutput(fileName, args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,14 +23,7 @@ public class ProxySettingOSX
|
|||||||
|
|
||||||
private static async Task ExecCmd(List<string> args)
|
private static async Task ExecCmd(List<string> args)
|
||||||
{
|
{
|
||||||
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName), false);
|
||||||
if (!File.Exists(fileName))
|
|
||||||
{
|
|
||||||
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
|
|
||||||
await File.AppendAllTextAsync(fileName, contents);
|
|
||||||
|
|
||||||
await Utils.SetLinuxChmod(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Utils.GetCliWrapOutput(fileName, args);
|
await Utils.GetCliWrapOutput(fileName, args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class Config
|
|||||||
public List<InItem> Inbound { get; set; }
|
public List<InItem> Inbound { get; set; }
|
||||||
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||||
|
public SimpleDNSItem SimpleDNSItem { get; set; }
|
||||||
|
|
||||||
#endregion other entities
|
#endregion other entities
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,10 +89,8 @@ public class UIItem
|
|||||||
{
|
{
|
||||||
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
||||||
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
||||||
public double MainWidth { get; set; }
|
public int MainGirdHeight1 { get; set; }
|
||||||
public double MainHeight { get; set; }
|
public int MainGirdHeight2 { get; set; }
|
||||||
public double MainGirdHeight1 { get; set; }
|
|
||||||
public double MainGirdHeight2 { get; set; }
|
|
||||||
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public string? ColorPrimaryName { get; set; }
|
public string? ColorPrimaryName { get; set; }
|
||||||
public string? CurrentTheme { get; set; }
|
public string? CurrentTheme { get; set; }
|
||||||
@@ -103,8 +101,10 @@ public class UIItem
|
|||||||
public bool DoubleClick2Activate { get; set; }
|
public bool DoubleClick2Activate { get; set; }
|
||||||
public bool AutoHideStartup { get; set; }
|
public bool AutoHideStartup { get; set; }
|
||||||
public bool Hide2TrayWhenClose { get; set; }
|
public bool Hide2TrayWhenClose { get; set; }
|
||||||
public List<ColumnItem> MainColumnItem { get; set; }
|
|
||||||
public bool ShowInTaskbar { get; set; }
|
public bool ShowInTaskbar { get; set; }
|
||||||
|
public bool MacOSShowInDock { get; set; }
|
||||||
|
public List<ColumnItem> MainColumnItem { get; set; }
|
||||||
|
public List<WindowSizeItem> WindowSizeItem { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -147,7 +147,6 @@ public class TunModeItem
|
|||||||
public int Mtu { get; set; }
|
public int Mtu { get; set; }
|
||||||
public bool EnableExInbound { get; set; }
|
public bool EnableExInbound { get; set; }
|
||||||
public bool EnableIPv6Address { get; set; }
|
public bool EnableIPv6Address { get; set; }
|
||||||
public string? LinuxSudoPwd { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -157,6 +156,7 @@ public class SpeedTestItem
|
|||||||
public string SpeedTestUrl { get; set; }
|
public string SpeedTestUrl { get; set; }
|
||||||
public string SpeedPingTestUrl { get; set; }
|
public string SpeedPingTestUrl { get; set; }
|
||||||
public int MixedConcurrencyCount { get; set; }
|
public int MixedConcurrencyCount { get; set; }
|
||||||
|
public string IPAPIUrl { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -245,3 +245,29 @@ public class Fragment4RayItem
|
|||||||
public string? Length { get; set; }
|
public string? Length { get; set; }
|
||||||
public string? Interval { get; set; }
|
public string? Interval { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class WindowSizeItem
|
||||||
|
{
|
||||||
|
public string TypeName { get; set; }
|
||||||
|
public int Width { get; set; }
|
||||||
|
public int Height { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class SimpleDNSItem
|
||||||
|
{
|
||||||
|
public bool? UseSystemHosts { get; set; }
|
||||||
|
public bool? AddCommonHosts { get; set; }
|
||||||
|
public bool? FakeIP { get; set; }
|
||||||
|
public bool? BlockBindingQuery { get; set; }
|
||||||
|
public string? DirectDNS { get; set; }
|
||||||
|
public string? RemoteDNS { get; set; }
|
||||||
|
public string? SingboxOutboundsResolveDNS { get; set; }
|
||||||
|
public string? SingboxFinalResolveDNS { get; set; }
|
||||||
|
public string? RayStrategy4Freedom { get; set; }
|
||||||
|
public string? SingboxStrategy4Direct { get; set; }
|
||||||
|
public string? SingboxStrategy4Proxy { get; set; }
|
||||||
|
public string? Hosts { get; set; }
|
||||||
|
public string? DirectExpectedIPs { get; set; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public class DNSItem
|
|||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
public string Remarks { get; set; }
|
public string Remarks { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = false;
|
||||||
public ECoreType CoreType { get; set; }
|
public ECoreType CoreType { get; set; }
|
||||||
public bool UseSystemHosts { get; set; }
|
public bool UseSystemHosts { get; set; }
|
||||||
public string? NormalDNS { get; set; }
|
public string? NormalDNS { get; set; }
|
||||||
|
|||||||
@@ -3,10 +3,17 @@ namespace ServiceLib.Models;
|
|||||||
internal class IPAPIInfo
|
internal class IPAPIInfo
|
||||||
{
|
{
|
||||||
public string? ip { get; set; }
|
public string? ip { get; set; }
|
||||||
public string? city { get; set; }
|
public string? clientIp { get; set; }
|
||||||
public string? region { get; set; }
|
public string? ip_addr { get; set; }
|
||||||
public string? region_code { get; set; }
|
public string? query { get; set; }
|
||||||
public string? country { get; set; }
|
public string? country { get; set; }
|
||||||
public string? country_name { get; set; }
|
public string? country_name { get; set; }
|
||||||
public string? country_code { get; set; }
|
public string? country_code { get; set; }
|
||||||
|
public string? countryCode { get; set; }
|
||||||
|
public LocationInfo? location { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LocationInfo
|
||||||
|
{
|
||||||
|
public string? country_code { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
using ReactiveUI;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItem
|
public class ProfileItem : ReactiveObject
|
||||||
{
|
{
|
||||||
public ProfileItem()
|
public ProfileItem()
|
||||||
{
|
{
|
||||||
@@ -31,7 +32,7 @@ public class ProfileItem
|
|||||||
public string GetSummary()
|
public string GetSummary()
|
||||||
{
|
{
|
||||||
var summary = $"[{(ConfigType).ToString()}] ";
|
var summary = $"[{(ConfigType).ToString()}] ";
|
||||||
var arrAddr = Address.Split('.');
|
var arrAddr = Address.Contains(':') ? Address.Split(':') : Address.Split('.');
|
||||||
var addr = arrAddr.Length switch
|
var addr = arrAddr.Length switch
|
||||||
{
|
{
|
||||||
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
|
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
|
||||||
@@ -92,5 +93,7 @@ public class ProfileItem
|
|||||||
public string PublicKey { get; set; }
|
public string PublicKey { get; set; }
|
||||||
public string ShortId { get; set; }
|
public string ShortId { get; set; }
|
||||||
public string SpiderX { get; set; }
|
public string SpiderX { get; set; }
|
||||||
|
public string Mldsa65Verify { get; set; }
|
||||||
public string Extra { get; set; }
|
public string Extra { get; set; }
|
||||||
|
public bool? MuxEnabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -5,13 +7,28 @@ public class ProfileItemModel : ProfileItem
|
|||||||
{
|
{
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
public string SubRemarks { get; set; }
|
public string SubRemarks { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public int Delay { get; set; }
|
public int Delay { get; set; }
|
||||||
|
|
||||||
public decimal Speed { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string DelayVal { get; set; }
|
public string DelayVal { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string SpeedVal { get; set; }
|
public string SpeedVal { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TodayUp { get; set; }
|
public string TodayUp { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TodayDown { get; set; }
|
public string TodayDown { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TotalUp { get; set; }
|
public string TotalUp { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TotalDown { get; set; }
|
public string TotalDown { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,4 +19,5 @@ public class RoutingItem
|
|||||||
public string DomainStrategy { get; set; }
|
public string DomainStrategy { get; set; }
|
||||||
public string DomainStrategy4Singbox { get; set; }
|
public string DomainStrategy4Singbox { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,4 @@ namespace ServiceLib.Models;
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItemModel : RoutingItem
|
public class RoutingItemModel : RoutingItem
|
||||||
{
|
{
|
||||||
public bool IsActive { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
public class SingboxConfig
|
public class SingboxConfig
|
||||||
@@ -6,6 +8,7 @@ public class SingboxConfig
|
|||||||
public Dns4Sbox? dns { get; set; }
|
public Dns4Sbox? dns { get; set; }
|
||||||
public List<Inbound4Sbox> inbounds { get; set; }
|
public List<Inbound4Sbox> inbounds { get; set; }
|
||||||
public List<Outbound4Sbox> outbounds { get; set; }
|
public List<Outbound4Sbox> outbounds { get; set; }
|
||||||
|
public List<Endpoints4Sbox>? endpoints { get; set; }
|
||||||
public Route4Sbox route { get; set; }
|
public Route4Sbox route { get; set; }
|
||||||
public Experimental4Sbox? experimental { get; set; }
|
public Experimental4Sbox? experimental { get; set; }
|
||||||
}
|
}
|
||||||
@@ -29,14 +32,15 @@ public class Dns4Sbox
|
|||||||
public bool? independent_cache { get; set; }
|
public bool? independent_cache { get; set; }
|
||||||
public bool? reverse_mapping { get; set; }
|
public bool? reverse_mapping { get; set; }
|
||||||
public string? client_subnet { get; set; }
|
public string? client_subnet { get; set; }
|
||||||
public Fakeip4Sbox? fakeip { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Route4Sbox
|
public class Route4Sbox
|
||||||
{
|
{
|
||||||
|
public Rule4Sbox? default_domain_resolver { get; set; } // or string
|
||||||
public bool? auto_detect_interface { get; set; }
|
public bool? auto_detect_interface { get; set; }
|
||||||
public List<Rule4Sbox> rules { get; set; }
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
public List<Ruleset4Sbox>? rule_set { get; set; }
|
public List<Ruleset4Sbox>? rule_set { get; set; }
|
||||||
|
public string? final { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -49,6 +53,7 @@ public class Rule4Sbox
|
|||||||
public string? mode { get; set; }
|
public string? mode { get; set; }
|
||||||
public bool? ip_is_private { get; set; }
|
public bool? ip_is_private { get; set; }
|
||||||
public string? client_subnet { get; set; }
|
public string? client_subnet { get; set; }
|
||||||
|
public int? rewrite_ttl { get; set; }
|
||||||
public bool? invert { get; set; }
|
public bool? invert { get; set; }
|
||||||
public string? clash_mode { get; set; }
|
public string? clash_mode { get; set; }
|
||||||
public List<string>? inbound { get; set; }
|
public List<string>? inbound { get; set; }
|
||||||
@@ -67,6 +72,27 @@ public class Rule4Sbox
|
|||||||
public List<string>? process_name { get; set; }
|
public List<string>? process_name { get; set; }
|
||||||
public List<string>? rule_set { get; set; }
|
public List<string>? rule_set { get; set; }
|
||||||
public List<Rule4Sbox>? rules { get; set; }
|
public List<Rule4Sbox>? rules { get; set; }
|
||||||
|
public string? action { get; set; }
|
||||||
|
public string? strategy { get; set; }
|
||||||
|
public List<string>? sniffer { get; set; }
|
||||||
|
public string? rcode { get; set; }
|
||||||
|
public List<int>? query_type { get; set; }
|
||||||
|
public List<string>? answer { get; set; }
|
||||||
|
public List<string>? ns { get; set; }
|
||||||
|
public List<string>? extra { get; set; }
|
||||||
|
public string? method { get; set; }
|
||||||
|
public bool? no_drop { get; set; }
|
||||||
|
public bool? source_ip_is_private { get; set; }
|
||||||
|
public bool? ip_accept_any { get; set; }
|
||||||
|
public int? source_port { get; set; }
|
||||||
|
public List<string>? source_port_range { get; set; }
|
||||||
|
public List<string>? network_type { get; set; }
|
||||||
|
public bool? network_is_expensive { get; set; }
|
||||||
|
public bool? network_is_constrained { get; set; }
|
||||||
|
public List<string>? wifi_ssid { get; set; }
|
||||||
|
public List<string>? wifi_bssid { get; set; }
|
||||||
|
public bool? rule_set_ip_cidr_match_source { get; set; }
|
||||||
|
public bool? rule_set_ip_cidr_accept_empty { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -76,7 +102,6 @@ public class Inbound4Sbox
|
|||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
public string listen { get; set; }
|
public string listen { get; set; }
|
||||||
public int? listen_port { get; set; }
|
public int? listen_port { get; set; }
|
||||||
public string? domain_strategy { get; set; }
|
|
||||||
public string interface_name { get; set; }
|
public string interface_name { get; set; }
|
||||||
public List<string>? address { get; set; }
|
public List<string>? address { get; set; }
|
||||||
public int? mtu { get; set; }
|
public int? mtu { get; set; }
|
||||||
@@ -84,8 +109,6 @@ public class Inbound4Sbox
|
|||||||
public bool? strict_route { get; set; }
|
public bool? strict_route { get; set; }
|
||||||
public bool? endpoint_independent_nat { get; set; }
|
public bool? endpoint_independent_nat { get; set; }
|
||||||
public string? stack { get; set; }
|
public string? stack { get; set; }
|
||||||
public bool? sniff { get; set; }
|
|
||||||
public bool? sniff_override_destination { get; set; }
|
|
||||||
public List<User4Sbox> users { get; set; }
|
public List<User4Sbox> users { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,10 +118,8 @@ public class User4Sbox
|
|||||||
public string password { get; set; }
|
public string password { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Outbound4Sbox
|
public class Outbound4Sbox : BaseServer4Sbox
|
||||||
{
|
{
|
||||||
public string type { get; set; }
|
|
||||||
public string tag { get; set; }
|
|
||||||
public string? server { get; set; }
|
public string? server { get; set; }
|
||||||
public int? server_port { get; set; }
|
public int? server_port { get; set; }
|
||||||
public List<string>? server_ports { get; set; }
|
public List<string>? server_ports { get; set; }
|
||||||
@@ -113,7 +134,6 @@ public class Outbound4Sbox
|
|||||||
public int? recv_window_conn { get; set; }
|
public int? recv_window_conn { get; set; }
|
||||||
public int? recv_window { get; set; }
|
public int? recv_window { get; set; }
|
||||||
public bool? disable_mtu_discovery { get; set; }
|
public bool? disable_mtu_discovery { get; set; }
|
||||||
public string? detour { get; set; }
|
|
||||||
public string? method { get; set; }
|
public string? method { get; set; }
|
||||||
public string? username { get; set; }
|
public string? username { get; set; }
|
||||||
public string? password { get; set; }
|
public string? password { get; set; }
|
||||||
@@ -121,21 +141,36 @@ public class Outbound4Sbox
|
|||||||
public string? version { get; set; }
|
public string? version { get; set; }
|
||||||
public string? network { get; set; }
|
public string? network { get; set; }
|
||||||
public string? packet_encoding { get; set; }
|
public string? packet_encoding { get; set; }
|
||||||
public List<string>? local_address { get; set; }
|
|
||||||
public string? private_key { get; set; }
|
|
||||||
public string? peer_public_key { get; set; }
|
|
||||||
public List<int>? reserved { get; set; }
|
|
||||||
public int? mtu { get; set; }
|
|
||||||
public string? plugin { get; set; }
|
public string? plugin { get; set; }
|
||||||
public string? plugin_opts { get; set; }
|
public string? plugin_opts { get; set; }
|
||||||
public Tls4Sbox? tls { get; set; }
|
|
||||||
public Multiplex4Sbox? multiplex { get; set; }
|
|
||||||
public Transport4Sbox? transport { get; set; }
|
|
||||||
public HyObfs4Sbox? obfs { get; set; }
|
|
||||||
public List<string>? outbounds { get; set; }
|
public List<string>? outbounds { get; set; }
|
||||||
public bool? interrupt_exist_connections { get; set; }
|
public bool? interrupt_exist_connections { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Endpoints4Sbox : BaseServer4Sbox
|
||||||
|
{
|
||||||
|
public bool? system { get; set; }
|
||||||
|
public string? name { get; set; }
|
||||||
|
public int? mtu { get; set; }
|
||||||
|
public List<string> address { get; set; }
|
||||||
|
public string private_key { get; set; }
|
||||||
|
public int? listen_port { get; set; }
|
||||||
|
public string? udp_timeout { get; set; }
|
||||||
|
public int? workers { get; set; }
|
||||||
|
public List<Peer4Sbox> peers { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Peer4Sbox
|
||||||
|
{
|
||||||
|
public string address { get; set; }
|
||||||
|
public int port { get; set; }
|
||||||
|
public string public_key { get; set; }
|
||||||
|
public string? pre_shared_key { get; set; }
|
||||||
|
public List<string> allowed_ips { get; set; }
|
||||||
|
public int? persistent_keepalive_interval { get; set; }
|
||||||
|
public List<int> reserved { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Tls4Sbox
|
public class Tls4Sbox
|
||||||
{
|
{
|
||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
@@ -144,6 +179,9 @@ public class Tls4Sbox
|
|||||||
public List<string>? alpn { get; set; }
|
public List<string>? alpn { get; set; }
|
||||||
public Utls4Sbox? utls { get; set; }
|
public Utls4Sbox? utls { get; set; }
|
||||||
public Reality4Sbox? reality { get; set; }
|
public Reality4Sbox? reality { get; set; }
|
||||||
|
public bool? fragment { get; set; }
|
||||||
|
public string? fragment_fallback_delay { get; set; }
|
||||||
|
public bool? record_fragment { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Multiplex4Sbox
|
public class Multiplex4Sbox
|
||||||
@@ -191,15 +229,28 @@ public class HyObfs4Sbox
|
|||||||
public string? password { get; set; }
|
public string? password { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Server4Sbox
|
public class Server4Sbox : BaseServer4Sbox
|
||||||
{
|
{
|
||||||
public string? tag { get; set; }
|
public string? inet4_range { get; set; }
|
||||||
|
public string? inet6_range { get; set; }
|
||||||
|
public string? client_subnet { get; set; }
|
||||||
|
public string? server { get; set; }
|
||||||
|
public new string? domain_resolver { get; set; }
|
||||||
|
[JsonPropertyName("interface")] public string? Interface { get; set; }
|
||||||
|
public int? server_port { get; set; }
|
||||||
|
public string? path { get; set; }
|
||||||
|
public Headers4Sbox? headers { get; set; }
|
||||||
|
|
||||||
|
// public List<string>? path { get; set; } // hosts
|
||||||
|
public Dictionary<string, List<string>>? predefined { get; set; }
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
public string? address { get; set; }
|
public string? address { get; set; }
|
||||||
|
|
||||||
public string? address_resolver { get; set; }
|
public string? address_resolver { get; set; }
|
||||||
public string? address_strategy { get; set; }
|
public string? address_strategy { get; set; }
|
||||||
public string? strategy { get; set; }
|
public string? strategy { get; set; }
|
||||||
public string? detour { get; set; }
|
// Deprecated End
|
||||||
public string? client_subnet { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Experimental4Sbox
|
public class Experimental4Sbox
|
||||||
@@ -229,13 +280,6 @@ public class Stats4Sbox
|
|||||||
public List<string>? users { get; set; }
|
public List<string>? users { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Fakeip4Sbox
|
|
||||||
{
|
|
||||||
public bool enabled { get; set; }
|
|
||||||
public string inet4_range { get; set; }
|
|
||||||
public string inet6_range { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CacheFile4Sbox
|
public class CacheFile4Sbox
|
||||||
{
|
{
|
||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
@@ -254,3 +298,33 @@ public class Ruleset4Sbox
|
|||||||
public string? download_detour { get; set; }
|
public string? download_detour { get; set; }
|
||||||
public string? update_interval { get; set; }
|
public string? update_interval { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class DialFields4Sbox
|
||||||
|
{
|
||||||
|
public string? detour { get; set; }
|
||||||
|
public string? bind_interface { get; set; }
|
||||||
|
public string? inet4_bind_address { get; set; }
|
||||||
|
public string? inet6_bind_address { get; set; }
|
||||||
|
public int? routing_mark { get; set; }
|
||||||
|
public bool? reuse_addr { get; set; }
|
||||||
|
public string? netns { get; set; }
|
||||||
|
public string? connect_timeout { get; set; }
|
||||||
|
public bool? tcp_fast_open { get; set; }
|
||||||
|
public bool? tcp_multi_path { get; set; }
|
||||||
|
public bool? udp_fragment { get; set; }
|
||||||
|
public Rule4Sbox? domain_resolver { get; set; } // or string
|
||||||
|
public string? network_strategy { get; set; }
|
||||||
|
public List<string>? network_type { get; set; }
|
||||||
|
public List<string>? fallback_network_type { get; set; }
|
||||||
|
public string? fallback_delay { get; set; }
|
||||||
|
public Tls4Sbox? tls { get; set; }
|
||||||
|
public Multiplex4Sbox? multiplex { get; set; }
|
||||||
|
public Transport4Sbox? transport { get; set; }
|
||||||
|
public HyObfs4Sbox? obfs { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class BaseServer4Sbox : DialFields4Sbox
|
||||||
|
{
|
||||||
|
public string type { get; set; }
|
||||||
|
public string tag { get; set; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace ServiceLib.Models;
|
|||||||
public class V2rayConfig
|
public class V2rayConfig
|
||||||
{
|
{
|
||||||
public Log4Ray log { get; set; }
|
public Log4Ray log { get; set; }
|
||||||
public object dns { get; set; }
|
public Dns4Ray dns { get; set; }
|
||||||
public List<Inbounds4Ray> inbounds { get; set; }
|
public List<Inbounds4Ray> inbounds { get; set; }
|
||||||
public List<Outbounds4Ray> outbounds { get; set; }
|
public List<Outbounds4Ray> outbounds { get; set; }
|
||||||
public Routing4Ray routing { get; set; }
|
public Routing4Ray routing { get; set; }
|
||||||
@@ -203,13 +203,17 @@ public class Response4Ray
|
|||||||
|
|
||||||
public class Dns4Ray
|
public class Dns4Ray
|
||||||
{
|
{
|
||||||
public List<string> servers { get; set; }
|
public Dictionary<string, List<string>>? hosts { get; set; }
|
||||||
|
public List<object> servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DnsServer4Ray
|
public class DnsServer4Ray
|
||||||
{
|
{
|
||||||
public string? address { get; set; }
|
public string? address { get; set; }
|
||||||
public List<string>? domains { get; set; }
|
public List<string>? domains { get; set; }
|
||||||
|
public bool? skipFallback { get; set; }
|
||||||
|
public List<string>? expectedIPs { get; set; }
|
||||||
|
public List<string>? unexpectedIPs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Routing4Ray
|
public class Routing4Ray
|
||||||
@@ -339,6 +343,7 @@ public class TlsSettings4Ray
|
|||||||
public string? publicKey { get; set; }
|
public string? publicKey { get; set; }
|
||||||
public string? shortId { get; set; }
|
public string? shortId { get; set; }
|
||||||
public string? spiderX { get; set; }
|
public string? spiderX { get; set; }
|
||||||
|
public string? mldsa65Verify { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TcpSettings4Ray
|
public class TcpSettings4Ray
|
||||||
|
|||||||
328
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
328
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -132,24 +132,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Download speed 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string downloadSpeed {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("downloadSpeed", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Do you want to download {0}? 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string DownloadYesNo {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("DownloadYesNo", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Failed to convert configuration file 的本地化字符串。
|
/// 查找类似 Failed to convert configuration file 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -672,6 +654,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Add [Anytls] Configuration 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuAddAnytlsServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuAddAnytlsServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add a custom configuration Configuration 的本地化字符串。
|
/// 查找类似 Add a custom configuration Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1347,15 +1338,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Advanced Function 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuRoutingAdvanced {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuRoutingAdvanced", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add 的本地化字符串。
|
/// 查找类似 Add 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2229,6 +2211,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Incorrect password, please try again. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string SudoIncorrectPasswordTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SudoIncorrectPasswordTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Add Common DNS Hosts 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbAddCommonDNSHosts {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbAddCommonDNSHosts", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Address 的本地化字符串。
|
/// 查找类似 Address 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2265,6 +2265,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Apply to Proxy Domains Only 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbApplyProxyDomainsOnly {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbApplyProxyDomainsOnly", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Auto refresh 的本地化字符串。
|
/// 查找类似 Auto refresh 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2292,6 +2301,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Block SVCB and HTTPS Queries 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbBlockSVCBHTTPSQueries {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbBlockSVCBHTTPSQueries", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Browse 的本地化字符串。
|
/// 查找类似 Browse 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2346,6 +2364,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Enable Custom DNS 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbCustomDNSEnable {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbCustomDNSEnable", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Custom DNS Enabled, This Page's Settings Invalid 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbCustomDNSEnabledPageInvalid {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbCustomDNSEnabledPageInvalid", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Display GUI 的本地化字符串。
|
/// 查找类似 Display GUI 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2364,6 +2400,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 DNS Hosts: ("domain1 ip1 ip2" per line) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbDNSHostsConfig {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbDNSHostsConfig", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Supports DNS Object; Click to view documentation 的本地化字符串。
|
/// 查找类似 Supports DNS Object; Click to view documentation 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2409,6 +2454,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Domestic DNS 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbDomesticDNS {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbDomesticDNS", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Edit 的本地化字符串。
|
/// 查找类似 Edit 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2427,6 +2481,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 FakeIP 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbFakeIP {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbFakeIP", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Fingerprint 的本地化字符串。
|
/// 查找类似 Fingerprint 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2535,6 +2598,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Mldsa65Verify 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbMldsa65Verify {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbMldsa65Verify", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Transport protocol(network) 的本地化字符串。
|
/// 查找类似 Transport protocol(network) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2616,6 +2688,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Prevent DNS Leaks 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbPreventDNSLeaks {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbPreventDNSLeaks", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Private Key 的本地化字符串。
|
/// 查找类似 Private Key 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2652,6 +2733,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remote DNS 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbRemoteDNS {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbRemoteDNS", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Camouflage domain(host) 的本地化字符串。
|
/// 查找类似 Camouflage domain(host) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2715,33 +2805,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 3. Block Domain or IP 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbRoutingTabBlock {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbRoutingTabBlock", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 2. Direct Domain or IP 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbRoutingTabDirect {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbRoutingTabDirect", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 1. Proxy Domain or IP 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbRoutingTabProxy {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbRoutingTabProxy", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Pre-defined Rule Set List 的本地化字符串。
|
/// 查找类似 Pre-defined Rule Set List 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2778,6 +2841,78 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Can fill in the configuration remarks, please make sure it exist and are unique 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbRuleOutboundTagTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbRuleOutboundTagTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 sing-box Direct Resolution Strategy 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSBDirectResolveStrategy {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSBDirectResolveStrategy", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 The sing-box DoH resolution server can be overwritten 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSBDoHOverride {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSBDoHOverride", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 sing-box DoH Resolver Server 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSBDoHResolverServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSBDoHResolverServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Fallback DNS Resolution, Suggest IP 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSBFallbackDNSResolve {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSBFallbackDNSResolve", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Resolve Outbound Domains 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSBOutboundDomainResolve {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSBOutboundDomainResolve", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Outbound DNS Resolution (sing-box) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSBOutboundsResolverDNS {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSBOutboundsResolverDNS", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 sing-box Remote Resolution Strategy 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSBRemoteResolveStrategy {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSBRemoteResolveStrategy", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Encryption method (security) 的本地化字符串。
|
/// 查找类似 Encryption method (security) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3103,7 +3238,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Use Xray and enable non-Tun mode, which conflicts with the group previous proxy 的本地化字符串。
|
/// 查找类似 which conflicts with the group previous proxy 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsEnableFragmentTips {
|
public static string TbSettingsEnableFragmentTips {
|
||||||
get {
|
get {
|
||||||
@@ -3201,6 +3336,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Current connection info test URL 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsIPAPIUrl {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsIPAPIUrl", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Keep older entries when de-duplicating 的本地化字符串。
|
/// 查找类似 Keep older entries when de-duplicating 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3229,25 +3373,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please set the sudo password in Tun mode settings first 的本地化字符串。
|
/// 查找类似 The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart. 的本地化字符串。
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsLinuxSudoPasswordIsEmpty {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordIsEmpty", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Please do not run this app with sudo 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsLinuxSudoPasswordNotSudoRunApp {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordNotSudoRunApp", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 The password is encrypted and stored only in local files 的本地化字符串。
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsLinuxSudoPasswordTip {
|
public static string TbSettingsLinuxSudoPasswordTip {
|
||||||
get {
|
get {
|
||||||
@@ -3732,6 +3858,33 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Validate Regional Domain IPs 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbValidateDirectExpectedIPs {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbValidateDirectExpectedIPs", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbValidateDirectExpectedIPsDesc {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbValidateDirectExpectedIPsDesc", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 xray Freedom Resolution Strategy 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbXrayFreedomResolveStrategy {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbXrayFreedomResolveStrategy", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 The delay: {0} ms, {1} 的本地化字符串。
|
/// 查找类似 The delay: {0} ms, {1} 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3741,6 +3894,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Advanced DNS Settings 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string ThAdvancedDNSSettings {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ThAdvancedDNSSettings", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Basic DNS Settings 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string ThBasicDNSSettings {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ThBasicDNSSettings", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Active 的本地化字符串。
|
/// 查找类似 Active 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3939,15 +4110,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Ungrouped 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string UngroupedServers {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("UngroupedServers", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Upgrade App does not exist 的本地化字符串。
|
/// 查找类似 Upgrade App does not exist 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -132,12 +132,6 @@
|
|||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>درحال دانلود...</value>
|
<value>درحال دانلود...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>دانلود</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>آیا می خواهید {0} را دانلود کنید؟</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>تبدیل فایل پیکربندی انجام نشد</value>
|
<value>تبدیل فایل پیکربندی انجام نشد</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -387,9 +381,6 @@
|
|||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>کلید میانبر جهانی {0} با موفقیت ثبت شد</value>
|
<value>کلید میانبر جهانی {0} با موفقیت ثبت شد</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>گروه بندی نشده</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>همه سرورها</value>
|
<value>همه سرورها</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -822,9 +813,6 @@
|
|||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} وب سایت</value>
|
<value>{0} وب سایت</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>عملکرد پیشرفته</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>اضافه کردن</value>
|
<value>اضافه کردن</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -843,15 +831,6 @@
|
|||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>استراتژی دامنه</value>
|
<value>استراتژی دامنه</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3. مسدود کردن دامنه یا آیپی</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2. دایرکت کردن دامنه یا IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1. پروکسی کردن دامنه یا IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>لیست مجموعه قوانین از پیش تعریف شده</value>
|
<value>لیست مجموعه قوانین از پیش تعریف شده</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1126,7 +1105,7 @@
|
|||||||
<value>افزودن سرور [HTTP]</value>
|
<value>افزودن سرور [HTTP]</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>از Xray استفاده کنید و حالت non-Tun را فعال کنید، که با پراکسی قبلی گروه در تضاد است</value>
|
<value>which conflicts with the group previous proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>فعال کردن فرگمنت</value>
|
<value>فعال کردن فرگمنت</value>
|
||||||
@@ -1339,13 +1318,7 @@
|
|||||||
<value>رمز عبور sudo سیستم</value>
|
<value>رمز عبور sudo سیستم</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>رمز عبور رمزگذاری شده و فقط در فایل های محلی ذخیره می شود.</value>
|
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>لطفا این برنامه را با sudo اجرا نکنید</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*حالت xhttp</value>
|
<value>*حالت xhttp</value>
|
||||||
@@ -1416,4 +1389,85 @@
|
|||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>صادر کردن سرور</value>
|
<value>صادر کردن سرور</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>URL آزمایش اطلاعات اتصال فعلی</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>Incorrect password, please try again.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbMldsa65Verify" xml:space="preserve">
|
||||||
|
<value>Mldsa65Verify</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddAnytlsServer" xml:space="preserve">
|
||||||
|
<value>Add [Anytls] Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRemoteDNS" xml:space="preserve">
|
||||||
|
<value>Remote DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDomesticDNS" xml:space="preserve">
|
||||||
|
<value>Domestic DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
|
||||||
|
<value>Outbound DNS Resolution (sing-box)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
|
||||||
|
<value>Resolve Outbound Domains</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHResolverServer" xml:space="preserve">
|
||||||
|
<value>sing-box DoH Resolver Server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
|
||||||
|
<value>Fallback DNS Resolution, Suggest IP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
|
||||||
|
<value>xray Freedom Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Direct Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Remote Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbAddCommonDNSHosts" xml:space="preserve">
|
||||||
|
<value>Add Common DNS Hosts</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHOverride" xml:space="preserve">
|
||||||
|
<value>The sing-box DoH resolution server can be overwritten</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbFakeIP" xml:space="preserve">
|
||||||
|
<value>FakeIP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
|
||||||
|
<value>Block SVCB and HTTPS Queries</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPreventDNSLeaks" xml:space="preserve">
|
||||||
|
<value>Prevent DNS Leaks</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDNSHostsConfig" xml:space="preserve">
|
||||||
|
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
|
||||||
|
<value>Apply to Proxy Domains Only</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThBasicDNSSettings" xml:space="preserve">
|
||||||
|
<value>Basic DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThAdvancedDNSSettings" xml:space="preserve">
|
||||||
|
<value>Advanced DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
|
<value>Validate Regional Domain IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnable" xml:space="preserve">
|
||||||
|
<value>Enable Custom DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
|
||||||
|
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -132,12 +132,6 @@
|
|||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>Downloading...</value>
|
<value>Downloading...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>Download speed</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>Do you want to download {0}?</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>Failed to convert configuration file</value>
|
<value>Failed to convert configuration file</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -387,9 +381,6 @@
|
|||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>Global hotkey {0} registered successfully</value>
|
<value>Global hotkey {0} registered successfully</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>Ungrouped</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>All</value>
|
<value>All</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -822,9 +813,6 @@
|
|||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} Website</value>
|
<value>{0} Website</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>Advanced Function</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>Add</value>
|
<value>Add</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -843,15 +831,6 @@
|
|||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>Domain strategy</value>
|
<value>Domain strategy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3. Block Domain or IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2. Direct Domain or IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1. Proxy Domain or IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>Pre-defined Rule Set List</value>
|
<value>Pre-defined Rule Set List</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1126,7 +1105,7 @@
|
|||||||
<value>Add [HTTP] Configuration</value>
|
<value>Add [HTTP] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
<value>which conflicts with the group previous proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>Enable fragment</value>
|
<value>Enable fragment</value>
|
||||||
@@ -1339,13 +1318,7 @@
|
|||||||
<value>System sudo password</value>
|
<value>System sudo password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>The password is encrypted and stored only in local files</value>
|
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>Please set the sudo password in Tun mode settings first</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>Please do not run this app with sudo</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp mode</value>
|
<value>*xhttp mode</value>
|
||||||
@@ -1416,4 +1389,85 @@
|
|||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>Export Configuration</value>
|
<value>Export Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>Current connection info test URL</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>Incorrect password, please try again.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbMldsa65Verify" xml:space="preserve">
|
||||||
|
<value>Mldsa65Verify</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddAnytlsServer" xml:space="preserve">
|
||||||
|
<value>Add [Anytls] Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRemoteDNS" xml:space="preserve">
|
||||||
|
<value>Remote DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDomesticDNS" xml:space="preserve">
|
||||||
|
<value>Domestic DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
|
||||||
|
<value>Outbound DNS Resolution (sing-box)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
|
||||||
|
<value>Resolve Outbound Domains</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHResolverServer" xml:space="preserve">
|
||||||
|
<value>sing-box DoH Resolver Server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
|
||||||
|
<value>Fallback DNS Resolution, Suggest IP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
|
||||||
|
<value>xray Freedom Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Direct Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Remote Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbAddCommonDNSHosts" xml:space="preserve">
|
||||||
|
<value>Add Common DNS Hosts</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHOverride" xml:space="preserve">
|
||||||
|
<value>The sing-box DoH resolution server can be overwritten</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbFakeIP" xml:space="preserve">
|
||||||
|
<value>FakeIP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
|
||||||
|
<value>Block SVCB and HTTPS Queries</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPreventDNSLeaks" xml:space="preserve">
|
||||||
|
<value>Prevent DNS Leaks</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDNSHostsConfig" xml:space="preserve">
|
||||||
|
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
|
||||||
|
<value>Apply to Proxy Domains Only</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThBasicDNSSettings" xml:space="preserve">
|
||||||
|
<value>Basic DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThAdvancedDNSSettings" xml:space="preserve">
|
||||||
|
<value>Advanced DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
|
<value>Validate Regional Domain IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnable" xml:space="preserve">
|
||||||
|
<value>Enable Custom DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
|
||||||
|
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -118,31 +118,25 @@
|
|||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>Экспортирование URL в буфер обмена успешно завершено</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>
|
||||||
</data>
|
</data>
|
||||||
<data name="CustomServerTips" xml:space="preserve">
|
<data name="CustomServerTips" xml:space="preserve">
|
||||||
<value>Обратите внимание, что пользовательская конфигурация полностью зависит от вашей собственной конфигурации и работает не со всеми настройками. Если вы хотите использовать системный прокси, пожалуйста, измените порт прослушивания вручную.</value>
|
<value>Обратите внимание, что пользовательская конфигурация полностью зависит от вашей собственной конфигурации и работает не со всеми настройками. Если вы хотите использовать системный прокси, то измените порт прослушивания вручную</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>Загрузка...</value>
|
<value>Загрузка...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>Скорость загрузки</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>Хотите загрузить? {0}</value>
|
|
||||||
</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>Не удалось создать файл конфигурации по умолчаниюe</value>
|
<value>Не удалось создать файл конфигурации по умолчанию</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
||||||
<value>Не удалось получить конфигурацию по умолчанию</value>
|
<value>Не удалось получить конфигурацию по умолчанию</value>
|
||||||
@@ -154,37 +148,37 @@
|
|||||||
<value>Не удалось прочитать файл конфигурации</value>
|
<value>Не удалось прочитать файл конфигурации</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>Пожалуйста, укажите порт сервера в правильном формате</value>
|
<value>Укажите порт сервера в правильном формате</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>Пожалуйста, укажите локальный порт прослушивания</value>
|
<value>Введите локальный порт для прослушивания</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillPassword" xml:space="preserve">
|
<data name="FillPassword" xml:space="preserve">
|
||||||
<value>Пожалуйста, введите пароль</value>
|
<value>Введите пароль</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddress" xml:space="preserve">
|
<data name="FillServerAddress" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните адрес сервера</value>
|
<value>Введите адрес сервера</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните идентификатор пользователя</value>
|
<value>Введите идентификатор пользователя</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>Некорректная конфигурация, пожалуйста, проверьте</value>
|
<value>Некорректная конфигурация. Проверьте</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>Исходная конфигурация</value>
|
<value>Исходная конфигурация</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} {1} является последней версией.</value>
|
<value>{0} {1} является последней версией</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestN" xml:space="preserve">
|
<data name="IsLatestN" xml:space="preserve">
|
||||||
<value>{0} {1} является последней версией.</value>
|
<value>{0} {1} является последней версией</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAddress" xml:space="preserve">
|
<data name="LvAddress" xml:space="preserve">
|
||||||
<value>Адрес</value>
|
<value>Адрес</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvEncryptionMethod" xml:space="preserve">
|
<data name="LvEncryptionMethod" xml:space="preserve">
|
||||||
<value>Безопасность</value>
|
<value>Метод шифрования</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPort" xml:space="preserve">
|
<data name="LvPort" xml:space="preserve">
|
||||||
<value>Порт</value>
|
<value>Порт</value>
|
||||||
@@ -199,7 +193,7 @@
|
|||||||
<value>Загружено трафика сегодня</value>
|
<value>Загружено трафика сегодня</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTodayUploadDataAmount" xml:space="preserve">
|
<data name="LvTodayUploadDataAmount" xml:space="preserve">
|
||||||
<value>Отдано трафика сегодня</value>
|
<value>Отправлено сегодня</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTotalDownloadDataAmount" xml:space="preserve">
|
<data name="LvTotalDownloadDataAmount" xml:space="preserve">
|
||||||
<value>Всего загружено</value>
|
<value>Всего загружено</value>
|
||||||
@@ -214,13 +208,13 @@
|
|||||||
<value>Ядро успешно загружено</value>
|
<value>Ядро успешно загружено</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgFailedImportSubscription" xml:space="preserve">
|
<data name="MsgFailedImportSubscription" xml:space="preserve">
|
||||||
<value>Не удалось импортировать содержимое подписки</value>
|
<value>Не удалось импортировать подписку</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgGetSubscriptionSuccessfully" xml:space="preserve">
|
<data name="MsgGetSubscriptionSuccessfully" xml:space="preserve">
|
||||||
<value>Содержимое подписки успешно импортировано</value>
|
<value>Содержимое подписки успешно импортировано</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgNoValidSubscription" xml:space="preserve">
|
<data name="MsgNoValidSubscription" xml:space="preserve">
|
||||||
<value>Нет установлены подписки</value>
|
<value>Нет установленных подписок</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgParsingSuccessfully" xml:space="preserve">
|
<data name="MsgParsingSuccessfully" xml:space="preserve">
|
||||||
<value>Парсинг {0} прошел успешно</value>
|
<value>Парсинг {0} прошел успешно</value>
|
||||||
@@ -235,7 +229,7 @@
|
|||||||
<value>Некорректное содержимое подписки</value>
|
<value>Некорректное содержимое подписки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUnpacking" xml:space="preserve">
|
<data name="MsgUnpacking" xml:space="preserve">
|
||||||
<value>распаковывается...</value>
|
<value>Распаковка…</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
|
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
|
||||||
<value>Обновление подписки закончено</value>
|
<value>Обновление подписки закончено</value>
|
||||||
@@ -244,37 +238,37 @@
|
|||||||
<value>Обновление подписки начинается</value>
|
<value>Обновление подписки начинается</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>Успешное обновление ядра</value>
|
<value>Ядро успешно обновлено</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
|
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
|
||||||
<value>Успешное обновление ядра! Перезапуск службы...</value>
|
<value>Успешное обновление ядра! Перезапуск службы...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>Не является протоколом Vmess или SS</value>
|
<value>Не является протоколом VMess или Shadowsocks</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value>
|
<value>Файл ядра ({1}) не найден в папке {0}. Скачайте по адресу {2} и поместите его туда</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NoValidQRcodeFound" xml:space="preserve">
|
<data name="NoValidQRcodeFound" xml:space="preserve">
|
||||||
<value>Сканирование завершено, не найден корректный QR код</value>
|
<value>Сканирование завершено, не найден корректный QR код</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OperationFailed" xml:space="preserve">
|
<data name="OperationFailed" xml:space="preserve">
|
||||||
<value> операция безуспешна, проверьте и попробуйте ещё раз</value>
|
<value>Операция безуспешна, проверьте и попробуйте ещё раз</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseFillRemarks" xml:space="preserve">
|
<data name="PleaseFillRemarks" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните примечания</value>
|
<value>Введите примечания</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseSelectEncryption" xml:space="preserve">
|
<data name="PleaseSelectEncryption" xml:space="preserve">
|
||||||
<value>Пожалуйста, выберите метод шифрования</value>
|
<value>Выберите метод шифрования</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseSelectProtocol" xml:space="preserve">
|
<data name="PleaseSelectProtocol" xml:space="preserve">
|
||||||
<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>
|
||||||
@@ -286,16 +280,16 @@
|
|||||||
<value>Запуск сервиса ({0})...</value>
|
<value>Запуск сервиса ({0})...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfulConfiguration" xml:space="preserve">
|
<data name="SuccessfulConfiguration" xml:space="preserve">
|
||||||
<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>Сканирование URL-адреса импорта успешна.</value>
|
<value>Сканирование URL-адреса импорта прошло успешно</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TestMeOutput" xml:space="preserve">
|
<data name="TestMeOutput" xml:space="preserve">
|
||||||
<value>Задержка текущего сервера: {0} мс, {1}</value>
|
<value>Задержка текущего сервера: {0} мс, {1}</value>
|
||||||
@@ -310,7 +304,7 @@
|
|||||||
<value>Вы уверены, что хотите удалить правила?</value>
|
<value>Вы уверены, что хотите удалить правила?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
|
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
|
||||||
<value>{0}, Один из обязательных..</value>
|
<value>{0}: одно из обязательных полей</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvRemarks" xml:space="preserve">
|
<data name="LvRemarks" xml:space="preserve">
|
||||||
<value>Примечания</value>
|
<value>Примечания</value>
|
||||||
@@ -322,13 +316,13 @@
|
|||||||
<value>Количество</value>
|
<value>Количество</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgNeedUrl" xml:space="preserve">
|
<data name="MsgNeedUrl" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните адрес (Url)</value>
|
<value>Введите URL-адрес</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
|
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
|
||||||
<value>Вы хотите добавить правила? Выберите «Да», чтобы добавить, выберите иное, чтобы заменить</value>
|
<value>Хотите добавить правила? Выберите «Да» для добавления или «Нет» для замены</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
||||||
<value>Загрузка GeoFile: {0} успешна</value>
|
<value>Загрузка GeoFile {0} прошла успешно</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgInformationTitle" xml:space="preserve">
|
<data name="MsgInformationTitle" xml:space="preserve">
|
||||||
<value>Информация</value>
|
<value>Информация</value>
|
||||||
@@ -337,49 +331,49 @@
|
|||||||
<value>Пользовательская иконка</value>
|
<value>Пользовательская иконка</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectDNSText" xml:space="preserve">
|
<data name="FillCorrectDNSText" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните правильный пользовательский DNS</value>
|
<value>Введите корректный пользовательский DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip1" xml:space="preserve">
|
<data name="TransportPathTip1" xml:space="preserve">
|
||||||
<value>*ws путь</value>
|
<value>*WebSocket-путь</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip2" xml:space="preserve">
|
<data name="TransportPathTip2" xml:space="preserve">
|
||||||
<value>*h2 путь</value>
|
<value>*HTTP2-путь</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip3" xml:space="preserve">
|
<data name="TransportPathTip3" xml:space="preserve">
|
||||||
<value>*QUIC ключ/Kcp seed</value>
|
<value>*QUIC-ключ / KCP-seed</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip4" xml:space="preserve">
|
<data name="TransportPathTip4" xml:space="preserve">
|
||||||
<value>*grpc serviceName</value>
|
<value>Имя сервиса *gRPC</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip1" xml:space="preserve">
|
<data name="TransportRequestHostTip1" xml:space="preserve">
|
||||||
<value>*http хосты разделенные запятыми (,)</value>
|
<value>*http-хосты, разделённые запятыми (,)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip2" xml:space="preserve">
|
<data name="TransportRequestHostTip2" xml:space="preserve">
|
||||||
<value>*ws хост</value>
|
<value>*WebSocket-хост</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||||
<value>*h2 хосты разделенные запятыми (,)</value>
|
<value>*HTTP2-хосты, разделённые запятыми (,)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip4" xml:space="preserve">
|
<data name="TransportRequestHostTip4" xml:space="preserve">
|
||||||
<value>* безопасность QUIC</value>
|
<value>Безопасность *QUIC</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip1" xml:space="preserve">
|
<data name="TransportHeaderTypeTip1" xml:space="preserve">
|
||||||
<value>* тип TCP камуфляжа</value>
|
<value>Тип *TCP-камуфляжа</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip2" xml:space="preserve">
|
<data name="TransportHeaderTypeTip2" xml:space="preserve">
|
||||||
<value>* тип KCP камуфляжа</value>
|
<value>Тип *KCP-камуфляжа</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip3" xml:space="preserve">
|
<data name="TransportHeaderTypeTip3" xml:space="preserve">
|
||||||
<value>* тип QUIC камуфляжа</value>
|
<value>Тип *QUIC-камуфляжа</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip4" xml:space="preserve">
|
<data name="TransportHeaderTypeTip4" xml:space="preserve">
|
||||||
<value>* режим grpc</value>
|
<value>Режим *gRPC</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTLS" xml:space="preserve">
|
<data name="LvTLS" xml:space="preserve">
|
||||||
<value>TLS</value>
|
<value>TLS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip5" xml:space="preserve">
|
<data name="TransportPathTip5" xml:space="preserve">
|
||||||
<value>*Kcp seed</value>
|
<value>*KCP-seed</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
|
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
|
||||||
<value>Не удалось зарегистрировать глобальную горячую клавишу {0}, причина: {1}</value>
|
<value>Не удалось зарегистрировать глобальную горячую клавишу {0}, причина: {1}</value>
|
||||||
@@ -387,14 +381,11 @@
|
|||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>Глобальная горячая клавиша {0} зарегистрирована успешно</value>
|
<value>Глобальная горячая клавиша {0} зарегистрирована успешно</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>Разгруппировано</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<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>
|
||||||
@@ -436,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>
|
||||||
@@ -445,7 +436,7 @@
|
|||||||
<value>Обновить текущую подписку без прокси</value>
|
<value>Обновить текущую подписку без прокси</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubGroupUpdateViaProxy" xml:space="preserve">
|
<data name="menuSubGroupUpdateViaProxy" xml:space="preserve">
|
||||||
<value>Обновить текущую подписку с прокси</value>
|
<value>Обновить подписку через прокси</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubscription" xml:space="preserve">
|
<data name="menuSubscription" xml:space="preserve">
|
||||||
<value>Группа подписки</value>
|
<value>Группа подписки</value>
|
||||||
@@ -571,7 +562,7 @@
|
|||||||
<value>Сортировка</value>
|
<value>Сортировка</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvUserAgent" xml:space="preserve">
|
<data name="LvUserAgent" xml:space="preserve">
|
||||||
<value>User Agent</value>
|
<value>Заголовок User-Agent</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbCancel" xml:space="preserve">
|
<data name="TbCancel" xml:space="preserve">
|
||||||
<value>Отмена</value>
|
<value>Отмена</value>
|
||||||
@@ -628,7 +619,7 @@
|
|||||||
<value>TLS</value>
|
<value>TLS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipNetwork" xml:space="preserve">
|
<data name="TipNetwork" xml:space="preserve">
|
||||||
<value>* По-умолчанию TCP</value>
|
<value>*По-умолчанию TCP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbCoreType" xml:space="preserve">
|
<data name="TbCoreType" xml:space="preserve">
|
||||||
<value>Ядро</value>
|
<value>Ядро</value>
|
||||||
@@ -658,10 +649,10 @@
|
|||||||
<value>Шифрования</value>
|
<value>Шифрования</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPreSocksPort" xml:space="preserve">
|
<data name="TbPreSocksPort" xml:space="preserve">
|
||||||
<value>txtPreSocksPort</value>
|
<value>Порт SOCKS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipPreSocksPort" xml:space="preserve">
|
<data name="TipPreSocksPort" xml:space="preserve">
|
||||||
<value>* После установки этого значения служба socks будет запущена с использованием Xray/sing-box(Tun) для обеспечения таких функций, как отображение скорости</value>
|
<value>* После установки этого значения служба SOCKS будет запущена с использованием Xray/sing-box(TUN) для обеспечения таких функций, как отображение скорости</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBrowse" xml:space="preserve">
|
<data name="TbBrowse" xml:space="preserve">
|
||||||
<value>Просмотр</value>
|
<value>Просмотр</value>
|
||||||
@@ -697,7 +688,7 @@
|
|||||||
<value>Разрешить небезопасные</value>
|
<value>Разрешить небезопасные</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve">
|
<data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve">
|
||||||
<value>Outbound Freedom domainStrategy</value>
|
<value>«Freedom»: стратегия обработки доменов исходящего трафика</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
||||||
<value>Автоматически регулировать ширину столбца после обновления подписки</value>
|
<value>Автоматически регулировать ширину столбца после обновления подписки</value>
|
||||||
@@ -712,7 +703,7 @@
|
|||||||
<value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value>
|
<value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>Display real-time speed</value>
|
<value>Показывать скорость в реальном времени</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||||
<value>Сохранить старые при удалении дублей</value>
|
<value>Сохранить старые при удалении дублей</value>
|
||||||
@@ -721,10 +712,10 @@
|
|||||||
<value>Записывать логи</value>
|
<value>Записывать логи</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLogLevel" xml:space="preserve">
|
<data name="TbSettingsLogLevel" xml:space="preserve">
|
||||||
<value>Уровень логгирования</value>
|
<value>Уровень записи логов</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsMuxEnabled" xml:space="preserve">
|
<data name="TbSettingsMuxEnabled" xml:space="preserve">
|
||||||
<value>Включите мультиплексирование Mux</value>
|
<value>Включить мультиплексирование Mux</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsN" xml:space="preserve">
|
<data name="TbSettingsN" xml:space="preserve">
|
||||||
<value>Настройки v2rayN</value>
|
<value>Настройки v2rayN</value>
|
||||||
@@ -733,16 +724,16 @@
|
|||||||
<value>Пароль аутентификации</value>
|
<value>Пароль аутентификации</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsRemoteDNS" xml:space="preserve">
|
<data name="TbSettingsRemoteDNS" xml:space="preserve">
|
||||||
<value>Пользовательский DNS (если несколько делите с запятыми (,))</value>
|
<value>Пользовательский DNS (если несколько, то делите запятыми (,))</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSetUWP" xml:space="preserve">
|
<data name="TbSettingsSetUWP" xml:space="preserve">
|
||||||
<value>Set Win10 UWP Loopback</value>
|
<value>Разрешить loopback для приложений UWP (Win10)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSniffingEnabled" xml:space="preserve">
|
<data name="TbSettingsSniffingEnabled" xml:space="preserve">
|
||||||
<value>Включить сниффинг</value>
|
<value>Включить сниффинг</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||||
<value>Mixed Port</value>
|
<value>Смешанный порт</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||||
<value>Автозапуск</value>
|
<value>Автозапуск</value>
|
||||||
@@ -751,7 +742,7 @@
|
|||||||
<value>Включить статистику (требуется перезагрузка)</value>
|
<value>Включить статистику (требуется перезагрузка)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||||
<value>URL-адрес конверсии подписки</value>
|
<value>URL конвертации подписок</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSystemproxy" xml:space="preserve">
|
<data name="TbSettingsSystemproxy" xml:space="preserve">
|
||||||
<value>Настройки системного прокси</value>
|
<value>Настройки системного прокси</value>
|
||||||
@@ -766,7 +757,7 @@
|
|||||||
<value>Включить UDP</value>
|
<value>Включить UDP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUser" xml:space="preserve">
|
<data name="TbSettingsUser" xml:space="preserve">
|
||||||
<value>Auth user</value>
|
<value>Имя пользователя (логин)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbClearSystemProxy" xml:space="preserve">
|
<data name="TbClearSystemProxy" xml:space="preserve">
|
||||||
<value>Очистить системный прокси</value>
|
<value>Очистить системный прокси</value>
|
||||||
@@ -822,9 +813,6 @@
|
|||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} веб-сайт</value>
|
<value>{0} веб-сайт</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>Расширенная функция</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>Добавить</value>
|
<value>Добавить</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -843,20 +831,11 @@
|
|||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>Доменная стратегия</value>
|
<value>Доменная стратегия</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3.Заблокировать домен или IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2.Прямой домен или IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1.Прокси-домен или IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>Предустановленный список наборов правил</value>
|
<value>Предустановленный список наборов правил</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTips" xml:space="preserve">
|
<data name="TbRoutingTips" xml:space="preserve">
|
||||||
<value>* Установите правила, разделенные запятыми (,); Запятая в регулярке заменена на <COMMA></value>
|
<value>*Разделяйте правила запятыми (,). Литерал «,» — <COMMA>. Префикс # — отключить правило</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuImportRulesFromClipboard" xml:space="preserve">
|
<data name="menuImportRulesFromClipboard" xml:space="preserve">
|
||||||
<value>Импорт правил из буфера обмена</value>
|
<value>Импорт правил из буфера обмена</value>
|
||||||
@@ -883,16 +862,16 @@
|
|||||||
<value>Удалить правила (Delete)</value>
|
<value>Удалить правила (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
||||||
<value>RoutingRuleDetailsSetting</value>
|
<value>Детальные настройки правил маршрутизации</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoSort" xml:space="preserve">
|
<data name="TbAutoSort" xml:space="preserve">
|
||||||
<value>Домен и IP автоматически сортируются при сохранении</value>
|
<value>Домен и IP автоматически сортируются при сохранении</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||||
<value>Ruleobject Doc</value>
|
<value>Документация RuleObject</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||||
<value>Поддержка DnsObject</value>
|
<value>Поддерживаются DNS-объекты, нажмите для просмотра документации</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>Необязательное поле</value>
|
<value>Необязательное поле</value>
|
||||||
@@ -913,16 +892,16 @@
|
|||||||
<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>Задержка (мс)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTestSpeed" xml:space="preserve">
|
<data name="LvTestSpeed" xml:space="preserve">
|
||||||
<value>Скорость (M/s)</value>
|
<value>Скорость (МБ/с)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedToRunCore" xml:space="preserve">
|
<data name="FailedToRunCore" xml:space="preserve">
|
||||||
<value>Не удалось запустить ядро, посмотрите логи</value>
|
<value>Не удалось запустить ядро, посмотрите логи</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvFilter" xml:space="preserve">
|
<data name="LvFilter" xml:space="preserve">
|
||||||
<value>Remarks regular filter</value>
|
<value>Фильтр примечаний (Regex)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDisplayLog" xml:space="preserve">
|
<data name="TbDisplayLog" xml:space="preserve">
|
||||||
<value>Показать логи</value>
|
<value>Показать логи</value>
|
||||||
@@ -934,7 +913,7 @@
|
|||||||
<value>Новый порт для локальной сети</value>
|
<value>Новый порт для локальной сети</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>Настройки TunMode</value>
|
<value>Настройки режима TUN</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>Перейти в группу</value>
|
<value>Перейти в группу</value>
|
||||||
@@ -958,22 +937,22 @@
|
|||||||
<value>Тест завершен</value>
|
<value>Тест завершен</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDefFingerprint" xml:space="preserve">
|
<data name="TbSettingsDefFingerprint" xml:space="preserve">
|
||||||
<value>TLS отпечаток по умлочанию</value>
|
<value>TLS отпечаток по умолчанию</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
||||||
<value>User-Agent</value>
|
<value>User-Agent</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDefUserAgentTips" xml:space="preserve">
|
<data name="TbSettingsDefUserAgentTips" xml:space="preserve">
|
||||||
<value>Этот параметр действителен только для TCP/HTTP и WS</value>
|
<value>Параметр действует только для TCP/HTTP и WebSocket (WS)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
||||||
<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>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>Установите это с правами администратора</value>
|
<value>Установите это с правами администратора</value>
|
||||||
@@ -982,13 +961,13 @@
|
|||||||
<value>Размер шрифта</value>
|
<value>Размер шрифта</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||||
<value>Таймаут одиночного спидтеста</value>
|
<value>Тайм-аут одиночного тестирования скорости</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
<value>URL спидтеста</value>
|
<value>URL для тестирования скорости</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMoveTo" xml:space="preserve">
|
<data name="menuMoveTo" xml:space="preserve">
|
||||||
<value>Move up and down</value>
|
<value>Переместить вверх/вниз</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPublicKey" xml:space="preserve">
|
<data name="TbPublicKey" xml:space="preserve">
|
||||||
<value>PublicKey</value>
|
<value>PublicKey</value>
|
||||||
@@ -1003,19 +982,19 @@
|
|||||||
<value>Включить аппаратное ускорение (требуется перезагрузка)</value>
|
<value>Включить аппаратное ускорение (требуется перезагрузка)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingWait" xml:space="preserve">
|
<data name="SpeedtestingWait" xml:space="preserve">
|
||||||
<value>Ожидание тестирования (нажмите ESC для отмены)...</value>
|
<value>Ожидание тестирования (нажмите ESC для отмены)…</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipDisplayLog" xml:space="preserve">
|
<data name="TipDisplayLog" xml:space="preserve">
|
||||||
<value>Please turn off when there is an abnormal disconnection</value>
|
<value>Отключите при аномальном разрыве соединения</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
|
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
|
||||||
<value>Updates are not enabled, skip this subscription</value>
|
<value>Обновления не включены — подписка пропущена</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRebootAsAdmin" xml:space="preserve">
|
<data name="menuRebootAsAdmin" xml:space="preserve">
|
||||||
<value>Перезагрузить как администратор</value>
|
<value>Перезагрузить как администратор</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvMoreUrl" xml:space="preserve">
|
<data name="LvMoreUrl" xml:space="preserve">
|
||||||
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
|
<value>Дополнительные URL через запятую, конвертация подписки недоступна</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedDisplayText" xml:space="preserve">
|
<data name="SpeedDisplayText" xml:space="preserve">
|
||||||
<value>{0} : {1}/s↑ | {2}/s↓</value>
|
<value>{0} : {1}/s↑ | {2}/s↓</value>
|
||||||
@@ -1024,13 +1003,13 @@
|
|||||||
<value>Интервал автоматического обновления в минутах</value>
|
<value>Интервал автоматического обновления в минутах</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
||||||
<value>Включить логгирование в файл</value>
|
<value>Включить запись логов в файл</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvConvertTarget" xml:space="preserve">
|
<data name="LvConvertTarget" xml:space="preserve">
|
||||||
<value>Преобразовать тип цели</value>
|
<value>Преобразовать тип цели</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvConvertTargetTip" xml:space="preserve">
|
<data name="LvConvertTargetTip" xml:space="preserve">
|
||||||
<value>Если преобразование не требуется, оставьте поле пустым.</value>
|
<value>Если преобразование не требуется, оставьте поле пустым</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuDNSSetting" xml:space="preserve">
|
<data name="menuDNSSetting" xml:space="preserve">
|
||||||
<value>Настройки DNS</value>
|
<value>Настройки DNS</value>
|
||||||
@@ -1039,7 +1018,7 @@
|
|||||||
<value>Настройки DNS sing-box</value>
|
<value>Настройки DNS sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните структуру DNS. Нажмите, чтобы просмотреть документ.</value>
|
<value>Заполните структуру DNS, нажмите, чтобы открыть документ</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
|
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
|
||||||
<value>Нажмите, чтобы импортировать конфигурацию DNS по умолчанию</value>
|
<value>Нажмите, чтобы импортировать конфигурацию DNS по умолчанию</value>
|
||||||
@@ -1048,88 +1027,88 @@
|
|||||||
<value>Стратегия домена для sing-box</value>
|
<value>Стратегия домена для sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
|
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
|
||||||
<value>sing-box Mux Protocol</value>
|
<value>Протокол Mux для sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
||||||
<value>Full process name (Tun mode)</value>
|
<value>Полное имя процесса (режим TUN)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingRuleIP" xml:space="preserve">
|
<data name="TbRoutingRuleIP" xml:space="preserve">
|
||||||
<value>IP or IP CIDR</value>
|
<value>IP-адрес или сеть CIDR</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
||||||
<value>Домен</value>
|
<value>Домен</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 Max bandwidth (Up/Dw)</value>
|
<value>Максимальная пропускная способность Hysteria (загрузка/отдача)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
|
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
|
||||||
<value>Использовать системные узлы</value>
|
<value>Использовать системные узлы</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>Previous proxy remarks</value>
|
<value>Примечания к предыдущему прокси</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvNextProfile" xml:space="preserve">
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
<value>Next proxy remarks</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="TbSettingsEnableExInbound" xml:space="preserve">
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
<value>Enable additional Inbound</value>
|
<value>Включить дополнительный входящий канал</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||||
<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>Приватный ключ</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbReserved" xml:space="preserve">
|
<data name="TbReserved" xml:space="preserve">
|
||||||
<value>Reserved(2,3,4)</value>
|
<value>Зарезервировано (2, 3, 4)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbLocalAddress" xml:space="preserve">
|
<data name="TbLocalAddress" xml:space="preserve">
|
||||||
<value>Адрес(Ipv4,Ipv6)</value>
|
<value>Адрес (Ipv4,Ipv6)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPath7" xml:space="preserve">
|
<data name="TbPath7" xml:space="preserve">
|
||||||
<value>obfs password</value>
|
<value>Пароль obfs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleMatchingTips" xml:space="preserve">
|
<data name="TbRuleMatchingTips" xml:space="preserve">
|
||||||
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag => OutboundTag</value>
|
<value>(Домен или IP или имя процесса) и порт, и протокол, и InboundTag => OutboundTag</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
||||||
<value>Автоматическая прокрутка в конец</value>
|
<value>Автоматическая прокрутка в конец</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
||||||
<value>URL-адрес для проверки скорости пинга</value>
|
<value>URL для быстрой проверки реальной задержки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
|
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
|
||||||
<value>Updating subscription, only determine remarks exists</value>
|
<value>Обновляя подписку, проверять лишь наличие примечаний</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingStop" xml:space="preserve">
|
<data name="SpeedtestingStop" xml:space="preserve">
|
||||||
<value>Отмена тестирования...</value>
|
<value>Отмена тестирования...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip5" xml:space="preserve">
|
<data name="TransportRequestHostTip5" xml:space="preserve">
|
||||||
<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>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
<value>which conflicts with the group previous proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>Включить фрагмент</value>
|
<value>Включить фрагментацию (Fragment)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
<value>Включить файл кэша для sing-box (файлы наборов правил)</value>
|
<value>Включить файл кэша для sing-box (файлы наборов правил)</value>
|
||||||
@@ -1138,7 +1117,7 @@
|
|||||||
<value>Пользовательский набор правил для sing-box</value>
|
<value>Пользовательский набор правил для sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NeedRebootTips" xml:space="preserve">
|
<data name="NeedRebootTips" xml:space="preserve">
|
||||||
<value>Successful operation. Click the settings menu to reboot the app.</value>
|
<value>Операция успешна. Перезапустите приложение</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
||||||
<value>Открыть место хранения</value>
|
<value>Открыть место хранения</value>
|
||||||
@@ -1147,7 +1126,7 @@
|
|||||||
<value>Сортировка</value>
|
<value>Сортировка</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingChain" xml:space="preserve">
|
<data name="TbSortingChain" xml:space="preserve">
|
||||||
<value>Chain</value>
|
<value>Цепочка</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingDefault" xml:space="preserve">
|
<data name="TbSortingDefault" xml:space="preserve">
|
||||||
<value>По умолчанию</value>
|
<value>По умолчанию</value>
|
||||||
@@ -1159,7 +1138,7 @@
|
|||||||
<value>Скорость загрузки</value>
|
<value>Скорость загрузки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingDownTraffic" xml:space="preserve">
|
<data name="TbSortingDownTraffic" xml:space="preserve">
|
||||||
<value>Download Traffic</value>
|
<value>Скачанный трафик</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingHost" xml:space="preserve">
|
<data name="TbSortingHost" xml:space="preserve">
|
||||||
<value>Узел</value>
|
<value>Узел</value>
|
||||||
@@ -1177,10 +1156,10 @@
|
|||||||
<value>Тип</value>
|
<value>Тип</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingUpSpeed" xml:space="preserve">
|
<data name="TbSortingUpSpeed" xml:space="preserve">
|
||||||
<value>Скорость загрузки</value>
|
<value>Скорость отдачи</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingUpTraffic" xml:space="preserve">
|
<data name="TbSortingUpTraffic" xml:space="preserve">
|
||||||
<value>Upload Traffic</value>
|
<value>Отправленный трафик</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbConnections" xml:space="preserve">
|
<data name="TbConnections" xml:space="preserve">
|
||||||
<value>Соединения</value>
|
<value>Соединения</value>
|
||||||
@@ -1198,13 +1177,13 @@
|
|||||||
<value>Режим правила</value>
|
<value>Режим правила</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeDirect" xml:space="preserve">
|
<data name="menuModeDirect" xml:space="preserve">
|
||||||
<value>Direct</value>
|
<value>Прямое соединение</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeGlobal" xml:space="preserve">
|
<data name="menuModeGlobal" xml:space="preserve">
|
||||||
<value>Global</value>
|
<value>Глобальный режим</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeNothing" xml:space="preserve">
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
<value>Do not change</value>
|
<value>Не менять</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeRule" xml:space="preserve">
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
<value>Правила</value>
|
<value>Правила</value>
|
||||||
@@ -1213,13 +1192,13 @@
|
|||||||
<value>Тест задержки</value>
|
<value>Тест задержки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
<value>Part Node Latency Test</value>
|
<value>Тест задержки выбранных узлов</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesReload" xml:space="preserve">
|
<data name="menuProxiesReload" xml:space="preserve">
|
||||||
<value>Обновить прокси</value>
|
<value>Обновить прокси</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
<value>Активировать узел (Enter)</value>
|
<value>Сделать узел активным (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||||
<value>Стратегия домена по умолчанию для исходящих</value>
|
<value>Стратегия домена по умолчанию для исходящих</value>
|
||||||
@@ -1234,7 +1213,7 @@
|
|||||||
<value>Автоматическая регулировка ширины столбца</value>
|
<value>Автоматическая регулировка ширины столбца</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
||||||
<value>Export Base64-encoded Share Links to Clipboard</value>
|
<value>Экспорт ссылок в формате Base64 в буфер обмена</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>Экспортировать выбранный сервер для полной конфигурации в буфер обмена</value>
|
<value>Экспортировать выбранный сервер для полной конфигурации в буфер обмена</value>
|
||||||
@@ -1243,7 +1222,7 @@
|
|||||||
<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>
|
||||||
@@ -1255,28 +1234,28 @@
|
|||||||
<value>Восстановить из файла</value>
|
<value>Восстановить из файла</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoteBackup" xml:space="preserve">
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
<value>Backup to remote (WebDAV)</value>
|
<value>Резервное копирование на удалённый сервер (WebDAV)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoteRestore" xml:space="preserve">
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
<value>Restore from remote (WebDAV)</value>
|
<value>Восстановить с удалённого сервера (WebDAV)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
<value>Local</value>
|
<value>Локально</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
<value>Remote (WebDAV)</value>
|
<value>Удалённо (WebDAV)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavUrl" xml:space="preserve">
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
<value>WebDav Url</value>
|
<value>URL WebDAV</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavUserName" xml:space="preserve">
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
<value>WebDav User Name</value>
|
<value>Имя пользователя WebDAV</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavPassword" xml:space="preserve">
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
<value>WebDav Password</value>
|
<value>Пароль WebDAV</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavCheck" xml:space="preserve">
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
<value>WebDav Check</value>
|
<value>Проверить WebDAV</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavDirName" xml:space="preserve">
|
<data name="LvWebDavDirName" xml:space="preserve">
|
||||||
<value>Имя удаленной папки (необязательно)</value>
|
<value>Имя удаленной папки (необязательно)</value>
|
||||||
@@ -1285,16 +1264,16 @@
|
|||||||
<value>Неверный файл резервной копии</value>
|
<value>Неверный файл резервной копии</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
||||||
<value>Host filter</value>
|
<value>Фильтр хостов</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipActiveServer" xml:space="preserve">
|
<data name="TipActiveServer" xml:space="preserve">
|
||||||
<value>Active</value>
|
<value>Активный</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||||
<value>Источник geo файлов</value>
|
<value>Источник файлов Geo (необязательно)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
|
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
|
||||||
<value>Источник sing-box srs файлов</value>
|
<value>Источник файлов наборов правил sing-box (необязательно)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
||||||
<value>Программы для обновления не существует</value>
|
<value>Программы для обновления не существует</value>
|
||||||
@@ -1315,7 +1294,7 @@
|
|||||||
<value>Иран</value>
|
<value>Иран</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||||
<value>Используйте Настройки -> Региональные пресеты вместо изменения этого поля</value>
|
<value>Пользователи из Китая могут пропустить этот пункт</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaImage" xml:space="preserve">
|
<data name="menuAddServerViaImage" xml:space="preserve">
|
||||||
<value>Сканировать QR-код с изображения</value>
|
<value>Сканировать QR-код с изображения</value>
|
||||||
@@ -1324,7 +1303,7 @@
|
|||||||
<value>Неверный адрес (Url)</value>
|
<value>Неверный адрес (Url)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InsecureUrlProtocol" xml:space="preserve">
|
<data name="InsecureUrlProtocol" xml:space="preserve">
|
||||||
<value>Пожалуйста, не используйте небезопасный адрес подписки по протоколу HTTP.</value>
|
<value>Не используйте небезопасный адрес подписки по протоколу HTTP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||||
<value>Установите шрифт в систему и перезапустите настройки</value>
|
<value>Установите шрифт в систему и перезапустите настройки</value>
|
||||||
@@ -1333,43 +1312,37 @@
|
|||||||
<value>Вы уверены, что хотите выйти?</value>
|
<value>Вы уверены, что хотите выйти?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvMemo" xml:space="preserve">
|
<data name="LvMemo" xml:space="preserve">
|
||||||
<value>Remarks Memo</value>
|
<value>Заметка (Memo)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
||||||
<value>System sudo password</value>
|
<value>Пароль sudo системы</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>Пароль зашифрован и хранится только в локальных файлах..</value>
|
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>Please set the sudo password in Tun mode settings first</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>Пожалуйста, не запускайте программу как суперпользователь.</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp mode</value>
|
<value>*XHTTP-режим</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportExtraTip" xml:space="preserve">
|
<data name="TransportExtraTip" xml:space="preserve">
|
||||||
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
|
<value>Дополнительный XHTTP сырой JSON, формат: { XHTTPObject }</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||||
<value>Скрыть в трее при закрытии окна</value>
|
<value>Скрыть в трее при закрытии окна</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
||||||
<value>The number of concurrent during multi-test</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>Sniffing type</value>
|
<value>Тип сниффинга</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
||||||
<value>Enable second mixed port</value>
|
<value>Включить второй смешанный порт</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||||
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
|
<value>socks: локальный порт, socks2: второй локальный порт, socks3: LAN порт</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTheme" xml:space="preserve">
|
<data name="TbSettingsTheme" xml:space="preserve">
|
||||||
<value>Темы</value>
|
<value>Темы</value>
|
||||||
@@ -1378,7 +1351,7 @@
|
|||||||
<value>Копировать команду прокси в буфер обмена</value>
|
<value>Копировать команду прокси в буфер обмена</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
<value>Повторное тестирование неудачных элементов, осталось {0}. Нажмите ESC для остановки…</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestServerResult" xml:space="preserve">
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
<value>По результату теста</value>
|
<value>По результату теста</value>
|
||||||
@@ -1387,33 +1360,114 @@
|
|||||||
<value>Удалить недействительные по результатам теста</value>
|
<value>Удалить недействительные по результатам теста</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||||
<value>Удалено {0} недействительных.</value>
|
<value>Удалено {0} недействительных</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7" xml:space="preserve">
|
<data name="TbPorts7" xml:space="preserve">
|
||||||
<value>Диапазон портов сервера</value>
|
<value>Диапазон портов сервера</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7Tips" xml:space="preserve">
|
<data name="TbPorts7Tips" xml:space="preserve">
|
||||||
<value>Will cover the port, separate with commas (,)</value>
|
<value>Заменит указанный порт, перечисляйте через запятую (,)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>Multi-server to custom configuration</value>
|
<value>От мультиконфигурации к пользовательской конфигурации</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
||||||
<value>Multi-server Random by Xray</value>
|
<value>Случайный (Xray)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>Multi-server RoundRobin by Xray</value>
|
<value>Круговой (Xray)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>Multi-server LeastPing by Xray</value>
|
<value>Минимальное RTT (минимальное время туда-обратно) (Xray)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>Multi-server LeastLoad by Xray</value>
|
<value>Минимальная нагрузка (Xray)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>Multi-server LeastPing by sing-box</value>
|
<value>Минимальное RTT (минимальное время туда-обратно) (sing-box)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>Export server</value>
|
<value>Экспортировать конфигурацию</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>URL для тестирования текущего соединения</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>Incorrect password, please try again.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbMldsa65Verify" xml:space="preserve">
|
||||||
|
<value>Mldsa65Verify</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddAnytlsServer" xml:space="preserve">
|
||||||
|
<value>Добавить сервер [Anytls]</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRemoteDNS" xml:space="preserve">
|
||||||
|
<value>Remote DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDomesticDNS" xml:space="preserve">
|
||||||
|
<value>Domestic DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
|
||||||
|
<value>Outbound DNS Resolution (sing-box)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
|
||||||
|
<value>Resolve Outbound Domains</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHResolverServer" xml:space="preserve">
|
||||||
|
<value>sing-box DoH Resolver Server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
|
||||||
|
<value>Fallback DNS Resolution, Suggest IP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
|
||||||
|
<value>xray Freedom Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Direct Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Remote Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbAddCommonDNSHosts" xml:space="preserve">
|
||||||
|
<value>Add Common DNS Hosts</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHOverride" xml:space="preserve">
|
||||||
|
<value>The sing-box DoH resolution server can be overwritten</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbFakeIP" xml:space="preserve">
|
||||||
|
<value>FakeIP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
|
||||||
|
<value>Block SVCB and HTTPS Queries</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPreventDNSLeaks" xml:space="preserve">
|
||||||
|
<value>Prevent DNS Leaks</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDNSHostsConfig" xml:space="preserve">
|
||||||
|
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
|
||||||
|
<value>Apply to Proxy Domains Only</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThBasicDNSSettings" xml:space="preserve">
|
||||||
|
<value>Basic DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThAdvancedDNSSettings" xml:space="preserve">
|
||||||
|
<value>Advanced DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
|
<value>Validate Regional Domain IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnable" xml:space="preserve">
|
||||||
|
<value>Enable Custom DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
|
||||||
|
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -132,12 +132,6 @@
|
|||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>下载开始...</value>
|
<value>下载开始...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>下载</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>是否下载?{0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>转换配置文件失败</value>
|
<value>转换配置文件失败</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -387,9 +381,6 @@
|
|||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>注册全局热键 {0} 成功</value>
|
<value>注册全局热键 {0} 成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>未分组配置文件</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -712,7 +703,7 @@
|
|||||||
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号 (;) 分隔。</value>
|
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号 (;) 分隔。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>显示实时速度(需重启)</value>
|
<value>显示实时速度 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||||
<value>去重时保留序号较小的项</value>
|
<value>去重时保留序号较小的项</value>
|
||||||
@@ -748,7 +739,7 @@
|
|||||||
<value>开机启动 (可能会不成功)</value>
|
<value>开机启动 (可能会不成功)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||||
<value>启用流量统计(需重启)</value>
|
<value>启用流量统计 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||||
<value>订阅转换网址 (可选)</value>
|
<value>订阅转换网址 (可选)</value>
|
||||||
@@ -822,9 +813,6 @@
|
|||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} 官网</value>
|
<value>{0} 官网</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>高级功能</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>添加规则集</value>
|
<value>添加规则集</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -843,15 +831,6 @@
|
|||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>域名解析策略</value>
|
<value>域名解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3.阻止的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2.直连的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1.代理的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>预定义规则集列表</value>
|
<value>预定义规则集列表</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -907,7 +886,7 @@
|
|||||||
<value>仅限路由 (routeOnly)</value>
|
<value>仅限路由 (routeOnly)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
<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>
|
||||||
@@ -940,7 +919,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>
|
||||||
@@ -967,10 +946,10 @@
|
|||||||
<value>仅对 tcp/http、ws 协议生效</value>
|
<value>仅对 tcp/http、ws 协议生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
||||||
<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>
|
||||||
@@ -1000,10 +979,10 @@
|
|||||||
<value>SpiderX</value>
|
<value>SpiderX</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
||||||
<value>启用硬件加速(需重启)</value>
|
<value>启用硬件加速 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingWait" xml:space="preserve">
|
<data name="SpeedtestingWait" xml:space="preserve">
|
||||||
<value>等待测试中(按 ESC 终止)...</value>
|
<value>等待测试中 (按 ESC 终止)...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipDisplayLog" xml:space="preserve">
|
<data name="TipDisplayLog" xml:space="preserve">
|
||||||
<value>当有异常断流时请关闭</value>
|
<value>当有异常断流时请关闭</value>
|
||||||
@@ -1071,13 +1050,13 @@
|
|||||||
<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="TbSettingsEnableExInbound" xml:space="preserve">
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
@@ -1096,7 +1075,7 @@
|
|||||||
<value>Reserved (2,3,4)</value>
|
<value>Reserved (2,3,4)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbLocalAddress" xml:space="preserve">
|
<data name="TbLocalAddress" xml:space="preserve">
|
||||||
<value>Address (Ipv4,Ipv6)</value>
|
<value>Address (IPv4,IPv6)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPath7" xml:space="preserve">
|
<data name="TbPath7" xml:space="preserve">
|
||||||
<value>混淆密码 (obfs password)</value>
|
<value>混淆密码 (obfs password)</value>
|
||||||
@@ -1123,13 +1102,13 @@
|
|||||||
<value>添加 [HTTP] 配置文件</value>
|
<value>添加 [HTTP] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>使用 Xray 且非 Tun 模式启用,和分组前置代理冲突</value>
|
<value>和分组前置代理冲突</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>启用分片(Fragment)</value>
|
<value>启用分片 (Fragment)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
<value>启用 sing-box(规则集文件)的缓存文件</value>
|
<value>启用 sing-box (规则集文件) 的缓存文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
||||||
<value>自定义 sing-box rule-set</value>
|
<value>自定义 sing-box rule-set</value>
|
||||||
@@ -1222,7 +1201,7 @@
|
|||||||
<value>Outbound 默认解析策略</value>
|
<value>Outbound 默认解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
||||||
<value>主界面布局方向(需重启)</value>
|
<value>主界面布局方向 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
||||||
<value>Outbound 域名解析地址</value>
|
<value>Outbound 域名解析地址</value>
|
||||||
@@ -1324,7 +1303,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,16 +1315,10 @@
|
|||||||
<value>系统的 sudo 密码</value>
|
<value>系统的 sudo 密码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
|
<value>密码将调用命令行校验,如果因为校验错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>请先在 Tun 模式设置中设置 sudo 密码</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>请不要用 sudo 运行本程序</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp 模式</value>
|
<value>*XHTTP 模式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportExtraTip" xml:space="preserve">
|
<data name="TransportExtraTip" xml:space="preserve">
|
||||||
<value>XHTTP Extra 原始 JSON,格式: { XHTTPObject }</value>
|
<value>XHTTP Extra 原始 JSON,格式: { XHTTPObject }</value>
|
||||||
@@ -1366,7 +1339,7 @@
|
|||||||
<value>开启第二个本地监听端口</value>
|
<value>开启第二个本地监听端口</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||||
<value>socks:本地端口,socks2:第二个本地端口,socks3:局域网端口</value>
|
<value>Socks:本地端口,Socks2:第二个本地端口,Socks3:局域网端口</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTheme" xml:space="preserve">
|
<data name="TbSettingsTheme" xml:space="preserve">
|
||||||
<value>主题</value>
|
<value>主题</value>
|
||||||
@@ -1399,13 +1372,13 @@
|
|||||||
<value>多配置文件随机 Xray</value>
|
<value>多配置文件随机 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>多配置文件负载均衡 Xray</value>
|
<value>多配置文件负载均衡 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>多配置文件最低延迟 Xray</value>
|
<value>多配置文件最低延迟 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>多配置文件最稳定 Xray</value>
|
<value>多配置文件最稳定 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>多配置文件最低延迟 sing-box</value>
|
<value>多配置文件最低延迟 sing-box</value>
|
||||||
@@ -1413,4 +1386,85 @@
|
|||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>导出配置文件</value>
|
<value>导出配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>当前连接信息测试地址</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>可以填写配置文件别名,请确保存在并唯一</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>密码错误,请重试。</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbMldsa65Verify" xml:space="preserve">
|
||||||
|
<value>Mldsa65Verify</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddAnytlsServer" xml:space="preserve">
|
||||||
|
<value>添加 [Anytls] 配置文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRemoteDNS" xml:space="preserve">
|
||||||
|
<value>远程 DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDomesticDNS" xml:space="preserve">
|
||||||
|
<value>直连 DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
|
||||||
|
<value>出站 DNS 解析(sing-box)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
|
||||||
|
<value>解析出站域名</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHResolverServer" xml:space="preserve">
|
||||||
|
<value>sing-box DoH 解析服务器</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
|
||||||
|
<value>兜底解析其他 DNS 域名,建议设为 ip</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
|
||||||
|
<value>xray freedom 解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box 直连解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box 远程解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbAddCommonDNSHosts" xml:space="preserve">
|
||||||
|
<value>添加常用 DNS Hosts</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHOverride" xml:space="preserve">
|
||||||
|
<value>开启后可覆盖 sing-box DoH 解析服务器</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbFakeIP" xml:space="preserve">
|
||||||
|
<value>FakeIP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
|
||||||
|
<value>阻止 SVCB 和 HTTPS 查询</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPreventDNSLeaks" xml:space="preserve">
|
||||||
|
<value>避免 DNS 泄漏</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDNSHostsConfig" xml:space="preserve">
|
||||||
|
<value>DNS Hosts:(“域名1 ip1 ip2” 一行一个)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
|
||||||
|
<value>仅对代理域名生效</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThBasicDNSSettings" xml:space="preserve">
|
||||||
|
<value>DNS 基础设置</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThAdvancedDNSSettings" xml:space="preserve">
|
||||||
|
<value>DNS 进阶设置</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
|
<value>校验相应地区域名 IP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
|
<value>配置后,会对相应地区域名(如 geosite:cn)的返回 IP 进行校验,仅返回期望 IP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnable" xml:space="preserve">
|
||||||
|
<value>启用自定义 DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
|
||||||
|
<value>自定义 DNS 已启用,此页面配置将无效</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>匯出分享链接至剪貼簿成功</value>
|
<value>匯出分享連結至剪貼簿成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CheckServerSettings" xml:space="preserve">
|
<data name="CheckServerSettings" xml:space="preserve">
|
||||||
<value>請先檢查設定檔設定</value>
|
<value>請先檢查設定檔設定</value>
|
||||||
@@ -132,12 +132,6 @@
|
|||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>下載開始...</value>
|
<value>下載開始...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>下載</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>是否下載?{0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>轉換設定檔失敗</value>
|
<value>轉換設定檔失敗</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -295,7 +289,7 @@
|
|||||||
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>掃描匯入分享链接成功</value>
|
<value>掃描匯入分享連結成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TestMeOutput" xml:space="preserve">
|
<data name="TestMeOutput" xml:space="preserve">
|
||||||
<value>目前延遲: {0} ms,{1}</value>
|
<value>目前延遲: {0} ms,{1}</value>
|
||||||
@@ -387,9 +381,6 @@
|
|||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>註冊全域快速鍵 {0} 成功</value>
|
<value>註冊全域快速鍵 {0} 成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>未分組設定檔</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -481,7 +472,7 @@
|
|||||||
<value>語言 (需重啟)</value>
|
<value>語言 (需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||||
<value>從剪貼簿導入分享鏈接 (Ctrl+V)</value>
|
<value>從剪貼簿導入分享連結 (Ctrl+V)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaScan" xml:space="preserve">
|
<data name="menuAddServerViaScan" xml:space="preserve">
|
||||||
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
||||||
@@ -517,7 +508,7 @@
|
|||||||
<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>
|
||||||
@@ -822,9 +813,6 @@
|
|||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} 官網</value>
|
<value>{0} 官網</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>進階功能</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>新增規則集</value>
|
<value>新增規則集</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -843,15 +831,6 @@
|
|||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>域名解析策略</value>
|
<value>域名解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3.阻止的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2.直連的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1.代理的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>預定義規則集列表</value>
|
<value>預定義規則集列表</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -892,7 +871,7 @@
|
|||||||
<value>規則詳細說明檔案</value>
|
<value>規則詳細說明檔案</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||||
<value>支援填寫 DnsObject,JSON 格式,點擊查看説明</value>
|
<value>支援填寫 DnsObject,JSON 格式,點擊查看說明</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>普通分組此處請留空</value>
|
<value>普通分組此處請留空</value>
|
||||||
@@ -1003,7 +982,7 @@
|
|||||||
<value>啟用硬體加速 (需重啟)</value>
|
<value>啟用硬體加速 (需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingWait" xml:space="preserve">
|
<data name="SpeedtestingWait" xml:space="preserve">
|
||||||
<value>等待测试中(按 ESC 终止)...</value>
|
<value>等待測試中(按 ESC 終止)...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipDisplayLog" xml:space="preserve">
|
<data name="TipDisplayLog" xml:space="preserve">
|
||||||
<value>當有異常斷流時請關閉</value>
|
<value>當有異常斷流時請關閉</value>
|
||||||
@@ -1071,13 +1050,13 @@
|
|||||||
<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="TbSettingsEnableExInbound" xml:space="preserve">
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
@@ -1102,10 +1081,10 @@
|
|||||||
<value>混淆密碼 (obfs password)</value>
|
<value>混淆密碼 (obfs password)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleMatchingTips" xml:space="preserve">
|
<data name="TbRuleMatchingTips" xml:space="preserve">
|
||||||
<value>(Domain 或 IP 或 行程名) 与 Port 与 Protocol 与 InboundTag => OutboundTag</value>
|
<value>(Domain 或 IP 或 行程名) 與 Port 與 Protocol 與 InboundTag => OutboundTag</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
||||||
<value>自动滚动到末尾</value>
|
<value>自動滾動到末尾</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
||||||
<value>真連線測試位址</value>
|
<value>真連線測試位址</value>
|
||||||
@@ -1123,7 +1102,7 @@
|
|||||||
<value>新增 [HTTP] 設定檔</value>
|
<value>新增 [HTTP] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>使用 Xray 且非 Tun 模式啟用,和分組前置代理衝突</value>
|
<value>和分組前置代理衝突</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>啟用分片(Fragment)</value>
|
<value>啟用分片(Fragment)</value>
|
||||||
@@ -1201,7 +1180,7 @@
|
|||||||
<value>全局</value>
|
<value>全局</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeNothing" xml:space="preserve">
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
<value>随原配置</value>
|
<value>隨原配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeRule" xml:space="preserve">
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
<value>規則</value>
|
<value>規則</value>
|
||||||
@@ -1231,7 +1210,7 @@
|
|||||||
<value>自動調整列寬</value>
|
<value>自動調整列寬</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
||||||
<value>匯出分享链接至剪貼簿 (多選) Base64 编码</value>
|
<value>匯出分享連結至剪貼簿 (多選) Base64 編碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>匯出所選設定檔完整設定至剪貼簿</value>
|
<value>匯出所選設定檔完整設定至剪貼簿</value>
|
||||||
@@ -1267,7 +1246,7 @@
|
|||||||
<value>WebDav 伺服器位址</value>
|
<value>WebDav 伺服器位址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavUserName" xml:space="preserve">
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
<value>WebDav 賬戶</value>
|
<value>WebDav 帳戶</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavPassword" xml:space="preserve">
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
<value>WebDav 密碼</value>
|
<value>WebDav 密碼</value>
|
||||||
@@ -1336,13 +1315,7 @@
|
|||||||
<value>系統的 sudo 密碼</value>
|
<value>系統的 sudo 密碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
|
<value>密碼將調用命令行校驗,如果因為校驗錯誤導致無法正常運行時,請重啟本應用。密碼不會存儲,每次重啟後都需要再次輸入。</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>請不要用 sudo 來運行此 App</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp 模式</value>
|
<value>*xhttp 模式</value>
|
||||||
@@ -1366,7 +1339,7 @@
|
|||||||
<value>開啟第二個本機監聽埠</value>
|
<value>開啟第二個本機監聽埠</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||||
<value>socks:本地端口,socks2:第二個本地端口,socks3:區域網路端口</value>
|
<value>socks:本地埠,socks2:第二個本地埠,socks3:區域網路埠</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTheme" xml:space="preserve">
|
<data name="TbSettingsTheme" xml:space="preserve">
|
||||||
<value>主題</value>
|
<value>主題</value>
|
||||||
@@ -1387,10 +1360,10 @@
|
|||||||
<value>移除無效測試結果 {0} 個。</value>
|
<value>移除無效測試結果 {0} 個。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7" xml:space="preserve">
|
<data name="TbPorts7" xml:space="preserve">
|
||||||
<value>跳躍端口範圍</value>
|
<value>跳躍埠範圍</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7Tips" xml:space="preserve">
|
<data name="TbPorts7Tips" xml:space="preserve">
|
||||||
<value>會覆蓋端口,多組時用逗號 (,) 隔開</value>
|
<value>會覆蓋埠,多組時用逗號 (,) 隔開</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>多設定檔產生自訂配置 (多選)</value>
|
<value>多設定檔產生自訂配置 (多選)</value>
|
||||||
@@ -1413,4 +1386,85 @@
|
|||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>匯出設定檔</value>
|
<value>匯出設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>目前連接資訊測試地址</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>可以填寫設定檔別名,請確保存在並唯一</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>密碼錯誤,請重試。</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbMldsa65Verify" xml:space="preserve">
|
||||||
|
<value>Mldsa65Verify</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddAnytlsServer" xml:space="preserve">
|
||||||
|
<value>新增 [Anytls] 設定檔</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRemoteDNS" xml:space="preserve">
|
||||||
|
<value>Remote DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDomesticDNS" xml:space="preserve">
|
||||||
|
<value>Domestic DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
|
||||||
|
<value>Outbound DNS Resolution (sing-box)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
|
||||||
|
<value>Resolve Outbound Domains</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHResolverServer" xml:space="preserve">
|
||||||
|
<value>sing-box DoH Resolver Server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
|
||||||
|
<value>Fallback DNS Resolution, Suggest IP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
|
||||||
|
<value>xray Freedom Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Direct Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
|
||||||
|
<value>sing-box Remote Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbAddCommonDNSHosts" xml:space="preserve">
|
||||||
|
<value>Add Common DNS Hosts</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSBDoHOverride" xml:space="preserve">
|
||||||
|
<value>The sing-box DoH resolution server can be overwritten</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbFakeIP" xml:space="preserve">
|
||||||
|
<value>FakeIP</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
|
||||||
|
<value>Block SVCB and HTTPS Queries</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPreventDNSLeaks" xml:space="preserve">
|
||||||
|
<value>Prevent DNS Leaks</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDNSHostsConfig" xml:space="preserve">
|
||||||
|
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
|
||||||
|
<value>Apply to Proxy Domains Only</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThBasicDNSSettings" xml:space="preserve">
|
||||||
|
<value>Basic DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="ThAdvancedDNSSettings" xml:space="preserve">
|
||||||
|
<value>Advanced DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
|
||||||
|
<value>Validate Regional Domain IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
|
||||||
|
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnable" xml:space="preserve">
|
||||||
|
<value>Enable Custom DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
|
||||||
|
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"log": {
|
"log": {
|
||||||
"level": "debug",
|
"level": "debug",
|
||||||
"timestamp": true
|
"timestamp": true
|
||||||
@@ -14,22 +14,10 @@
|
|||||||
{
|
{
|
||||||
"type": "direct",
|
"type": "direct",
|
||||||
"tag": "direct"
|
"tag": "direct"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "block",
|
|
||||||
"tag": "block"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "dns_out",
|
|
||||||
"type": "dns"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"route": {
|
"route": {
|
||||||
"rules": [
|
"rules": [
|
||||||
{
|
|
||||||
"protocol": [ "dns" ],
|
|
||||||
"outbound": "dns_out"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,28 +2,33 @@
|
|||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"tag": "remote",
|
"tag": "remote",
|
||||||
"address": "tcp://8.8.8.8",
|
"type": "tcp",
|
||||||
"strategy": "prefer_ipv4",
|
"server": "8.8.8.8",
|
||||||
"detour": "proxy"
|
"detour": "proxy"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tag": "local",
|
"tag": "local",
|
||||||
"address": "223.5.5.5",
|
"type": "udp",
|
||||||
"strategy": "prefer_ipv4",
|
"server": "223.5.5.5"
|
||||||
"detour": "direct"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "block",
|
|
||||||
"address": "rcode://success"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rules": [
|
"rules": [
|
||||||
|
{
|
||||||
|
"domain_suffix": [
|
||||||
|
"googleapis.cn",
|
||||||
|
"gstatic.com"
|
||||||
|
],
|
||||||
|
"server": "remote",
|
||||||
|
"strategy": "prefer_ipv4"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"rule_set": [
|
"rule_set": [
|
||||||
"geosite-cn"
|
"geosite-cn"
|
||||||
],
|
],
|
||||||
"server": "local"
|
"server": "local",
|
||||||
|
"strategy": "prefer_ipv4"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"final": "remote"
|
"final": "remote",
|
||||||
|
"strategy": "prefer_ipv4"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"address": "1.1.1.1",
|
"address": "1.1.1.1",
|
||||||
|
"skipFallback": true,
|
||||||
"domains": [
|
"domains": [
|
||||||
"geosite:geolocation-!cn"
|
"domain:googleapis.cn",
|
||||||
],
|
"domain:gstatic.com"
|
||||||
"expectIPs": [
|
|
||||||
"geoip:!cn"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "223.5.5.5",
|
"address": "223.5.5.5",
|
||||||
|
"skipFallback": true,
|
||||||
"domains": [
|
"domains": [
|
||||||
"geosite:cn"
|
"geosite:cn"
|
||||||
],
|
],
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"geoip:cn"
|
"geoip:cn"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"1.1.1.1",
|
||||||
"8.8.8.8",
|
"8.8.8.8",
|
||||||
"https://dns.google/dns-query"
|
"https://dns.google/dns-query"
|
||||||
]
|
]
|
||||||
|
|||||||
61
v2rayN/ServiceLib/Sample/kill_as_sudo_linux_sh
Normal file
61
v2rayN/ServiceLib/Sample/kill_as_sudo_linux_sh
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Process Terminator Script for Linux
|
||||||
|
# This script forcibly terminates a process and all its child processes
|
||||||
|
#
|
||||||
|
|
||||||
|
# Check if PID argument is provided
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "Usage: $0 <PID>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PID=$1
|
||||||
|
|
||||||
|
# Validate that input is a valid PID (numeric)
|
||||||
|
if ! [[ "$PID" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Error: The PID must be a numeric value"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the process exists
|
||||||
|
if ! ps -p $PID > /dev/null; then
|
||||||
|
echo "Warning: No process found with PID $PID"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Recursive function to find and kill all child processes
|
||||||
|
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
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "============================================"
|
||||||
|
echo "Starting termination of process $PID and all its children"
|
||||||
|
echo "============================================"
|
||||||
|
|
||||||
|
# Find and kill all child processes
|
||||||
|
kill_children "$PID"
|
||||||
|
|
||||||
|
# Finally kill the main process
|
||||||
|
echo "Terminating main process: $PID"
|
||||||
|
kill -9 "$PID" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "============================================"
|
||||||
|
echo "Process $PID and all its children have been terminated"
|
||||||
|
echo "============================================"
|
||||||
|
|
||||||
|
exit 0
|
||||||
56
v2rayN/ServiceLib/Sample/kill_as_sudo_osx_sh
Normal file
56
v2rayN/ServiceLib/Sample/kill_as_sudo_osx_sh
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Process Terminator Script for macOS
|
||||||
|
# This script forcibly terminates a process and all its descendant processes
|
||||||
|
#
|
||||||
|
|
||||||
|
# Check if PID argument is provided
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "Usage: $0 <PID>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PID=$1
|
||||||
|
|
||||||
|
# Validate that input is a valid PID (numeric)
|
||||||
|
if ! [[ "$PID" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Error: The PID must be a numeric value"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the process exists - using kill -0 which is more reliable on macOS
|
||||||
|
if ! kill -0 $PID 2>/dev/null; then
|
||||||
|
echo "Warning: No process found with PID $PID"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Recursive function to find and kill all descendant processes
|
||||||
|
kill_descendants() {
|
||||||
|
local parent=$1
|
||||||
|
# Use ps -axo for macOS to ensure all processes are included
|
||||||
|
local children=$(ps -axo pid=,ppid= | awk -v ppid=$parent '$2==ppid {print $1}')
|
||||||
|
|
||||||
|
echo "Processing children of PID: $parent..."
|
||||||
|
for child in $children; do
|
||||||
|
kill_descendants "$child"
|
||||||
|
echo "Terminating child process: $child"
|
||||||
|
kill -9 "$child" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "============================================"
|
||||||
|
echo "Starting termination of process $PID and all its descendants"
|
||||||
|
echo "============================================"
|
||||||
|
|
||||||
|
# Find and kill all descendant processes
|
||||||
|
kill_descendants "$PID"
|
||||||
|
|
||||||
|
# Finally kill the main process
|
||||||
|
echo "Terminating main process: $PID"
|
||||||
|
kill -9 "$PID" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "============================================"
|
||||||
|
echo "Process $PID and all its descendants have been terminated"
|
||||||
|
echo "============================================"
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -7,4 +7,4 @@ X-GNOME-Autostart-enabled=true
|
|||||||
Name[en_US]=v2rayN
|
Name[en_US]=v2rayN
|
||||||
Name=v2rayN
|
Name=v2rayN
|
||||||
Comment[en_US]=v2rayN
|
Comment[en_US]=v2rayN
|
||||||
Comment=v2rayN
|
Comment=v2rayN
|
||||||
|
|||||||
@@ -29,9 +29,6 @@ set_gnome_proxy() {
|
|||||||
echo "Ignored Hosts: $IGNORE_HOSTS"
|
echo "Ignored Hosts: $IGNORE_HOSTS"
|
||||||
elif [ "$MODE" == "none" ]; then
|
elif [ "$MODE" == "none" ]; then
|
||||||
echo "GNOME: Proxy disabled."
|
echo "GNOME: Proxy disabled."
|
||||||
else
|
|
||||||
echo "GNOME: Invalid mode. Use 'none' or 'manual'."
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,9 +66,6 @@ set_kde_proxy() {
|
|||||||
# Disable proxy
|
# Disable proxy
|
||||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 0
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 0
|
||||||
echo "KDE: Proxy disabled."
|
echo "KDE: Proxy disabled."
|
||||||
else
|
|
||||||
echo "KDE: Invalid mode. Use 'none' or 'manual'."
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Apply changes by restarting KDE's network settings
|
# Apply changes by restarting KDE's network settings
|
||||||
@@ -84,7 +78,7 @@ detect_desktop_environment() {
|
|||||||
echo "gnome"
|
echo "gnome"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$XDG_CURRENT_DESKTOP" == *"XFCE"* ]] || [[ "$XDG_SESSION_DESKTOP" == *"XFCE"* ]]; then
|
if [[ "$XDG_CURRENT_DESKTOP" == *"XFCE"* ]] || [[ "$XDG_SESSION_DESKTOP" == *"XFCE"* ]]; then
|
||||||
echo "gnome"
|
echo "gnome"
|
||||||
return
|
return
|
||||||
@@ -94,7 +88,22 @@ detect_desktop_environment() {
|
|||||||
echo "gnome"
|
echo "gnome"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "$XDG_CURRENT_DESKTOP" == *"UKUI"* ]] || [[ "$XDG_SESSION_DESKTOP" == *"ukui"* ]]; then
|
||||||
|
echo "gnome"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$XDG_CURRENT_DESKTOP" == *"DDE"* ]] || [[ "$XDG_SESSION_DESKTOP" == *"dde"* ]]; then
|
||||||
|
echo "gnome"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$XDG_CURRENT_DESKTOP" == *"MATE"* ]] || [[ "$XDG_SESSION_DESKTOP" == *"mate"* ]]; then
|
||||||
|
echo "gnome"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
local KDE_ENVIRONMENTS=("KDE" "plasma")
|
local KDE_ENVIRONMENTS=("KDE" "plasma")
|
||||||
for ENV in "${KDE_ENVIRONMENTS[@]}"; do
|
for ENV in "${KDE_ENVIRONMENTS[@]}"; do
|
||||||
if [ "$XDG_CURRENT_DESKTOP" == "$ENV" ] || [ "$XDG_SESSION_DESKTOP" == "$ENV" ]; then
|
if [ "$XDG_CURRENT_DESKTOP" == "$ENV" ] || [ "$XDG_SESSION_DESKTOP" == "$ENV" ]; then
|
||||||
@@ -102,6 +111,15 @@ detect_desktop_environment() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Fallback to GNOME method if CLI utility is available. This solves the
|
||||||
|
# proxy configuration issues on minimal installation systems, like setups
|
||||||
|
# with only window managers, that borrow some parts from big DEs.
|
||||||
|
if command -v gsettings >/dev/null 2>&1; then
|
||||||
|
echo "gnome"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
echo "unsupported"
|
echo "unsupported"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +137,11 @@ PROXY_IP=$2
|
|||||||
PROXY_PORT=$3
|
PROXY_PORT=$3
|
||||||
IGNORE_HOSTS=$4
|
IGNORE_HOSTS=$4
|
||||||
|
|
||||||
|
if ! [[ "$MODE" =~ ^(manual|none)$ ]]; then
|
||||||
|
echo "Invalid mode. Use 'none' or 'manual'." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Detect desktop environment
|
# Detect desktop environment
|
||||||
DE=$(detect_desktop_environment)
|
DE=$(detect_desktop_environment)
|
||||||
|
|
||||||
@@ -129,6 +152,6 @@ elif [ "$DE" == "kde" ]; then
|
|||||||
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||||
set_kde_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
set_kde_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||||
else
|
else
|
||||||
echo "Unsupported desktop environment: $DE"
|
echo "Unsupported desktop environment: $DE" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -2,29 +2,33 @@
|
|||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"tag": "remote",
|
"tag": "remote",
|
||||||
"address": "tcp://8.8.8.8",
|
"type": "tcp",
|
||||||
"strategy": "prefer_ipv4",
|
"server": "8.8.8.8",
|
||||||
"detour": "proxy"
|
"detour": "proxy"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tag": "local",
|
"tag": "local",
|
||||||
"address": "223.5.5.5",
|
"type": "udp",
|
||||||
"strategy": "prefer_ipv4",
|
"server": "223.5.5.5"
|
||||||
"detour": "direct"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "block",
|
|
||||||
"address": "rcode://success"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
"rule_set": [
|
"domain_suffix": [
|
||||||
"geosite-cn",
|
"googleapis.cn",
|
||||||
"geosite-geolocation-cn"
|
"gstatic.com"
|
||||||
],
|
],
|
||||||
"server": "local"
|
"server": "remote",
|
||||||
|
"strategy": "prefer_ipv4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule_set": [
|
||||||
|
"geosite-cn"
|
||||||
|
],
|
||||||
|
"server": "local",
|
||||||
|
"strategy": "prefer_ipv4"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"final": "remote"
|
"final": "remote",
|
||||||
}
|
"strategy": "prefer_ipv4"
|
||||||
|
}
|
||||||
@@ -8,13 +8,13 @@
|
|||||||
139,
|
139,
|
||||||
5353
|
5353
|
||||||
],
|
],
|
||||||
"outbound": "block"
|
"action": "reject"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ip_cidr": [
|
"ip_cidr": [
|
||||||
"224.0.0.0/3",
|
"224.0.0.0/3",
|
||||||
"ff00::/8"
|
"ff00::/8"
|
||||||
],
|
],
|
||||||
"outbound": "block"
|
"action": "reject"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -28,6 +28,8 @@
|
|||||||
<EmbeddedResource Include="Sample\custom_routing_white" />
|
<EmbeddedResource Include="Sample\custom_routing_white" />
|
||||||
<EmbeddedResource Include="Sample\dns_singbox_normal" />
|
<EmbeddedResource Include="Sample\dns_singbox_normal" />
|
||||||
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
|
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
|
||||||
|
<EmbeddedResource Include="Sample\kill_as_sudo_linux_sh" />
|
||||||
|
<EmbeddedResource Include="Sample\kill_as_sudo_osx_sh" />
|
||||||
<EmbeddedResource Include="Sample\pac" />
|
<EmbeddedResource Include="Sample\pac" />
|
||||||
<EmbeddedResource Include="Sample\proxy_set_linux_sh" />
|
<EmbeddedResource Include="Sample\proxy_set_linux_sh" />
|
||||||
<EmbeddedResource Include="Sample\proxy_set_osx_sh" />
|
<EmbeddedResource Include="Sample\proxy_set_osx_sh" />
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class CoreConfigClashService
|
|||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
|
public async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
|
||||||
{
|
{
|
||||||
var ret = new RetResult();
|
var ret = new RetResult();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ServiceLib.Services.CoreConfig;
|
namespace ServiceLib.Services.CoreConfig;
|
||||||
|
|
||||||
@@ -54,12 +56,12 @@ public class CoreConfigV2rayService
|
|||||||
|
|
||||||
await GenInbounds(v2rayConfig);
|
await GenInbounds(v2rayConfig);
|
||||||
|
|
||||||
await GenRouting(v2rayConfig);
|
|
||||||
|
|
||||||
await GenOutbound(node, v2rayConfig.outbounds.First());
|
await GenOutbound(node, v2rayConfig.outbounds.First());
|
||||||
|
|
||||||
await GenMoreOutbounds(node, v2rayConfig);
|
await GenMoreOutbounds(node, v2rayConfig);
|
||||||
|
|
||||||
|
await GenRouting(v2rayConfig);
|
||||||
|
|
||||||
await GenDns(node, v2rayConfig);
|
await GenDns(node, v2rayConfig);
|
||||||
|
|
||||||
await GenStatistic(v2rayConfig);
|
await GenStatistic(v2rayConfig);
|
||||||
@@ -113,14 +115,14 @@ public class CoreConfigV2rayService
|
|||||||
await GenStatistic(v2rayConfig);
|
await GenStatistic(v2rayConfig);
|
||||||
v2rayConfig.outbounds.RemoveAt(0);
|
v2rayConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
var tagProxy = new List<string>();
|
var proxyProfiles = new List<ProfileItem>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (it.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC)
|
if (it.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -151,17 +153,14 @@ public class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
|
|
||||||
//outbound
|
//outbound
|
||||||
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
proxyProfiles.Add(item);
|
||||||
await GenOutbound(item, outbound);
|
|
||||||
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
|
||||||
v2rayConfig.outbounds.Insert(0, outbound);
|
|
||||||
tagProxy.Add(outbound.tag);
|
|
||||||
}
|
}
|
||||||
if (tagProxy.Count <= 0)
|
if (proxyProfiles.Count <= 0)
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
await GenOutboundsList(proxyProfiles, v2rayConfig);
|
||||||
|
|
||||||
//add balancers
|
//add balancers
|
||||||
await GenBalancer(v2rayConfig, multipleLoad);
|
await GenBalancer(v2rayConfig, multipleLoad);
|
||||||
@@ -328,7 +327,7 @@ public class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
listen = Global.Loopback,
|
listen = Global.Loopback,
|
||||||
port = port,
|
port = port,
|
||||||
protocol = EInboundProtocol.socks.ToString(),
|
protocol = EInboundProtocol.mixed.ToString(),
|
||||||
};
|
};
|
||||||
inbound.tag = inbound.protocol + inbound.port.ToString();
|
inbound.tag = inbound.protocol + inbound.port.ToString();
|
||||||
v2rayConfig.inbounds.Add(inbound);
|
v2rayConfig.inbounds.Add(inbound);
|
||||||
@@ -403,7 +402,7 @@ public class CoreConfigV2rayService
|
|||||||
tag = $"{EInboundProtocol.socks}{port}",
|
tag = $"{EInboundProtocol.socks}{port}",
|
||||||
listen = Global.Loopback,
|
listen = Global.Loopback,
|
||||||
port = port,
|
port = port,
|
||||||
protocol = EInboundProtocol.socks.ToString(),
|
protocol = EInboundProtocol.mixed.ToString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
@@ -507,7 +506,7 @@ public class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
inbound.tag = protocol.ToString();
|
inbound.tag = protocol.ToString();
|
||||||
inbound.port = inItem.LocalPort + (int)protocol;
|
inbound.port = inItem.LocalPort + (int)protocol;
|
||||||
inbound.protocol = EInboundProtocol.socks.ToString();
|
inbound.protocol = EInboundProtocol.mixed.ToString();
|
||||||
inbound.settings.udp = inItem.UdpEnabled;
|
inbound.settings.udp = inItem.UdpEnabled;
|
||||||
inbound.sniffing.enabled = inItem.SniffingEnabled;
|
inbound.sniffing.enabled = inItem.SniffingEnabled;
|
||||||
inbound.sniffing.destOverride = inItem.DestOverride;
|
inbound.sniffing.destOverride = inItem.DestOverride;
|
||||||
@@ -559,6 +558,8 @@ public class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
rule.outboundTag = await GenRoutingUserRuleOutbound(rule.outboundTag, v2rayConfig);
|
||||||
|
|
||||||
if (rule.port.IsNullOrEmpty())
|
if (rule.port.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
rule.port = null;
|
rule.port = null;
|
||||||
@@ -614,6 +615,7 @@ public class CoreConfigV2rayService
|
|||||||
if (rule.port.IsNotEmpty()
|
if (rule.port.IsNotEmpty()
|
||||||
|| rule.protocol?.Count > 0
|
|| rule.protocol?.Count > 0
|
||||||
|| rule.inboundTag?.Count > 0
|
|| rule.inboundTag?.Count > 0
|
||||||
|
|| rule.network != null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var it = JsonUtils.DeepCopy(rule);
|
var it = JsonUtils.DeepCopy(rule);
|
||||||
@@ -629,11 +631,37 @@ public class CoreConfigV2rayService
|
|||||||
return await Task.FromResult(0);
|
return await Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string?> GenRoutingUserRuleOutbound(string outboundTag, V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
if (Global.OutboundTags.Contains(outboundTag))
|
||||||
|
{
|
||||||
|
return outboundTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
var node = await AppHandler.Instance.GetProfileItemViaRemarks(outboundTag);
|
||||||
|
if (node == null
|
||||||
|
|| node.ConfigType == EConfigType.Custom
|
||||||
|
|| node.ConfigType == EConfigType.Hysteria2
|
||||||
|
|| node.ConfigType == EConfigType.TUIC
|
||||||
|
|| node.ConfigType == EConfigType.Anytls)
|
||||||
|
{
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(node, outbound);
|
||||||
|
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
|
||||||
|
v2rayConfig.outbounds.Add(outbound);
|
||||||
|
|
||||||
|
return outbound.tag;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
|
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var muxEnabled = _config.CoreBasicItem.MuxEnabled;
|
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
|
||||||
switch (node.ConfigType)
|
switch (node.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.VMess:
|
||||||
@@ -661,7 +689,7 @@ public class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
usersItem = vnextItem.users.First();
|
usersItem = vnextItem.users.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
usersItem.id = node.Id;
|
usersItem.id = node.Id;
|
||||||
usersItem.alterId = node.AlterId;
|
usersItem.alterId = node.AlterId;
|
||||||
usersItem.email = Global.UserEMail;
|
usersItem.email = Global.UserEMail;
|
||||||
@@ -919,6 +947,7 @@ public class CoreConfigV2rayService
|
|||||||
publicKey = node.PublicKey,
|
publicKey = node.PublicKey,
|
||||||
shortId = node.ShortId,
|
shortId = node.ShortId,
|
||||||
spiderX = node.SpiderX,
|
spiderX = node.SpiderX,
|
||||||
|
mldsa65Verify = node.Mldsa65Verify,
|
||||||
show = false,
|
show = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1107,6 +1136,264 @@ public class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
|
private async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
|
if (item != null && item.Enabled == true)
|
||||||
|
{
|
||||||
|
return await GenDnsCompatible(node, v2rayConfig);
|
||||||
|
}
|
||||||
|
var simpleDNSItem = _config.SimpleDNSItem;
|
||||||
|
var domainStrategy4Freedom = simpleDNSItem?.RayStrategy4Freedom;
|
||||||
|
|
||||||
|
//Outbound Freedom domainStrategy
|
||||||
|
if (domainStrategy4Freedom.IsNotEmpty())
|
||||||
|
{
|
||||||
|
var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
||||||
|
if (outbound != null)
|
||||||
|
{
|
||||||
|
outbound.settings = new()
|
||||||
|
{
|
||||||
|
domainStrategy = domainStrategy4Freedom,
|
||||||
|
userLevel = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await GenDnsServers(node, v2rayConfig, simpleDNSItem);
|
||||||
|
await GenDnsHosts(v2rayConfig, simpleDNSItem);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<int> GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem)
|
||||||
|
{
|
||||||
|
static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress)
|
||||||
|
{
|
||||||
|
var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';')
|
||||||
|
.Select(addr => addr.Trim())
|
||||||
|
.Where(addr => !string.IsNullOrEmpty(addr))
|
||||||
|
.Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr)
|
||||||
|
.Distinct()
|
||||||
|
.ToList() ?? new List<string> { defaultAddress };
|
||||||
|
return addresses.Count > 0 ? addresses : new List<string> { defaultAddress };
|
||||||
|
}
|
||||||
|
|
||||||
|
static object CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
||||||
|
{
|
||||||
|
var dnsServer = new DnsServer4Ray
|
||||||
|
{
|
||||||
|
address = dnsAddress,
|
||||||
|
skipFallback = true,
|
||||||
|
domains = domains.Count > 0 ? domains : null,
|
||||||
|
expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null
|
||||||
|
};
|
||||||
|
return JsonUtils.SerializeToNode(dnsServer, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.FirstOrDefault());
|
||||||
|
var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.FirstOrDefault());
|
||||||
|
|
||||||
|
var directDomainList = new List<string>();
|
||||||
|
var directGeositeList = new List<string>();
|
||||||
|
var proxyDomainList = new List<string>();
|
||||||
|
var proxyGeositeList = new List<string>();
|
||||||
|
var expectedDomainList = new List<string>();
|
||||||
|
var expectedIPs = new List<string>();
|
||||||
|
var regionNames = new HashSet<string>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(simpleDNSItem?.DirectExpectedIPs))
|
||||||
|
{
|
||||||
|
expectedIPs = simpleDNSItem.DirectExpectedIPs
|
||||||
|
.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(s => s.Trim())
|
||||||
|
.Where(s => !string.IsNullOrEmpty(s))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var ip in expectedIPs)
|
||||||
|
{
|
||||||
|
if (ip.StartsWith("geoip:", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var region = ip["geoip:".Length..];
|
||||||
|
if (!string.IsNullOrEmpty(region))
|
||||||
|
{
|
||||||
|
regionNames.Add($"geosite:{region}");
|
||||||
|
regionNames.Add($"geosite:geolocation-{region}");
|
||||||
|
regionNames.Add($"geosite:tld-{region}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||||
|
List<RulesItem>? rules = null;
|
||||||
|
if (routing != null)
|
||||||
|
{
|
||||||
|
rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
|
||||||
|
foreach (var item in rules)
|
||||||
|
{
|
||||||
|
if (!item.Enabled || item.Domain is null || item.Domain.Count == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var domain in item.Domain)
|
||||||
|
{
|
||||||
|
if (domain.StartsWith('#'))
|
||||||
|
continue;
|
||||||
|
var normalizedDomain = domain.Replace(Global.RoutingRuleComma, ",");
|
||||||
|
|
||||||
|
if (item.OutboundTag == Global.DirectTag)
|
||||||
|
{
|
||||||
|
if (normalizedDomain.StartsWith("geosite:"))
|
||||||
|
{
|
||||||
|
(regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
directDomainList.Add(normalizedDomain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (item.OutboundTag == Global.ProxyTag)
|
||||||
|
{
|
||||||
|
if (normalizedDomain.StartsWith("geosite:"))
|
||||||
|
{
|
||||||
|
proxyGeositeList.Add(normalizedDomain);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proxyDomainList.Add(normalizedDomain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.IsDomain(node?.Address))
|
||||||
|
{
|
||||||
|
directDomainList.Add(node.Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node?.Subid is not null)
|
||||||
|
{
|
||||||
|
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
|
||||||
|
if (subItem is not null)
|
||||||
|
{
|
||||||
|
foreach (var profile in new[] { subItem.PrevProfile, subItem.NextProfile })
|
||||||
|
{
|
||||||
|
var profileNode = await AppHandler.Instance.GetProfileItemViaRemarks(profile);
|
||||||
|
if (profileNode is not null &&
|
||||||
|
profileNode.ConfigType is not (EConfigType.Custom or EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls) &&
|
||||||
|
Utils.IsDomain(profileNode.Address))
|
||||||
|
{
|
||||||
|
directDomainList.Add(profileNode.Address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v2rayConfig.dns ??= new Dns4Ray();
|
||||||
|
v2rayConfig.dns.servers ??= new List<object>();
|
||||||
|
|
||||||
|
void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null)
|
||||||
|
{
|
||||||
|
if (domains.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var dnsAddress in dnsAddresses)
|
||||||
|
{
|
||||||
|
v2rayConfig.dns.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
||||||
|
AddDnsServers(directDNSAddress, directDomainList);
|
||||||
|
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
||||||
|
AddDnsServers(directDNSAddress, directGeositeList);
|
||||||
|
AddDnsServers(directDNSAddress, expectedDomainList, expectedIPs);
|
||||||
|
|
||||||
|
var useDirectDns = rules?.LastOrDefault() is { } lastRule &&
|
||||||
|
lastRule.OutboundTag == Global.DirectTag &&
|
||||||
|
(lastRule.Port == "0-65535" ||
|
||||||
|
lastRule.Network == "tcp,udp" ||
|
||||||
|
lastRule.Ip?.Contains("0.0.0.0/0") == true);
|
||||||
|
|
||||||
|
var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress;
|
||||||
|
v2rayConfig.dns.servers.AddRange(defaultDnsServers);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<int> GenDnsHosts(V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem)
|
||||||
|
{
|
||||||
|
if (simpleDNSItem.AddCommonHosts == false && simpleDNSItem.UseSystemHosts == false && simpleDNSItem.Hosts.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return await Task.FromResult(0);
|
||||||
|
}
|
||||||
|
v2rayConfig.dns ??= new Dns4Ray();
|
||||||
|
v2rayConfig.dns.hosts ??= new Dictionary<string, List<string>>();
|
||||||
|
if (simpleDNSItem.AddCommonHosts == true)
|
||||||
|
{
|
||||||
|
v2rayConfig.dns.hosts = Global.PredefinedHosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simpleDNSItem.UseSystemHosts == true)
|
||||||
|
{
|
||||||
|
var systemHosts = Utils.GetSystemHosts();
|
||||||
|
if (systemHosts.Count > 0)
|
||||||
|
{
|
||||||
|
var normalHost = v2rayConfig.dns.hosts;
|
||||||
|
if (normalHost != null)
|
||||||
|
{
|
||||||
|
foreach (var host in systemHosts)
|
||||||
|
{
|
||||||
|
if (normalHost[host.Key] != null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
normalHost[host.Key] = new List<string> { host.Value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var userHostsMap = simpleDNSItem.Hosts?
|
||||||
|
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||||
|
.Where(line => line.Contains(' '))
|
||||||
|
.ToDictionary(
|
||||||
|
line =>
|
||||||
|
{
|
||||||
|
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
return parts[0];
|
||||||
|
},
|
||||||
|
line =>
|
||||||
|
{
|
||||||
|
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var values = parts.Skip(1).ToList();
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userHostsMap != null)
|
||||||
|
{
|
||||||
|
foreach (var kvp in userHostsMap)
|
||||||
|
{
|
||||||
|
v2rayConfig.dns.hosts[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<int> GenDnsCompatible(ProfileItem? node, V2rayConfig v2rayConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1149,22 +1436,33 @@ public class CoreConfigV2rayService
|
|||||||
var systemHosts = Utils.GetSystemHosts();
|
var systemHosts = Utils.GetSystemHosts();
|
||||||
if (systemHosts.Count > 0)
|
if (systemHosts.Count > 0)
|
||||||
{
|
{
|
||||||
var normalHost = obj["hosts"];
|
var normalHost1 = obj["hosts"];
|
||||||
if (normalHost != null)
|
if (normalHost1 != null)
|
||||||
{
|
{
|
||||||
foreach (var host in systemHosts)
|
foreach (var host in systemHosts)
|
||||||
{
|
{
|
||||||
if (normalHost[host.Key] != null)
|
if (normalHost1[host.Key] != null)
|
||||||
continue;
|
continue;
|
||||||
normalHost[host.Key] = host.Value;
|
normalHost1[host.Key] = host.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var normalHost = obj["hosts"];
|
||||||
|
if (normalHost != null)
|
||||||
|
{
|
||||||
|
foreach (var hostProp in normalHost.AsObject().ToList())
|
||||||
|
{
|
||||||
|
if (hostProp.Value is JsonValue value && value.TryGetValue<string>(out var ip))
|
||||||
|
{
|
||||||
|
normalHost[hostProp.Key] = new JsonArray(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await GenDnsDomains(node, obj, item);
|
await GenDnsDomainsCompatible(node, obj, item);
|
||||||
|
|
||||||
v2rayConfig.dns = obj;
|
v2rayConfig.dns = JsonUtils.Deserialize<Dns4Ray>(obj.ToJsonString());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -1173,19 +1471,52 @@ public class CoreConfigV2rayService
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
|
private async Task<int> GenDnsDomainsCompatible(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
|
||||||
{
|
{
|
||||||
if (node == null)
|
if (node == null)
|
||||||
{ return 0; }
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
var servers = dns["servers"];
|
var servers = dns["servers"];
|
||||||
if (servers != null)
|
if (servers != null)
|
||||||
{
|
{
|
||||||
|
var domainList = new List<string>();
|
||||||
if (Utils.IsDomain(node.Address))
|
if (Utils.IsDomain(node.Address))
|
||||||
|
{
|
||||||
|
domainList.Add(node.Address);
|
||||||
|
}
|
||||||
|
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
|
||||||
|
if (subItem is not null)
|
||||||
|
{
|
||||||
|
// Previous proxy
|
||||||
|
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
||||||
|
if (prevNode is not null
|
||||||
|
&& prevNode.ConfigType != EConfigType.Custom
|
||||||
|
&& prevNode.ConfigType != EConfigType.Hysteria2
|
||||||
|
&& prevNode.ConfigType != EConfigType.TUIC
|
||||||
|
&& Utils.IsDomain(prevNode.Address))
|
||||||
|
{
|
||||||
|
domainList.Add(prevNode.Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next proxy
|
||||||
|
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
||||||
|
if (nextNode is not null
|
||||||
|
&& nextNode.ConfigType != EConfigType.Custom
|
||||||
|
&& nextNode.ConfigType != EConfigType.Hysteria2
|
||||||
|
&& nextNode.ConfigType != EConfigType.TUIC
|
||||||
|
&& Utils.IsDomain(nextNode.Address))
|
||||||
|
{
|
||||||
|
domainList.Add(nextNode.Address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (domainList.Count > 0)
|
||||||
{
|
{
|
||||||
var dnsServer = new DnsServer4Ray()
|
var dnsServer = new DnsServer4Ray()
|
||||||
{
|
{
|
||||||
address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress,
|
address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainPureIPDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress,
|
||||||
domains = [node.Address]
|
skipFallback = true,
|
||||||
|
domains = domainList
|
||||||
};
|
};
|
||||||
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
||||||
}
|
}
|
||||||
@@ -1287,39 +1618,24 @@ public class CoreConfigV2rayService
|
|||||||
|
|
||||||
//Previous proxy
|
//Previous proxy
|
||||||
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
||||||
|
string? prevOutboundTag = null;
|
||||||
if (prevNode is not null
|
if (prevNode is not null
|
||||||
&& prevNode.ConfigType != EConfigType.Custom
|
&& prevNode.ConfigType != EConfigType.Custom
|
||||||
&& prevNode.ConfigType != EConfigType.Hysteria2
|
&& prevNode.ConfigType != EConfigType.Hysteria2
|
||||||
&& prevNode.ConfigType != EConfigType.TUIC)
|
&& prevNode.ConfigType != EConfigType.TUIC
|
||||||
|
&& prevNode.ConfigType != EConfigType.Anytls)
|
||||||
{
|
{
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
prevOutbound.tag = $"{Global.ProxyTag}2";
|
prevOutboundTag = $"prev-{Global.ProxyTag}";
|
||||||
|
prevOutbound.tag = prevOutboundTag;
|
||||||
v2rayConfig.outbounds.Add(prevOutbound);
|
v2rayConfig.outbounds.Add(prevOutbound);
|
||||||
|
|
||||||
outbound.streamSettings.sockopt = new()
|
|
||||||
{
|
|
||||||
dialerProxy = prevOutbound.tag
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
|
||||||
|
|
||||||
//Next proxy
|
if (nextOutbound is not null)
|
||||||
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
|
||||||
if (nextNode is not null
|
|
||||||
&& nextNode.ConfigType != EConfigType.Custom
|
|
||||||
&& nextNode.ConfigType != EConfigType.Hysteria2
|
|
||||||
&& nextNode.ConfigType != EConfigType.TUIC)
|
|
||||||
{
|
{
|
||||||
var nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
|
||||||
nextOutbound.tag = Global.ProxyTag;
|
|
||||||
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
||||||
|
|
||||||
outbound.tag = $"{Global.ProxyTag}1";
|
|
||||||
nextOutbound.streamSettings.sockopt = new()
|
|
||||||
{
|
|
||||||
dialerProxy = outbound.tag
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -1330,18 +1646,181 @@ public class CoreConfigV2rayService
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get template and initialize list
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
if (txtOutbound.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultOutbounds = new List<Outbounds4Ray>();
|
||||||
|
var prevOutbounds = new List<Outbounds4Ray>(); // Separate list for prev outbounds and fragment
|
||||||
|
|
||||||
|
// Cache for chain proxies to avoid duplicate generation
|
||||||
|
var nextProxyCache = new Dictionary<string, Outbounds4Ray?>();
|
||||||
|
var prevProxyTags = new Dictionary<string, string?>(); // Map from profile name to tag
|
||||||
|
int prevIndex = 0; // Index for prev outbounds
|
||||||
|
|
||||||
|
// Process nodes
|
||||||
|
int index = 0;
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
|
||||||
|
// Handle proxy chain
|
||||||
|
string? prevTag = null;
|
||||||
|
var currentOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
var nextOutbound = nextProxyCache.GetValueOrDefault(node.Subid, null);
|
||||||
|
if (nextOutbound != null)
|
||||||
|
{
|
||||||
|
nextOutbound = JsonUtils.DeepCopy(nextOutbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
|
||||||
|
|
||||||
|
// current proxy
|
||||||
|
await GenOutbound(node, currentOutbound);
|
||||||
|
currentOutbound.tag = $"{Global.ProxyTag}-{index}";
|
||||||
|
|
||||||
|
if (!node.Subid.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
if (prevProxyTags.TryGetValue(node.Subid, out var value))
|
||||||
|
{
|
||||||
|
prevTag = value; // maybe null
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
||||||
|
if (prevNode is not null
|
||||||
|
&& prevNode.ConfigType != EConfigType.Custom
|
||||||
|
&& prevNode.ConfigType != EConfigType.Hysteria2
|
||||||
|
&& prevNode.ConfigType != EConfigType.TUIC
|
||||||
|
&& prevNode.ConfigType != EConfigType.Anytls)
|
||||||
|
{
|
||||||
|
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
|
prevTag = $"prev-{Global.ProxyTag}-{++prevIndex}";
|
||||||
|
prevOutbound.tag = prevTag;
|
||||||
|
prevOutbounds.Add(prevOutbound);
|
||||||
|
}
|
||||||
|
prevProxyTags[node.Subid] = prevTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag, nextOutbound);
|
||||||
|
if (!nextProxyCache.ContainsKey(node.Subid))
|
||||||
|
{
|
||||||
|
nextProxyCache[node.Subid] = nextOutbound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextOutbound is not null)
|
||||||
|
{
|
||||||
|
resultOutbounds.Add(nextOutbound);
|
||||||
|
}
|
||||||
|
resultOutbounds.Add(currentOutbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge results: first the main chain outbounds, then other outbounds, and finally utility outbounds
|
||||||
|
resultOutbounds.AddRange(prevOutbounds);
|
||||||
|
resultOutbounds.AddRange(v2rayConfig.outbounds);
|
||||||
|
v2rayConfig.outbounds = resultOutbounds;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a chained outbound configuration for the given subItem and outbound.
|
||||||
|
/// The outbound's tag must be set before calling this method.
|
||||||
|
/// Returns the next proxy's outbound configuration, which may be null if no next proxy exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="subItem">The subscription item containing proxy chain information.</param>
|
||||||
|
/// <param name="outbound">The current outbound configuration. Its tag must be set before calling this method.</param>
|
||||||
|
/// <param name="prevOutboundTag">The tag of the previous outbound in the chain, if any.</param>
|
||||||
|
/// <param name="nextOutbound">The outbound for the next proxy in the chain, if already created. If null, will be created inside.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The outbound configuration for the next proxy in the chain, or null if no next proxy exists.
|
||||||
|
/// </returns>
|
||||||
|
private async Task<Outbounds4Ray?> GenChainOutbounds(SubItem subItem, Outbounds4Ray outbound, string? prevOutboundTag, Outbounds4Ray? nextOutbound = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
|
||||||
|
if (!prevOutboundTag.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
outbound.streamSettings.sockopt = new()
|
||||||
|
{
|
||||||
|
dialerProxy = prevOutboundTag
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next proxy
|
||||||
|
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
||||||
|
if (nextNode is not null
|
||||||
|
&& nextNode.ConfigType != EConfigType.Custom
|
||||||
|
&& nextNode.ConfigType != EConfigType.Hysteria2
|
||||||
|
&& nextNode.ConfigType != EConfigType.TUIC
|
||||||
|
&& nextNode.ConfigType != EConfigType.Anytls)
|
||||||
|
{
|
||||||
|
if (nextOutbound == null)
|
||||||
|
{
|
||||||
|
nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
|
}
|
||||||
|
nextOutbound.tag = outbound.tag;
|
||||||
|
|
||||||
|
outbound.tag = $"mid-{outbound.tag}";
|
||||||
|
nextOutbound.streamSettings.sockopt = new()
|
||||||
|
{
|
||||||
|
dialerProxy = outbound.tag
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return nextOutbound;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
||||||
{
|
{
|
||||||
if (multipleLoad is EMultipleLoad.LeastLoad or EMultipleLoad.LeastPing)
|
if (multipleLoad == EMultipleLoad.LeastPing)
|
||||||
{
|
{
|
||||||
var observatory = new Observatory4Ray
|
var observatory = new Observatory4Ray
|
||||||
{
|
{
|
||||||
subjectSelector = [Global.ProxyTag],
|
subjectSelector = [Global.ProxyTag],
|
||||||
probeUrl = AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
probeUrl = AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
||||||
probeInterval = "3m"
|
probeInterval = "3m",
|
||||||
|
enableConcurrency = true,
|
||||||
};
|
};
|
||||||
v2rayConfig.observatory = observatory;
|
v2rayConfig.observatory = observatory;
|
||||||
}
|
}
|
||||||
|
else if (multipleLoad == EMultipleLoad.LeastLoad)
|
||||||
|
{
|
||||||
|
var burstObservatory = new BurstObservatory4Ray
|
||||||
|
{
|
||||||
|
subjectSelector = [Global.ProxyTag],
|
||||||
|
pingConfig = new()
|
||||||
|
{
|
||||||
|
destination = AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
||||||
|
interval = "5m",
|
||||||
|
timeout = "30s",
|
||||||
|
sampling = 2,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
v2rayConfig.burstObservatory = burstObservatory;
|
||||||
|
}
|
||||||
var strategyType = multipleLoad switch
|
var strategyType = multipleLoad switch
|
||||||
{
|
{
|
||||||
EMultipleLoad.Random => "random",
|
EMultipleLoad.Random => "random",
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ public class SpeedtestService
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
var downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
|
|
||||||
@@ -255,9 +256,13 @@ public class SpeedtestService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
||||||
if (pid > 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
var delay = await DoRealPing(downloadHandle, it);
|
var delay = await DoRealPing(downloadHandle, it);
|
||||||
if (blSpeedTest)
|
if (blSpeedTest)
|
||||||
{
|
{
|
||||||
@@ -271,10 +276,6 @@ public class SpeedtestService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -357,8 +358,8 @@ public class SpeedtestService
|
|||||||
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
|
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
|
||||||
{
|
{
|
||||||
List<List<ServerTestItem>> lstTest = new();
|
List<List<ServerTestItem>> lstTest = new();
|
||||||
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList();
|
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls)).ToList();
|
||||||
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList();
|
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls).ToList();
|
||||||
|
|
||||||
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
|
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -194,11 +194,11 @@ public class UpdateService
|
|||||||
{
|
{
|
||||||
if (Utils.IsBase64String(result2))
|
if (Utils.IsBase64String(result2))
|
||||||
{
|
{
|
||||||
result += Utils.Base64Decode(result2);
|
result += Environment.NewLine + Utils.Base64Decode(result2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result += result2;
|
result += Environment.NewLine + result2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,21 +243,6 @@ public class UpdateService
|
|||||||
_updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
|
_updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> RunAvailabilityCheck()
|
|
||||||
{
|
|
||||||
var downloadHandle = new DownloadService();
|
|
||||||
var time = await downloadHandle.RunAvailabilityCheck(null);
|
|
||||||
var ip = Global.None;
|
|
||||||
if (time > 0)
|
|
||||||
{
|
|
||||||
var result = await downloadHandle.TryDownloadString(Global.IPAPIUrl, true, Global.IPAPIUrl);
|
|
||||||
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
|
|
||||||
ip = $"({ipInfo?.country_code}) {ipInfo?.ip}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Format(ResUI.TestMeOutput, time, ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region CheckUpdate private
|
#region CheckUpdate private
|
||||||
|
|
||||||
private async Task<RetResult> CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease)
|
private async Task<RetResult> CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease)
|
||||||
@@ -500,6 +485,12 @@ public class UpdateService
|
|||||||
|
|
||||||
private async Task UpdateOtherFiles(Config config, Action<bool, string> updateFunc)
|
private async Task UpdateOtherFiles(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
|
//If it is not in China area, no update is required
|
||||||
|
if (config.ConstItem.GeoSourceUrl.IsNotEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_updateFunc = updateFunc;
|
_updateFunc = updateFunc;
|
||||||
|
|
||||||
foreach (var url in Global.OtherGeoUrls)
|
foreach (var url in Global.OtherGeoUrls)
|
||||||
@@ -545,6 +536,11 @@ public class UpdateService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//append dns items TODO
|
||||||
|
geoSiteFiles.Add("cn");
|
||||||
|
geoSiteFiles.Add("geolocation-cn");
|
||||||
|
geoSiteFiles.Add("category-ads-all");
|
||||||
|
|
||||||
var path = Utils.GetBinPath("srss");
|
var path = Utils.GetBinPath("srss");
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -174,6 +174,11 @@ public class ClashProxiesViewModel : MyReactiveObject
|
|||||||
|
|
||||||
public void RefreshProxyGroups()
|
public void RefreshProxyGroups()
|
||||||
{
|
{
|
||||||
|
if (_proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var selectedName = SelectedGroup?.Name;
|
var selectedName = SelectedGroup?.Name;
|
||||||
_proxyGroups.Clear();
|
_proxyGroups.Clear();
|
||||||
|
|
||||||
@@ -297,8 +302,10 @@ public class ClashProxiesViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private ProxiesItem? TryGetProxy(string name)
|
private ProxiesItem? TryGetProxy(string name)
|
||||||
{
|
{
|
||||||
if (_proxies is null)
|
if (_proxies == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
_proxies.TryGetValue(name, out var proxy2);
|
_proxies.TryGetValue(name, out var proxy2);
|
||||||
if (proxy2 != null)
|
if (proxy2 != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,39 +6,52 @@ namespace ServiceLib.ViewModels;
|
|||||||
|
|
||||||
public class DNSSettingViewModel : MyReactiveObject
|
public class DNSSettingViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
[Reactive] public bool UseSystemHosts { get; set; }
|
[Reactive] public bool? UseSystemHosts { get; set; }
|
||||||
[Reactive] public string DomainStrategy4Freedom { get; set; }
|
[Reactive] public bool? AddCommonHosts { get; set; }
|
||||||
[Reactive] public string DomainDNSAddress { get; set; }
|
[Reactive] public bool? FakeIP { get; set; }
|
||||||
[Reactive] public string NormalDNS { get; set; }
|
[Reactive] public bool? BlockBindingQuery { get; set; }
|
||||||
|
[Reactive] public string? DirectDNS { get; set; }
|
||||||
|
[Reactive] public string? RemoteDNS { get; set; }
|
||||||
|
[Reactive] public string? SingboxOutboundsResolveDNS { get; set; }
|
||||||
|
[Reactive] public string? SingboxFinalResolveDNS { get; set; }
|
||||||
|
[Reactive] public string? RayStrategy4Freedom { get; set; }
|
||||||
|
[Reactive] public string? SingboxStrategy4Direct { get; set; }
|
||||||
|
[Reactive] public string? SingboxStrategy4Proxy { get; set; }
|
||||||
|
[Reactive] public string? Hosts { get; set; }
|
||||||
|
[Reactive] public string? DirectExpectedIPs { get; set; }
|
||||||
|
|
||||||
[Reactive] public string DomainStrategy4Freedom2 { get; set; }
|
[Reactive] public bool UseSystemHostsCompatible { get; set; }
|
||||||
[Reactive] public string DomainDNSAddress2 { get; set; }
|
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; }
|
||||||
[Reactive] public string NormalDNS2 { get; set; }
|
[Reactive] public string DomainDNSAddressCompatible { get; set; }
|
||||||
[Reactive] public string TunDNS2 { get; set; }
|
[Reactive] public string NormalDNSCompatible { get; set; }
|
||||||
|
|
||||||
|
[Reactive] public string DomainStrategy4Freedom2Compatible { get; set; }
|
||||||
|
[Reactive] public string DomainDNSAddress2Compatible { get; set; }
|
||||||
|
[Reactive] public string NormalDNS2Compatible { get; set; }
|
||||||
|
[Reactive] public string TunDNS2Compatible { get; set; }
|
||||||
|
[Reactive] public bool RayCustomDNSEnableCompatible { get; set; }
|
||||||
|
[Reactive] public bool SBCustomDNSEnableCompatible { get; set; }
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; }
|
public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCompatibleCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ImportDefConfig4SingboxCmd { get; }
|
public ReactiveCommand<Unit, Unit> ImportDefConfig4SingboxCompatibleCmd { get; }
|
||||||
|
|
||||||
public DNSSettingViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
public DNSSettingViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
||||||
{
|
{
|
||||||
_config = AppHandler.Instance.Config;
|
_config = AppHandler.Instance.Config;
|
||||||
_updateView = updateView;
|
_updateView = updateView;
|
||||||
SaveCmd = ReactiveCommand.CreateFromTask(async () =>
|
SaveCmd = ReactiveCommand.CreateFromTask(SaveSettingAsync);
|
||||||
{
|
|
||||||
await SaveSettingAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () =>
|
ImportDefConfig4V2rayCompatibleCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
NormalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
|
NormalDNSCompatible = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () =>
|
ImportDefConfig4SingboxCompatibleCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
NormalDNS2 = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName);
|
NormalDNS2Compatible = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName);
|
||||||
TunDNS2 = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName);
|
TunDNS2Compatible = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName);
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -47,48 +60,80 @@ public class DNSSettingViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private async Task Init()
|
private async Task Init()
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
|
_config = AppHandler.Instance.Config;
|
||||||
|
var item = _config.SimpleDNSItem;
|
||||||
UseSystemHosts = item.UseSystemHosts;
|
UseSystemHosts = item.UseSystemHosts;
|
||||||
DomainStrategy4Freedom = item?.DomainStrategy4Freedom ?? string.Empty;
|
AddCommonHosts = item.AddCommonHosts;
|
||||||
DomainDNSAddress = item?.DomainDNSAddress ?? string.Empty;
|
FakeIP = item.FakeIP;
|
||||||
NormalDNS = item?.NormalDNS ?? string.Empty;
|
BlockBindingQuery = item.BlockBindingQuery;
|
||||||
|
DirectDNS = item.DirectDNS;
|
||||||
|
RemoteDNS = item.RemoteDNS;
|
||||||
|
RayStrategy4Freedom = item.RayStrategy4Freedom;
|
||||||
|
SingboxOutboundsResolveDNS = item.SingboxOutboundsResolveDNS;
|
||||||
|
SingboxFinalResolveDNS = item.SingboxFinalResolveDNS;
|
||||||
|
SingboxStrategy4Direct = item.SingboxStrategy4Direct;
|
||||||
|
SingboxStrategy4Proxy = item.SingboxStrategy4Proxy;
|
||||||
|
Hosts = item.Hosts;
|
||||||
|
DirectExpectedIPs = item.DirectExpectedIPs;
|
||||||
|
|
||||||
|
var item1 = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
|
RayCustomDNSEnableCompatible = item1.Enabled;
|
||||||
|
UseSystemHostsCompatible = item1.UseSystemHosts;
|
||||||
|
DomainStrategy4FreedomCompatible = item1?.DomainStrategy4Freedom ?? string.Empty;
|
||||||
|
DomainDNSAddressCompatible = item1?.DomainDNSAddress ?? string.Empty;
|
||||||
|
NormalDNSCompatible = item1?.NormalDNS ?? string.Empty;
|
||||||
|
|
||||||
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
|
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
|
||||||
DomainStrategy4Freedom2 = item2?.DomainStrategy4Freedom ?? string.Empty;
|
SBCustomDNSEnableCompatible = item2.Enabled;
|
||||||
DomainDNSAddress2 = item2?.DomainDNSAddress ?? string.Empty;
|
DomainStrategy4Freedom2Compatible = item2?.DomainStrategy4Freedom ?? string.Empty;
|
||||||
NormalDNS2 = item2?.NormalDNS ?? string.Empty;
|
DomainDNSAddress2Compatible = item2?.DomainDNSAddress ?? string.Empty;
|
||||||
TunDNS2 = item2?.TunDNS ?? string.Empty;
|
NormalDNS2Compatible = item2?.NormalDNS ?? string.Empty;
|
||||||
|
TunDNS2Compatible = item2?.TunDNS ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveSettingAsync()
|
private async Task SaveSettingAsync()
|
||||||
{
|
{
|
||||||
if (NormalDNS.IsNotEmpty())
|
_config.SimpleDNSItem.UseSystemHosts = UseSystemHosts;
|
||||||
|
_config.SimpleDNSItem.AddCommonHosts = AddCommonHosts;
|
||||||
|
_config.SimpleDNSItem.FakeIP = FakeIP;
|
||||||
|
_config.SimpleDNSItem.BlockBindingQuery = BlockBindingQuery;
|
||||||
|
_config.SimpleDNSItem.DirectDNS = DirectDNS;
|
||||||
|
_config.SimpleDNSItem.RemoteDNS = RemoteDNS;
|
||||||
|
_config.SimpleDNSItem.RayStrategy4Freedom = RayStrategy4Freedom;
|
||||||
|
_config.SimpleDNSItem.SingboxOutboundsResolveDNS = SingboxOutboundsResolveDNS;
|
||||||
|
_config.SimpleDNSItem.SingboxFinalResolveDNS = SingboxFinalResolveDNS;
|
||||||
|
_config.SimpleDNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct;
|
||||||
|
_config.SimpleDNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy;
|
||||||
|
_config.SimpleDNSItem.Hosts = Hosts;
|
||||||
|
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
|
||||||
|
|
||||||
|
if (NormalDNSCompatible.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var obj = JsonUtils.ParseJson(NormalDNS);
|
var obj = JsonUtils.ParseJson(NormalDNSCompatible);
|
||||||
if (obj != null && obj["servers"] != null)
|
if (obj != null && obj["servers"] != null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (NormalDNS.Contains('{') || NormalDNS.Contains('}'))
|
if (NormalDNSCompatible.Contains('{') || NormalDNSCompatible.Contains('}'))
|
||||||
{
|
{
|
||||||
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
|
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (NormalDNS2.IsNotEmpty())
|
if (NormalDNS2Compatible.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(NormalDNS2);
|
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(NormalDNS2Compatible);
|
||||||
if (obj2 == null)
|
if (obj2 == null)
|
||||||
{
|
{
|
||||||
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
|
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (TunDNS2.IsNotEmpty())
|
if (TunDNS2Compatible.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(TunDNS2);
|
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(TunDNS2Compatible);
|
||||||
if (obj2 == null)
|
if (obj2 == null)
|
||||||
{
|
{
|
||||||
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
|
NoticeHandler.Instance.Enqueue(ResUI.FillCorrectDNSText);
|
||||||
@@ -96,21 +141,26 @@ public class DNSSettingViewModel : MyReactiveObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
|
var item1 = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
item.DomainStrategy4Freedom = DomainStrategy4Freedom;
|
item1.Enabled = RayCustomDNSEnableCompatible;
|
||||||
item.DomainDNSAddress = DomainDNSAddress;
|
item1.DomainStrategy4Freedom = DomainStrategy4FreedomCompatible;
|
||||||
item.UseSystemHosts = UseSystemHosts;
|
item1.DomainDNSAddress = DomainDNSAddressCompatible;
|
||||||
item.NormalDNS = NormalDNS;
|
item1.UseSystemHosts = UseSystemHostsCompatible;
|
||||||
await ConfigHandler.SaveDNSItems(_config, item);
|
item1.NormalDNS = NormalDNSCompatible;
|
||||||
|
await ConfigHandler.SaveDNSItems(_config, item1);
|
||||||
|
|
||||||
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
|
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
|
||||||
item2.DomainStrategy4Freedom = DomainStrategy4Freedom2;
|
item2.Enabled = RayCustomDNSEnableCompatible;
|
||||||
item2.DomainDNSAddress = DomainDNSAddress2;
|
item2.DomainStrategy4Freedom = DomainStrategy4Freedom2Compatible;
|
||||||
item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(NormalDNS2));
|
item2.DomainDNSAddress = DomainDNSAddress2Compatible;
|
||||||
item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(TunDNS2));
|
item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(NormalDNS2Compatible));
|
||||||
|
item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(TunDNS2Compatible));
|
||||||
await ConfigHandler.SaveDNSItems(_config, item2);
|
await ConfigHandler.SaveDNSItems(_config, item2);
|
||||||
|
|
||||||
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
|
await ConfigHandler.SaveConfig(_config);
|
||||||
_ = _updateView?.Invoke(EViewAction.CloseWindow, null);
|
if (_updateView != null)
|
||||||
|
{
|
||||||
|
await _updateView(EViewAction.CloseWindow, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
public ReactiveCommand<Unit, Unit> AddHysteria2ServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddHysteria2ServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddTuicServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddTuicServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
|
||||||
@@ -111,6 +112,10 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
await AddServerAsync(true, EConfigType.WireGuard);
|
await AddServerAsync(true, EConfigType.WireGuard);
|
||||||
});
|
});
|
||||||
|
AddAnytlsServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await AddServerAsync(true, EConfigType.Anytls);
|
||||||
|
});
|
||||||
AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
await AddServerAsync(true, EConfigType.Custom);
|
await AddServerAsync(true, EConfigType.Custom);
|
||||||
@@ -548,8 +553,12 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
|
|
||||||
BlReloadEnabled = false;
|
BlReloadEnabled = false;
|
||||||
|
|
||||||
await LoadCore();
|
await Task.Run(async () =>
|
||||||
await SysProxyHandler.UpdateSysProxy(_config, false);
|
{
|
||||||
|
await LoadCore();
|
||||||
|
await SysProxyHandler.UpdateSysProxy(_config, false);
|
||||||
|
await Task.Delay(1000);
|
||||||
|
});
|
||||||
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
||||||
|
|
||||||
_updateView?.Invoke(EViewAction.DispatcherReload, null);
|
_updateView?.Invoke(EViewAction.DispatcherReload, null);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
[Reactive] public string GeoFileSourceUrl { get; set; }
|
[Reactive] public string GeoFileSourceUrl { get; set; }
|
||||||
[Reactive] public string SrsFileSourceUrl { get; set; }
|
[Reactive] public string SrsFileSourceUrl { get; set; }
|
||||||
[Reactive] public string RoutingRulesSourceUrl { get; set; }
|
[Reactive] public string RoutingRulesSourceUrl { get; set; }
|
||||||
|
[Reactive] public string IPAPIUrl { get; set; }
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
@@ -88,7 +89,6 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
[Reactive] public int TunMtu { get; set; }
|
[Reactive] public int TunMtu { get; set; }
|
||||||
[Reactive] public bool TunEnableExInbound { get; set; }
|
[Reactive] public bool TunEnableExInbound { get; set; }
|
||||||
[Reactive] public bool TunEnableIPv6Address { get; set; }
|
[Reactive] public bool TunEnableIPv6Address { get; set; }
|
||||||
[Reactive] public string TunLinuxSudoPassword { get; set; }
|
|
||||||
|
|
||||||
#endregion Tun mode
|
#endregion Tun mode
|
||||||
|
|
||||||
@@ -187,6 +187,7 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
GeoFileSourceUrl = _config.ConstItem.GeoSourceUrl;
|
GeoFileSourceUrl = _config.ConstItem.GeoSourceUrl;
|
||||||
SrsFileSourceUrl = _config.ConstItem.SrsSourceUrl;
|
SrsFileSourceUrl = _config.ConstItem.SrsSourceUrl;
|
||||||
RoutingRulesSourceUrl = _config.ConstItem.RouteRulesTemplateSourceUrl;
|
RoutingRulesSourceUrl = _config.ConstItem.RouteRulesTemplateSourceUrl;
|
||||||
|
IPAPIUrl = _config.SpeedTestItem.IPAPIUrl;
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
@@ -205,7 +206,6 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
TunMtu = _config.TunModeItem.Mtu;
|
TunMtu = _config.TunModeItem.Mtu;
|
||||||
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
|
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
|
||||||
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
|
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
|
||||||
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
|
|
||||||
|
|
||||||
#endregion Tun mode
|
#endregion Tun mode
|
||||||
|
|
||||||
@@ -346,6 +346,7 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
_config.ConstItem.GeoSourceUrl = GeoFileSourceUrl;
|
_config.ConstItem.GeoSourceUrl = GeoFileSourceUrl;
|
||||||
_config.ConstItem.SrsSourceUrl = SrsFileSourceUrl;
|
_config.ConstItem.SrsSourceUrl = SrsFileSourceUrl;
|
||||||
_config.ConstItem.RouteRulesTemplateSourceUrl = RoutingRulesSourceUrl;
|
_config.ConstItem.RouteRulesTemplateSourceUrl = RoutingRulesSourceUrl;
|
||||||
|
_config.SpeedTestItem.IPAPIUrl = IPAPIUrl;
|
||||||
|
|
||||||
//systemProxy
|
//systemProxy
|
||||||
_config.SystemProxyItem.SystemProxyExceptions = systemProxyExceptions;
|
_config.SystemProxyItem.SystemProxyExceptions = systemProxyExceptions;
|
||||||
@@ -358,10 +359,6 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
_config.TunModeItem.Mtu = TunMtu;
|
_config.TunModeItem.Mtu = TunMtu;
|
||||||
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
|
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
|
||||||
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
|
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
|
||||||
if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
|
|
||||||
{
|
|
||||||
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
//coreType
|
//coreType
|
||||||
await SaveCoreType();
|
await SaveCoreType();
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
item.SpeedVal = result.Speed ?? string.Empty;
|
item.SpeedVal = result.Speed ?? string.Empty;
|
||||||
}
|
}
|
||||||
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
//_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateStatistics(ServerSpeedItem update)
|
public void UpdateStatistics(ServerSpeedItem update)
|
||||||
@@ -319,16 +319,16 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
item.TotalDown = Utils.HumanFy(update.TotalDown);
|
item.TotalDown = Utils.HumanFy(update.TotalDown);
|
||||||
item.TotalUp = Utils.HumanFy(update.TotalUp);
|
item.TotalUp = Utils.HumanFy(update.TotalUp);
|
||||||
|
|
||||||
if (SelectedProfile?.IndexId == item.IndexId)
|
//if (SelectedProfile?.IndexId == item.IndexId)
|
||||||
{
|
//{
|
||||||
var temp = JsonUtils.DeepCopy(item);
|
// var temp = JsonUtils.DeepCopy(item);
|
||||||
_profileItems.Replace(item, temp);
|
// _profileItems.Replace(item, temp);
|
||||||
SelectedProfile = temp;
|
// SelectedProfile = temp;
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
// _profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -91,11 +91,9 @@ public class RoutingSettingViewModel : MyReactiveObject
|
|||||||
var routings = await AppHandler.Instance.RoutingItems();
|
var routings = await AppHandler.Instance.RoutingItems();
|
||||||
foreach (var item in routings)
|
foreach (var item in routings)
|
||||||
{
|
{
|
||||||
var def = item.Id == _config.RoutingBasicItem.RoutingIndexId;
|
|
||||||
|
|
||||||
var it = new RoutingItemModel()
|
var it = new RoutingItemModel()
|
||||||
{
|
{
|
||||||
IsActive = def,
|
IsActive = item.IsActive,
|
||||||
RuleNum = item.RuleNum,
|
RuleNum = item.RuleNum,
|
||||||
Id = item.Id,
|
Id = item.Id,
|
||||||
Remarks = item.Remarks,
|
Remarks = item.Remarks,
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
public ReactiveCommand<Unit, Unit> SubUpdateViaProxyCmd { get; }
|
public ReactiveCommand<Unit, Unit> SubUpdateViaProxyCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> CopyProxyCmdToClipboardCmd { get; }
|
public ReactiveCommand<Unit, Unit> CopyProxyCmdToClipboardCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; }
|
public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ShowWindowCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> HideWindowCmd { get; }
|
||||||
|
|
||||||
#region System Proxy
|
#region System Proxy
|
||||||
|
|
||||||
@@ -91,6 +93,9 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
[Reactive]
|
[Reactive]
|
||||||
public bool EnableTun { get; set; }
|
public bool EnableTun { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool BlIsNonWindows { get; set; }
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
public StatusBarViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
public StatusBarViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
||||||
@@ -100,6 +105,7 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
SelectedServer = new();
|
SelectedServer = new();
|
||||||
RunningServerToolTipText = "-";
|
RunningServerToolTipText = "-";
|
||||||
BlSystemProxyPacVisible = Utils.IsWindows();
|
BlSystemProxyPacVisible = Utils.IsWindows();
|
||||||
|
BlIsNonWindows = Utils.IsNonWindows();
|
||||||
|
|
||||||
if (_config.TunModeItem.EnableTun && AllowEnableTun())
|
if (_config.TunModeItem.EnableTun && AllowEnableTun())
|
||||||
{
|
{
|
||||||
@@ -143,11 +149,21 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(null);
|
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(null);
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
ShowWindowCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(true);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
});
|
||||||
|
HideWindowCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(false);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
await AddServerViaClipboard();
|
await AddServerViaClipboard();
|
||||||
});
|
});
|
||||||
AddServerViaScanCmd = ReactiveCommand.CreateFromTask(async () =>
|
AddServerViaScanCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
await AddServerViaScan();
|
await AddServerViaScan();
|
||||||
@@ -318,7 +334,10 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
|
|
||||||
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
|
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
|
||||||
|
|
||||||
var msg = await (new UpdateService()).RunAvailabilityCheck();
|
var msg = await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
return await ConnectionHandler.Instance.RunAvailabilityCheck();
|
||||||
|
});
|
||||||
|
|
||||||
NoticeHandler.Instance.SendMessageEx(msg);
|
NoticeHandler.Instance.SendMessageEx(msg);
|
||||||
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
|
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
|
||||||
@@ -369,7 +388,7 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
foreach (var item in routings)
|
foreach (var item in routings)
|
||||||
{
|
{
|
||||||
_routingItems.Add(item);
|
_routingItems.Add(item);
|
||||||
if (item.Id == _config.RoutingBasicItem.RoutingIndexId)
|
if (item.IsActive)
|
||||||
{
|
{
|
||||||
SelectedRouting = item;
|
SelectedRouting = item;
|
||||||
}
|
}
|
||||||
@@ -393,10 +412,6 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_config.RoutingBasicItem.RoutingIndexId == item.Id)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
|
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
|
||||||
{
|
{
|
||||||
@@ -421,43 +436,49 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private async Task DoEnableTun(bool c)
|
private async Task DoEnableTun(bool c)
|
||||||
{
|
{
|
||||||
if (_config.TunModeItem.EnableTun != EnableTun)
|
if (_config.TunModeItem.EnableTun == EnableTun)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_config.TunModeItem.EnableTun = EnableTun;
|
||||||
|
|
||||||
|
if (EnableTun && AllowEnableTun() == false)
|
||||||
{
|
{
|
||||||
_config.TunModeItem.EnableTun = EnableTun;
|
|
||||||
// When running as a non-administrator, reboot to administrator mode
|
// When running as a non-administrator, reboot to administrator mode
|
||||||
if (EnableTun && AllowEnableTun() == false)
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
_config.TunModeItem.EnableTun = false;
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool? passwordResult = await _updateView?.Invoke(EViewAction.PasswordInput, null);
|
||||||
|
if (passwordResult == false)
|
||||||
{
|
{
|
||||||
_config.TunModeItem.EnableTun = false;
|
_config.TunModeItem.EnableTun = false;
|
||||||
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (Utils.IsOSX())
|
|
||||||
{
|
|
||||||
_config.TunModeItem.EnableTun = false;
|
|
||||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await ConfigHandler.SaveConfig(_config);
|
|
||||||
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
|
||||||
}
|
}
|
||||||
|
await ConfigHandler.SaveConfig(_config);
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AllowEnableTun()
|
private bool AllowEnableTun()
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
return AppHandler.Instance.IsAdministrator;
|
return Utils.IsAdministrator();
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
else if (Utils.IsLinux())
|
||||||
{
|
{
|
||||||
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
|
return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
|
||||||
}
|
}
|
||||||
else if (Utils.IsOSX())
|
else if (Utils.IsOSX())
|
||||||
{
|
{
|
||||||
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
|
return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -495,8 +516,16 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.ProxyTag, Utils.HumanFy(update.ProxyUp), Utils.HumanFy(update.ProxyDown));
|
if (_config.IsRunningCore(ECoreType.sing_box))
|
||||||
SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.DirectTag, Utils.HumanFy(update.DirectUp), Utils.HumanFy(update.DirectDown));
|
{
|
||||||
|
SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, EInboundProtocol.mixed, Utils.HumanFy(update.ProxyUp), Utils.HumanFy(update.ProxyDown));
|
||||||
|
SpeedDirectDisplay = string.Empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.ProxyTag, Utils.HumanFy(update.ProxyUp), Utils.HumanFy(update.ProxyDown));
|
||||||
|
SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.DirectTag, Utils.HumanFy(update.DirectUp), Utils.HumanFy(update.DirectDown));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
xmlns:semi="https://irihi.tech/semi"
|
xmlns:semi="https://irihi.tech/semi"
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
x:DataType="vms:StatusBarViewModel"
|
|
||||||
Name="v2rayN"
|
Name="v2rayN"
|
||||||
|
x:DataType="vms:StatusBarViewModel"
|
||||||
RequestedThemeVariant="Default">
|
RequestedThemeVariant="Default">
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<semi:SemiTheme />
|
<semi:SemiTheme />
|
||||||
@@ -32,6 +32,16 @@
|
|||||||
ToolTipText="{Binding RunningServerToolTipText}">
|
ToolTipText="{Binding RunningServerToolTipText}">
|
||||||
<TrayIcon.Menu>
|
<TrayIcon.Menu>
|
||||||
<NativeMenu>
|
<NativeMenu>
|
||||||
|
<NativeMenuItem
|
||||||
|
Command="{Binding ShowWindowCmd}"
|
||||||
|
Header="{x:Static resx:ResUI.TbDisplayGUI}"
|
||||||
|
IsVisible="{Binding BlIsNonWindows}" />
|
||||||
|
<NativeMenuItem
|
||||||
|
Command="{Binding NotifyLeftClickCmd}"
|
||||||
|
Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}"
|
||||||
|
IsVisible="{Binding BlIsNonWindows}" />
|
||||||
|
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
||||||
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem
|
<NativeMenuItem
|
||||||
Command="{Binding SystemProxyClearCmd}"
|
Command="{Binding SystemProxyClearCmd}"
|
||||||
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
||||||
@@ -55,13 +65,9 @@
|
|||||||
ToggleType="Radio" />
|
ToggleType="Radio" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
||||||
<NativeMenuItem Header="{x:Static resx:ResUI.menuAddServerViaScan}" IsVisible="False" />
|
|
||||||
<NativeMenuItem Command="{Binding SubUpdateCmd}" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
<NativeMenuItem Command="{Binding SubUpdateCmd}" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||||
<NativeMenuItem Command="{Binding SubUpdateViaProxyCmd}" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
<NativeMenuItem Command="{Binding SubUpdateViaProxyCmd}" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
|
||||||
<NativeMenuItemSeparator />
|
|
||||||
<NativeMenuItem Command="{Binding NotifyLeftClickCmd}" Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}" />
|
|
||||||
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
||||||
</NativeMenu>
|
</NativeMenu>
|
||||||
</TrayIcon.Menu>
|
</TrayIcon.Menu>
|
||||||
|
|||||||
@@ -11,11 +11,6 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
if (!AppHandler.Instance.InitApp())
|
|
||||||
{
|
|
||||||
Environment.Exit(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
@@ -43,7 +38,7 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
if (e.ExceptionObject != null)
|
if (e.ExceptionObject != null)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
|
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
v2rayN/v2rayN.Desktop/Base/WindowBase.cs
Normal file
52
v2rayN/v2rayN.Desktop/Base/WindowBase.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace v2rayN.Desktop.Base;
|
||||||
|
|
||||||
|
public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewModel : class
|
||||||
|
{
|
||||||
|
public WindowBase()
|
||||||
|
{
|
||||||
|
Loaded += OnLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReactiveWindowBase_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sizeItem = ConfigHandler.GetWindowSizeItem(AppHandler.Instance.Config, GetType().Name);
|
||||||
|
if (sizeItem == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Width = sizeItem.Width;
|
||||||
|
Height = sizeItem.Height;
|
||||||
|
|
||||||
|
var workingArea = (Screens.ScreenFromWindow(this) ?? Screens.Primary).WorkingArea;
|
||||||
|
var scaling = (Utils.IsOSX() ? null : VisualRoot?.RenderScaling) ?? 1.0;
|
||||||
|
|
||||||
|
var x = workingArea.X + ((workingArea.Width - (Width * scaling)) / 2);
|
||||||
|
var y = workingArea.Y + ((workingArea.Height - (Height * scaling)) / 2);
|
||||||
|
|
||||||
|
Position = new PixelPoint((int)x, (int)y);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClosed(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnClosed(e);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConfigHandler.SaveWindowSizeItem(AppHandler.Instance.Config, GetType().Name, Width, Height);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,13 +14,17 @@ internal class Program
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
OnStartup(args);
|
if (OnStartup(args) == false)
|
||||||
|
{
|
||||||
|
Environment.Exit(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BuildAvaloniaApp()
|
BuildAvaloniaApp()
|
||||||
.StartWithClassicDesktopLifetime(args);
|
.StartWithClassicDesktopLifetime(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnStartup(string[]? Args)
|
private static bool OnStartup(string[]? Args)
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
@@ -30,8 +34,7 @@ internal class Program
|
|||||||
if (!rebootas && !bCreatedNew)
|
if (!rebootas && !bCreatedNew)
|
||||||
{
|
{
|
||||||
ProgramStarted.Set();
|
ProgramStarted.Set();
|
||||||
Environment.Exit(0);
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -39,19 +42,26 @@ internal class Program
|
|||||||
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
||||||
if (!bOnlyOneInstance)
|
if (!bOnlyOneInstance)
|
||||||
{
|
{
|
||||||
Environment.Exit(0);
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!AppHandler.Instance.InitApp())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
||||||
=> AppBuilder.Configure<App>()
|
{
|
||||||
.UsePlatformDetect()
|
return AppBuilder.Configure<App>()
|
||||||
//.WithInterFont()
|
.UsePlatformDetect()
|
||||||
.WithFontByDefault()
|
//.WithInterFont()
|
||||||
.LogToTrace()
|
.WithFontByDefault()
|
||||||
.UseReactiveUI()
|
.LogToTrace()
|
||||||
.With(new MacOSPlatformOptions { ShowInDock = false });
|
.UseReactiveUI()
|
||||||
|
.With(new MacOSPlatformOptions { ShowInDock = AppHandler.Instance.Config.UiItem.MacOSShowInDock });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ public class ThemeSettingViewModel : MyReactiveObject
|
|||||||
x.OfType<Button>(),
|
x.OfType<Button>(),
|
||||||
x.OfType<TextBox>(),
|
x.OfType<TextBox>(),
|
||||||
x.OfType<TextBlock>(),
|
x.OfType<TextBlock>(),
|
||||||
|
x.OfType<SelectableTextBlock>(),
|
||||||
x.OfType<Menu>(),
|
x.OfType<Menu>(),
|
||||||
x.OfType<ContextMenu>(),
|
x.OfType<ContextMenu>(),
|
||||||
x.OfType<DataGridRow>(),
|
x.OfType<DataGridRow>(),
|
||||||
@@ -146,6 +147,7 @@ public class ThemeSettingViewModel : MyReactiveObject
|
|||||||
x.OfType<Button>(),
|
x.OfType<Button>(),
|
||||||
x.OfType<TextBox>(),
|
x.OfType<TextBox>(),
|
||||||
x.OfType<TextBlock>(),
|
x.OfType<TextBlock>(),
|
||||||
|
x.OfType<SelectableTextBlock>(),
|
||||||
x.OfType<Menu>(),
|
x.OfType<Menu>(),
|
||||||
x.OfType<ContextMenu>(),
|
x.OfType<ContextMenu>(),
|
||||||
x.OfType<DataGridRow>(),
|
x.OfType<DataGridRow>(),
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
public partial class AddServer2Window : WindowBase<AddServer2ViewModel>
|
||||||
{
|
{
|
||||||
public AddServer2Window()
|
public AddServer2Window()
|
||||||
{
|
{
|
||||||
@@ -21,13 +21,7 @@ public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
|||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
foreach (ECoreType it in Enum.GetValues(typeof(ECoreType)))
|
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
|
||||||
{
|
|
||||||
if (it == ECoreType.v2rayN)
|
|
||||||
continue;
|
|
||||||
cmbCoreType.Items.Add(it.ToString());
|
|
||||||
}
|
|
||||||
cmbCoreType.Items.Add(string.Empty);
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto,Auto"
|
ColumnDefinitions="180,Auto,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -152,13 +152,26 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSs"
|
x:Name="gridSs"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto"
|
ColumnDefinitions="180,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -185,6 +198,19 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled3"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSocks"
|
x:Name="gridSocks"
|
||||||
@@ -224,7 +250,7 @@
|
|||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto,Auto"
|
ColumnDefinitions="180,Auto,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -271,13 +297,26 @@
|
|||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled5"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridTrojan"
|
x:Name="gridTrojan"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto"
|
ColumnDefinitions="180,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -304,6 +343,19 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled6"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridHysteria2"
|
x:Name="gridHysteria2"
|
||||||
@@ -481,6 +533,26 @@
|
|||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Watermark="1500" />
|
Watermark="1500" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
x:Name="gridAnytls"
|
||||||
|
Grid.Row="2"
|
||||||
|
ColumnDefinitions="180,Auto"
|
||||||
|
IsVisible="False"
|
||||||
|
RowDefinitions="Auto,Auto,Auto">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbId3}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtId10"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<Separator
|
<Separator
|
||||||
x:Name="sepa2"
|
x:Name="sepa2"
|
||||||
@@ -701,7 +773,7 @@
|
|||||||
Grid.Row="7"
|
Grid.Row="7"
|
||||||
ColumnDefinitions="180,Auto"
|
ColumnDefinitions="180,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
@@ -771,6 +843,20 @@
|
|||||||
Width="400"
|
Width="400"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="5"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbMldsa65Verify}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtMldsa65Verify"
|
||||||
|
Grid.Row="5"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Separator Grid.Row="8" Margin="{StaticResource MarginTb8}" />
|
<Separator Grid.Row="8" Margin="{StaticResource MarginTb8}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
||||||
{
|
{
|
||||||
public AddServerWindow()
|
public AddServerWindow()
|
||||||
{
|
{
|
||||||
@@ -26,41 +26,22 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
|
|
||||||
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
Global.CoreTypes.ForEach(it =>
|
cmbCoreType.ItemsSource = Global.CoreTypes.AppendEmpty();
|
||||||
{
|
cmbNetwork.ItemsSource = Global.Networks;
|
||||||
cmbCoreType.Items.Add(it);
|
cmbFingerprint.ItemsSource = Global.Fingerprints;
|
||||||
});
|
cmbFingerprint2.ItemsSource = Global.Fingerprints;
|
||||||
cmbCoreType.Items.Add(string.Empty);
|
cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
|
||||||
|
cmbAlpn.ItemsSource = Global.Alpns;
|
||||||
|
|
||||||
cmbStreamSecurity.Items.Add(string.Empty);
|
var lstStreamSecurity = new List<string>();
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurity);
|
lstStreamSecurity.Add(string.Empty);
|
||||||
|
lstStreamSecurity.Add(Global.StreamSecurity);
|
||||||
Global.Networks.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbNetwork.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Fingerprints.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbFingerprint.Items.Add(it);
|
|
||||||
cmbFingerprint2.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.AllowInsecure.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbAllowInsecure.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Alpns.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbAlpn.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (profileItem.ConfigType)
|
switch (profileItem.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.VMess:
|
||||||
gridVMess.IsVisible = true;
|
gridVMess.IsVisible = true;
|
||||||
Global.VmessSecurities.ForEach(it =>
|
cmbSecurity.ItemsSource = Global.VmessSecurities;
|
||||||
{
|
|
||||||
cmbSecurity.Items.Add(it);
|
|
||||||
});
|
|
||||||
if (profileItem.Security.IsNullOrEmpty())
|
if (profileItem.Security.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Security = Global.DefaultSecurity;
|
profileItem.Security = Global.DefaultSecurity;
|
||||||
@@ -69,10 +50,7 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
|
|
||||||
case EConfigType.Shadowsocks:
|
case EConfigType.Shadowsocks:
|
||||||
gridSs.IsVisible = true;
|
gridSs.IsVisible = true;
|
||||||
AppHandler.Instance.GetShadowsocksSecurities(profileItem).ForEach(it =>
|
cmbSecurity3.ItemsSource = AppHandler.Instance.GetShadowsocksSecurities(profileItem);
|
||||||
{
|
|
||||||
cmbSecurity3.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
@@ -82,11 +60,8 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
|
|
||||||
case EConfigType.VLESS:
|
case EConfigType.VLESS:
|
||||||
gridVLESS.IsVisible = true;
|
gridVLESS.IsVisible = true;
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||||
Global.Flows.ForEach(it =>
|
cmbFlow5.ItemsSource = Global.Flows;
|
||||||
{
|
|
||||||
cmbFlow5.Items.Add(it);
|
|
||||||
});
|
|
||||||
if (profileItem.Security.IsNullOrEmpty())
|
if (profileItem.Security.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Security = Global.None;
|
profileItem.Security = Global.None;
|
||||||
@@ -95,11 +70,8 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
|
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
gridTrojan.IsVisible = true;
|
gridTrojan.IsVisible = true;
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||||
Global.Flows.ForEach(it =>
|
cmbFlow6.ItemsSource = Global.Flows;
|
||||||
{
|
|
||||||
cmbFlow6.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
@@ -119,10 +91,7 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
cmbFingerprint.IsEnabled = false;
|
cmbFingerprint.IsEnabled = false;
|
||||||
cmbFingerprint.SelectedValue = string.Empty;
|
cmbFingerprint.SelectedValue = string.Empty;
|
||||||
|
|
||||||
Global.TuicCongestionControls.ForEach(it =>
|
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls;
|
||||||
{
|
|
||||||
cmbHeaderType8.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.WireGuard:
|
case EConfigType.WireGuard:
|
||||||
@@ -133,7 +102,14 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
gridTls.IsVisible = false;
|
gridTls.IsVisible = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EConfigType.Anytls:
|
||||||
|
gridAnytls.IsVisible = true;
|
||||||
|
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||||
|
cmbCoreType.IsEnabled = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
|
||||||
|
|
||||||
gridTlsMore.IsVisible = false;
|
gridTlsMore.IsVisible = false;
|
||||||
|
|
||||||
@@ -150,11 +126,13 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Shadowsocks:
|
case EConfigType.Shadowsocks:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
@@ -167,11 +145,13 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled5.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled6.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
@@ -193,6 +173,10 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost9.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost9.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId9.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId9.Text).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EConfigType.Anytls:
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId10.Text).DisposeWith(disposables);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -211,6 +195,7 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.SelectedSource.PublicKey, v => v.txtPublicKey.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.PublicKey, v => v.txtPublicKey.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.SpiderX, v => v.txtSpiderX.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.SpiderX, v => v.txtSpiderX.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.Mldsa65Verify, v => v.txtMldsa65Verify.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
@@ -268,44 +253,41 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
|
|
||||||
private void SetHeaderType()
|
private void SetHeaderType()
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Clear();
|
var lstHeaderType = new List<string>();
|
||||||
|
|
||||||
var network = cmbNetwork.SelectedItem.ToString();
|
var network = cmbNetwork.SelectedItem.ToString();
|
||||||
if (network.IsNullOrEmpty())
|
if (network.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
|
cmbHeaderType.ItemsSource = lstHeaderType;
|
||||||
|
cmbHeaderType.SelectedIndex = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (network == nameof(ETransport.tcp))
|
if (network == nameof(ETransport.tcp))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
|
lstHeaderType.Add(Global.TcpHeaderHttp);
|
||||||
}
|
}
|
||||||
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
|
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
Global.KcpHeaderTypes.ForEach(it =>
|
lstHeaderType.AddRange(Global.KcpHeaderTypes);
|
||||||
{
|
|
||||||
cmbHeaderType.Items.Add(it);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (network is nameof(ETransport.xhttp))
|
else if (network is nameof(ETransport.xhttp))
|
||||||
{
|
{
|
||||||
Global.XhttpMode.ForEach(it =>
|
lstHeaderType.AddRange(Global.XhttpMode);
|
||||||
{
|
|
||||||
cmbHeaderType.Items.Add(it);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (network == nameof(ETransport.grpc))
|
else if (network == nameof(ETransport.grpc))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.GrpcGunMode);
|
lstHeaderType.Add(Global.GrpcGunMode);
|
||||||
cmbHeaderType.Items.Add(Global.GrpcMultiMode);
|
lstHeaderType.Add(Global.GrpcMultiMode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
}
|
}
|
||||||
|
cmbHeaderType.ItemsSource = lstHeaderType;
|
||||||
cmbHeaderType.SelectedIndex = 0;
|
cmbHeaderType.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,9 +52,16 @@ public partial class ClashConnectionsView : ReactiveUserControl<ClashConnections
|
|||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
foreach (var it in lstConnections.Columns)
|
try
|
||||||
{
|
{
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
foreach (var it in lstConnections.Columns)
|
||||||
|
{
|
||||||
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("ClashConnectionsView", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
x:Class="v2rayN.Desktop.Views.DNSSettingWindow"
|
x:Class="v2rayN.Desktop.Views.DNSSettingWindow"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ctrls="clr-namespace:v2rayN.Desktop.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
@@ -34,26 +35,300 @@
|
|||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TabControl HorizontalContentAlignment="Left">
|
<TabControl HorizontalContentAlignment="Stretch">
|
||||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
<TabItem Header="{x:Static resx:ResUI.ThBasicDNSSettings}">
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
<Grid
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
ColumnDefinitions="Auto,Auto,*"
|
||||||
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
x:Name="txtBasicDNSSettingsInvalid"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
|
Text="{x:Static resx:ResUI.TbCustomDNSEnabledPageInvalid}" />
|
||||||
|
|
||||||
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
|
<TextBlock
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click">
|
Grid.Row="1"
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
|
Grid.Column="0"
|
||||||
</HyperlinkButton>
|
|
||||||
</TextBlock>
|
|
||||||
<Button
|
|
||||||
x:Name="btnImportDefConfig4V2ray"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
VerticalAlignment="Center"
|
||||||
Cursor="Hand" />
|
Text="{x:Static resx:ResUI.TbDomesticDNS}" />
|
||||||
</StackPanel>
|
<ctrls:AutoCompleteBox
|
||||||
|
x:Name="cmbDirectDNS"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Text="{Binding DirectDNS, Mode=TwoWay}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbRemoteDNS}" />
|
||||||
|
<ctrls:AutoCompleteBox
|
||||||
|
x:Name="cmbRemoteDNS"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Text="{Binding RemoteDNS, Mode=TwoWay}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSBOutboundsResolverDNS}" />
|
||||||
|
<ctrls:AutoCompleteBox
|
||||||
|
x:Name="cmbSBResolverDNS"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Text="{Binding SingboxOutboundsResolveDNS, Mode=TwoWay}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSBDoHResolverServer}" />
|
||||||
|
<ctrls:AutoCompleteBox
|
||||||
|
x:Name="cmbSBFinalResolverDNS"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Text="{Binding SingboxFinalResolveDNS, Mode=TwoWay}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="5"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbXrayFreedomResolveStrategy}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbRayFreedomDNSStrategy"
|
||||||
|
Grid.Row="5"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
PlaceholderText="Default" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="6"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbSBDirectDNSStrategy"
|
||||||
|
Grid.Row="6"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
PlaceholderText="Default" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbSBRemoteDNSStrategy"
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
PlaceholderText="Default" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="8"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togAddCommonHosts"
|
||||||
|
Grid.Row="8"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="8"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSBDoHOverride}" />
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="{x:Static resx:ResUI.ThAdvancedDNSSettings}">
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||||
|
<Grid
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
ColumnDefinitions="Auto,Auto,*"
|
||||||
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,*">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
x:Name="txtAdvancedDNSSettingsInvalid"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbCustomDNSEnabledPageInvalid}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togUseSystemHosts"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togFakeIP"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbApplyProxyDomainsOnly}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togBlockBindingQuery"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
|
||||||
|
<ctrls:AutoCompleteBox
|
||||||
|
x:Name="cmbDirectExpectedIPs"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Text="{Binding DirectExpectedIPs, Mode=TwoWay}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="5"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbDNSHostsConfig}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtHosts"
|
||||||
|
Grid.Row="6"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
BorderThickness="1"
|
||||||
|
Classes="TextArea"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Watermark="{x:Static resx:ResUI.TbDNSHostsConfig}" />
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||||
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
|
<Grid DockPanel.Dock="Top">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbCustomDNSEnable}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togRayCustomDNSEnableCompatible"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
|
||||||
|
|
||||||
|
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
|
||||||
|
<HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</TextBlock>
|
||||||
|
<Button
|
||||||
|
x:Name="btnImportDefConfig4V2rayCompatible"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||||
|
Cursor="Hand" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
@@ -62,7 +337,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
|
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
x:Name="togUseSystemHosts"
|
x:Name="togUseSystemHostsCompatible"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -73,7 +348,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
|
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbdomainStrategy4Freedom"
|
x:Name="cmbdomainStrategy4FreedomCompatible"
|
||||||
Width="150"
|
Width="150"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -83,40 +358,61 @@
|
|||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbdomainDNSAddress"
|
x:Name="cmbdomainDNSAddressCompatible"
|
||||||
Width="150"
|
Width="150"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}"
|
||||||
|
Text="{Binding DomainDNSAddressCompatible, Mode=TwoWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin4}">
|
<HeaderedContentControl
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
BorderBrush="Gray"
|
||||||
|
BorderThickness="1"
|
||||||
|
Header="HTTP/SOCKS">
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtnormalDNS"
|
Name="txtnormalDNSCompatible"
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
BorderThickness="1"
|
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
TextWrapping="Wrap"
|
MinLines="10"
|
||||||
Watermark="HTTP/SOCKS" />
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</HeaderedContentControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}">
|
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}">
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
<Grid DockPanel.Dock="Top">
|
||||||
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
|
<Grid.RowDefinitions>
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkDnsSingboxObjectDoc_Click">
|
<RowDefinition Height="Auto" />
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
|
<RowDefinition Height="Auto" />
|
||||||
</HyperlinkButton>
|
</Grid.RowDefinitions>
|
||||||
</TextBlock>
|
|
||||||
<Button
|
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
||||||
x:Name="btnImportDefConfig4Singbox"
|
<TextBlock
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
VerticalAlignment="Center"
|
||||||
Cursor="Hand" />
|
Text="{x:Static resx:ResUI.TbCustomDNSEnable}" />
|
||||||
</StackPanel>
|
<ToggleSwitch
|
||||||
|
x:Name="togSBCustomDNSEnableCompatible"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal">
|
||||||
|
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
|
||||||
|
<HyperlinkButton Classes="WithIcon" Click="linkDnsSingboxObjectDoc_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</TextBlock>
|
||||||
|
<Button
|
||||||
|
x:Name="btnImportDefConfig4SingboxCompatible"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||||
|
Cursor="Hand" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
@@ -125,7 +421,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
|
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbdomainStrategy4Out"
|
x:Name="cmbdomainStrategy4OutCompatible"
|
||||||
Width="150"
|
Width="150"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -135,40 +431,44 @@
|
|||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbdomainDNSAddress2"
|
x:Name="cmbdomainDNSAddress2Compatible"
|
||||||
Width="150"
|
Width="150"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}"
|
||||||
|
Text="{Binding DomainDNSAddress2Compatible, Mode=TwoWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
||||||
|
|
||||||
<TextBox
|
<HeaderedContentControl
|
||||||
x:Name="txtnormalDNS2"
|
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="400"
|
BorderBrush="Gray"
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Header="HTTP/SOCKS">
|
||||||
Margin="{StaticResource Margin4}"
|
<TextBox
|
||||||
TextWrapping="Wrap"
|
Name="txtnormalDNS2Compatible"
|
||||||
Watermark="HTTP/SOCKS" />
|
VerticalAlignment="Stretch"
|
||||||
|
Classes="TextArea"
|
||||||
|
MinLines="10"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</HeaderedContentControl>
|
||||||
|
|
||||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||||
|
|
||||||
<TextBox
|
<HeaderedContentControl
|
||||||
x:Name="txttunDNS2"
|
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Width="400"
|
BorderBrush="Gray"
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Header="{x:Static resx:ResUI.TbSettingsTunMode}">
|
||||||
Margin="{StaticResource Margin4}"
|
<TextBox
|
||||||
TextWrapping="Wrap"
|
Name="txttunDNS2Compatible"
|
||||||
Watermark="{x:Static resx:ResUI.TbSettingsTunMode}" />
|
VerticalAlignment="Stretch"
|
||||||
|
Classes="TextArea"
|
||||||
|
MinLines="10"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</HeaderedContentControl>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
@@ -17,38 +18,64 @@ public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
|||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
Global.DomainStrategy4Freedoms.ForEach(it =>
|
cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms;
|
||||||
{
|
cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
|
||||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
|
||||||
});
|
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
||||||
Global.SingboxDomainStrategy4Out.ForEach(it =>
|
cmbSBResolverDNS.ItemsSource = Global.DomainDirectDNSAddress.Concat(new[] { "dhcp://auto,localhost" });
|
||||||
{
|
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||||
cmbdomainStrategy4Out.Items.Add(it);
|
cmbSBFinalResolverDNS.ItemsSource = Global.DomainPureIPDNSAddress.Concat(new[] { "dhcp://auto,localhost" });
|
||||||
});
|
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||||
Global.DomainDNSAddress.ForEach(it =>
|
|
||||||
{
|
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
|
||||||
cmbdomainDNSAddress.Items.Add(it);
|
cmbdomainStrategy4OutCompatible.ItemsSource = Global.SingboxDomainStrategy4Out;
|
||||||
});
|
cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
Global.SingboxDomainDNSAddress.ForEach(it =>
|
cmbdomainDNSAddress2Compatible.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
{
|
|
||||||
cmbdomainDNSAddress2.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DomainDNSAddress, v => v.cmbdomainDNSAddress.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.NormalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||||
|
//this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.SelectedValue).DisposeWith(disposables);
|
//this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DomainDNSAddress2, v => v.cmbdomainDNSAddress2.SelectedValue).DisposeWith(disposables);
|
//this.Bind(ViewModel, vm => vm.SingboxOutboundsResolveDNS, v => v.cmbSBResolverDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.NormalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables);
|
//this.Bind(ViewModel, vm => vm.SingboxFinalResolveDNS, v => v.cmbSBFinalResolverDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
|
||||||
|
//this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RayCustomDNSEnableCompatible, v => v.togRayCustomDNSEnableCompatible.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SBCustomDNSEnableCompatible, v => v.togSBCustomDNSEnableCompatible.IsChecked).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.Bind(ViewModel, vm => vm.UseSystemHostsCompatible, v => v.togUseSystemHostsCompatible.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.DomainStrategy4FreedomCompatible, v => v.cmbdomainStrategy4FreedomCompatible.SelectedItem).DisposeWith(disposables);
|
||||||
|
//this.Bind(ViewModel, vm => vm.DomainDNSAddressCompatible, v => v.cmbdomainDNSAddressCompatible.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.NormalDNSCompatible, v => v.txtnormalDNSCompatible.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2Compatible, v => v.cmbdomainStrategy4OutCompatible.SelectedItem).DisposeWith(disposables);
|
||||||
|
//this.Bind(ViewModel, vm => vm.DomainDNSAddress2Compatible, v => v.cmbdomainDNSAddress2Compatible.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.NormalDNS2Compatible, v => v.txtnormalDNS2Compatible.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TunDNS2Compatible, v => v.txttunDNS2Compatible.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCompatibleCmd, v => v.btnImportDefConfig4V2rayCompatible).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCompatibleCmd, v => v.btnImportDefConfig4SingboxCompatible).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.ViewModel.RayCustomDNSEnableCompatible,
|
||||||
|
x => x.ViewModel.SBCustomDNSEnableCompatible,
|
||||||
|
(ray, sb) => ray && sb
|
||||||
|
).BindTo(this.FindControl<TextBlock>("txtBasicDNSSettingsInvalid"), t => t.IsVisible);
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.ViewModel.RayCustomDNSEnableCompatible,
|
||||||
|
x => x.ViewModel.SBCustomDNSEnableCompatible,
|
||||||
|
(ray, sb) => ray && sb
|
||||||
|
).BindTo(this.FindControl<TextBlock>("txtAdvancedDNSSettingsInvalid"), t => t.IsVisible);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ using System.Text;
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Handler;
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingViewModel>
|
||||||
{
|
{
|
||||||
private readonly List<object> _textBoxKeyEventItem = new();
|
private readonly List<object> _textBoxKeyEventItem = new();
|
||||||
|
|
||||||
|
|||||||
@@ -39,13 +39,14 @@
|
|||||||
<MenuItem x:Name="menuAddVmessServer" Header="{x:Static resx:ResUI.menuAddVmessServer}" />
|
<MenuItem x:Name="menuAddVmessServer" Header="{x:Static resx:ResUI.menuAddVmessServer}" />
|
||||||
<MenuItem x:Name="menuAddVlessServer" Header="{x:Static resx:ResUI.menuAddVlessServer}" />
|
<MenuItem x:Name="menuAddVlessServer" Header="{x:Static resx:ResUI.menuAddVlessServer}" />
|
||||||
<MenuItem x:Name="menuAddShadowsocksServer" Header="{x:Static resx:ResUI.menuAddShadowsocksServer}" />
|
<MenuItem x:Name="menuAddShadowsocksServer" Header="{x:Static resx:ResUI.menuAddShadowsocksServer}" />
|
||||||
|
<MenuItem x:Name="menuAddTrojanServer" Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
|
||||||
|
<MenuItem x:Name="menuAddWireguardServer" Header="{x:Static resx:ResUI.menuAddWireguardServer}" />
|
||||||
<MenuItem x:Name="menuAddSocksServer" Header="{x:Static resx:ResUI.menuAddSocksServer}" />
|
<MenuItem x:Name="menuAddSocksServer" Header="{x:Static resx:ResUI.menuAddSocksServer}" />
|
||||||
<MenuItem x:Name="menuAddHttpServer" Header="{x:Static resx:ResUI.menuAddHttpServer}" />
|
<MenuItem x:Name="menuAddHttpServer" Header="{x:Static resx:ResUI.menuAddHttpServer}" />
|
||||||
<MenuItem x:Name="menuAddTrojanServer" Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
|
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem x:Name="menuAddHysteria2Server" Header="{x:Static resx:ResUI.menuAddHysteria2Server}" />
|
<MenuItem x:Name="menuAddHysteria2Server" Header="{x:Static resx:ResUI.menuAddHysteria2Server}" />
|
||||||
<MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" />
|
<MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" />
|
||||||
<MenuItem x:Name="menuAddWireguardServer" Header="{x:Static resx:ResUI.menuAddWireguardServer}" />
|
<MenuItem x:Name="menuAddAnytlsServer" Header="{x:Static resx:ResUI.menuAddAnytlsServer}" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem Padding="8,0">
|
<MenuItem Padding="8,0">
|
||||||
|
|||||||
@@ -5,18 +5,18 @@ using Avalonia.Controls.ApplicationLifetimes;
|
|||||||
using Avalonia.Controls.Notifications;
|
using Avalonia.Controls.Notifications;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Splat;
|
using Splat;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
using v2rayN.Desktop.Handler;
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
private WindowNotificationManager? _manager;
|
private WindowNotificationManager? _manager;
|
||||||
@@ -29,7 +29,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_config = AppHandler.Instance.Config;
|
_config = AppHandler.Instance.Config;
|
||||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
|
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
|
||||||
|
|
||||||
this.KeyDown += MainWindow_KeyDown;
|
this.KeyDown += MainWindow_KeyDown;
|
||||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||||
@@ -83,6 +83,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
|||||||
this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
||||||
@@ -135,26 +136,23 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Title = $"{Utils.GetVersion()}";
|
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
|
this.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);
|
||||||
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (AppHandler.Instance.IsAdministrator)
|
this.Title = $"{Utils.GetVersion()}";
|
||||||
{
|
|
||||||
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
|
|
||||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
|
|
||||||
}
|
|
||||||
menuRebootAsAdmin.IsVisible = false;
|
menuRebootAsAdmin.IsVisible = false;
|
||||||
menuSettingsSetUWP.IsVisible = false;
|
menuSettingsSetUWP.IsVisible = false;
|
||||||
menuGlobalHotkeySetting.IsVisible = false;
|
menuGlobalHotkeySetting.IsVisible = false;
|
||||||
}
|
}
|
||||||
menuAddServerViaScan.IsVisible = false;
|
menuAddServerViaScan.IsVisible = false;
|
||||||
|
|
||||||
RestoreUI();
|
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||||
}
|
}
|
||||||
@@ -388,7 +386,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
|||||||
|
|
||||||
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
|
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (await UI.ShowYesNo(this, ResUI.menuExitTips) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.menuExitTips) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -436,14 +434,14 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
|||||||
_config.UiItem.ShowInTaskbar = bl;
|
_config.UiItem.ShowInTaskbar = bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLoaded(sender, e);
|
||||||
|
RestoreUI();
|
||||||
|
}
|
||||||
|
|
||||||
private void RestoreUI()
|
private void RestoreUI()
|
||||||
{
|
{
|
||||||
if (_config.UiItem.MainWidth > 0 && _config.UiItem.MainHeight > 0)
|
|
||||||
{
|
|
||||||
Width = _config.UiItem.MainWidth;
|
|
||||||
Height = _config.UiItem.MainHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
||||||
{
|
{
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
@@ -461,18 +459,15 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
|||||||
|
|
||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainWidth = this.Width;
|
ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
|
||||||
_config.UiItem.MainHeight = this.Height;
|
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
|
||||||
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
|
|
||||||
}
|
}
|
||||||
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
|
||||||
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,34 +69,36 @@
|
|||||||
IsChecked="True"
|
IsChecked="True"
|
||||||
Theme="{DynamicResource SimpleToggleSwitch}" />
|
Theme="{DynamicResource SimpleToggleSwitch}" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
<TextBox
|
|
||||||
Name="txtMsg"
|
<ScrollViewer x:Name="msgScrollViewer" VerticalScrollBarVisibility="Auto">
|
||||||
VerticalAlignment="Stretch"
|
<SelectableTextBlock
|
||||||
BorderThickness="0"
|
Name="txtMsg"
|
||||||
Classes="TextArea"
|
Margin="{StaticResource Margin8}"
|
||||||
IsReadOnly="True"
|
VerticalAlignment="Stretch"
|
||||||
TextAlignment="Left"
|
Classes="TextArea"
|
||||||
TextWrapping="Wrap">
|
TextAlignment="Left"
|
||||||
<TextBox.ContextMenu>
|
TextWrapping="Wrap">
|
||||||
<ContextMenu>
|
<SelectableTextBlock.ContextMenu>
|
||||||
<MenuItem
|
<ContextMenu>
|
||||||
x:Name="menuMsgViewSelectAll"
|
<MenuItem
|
||||||
Click="menuMsgViewSelectAll_Click"
|
x:Name="menuMsgViewSelectAll"
|
||||||
Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" />
|
Click="menuMsgViewSelectAll_Click"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" />
|
||||||
x:Name="menuMsgViewCopy"
|
<MenuItem
|
||||||
Click="menuMsgViewCopy_Click"
|
x:Name="menuMsgViewCopy"
|
||||||
Header="{x:Static resx:ResUI.menuMsgViewCopy}" />
|
Click="menuMsgViewCopy_Click"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuMsgViewCopy}" />
|
||||||
x:Name="menuMsgViewCopyAll"
|
<MenuItem
|
||||||
Click="menuMsgViewCopyAll_Click"
|
x:Name="menuMsgViewCopyAll"
|
||||||
Header="{x:Static resx:ResUI.menuMsgViewCopyAll}" />
|
Click="menuMsgViewCopyAll_Click"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuMsgViewCopyAll}" />
|
||||||
x:Name="menuMsgViewClear"
|
<MenuItem
|
||||||
Click="menuMsgViewClear_Click"
|
x:Name="menuMsgViewClear"
|
||||||
Header="{x:Static resx:ResUI.menuMsgViewClear}" />
|
Click="menuMsgViewClear_Click"
|
||||||
</ContextMenu>
|
Header="{x:Static resx:ResUI.menuMsgViewClear}" />
|
||||||
</TextBox.ContextMenu>
|
</ContextMenu>
|
||||||
</TextBox>
|
</SelectableTextBlock.ContextMenu>
|
||||||
|
</SelectableTextBlock>
|
||||||
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
@@ -9,9 +10,12 @@ namespace v2rayN.Desktop.Views;
|
|||||||
|
|
||||||
public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||||
{
|
{
|
||||||
|
private readonly ScrollViewer _scrollViewer;
|
||||||
|
|
||||||
public MsgView()
|
public MsgView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_scrollViewer = this.FindControl<ScrollViewer>("msgScrollViewer");
|
||||||
|
|
||||||
ViewModel = new MsgViewModel(UpdateViewHandler);
|
ViewModel = new MsgViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
@@ -43,14 +47,14 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
|||||||
txtMsg.Text = msg.ToString();
|
txtMsg.Text = msg.ToString();
|
||||||
if (togScrollToEnd.IsChecked ?? true)
|
if (togScrollToEnd.IsChecked ?? true)
|
||||||
{
|
{
|
||||||
txtMsg.CaretIndex = int.MaxValue;
|
_scrollViewer?.ScrollToEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearMsg()
|
public void ClearMsg()
|
||||||
{
|
{
|
||||||
ViewModel?.ClearMsg();
|
ViewModel?.ClearMsg();
|
||||||
txtMsg.Clear();
|
txtMsg.Text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e)
|
private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -343,7 +343,7 @@
|
|||||||
<Grid
|
<Grid
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
ColumnDefinitions="Auto,Auto,*"
|
ColumnDefinitions="Auto,Auto,*"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="tbAutoRun"
|
x:Name="tbAutoRun"
|
||||||
@@ -575,9 +575,9 @@
|
|||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
||||||
<ctrls:AutoCompleteBox
|
<ComboBox
|
||||||
x:Name="cmbSubConvertUrl"
|
x:Name="cmbIPAPIUrl"
|
||||||
Grid.Row="20"
|
Grid.Row="20"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
@@ -588,28 +588,41 @@
|
|||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||||
|
<ctrls:AutoCompleteBox
|
||||||
|
x:Name="cmbSubConvertUrl"
|
||||||
|
Grid.Row="21"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="22"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="21"
|
Grid.Row="22"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbGetFilesSourceUrl"
|
x:Name="cmbGetFilesSourceUrl"
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@@ -617,19 +630,19 @@
|
|||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSrsFilesSourceUrl"
|
x:Name="cmbSrsFilesSourceUrl"
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@@ -637,24 +650,25 @@
|
|||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRoutingRulesSourceUrl"
|
x:Name="cmbRoutingRulesSourceUrl"
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -784,28 +798,6 @@
|
|||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
x:Name="labLinuxSudoPassword"
|
|
||||||
Grid.Row="7"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
|
|
||||||
<TextBox
|
|
||||||
x:Name="txtLinuxSudoPassword"
|
|
||||||
Grid.Row="7"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="200"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
<TextBlock
|
|
||||||
x:Name="labLinuxSudoPasswordTip"
|
|
||||||
Grid.Row="7"
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel>
|
public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
@@ -19,83 +19,39 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
|||||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
||||||
Global.destOverrideProtocols.ForEach(it =>
|
clbdestOverride.ItemsSource = Global.destOverrideProtocols;
|
||||||
{
|
|
||||||
clbdestOverride.Items.Add(it);
|
|
||||||
});
|
|
||||||
_config.Inbound.First().DestOverride?.ForEach(it =>
|
_config.Inbound.First().DestOverride?.ForEach(it =>
|
||||||
{
|
{
|
||||||
clbdestOverride.SelectedItems.Add(it);
|
clbdestOverride.SelectedItems.Add(it);
|
||||||
});
|
});
|
||||||
Global.IEProxyProtocols.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbsystemProxyAdvancedProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.LogLevels.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbloglevel.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Fingerprints.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdefFingerprint.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.UserAgent.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdefUserAgent.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxMuxs.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbmux4SboxProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
Global.TunMtus.ForEach(it =>
|
cmbsystemProxyAdvancedProtocol.ItemsSource = Global.IEProxyProtocols;
|
||||||
{
|
cmbloglevel.ItemsSource = Global.LogLevels;
|
||||||
cmbMtu.Items.Add(it);
|
cmbdefFingerprint.ItemsSource = Global.Fingerprints;
|
||||||
});
|
cmbdefUserAgent.ItemsSource = Global.UserAgent;
|
||||||
Global.TunStacks.ForEach(it =>
|
cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs;
|
||||||
{
|
cmbMtu.ItemsSource = Global.TunMtus;
|
||||||
cmbStack.Items.Add(it);
|
cmbStack.ItemsSource = Global.TunStacks;
|
||||||
});
|
|
||||||
Global.CoreTypes.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbCoreType1.Items.Add(it);
|
|
||||||
cmbCoreType2.Items.Add(it);
|
|
||||||
cmbCoreType3.Items.Add(it);
|
|
||||||
cmbCoreType4.Items.Add(it);
|
|
||||||
cmbCoreType5.Items.Add(it);
|
|
||||||
cmbCoreType6.Items.Add(it);
|
|
||||||
cmbCoreType9.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i = 2; i <= 8; i++)
|
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
||||||
{
|
cmbCoreType2.ItemsSource = Global.CoreTypes;
|
||||||
cmbMixedConcurrencyCount.Items.Add(i);
|
cmbCoreType3.ItemsSource = Global.CoreTypes;
|
||||||
}
|
cmbCoreType4.ItemsSource = Global.CoreTypes;
|
||||||
for (var i = 2; i <= 6; i++)
|
cmbCoreType5.ItemsSource = Global.CoreTypes;
|
||||||
{
|
cmbCoreType6.ItemsSource = Global.CoreTypes;
|
||||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
cmbCoreType9.ItemsSource = Global.CoreTypes;
|
||||||
}
|
|
||||||
|
|
||||||
|
cmbMixedConcurrencyCount.ItemsSource = Enumerable.Range(2, 7).ToList();
|
||||||
|
cmbSpeedTestTimeout.ItemsSource = Enumerable.Range(2, 5).Select(i => i * 5).ToList();
|
||||||
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
||||||
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
||||||
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
||||||
|
cmbGetFilesSourceUrl.ItemsSource = Global.GeoFilesSources;
|
||||||
|
cmbSrsFilesSourceUrl.ItemsSource = Global.SingboxRulesetSources;
|
||||||
|
cmbRoutingRulesSourceUrl.ItemsSource = Global.RoutingRulesSources;
|
||||||
|
cmbIPAPIUrl.ItemsSource = Global.IPAPIUrls;
|
||||||
|
|
||||||
Global.GeoFilesSources.ForEach(it =>
|
cmbMainGirdOrientation.ItemsSource = Utils.GetEnumNames<EGirdOrientation>();
|
||||||
{
|
|
||||||
cmbGetFilesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxRulesetSources.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbSrsFilesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.RoutingRulesSources.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbRoutingRulesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
|
||||||
{
|
|
||||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
@@ -143,6 +99,7 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
|||||||
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.IPAPIUrl, v => v.cmbIPAPIUrl.SelectedValue).DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -153,7 +110,6 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
|||||||
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
|
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -170,10 +126,6 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
|||||||
{
|
{
|
||||||
txbSettingsExceptionTip2.IsVisible = false;
|
txbSettingsExceptionTip2.IsVisible = false;
|
||||||
|
|
||||||
txtLinuxSudoPassword.IsVisible = false;
|
|
||||||
labLinuxSudoPassword.IsVisible = false;
|
|
||||||
labLinuxSudoPasswordTip.IsVisible = false;
|
|
||||||
|
|
||||||
labHide2TrayWhenClose.IsVisible = false;
|
labHide2TrayWhenClose.IsVisible = false;
|
||||||
togHide2TrayWhenClose.IsVisible = false;
|
togHide2TrayWhenClose.IsVisible = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(_window, ResUI.RemoveServer) == ButtonResult.No)
|
if (await UI.ShowYesNo(_window, ResUI.RemoveServer) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
|||||||
await ViewModel.RefreshServersBiz();
|
await ViewModel.RefreshServersBiz();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lstProfiles.SelectedIndex > 0)
|
if (lstProfiles.SelectedIndex >= 0)
|
||||||
{
|
{
|
||||||
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
||||||
}
|
}
|
||||||
@@ -345,9 +345,34 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
|||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
foreach (var it in lstProfiles.Columns)
|
try
|
||||||
{
|
{
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
//First scroll horizontally to the initial position to avoid the control crash bug
|
||||||
|
if (lstProfiles.SelectedIndex >= 0)
|
||||||
|
{
|
||||||
|
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, lstProfiles.Columns[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var model = lstProfiles.ItemsSource.Cast<ProfileItemModel>();
|
||||||
|
if (model.Any())
|
||||||
|
{
|
||||||
|
lstProfiles.ScrollIntoView(model.First(), lstProfiles.Columns[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var it in lstProfiles.Columns)
|
||||||
|
{
|
||||||
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("ProfilesView", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
|
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ctrls="clr-namespace:v2rayN.Desktop.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
@@ -22,86 +23,95 @@
|
|||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtRemarks"
|
x:Name="txtRemarks"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
HorizontalAlignment="Left"
|
Margin="{StaticResource Margin4}"
|
||||||
Margin="{StaticResource Margin4}" />
|
HorizontalAlignment="Left" />
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
x:Name="togEnabled"
|
x:Name="togEnabled"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Margin="{StaticResource Margin4}" />
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="outboundTag" />
|
Text="outboundTag" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbOutboundTag"
|
Name="cmbOutboundTag"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
MaxDropDownHeight="1000" />
|
Text="{Binding SelectedSource.OutboundTag, Mode=TwoWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbRuleOutboundTagTip}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="port" />
|
Text="port" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtPort"
|
x:Name="txtPort"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
HorizontalAlignment="Left"
|
Margin="{StaticResource Margin4}"
|
||||||
Margin="{StaticResource Margin4}" />
|
HorizontalAlignment="Left" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="{StaticResource Margin4}">
|
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="protocol" />
|
||||||
|
<ListBox
|
||||||
|
x:Name="clbProtocol"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
SelectionMode="Multiple,Toggle"
|
||||||
|
Theme="{DynamicResource CardCheckGroupListBox}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center">
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
|
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
||||||
</HyperlinkButton>
|
</HyperlinkButton>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="3"
|
|
||||||
Grid.Column="0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
Text="protocol" />
|
|
||||||
<ListBox
|
|
||||||
x:Name="clbProtocol"
|
|
||||||
Grid.Row="3"
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
SelectionMode="Multiple,Toggle"
|
|
||||||
Theme="{DynamicResource CardCheckGroupListBox}" />
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="inboundTag" />
|
Text="inboundTag" />
|
||||||
<ListBox
|
<ListBox
|
||||||
x:Name="clbInboundTag"
|
x:Name="clbInboundTag"
|
||||||
@@ -113,35 +123,36 @@
|
|||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
|
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
|
||||||
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="network" />
|
Text="network" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbNetwork"
|
x:Name="cmbNetwork"
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
MaxDropDownHeight="1000" />
|
MaxDropDownHeight="1000" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetailsViewModel>
|
public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleDetailsWindow()
|
public RoutingRuleDetailsWindow()
|
||||||
{
|
{
|
||||||
@@ -23,21 +23,11 @@ public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetail
|
|||||||
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
||||||
|
|
||||||
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
|
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
|
||||||
cmbOutboundTag.Items.Add(Global.ProxyTag);
|
|
||||||
cmbOutboundTag.Items.Add(Global.DirectTag);
|
cmbOutboundTag.ItemsSource = Global.OutboundTags;
|
||||||
cmbOutboundTag.Items.Add(Global.BlockTag);
|
clbProtocol.ItemsSource = Global.RuleProtocols;
|
||||||
Global.RuleProtocols.ForEach(it =>
|
clbInboundTag.ItemsSource = Global.InboundTags;
|
||||||
{
|
cmbNetwork.ItemsSource = Global.RuleNetworks;
|
||||||
clbProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.InboundTags.ForEach(it =>
|
|
||||||
{
|
|
||||||
clbInboundTag.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.RuleNetworks.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbNetwork.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!rulesItem.Id.IsNullOrEmpty())
|
if (!rulesItem.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
@@ -54,7 +44,7 @@ public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetail
|
|||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
|
||||||
@@ -80,7 +70,7 @@ public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetail
|
|||||||
|
|
||||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
cmbOutboundTag.Focus();
|
txtRemarks.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ using System.Reactive.Disposables;
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettingViewModel>
|
public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleSettingWindow()
|
public RoutingRuleSettingWindow()
|
||||||
{
|
{
|
||||||
@@ -30,15 +30,9 @@ public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettin
|
|||||||
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_ClickAsync;
|
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_ClickAsync;
|
||||||
|
|
||||||
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
|
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
|
||||||
Global.DomainStrategies.ForEach(it =>
|
|
||||||
{
|
cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty();
|
||||||
cmbdomainStrategy.Items.Add(it);
|
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
|
||||||
});
|
|
||||||
cmbdomainStrategy.Items.Add(string.Empty);
|
|
||||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
@@ -80,14 +74,14 @@ public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettin
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.RemoveServer) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.AddBatchRoutingRulesYesNo:
|
case EViewAction.AddBatchRoutingRulesYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.AddBatchRoutingRulesYesNo) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.AddBatchRoutingRulesYesNo) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,36 +24,13 @@
|
|||||||
<MenuItem x:Name="menuRoutingAdvancedAdd2" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
<MenuItem x:Name="menuRoutingAdvancedAdd2" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
<MenuItem x:Name="menuRoutingAdvancedImportRules2" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
<MenuItem x:Name="menuRoutingAdvancedImportRules2" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<TextBlock VerticalAlignment="Center">
|
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy_Click">
|
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
|
||||||
</HyperlinkButton>
|
|
||||||
</TextBlock>
|
|
||||||
<ComboBox x:Name="cmbdomainStrategy" Width="110" />
|
|
||||||
<Separator />
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
|
||||||
<ComboBox x:Name="cmbdomainMatcher" Width="60" />
|
|
||||||
<Separator />
|
|
||||||
<TextBlock VerticalAlignment="Center">
|
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
|
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
|
||||||
</HyperlinkButton>
|
|
||||||
</TextBlock>
|
|
||||||
<ComboBox x:Name="cmbdomainStrategy4Singbox" Width="100" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<StackPanel
|
|
||||||
Width="600"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
|
||||||
</StackPanel>
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnSave"
|
x:Name="btnSave"
|
||||||
Width="100"
|
Width="100"
|
||||||
@@ -69,58 +46,112 @@
|
|||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<DockPanel>
|
<Grid
|
||||||
<TabControl x:Name="tabAdvanced">
|
Margin="{StaticResource Margin4}"
|
||||||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
ColumnDefinitions="Auto,Auto"
|
||||||
<DataGrid
|
DockPanel.Dock="Top"
|
||||||
x:Name="lstRoutings"
|
RowDefinitions="Auto,Auto,Auto">
|
||||||
AutoGenerateColumns="False"
|
|
||||||
BorderThickness="1"
|
|
||||||
CanUserResizeColumns="True"
|
|
||||||
GridLinesVisibility="All"
|
|
||||||
HeadersVisibility="Column"
|
|
||||||
IsReadOnly="True"
|
|
||||||
ItemsSource="{Binding RoutingItems}">
|
|
||||||
<DataGrid.KeyBindings>
|
|
||||||
<KeyBinding Command="{Binding RoutingAdvancedSetDefaultCmd}" Gesture="Enter" />
|
|
||||||
</DataGrid.KeyBindings>
|
|
||||||
<DataGrid.ContextMenu>
|
|
||||||
<ContextMenu>
|
|
||||||
<MenuItem x:Name="menuRoutingAdvancedAdd" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
|
||||||
<MenuItem x:Name="menuRoutingAdvancedRemove" Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" />
|
|
||||||
<MenuItem x:Name="menuRoutingAdvancedSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" />
|
|
||||||
<MenuItem x:Name="menuRoutingAdvancedSetDefault" Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}" />
|
|
||||||
<Separator />
|
|
||||||
<MenuItem x:Name="menuRoutingAdvancedImportRules" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
|
||||||
</ContextMenu>
|
|
||||||
</DataGrid.ContextMenu>
|
|
||||||
|
|
||||||
<DataGrid.Columns>
|
<TextBlock
|
||||||
<DataGridCheckBoxColumn Width="40" Binding="{Binding IsActive}" />
|
Grid.Row="0"
|
||||||
<DataGridTextColumn
|
Grid.Column="0"
|
||||||
Width="*"
|
Margin="{StaticResource Margin4}"
|
||||||
Binding="{Binding Remarks}"
|
VerticalAlignment="Center">
|
||||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy_Click">
|
||||||
<DataGridTextColumn
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||||
Width="60"
|
</HyperlinkButton>
|
||||||
Binding="{Binding RuleNum}"
|
</TextBlock>
|
||||||
Header="{x:Static resx:ResUI.LvCount}" />
|
<ComboBox
|
||||||
<DataGridTextColumn
|
x:Name="cmbdomainStrategy"
|
||||||
Width="60"
|
Grid.Row="0"
|
||||||
Binding="{Binding Sort}"
|
Grid.Column="1"
|
||||||
Header="{x:Static resx:ResUI.LvSort}" />
|
Width="300"
|
||||||
<DataGridTextColumn
|
Margin="{StaticResource Margin4}"
|
||||||
Width="*"
|
HorizontalAlignment="Left"
|
||||||
Binding="{Binding Url}"
|
VerticalAlignment="Center" />
|
||||||
Header="{x:Static resx:ResUI.LvUrl}" />
|
|
||||||
<DataGridTextColumn
|
<TextBlock
|
||||||
Width="300"
|
Grid.Row="1"
|
||||||
Binding="{Binding CustomIcon}"
|
Grid.Column="0"
|
||||||
Header="{x:Static resx:ResUI.LvCustomIcon}" />
|
Margin="{StaticResource Margin4}"
|
||||||
</DataGrid.Columns>
|
VerticalAlignment="Center"
|
||||||
</DataGrid>
|
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
||||||
</TabItem>
|
<ComboBox
|
||||||
</TabControl>
|
x:Name="cmbdomainMatcher"
|
||||||
</DockPanel>
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</TextBlock>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy4Singbox"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TabControl x:Name="tabAdvanced">
|
||||||
|
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||||
|
<DataGrid
|
||||||
|
x:Name="lstRoutings"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
BorderThickness="1"
|
||||||
|
CanUserResizeColumns="True"
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
IsReadOnly="True"
|
||||||
|
ItemsSource="{Binding RoutingItems}">
|
||||||
|
<DataGrid.KeyBindings>
|
||||||
|
<KeyBinding Command="{Binding RoutingAdvancedSetDefaultCmd}" Gesture="Enter" />
|
||||||
|
</DataGrid.KeyBindings>
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu>
|
||||||
|
<MenuItem x:Name="menuRoutingAdvancedAdd" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
|
<MenuItem x:Name="menuRoutingAdvancedRemove" Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" />
|
||||||
|
<MenuItem x:Name="menuRoutingAdvancedSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||||
|
<MenuItem x:Name="menuRoutingAdvancedSetDefault" Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem x:Name="menuRoutingAdvancedImportRules" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridCheckBoxColumn Width="40" Binding="{Binding IsActive}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="*"
|
||||||
|
Binding="{Binding Remarks}"
|
||||||
|
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="60"
|
||||||
|
Binding="{Binding RuleNum}"
|
||||||
|
Header="{x:Static resx:ResUI.LvCount}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="60"
|
||||||
|
Binding="{Binding Sort}"
|
||||||
|
Header="{x:Static resx:ResUI.LvSort}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="*"
|
||||||
|
Binding="{Binding Url}"
|
||||||
|
Header="{x:Static resx:ResUI.LvUrl}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="300"
|
||||||
|
Binding="{Binding CustomIcon}"
|
||||||
|
Header="{x:Static resx:ResUI.LvCustomIcon}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ using System.Reactive.Disposables;
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewModel>
|
public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
@@ -26,18 +26,9 @@ public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewMod
|
|||||||
|
|
||||||
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
|
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
Global.DomainStrategies.ForEach(it =>
|
cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
|
||||||
{
|
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
|
||||||
cmbdomainStrategy.Items.Add(it);
|
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
|
||||||
});
|
|
||||||
Global.DomainMatchers.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainMatcher.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
@@ -68,7 +59,7 @@ public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewMod
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveRules) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.RemoveRules) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -126,7 +117,7 @@ public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewMod
|
|||||||
|
|
||||||
private void linkdomainStrategy4Singbox_Click(object? sender, RoutedEventArgs e)
|
private void linkdomainStrategy4Singbox_Click(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/shared/listen/#domain_strategy");
|
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/route/rule_action/#strategy");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnCancel_Click(object? sender, RoutedEventArgs e)
|
private void btnCancel_Click(object? sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using DialogHostAvalonia;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Splat;
|
using Splat;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
@@ -81,6 +82,9 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
|||||||
return false;
|
return false;
|
||||||
await AvaUtils.SetClipboardData(this, (string)obj);
|
await AvaUtils.SetClipboardData(this, (string)obj);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EViewAction.PasswordInput:
|
||||||
|
return await PasswordInputAsync();
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
@@ -96,6 +100,22 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<bool> PasswordInputAsync()
|
||||||
|
{
|
||||||
|
var dialog = new SudoPasswordInputView();
|
||||||
|
var obj = await DialogHost.Show(dialog);
|
||||||
|
|
||||||
|
var password = obj?.ToString();
|
||||||
|
if (password.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
togEnableTun.IsChecked = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppHandler.Instance.LinuxSudoPwd = password;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel?.TestServerAvailability();
|
ViewModel?.TestServerAvailability();
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
public partial class SubEditWindow : WindowBase<SubEditViewModel>
|
||||||
{
|
{
|
||||||
public SubEditWindow()
|
public SubEditWindow()
|
||||||
{
|
{
|
||||||
@@ -22,10 +22,7 @@ public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
|||||||
|
|
||||||
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
||||||
|
|
||||||
Global.SubConvertTargets.ForEach(it =>
|
cmbConvertTarget.ItemsSource = Global.SubConvertTargets;
|
||||||
{
|
|
||||||
cmbConvertTarget.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
if (await UI.ShowYesNo(this, ResUI.RemoveServer) != ButtonResult.Yes)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
70
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml
Normal file
70
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="v2rayN.Desktop.Views.SudoPasswordInputView"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
|
d:DesignHeight="200"
|
||||||
|
d:DesignWidth="400"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
|
|
||||||
|
<Border
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
DockPanel.Dock="Bottom"
|
||||||
|
Theme="{DynamicResource CardBorder}">
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
x:Name="btnSave"
|
||||||
|
Width="100"
|
||||||
|
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||||
|
Cursor="Hand"
|
||||||
|
IsDefault="True" />
|
||||||
|
<Button
|
||||||
|
x:Name="btnCancel"
|
||||||
|
Width="100"
|
||||||
|
Margin="{StaticResource MarginLr8}"
|
||||||
|
Content="{x:Static resx:ResUI.TbCancel}"
|
||||||
|
Cursor="Hand"
|
||||||
|
IsCancel="True" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Theme="{DynamicResource CardBorder}">
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="Auto,400" RowDefinitions="Auto,Auto,Auto">
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtPassword"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Classes="revealPasswordButton"
|
||||||
|
Focusable="True" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</DockPanel>
|
||||||
|
</UserControl>
|
||||||
82
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs
Normal file
82
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using CliWrap.Buffered;
|
||||||
|
using DialogHostAvalonia;
|
||||||
|
|
||||||
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
|
public partial class SudoPasswordInputView : UserControl
|
||||||
|
{
|
||||||
|
public SudoPasswordInputView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.Loaded += (s, e) => txtPassword.Focus();
|
||||||
|
|
||||||
|
btnSave.Click += async (_, _) => await SavePasswordAsync();
|
||||||
|
|
||||||
|
btnCancel.Click += (_, _) =>
|
||||||
|
{
|
||||||
|
DialogHost.Close(null);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SavePasswordAsync()
|
||||||
|
{
|
||||||
|
if (txtPassword.Text.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
txtPassword.Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var password = txtPassword.Text;
|
||||||
|
btnSave.IsEnabled = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Verify if the password is correct
|
||||||
|
if (await CheckSudoPasswordAsync(password))
|
||||||
|
{
|
||||||
|
// Password verification successful, return password and close dialog
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
DialogHost.Close(null, password);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Password verification failed, display error and let user try again
|
||||||
|
NoticeHandler.Instance.Enqueue(ResUI.SudoIncorrectPasswordTip);
|
||||||
|
txtPassword.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("SudoPassword", ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
btnSave.IsEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> CheckSudoPasswordAsync(string password)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Use sudo echo command to verify password
|
||||||
|
var arg = new List<string>() { "-c", "sudo -S echo SUDO_CHECK" };
|
||||||
|
var result = await CliWrap.Cli.Wrap(Global.LinuxBash)
|
||||||
|
.WithArguments(arg)
|
||||||
|
.WithStandardInputPipe(CliWrap.PipeSource.FromString(password))
|
||||||
|
.ExecuteBufferedAsync();
|
||||||
|
|
||||||
|
return result.ExitCode == 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("CheckSudoPassword", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,20 +16,9 @@ public partial class ThemeSettingView : ReactiveUserControl<ThemeSettingViewMode
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
ViewModel = new ThemeSettingViewModel();
|
ViewModel = new ThemeSettingViewModel();
|
||||||
|
|
||||||
foreach (ETheme it in Enum.GetValues(typeof(ETheme)))
|
cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>();
|
||||||
{
|
cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, 11).ToList();
|
||||||
cmbCurrentTheme.Items.Add(it.ToString());
|
cmbCurrentLanguage.ItemsSource = Global.Languages;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++)
|
|
||||||
{
|
|
||||||
cmbCurrentFontSize.Items.Add(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Global.Languages.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbCurrentLanguage.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<Application
|
<Application
|
||||||
x:Class="v2rayN.App"
|
x:Class="v2rayN.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
ShutdownMode="OnExplicitShutdown"
|
ShutdownMode="OnExplicitShutdown"
|
||||||
StartupUri="Views/MainWindow.xaml">
|
StartupUri="Views/MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
|
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
|
||||||
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||||
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||||
<Setter Property="ResizeMode" Value="NoResize" />
|
<Setter Property="ResizeMode" Value="CanResize" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ViewGlobal"
|
x:Key="ViewGlobal"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user