mirror of
https://github.com/2dust/v2rayN.git
synced 2025-07-03 13:32:10 +00:00
Compare commits
No commits in common. "master" and "7.12.0" have entirely different histories.
75 changed files with 961 additions and 1643 deletions
12
.github/workflows/winget-publish.yml
vendored
12
.github/workflows/winget-publish.yml
vendored
|
@ -22,18 +22,10 @@ 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) 2019-Present 2dust
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
v2rayN Copyright (C) 2019-Present 2dust
|
<program> Copyright (C) <year> <name of author>
|
||||||
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,18 +1,16 @@
|
||||||
# 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)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.12.7</Version>
|
<Version>7.12.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
@ -5,21 +5,21 @@
|
||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.1" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.8" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.1" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.2.8" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.1" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.8" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.1" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.8" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
<PackageVersion Include="CliWrap" Version="3.8.2" />
|
||||||
<PackageVersion Include="Downloader" Version="3.3.4" />
|
<PackageVersion Include="Downloader" Version="3.3.4" />
|
||||||
<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.3.1" />
|
<PackageVersion Include="ReactiveUI" Version="20.2.45" />
|
||||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.3.1" />
|
<PackageVersion Include="ReactiveUI.WPF" Version="20.2.45" />
|
||||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.8" />
|
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.7" />
|
||||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.8" />
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.7" />
|
||||||
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
<PackageVersion Include="Splat.NLog" Version="15.3.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.1" />
|
||||||
|
|
100
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
100
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
74
v2rayN/ServiceLib/Common/DesUtils.cs
Normal file
74
v2rayN/ServiceLib/Common/DesUtils.cs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -582,7 +582,7 @@ public class Utils
|
||||||
var result = await cmd.ExecuteBufferedAsync();
|
var result = await cmd.ExecuteBufferedAsync();
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
{
|
{
|
||||||
return result.StandardOutput ?? "";
|
return result.StandardOutput.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.SaveLog(result.ToString() ?? "");
|
Logging.SaveLog(result.ToString() ?? "");
|
||||||
|
@ -839,46 +839,14 @@ 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" };
|
||||||
|
|
|
@ -8,7 +8,9 @@ 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";
|
||||||
|
@ -517,15 +519,5 @@ 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",
|
|
||||||
@""
|
|
||||||
];
|
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,6 @@ 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())
|
||||||
{
|
{
|
||||||
|
@ -123,7 +122,7 @@ public class ConfigHandler
|
||||||
}
|
}
|
||||||
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
|
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrls.First();
|
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
|
||||||
}
|
}
|
||||||
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
|
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
|
||||||
{
|
{
|
||||||
|
@ -247,7 +246,6 @@ public class ConfigHandler
|
||||||
item.ShortId = profileItem.ShortId;
|
item.ShortId = profileItem.ShortId;
|
||||||
item.SpiderX = profileItem.SpiderX;
|
item.SpiderX = profileItem.SpiderX;
|
||||||
item.Extra = profileItem.Extra;
|
item.Extra = profileItem.Extra;
|
||||||
item.MuxEnabled = profileItem.MuxEnabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = item.ConfigType switch
|
var ret = item.ConfigType switch
|
||||||
|
@ -801,11 +799,8 @@ 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
|
||||||
|
@ -820,11 +815,7 @@ 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);
|
||||||
|
@ -842,10 +833,6 @@ 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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -862,10 +849,6 @@ 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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1981,7 +1964,7 @@ public class ConfigHandler
|
||||||
items = await AppHandler.Instance.RoutingItems();
|
items = await AppHandler.Instance.RoutingItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blImportAdvancedRules && items.Count > 0)
|
if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2175,44 +2158,4 @@ public class ConfigHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
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}";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,9 +6,9 @@ public class VmessFmt : BaseFmt
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
ProfileItem? item;
|
ProfileItem? item;
|
||||||
if (str.IndexOf('@') > 0)
|
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
||||||
{
|
{
|
||||||
item = ResolveStdVmess(str) ?? ResolveVmess(str, out msg);
|
item = ResolveStdVmess(str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -89,8 +89,10 @@ public class UIItem
|
||||||
{
|
{
|
||||||
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
||||||
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
||||||
public int MainGirdHeight1 { get; set; }
|
public double MainWidth { get; set; }
|
||||||
public int MainGirdHeight2 { get; set; }
|
public double MainHeight { 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; }
|
||||||
|
@ -101,10 +103,8 @@ 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 bool ShowInTaskbar { get; set; }
|
|
||||||
public bool MacOSShowInDock { get; set; }
|
|
||||||
public List<ColumnItem> MainColumnItem { get; set; }
|
public List<ColumnItem> MainColumnItem { get; set; }
|
||||||
public List<WindowSizeItem> WindowSizeItem { get; set; }
|
public bool ShowInTaskbar { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
@ -156,7 +156,6 @@ 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,11 +244,3 @@ 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; }
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,17 +3,10 @@ namespace ServiceLib.Models;
|
||||||
internal class IPAPIInfo
|
internal class IPAPIInfo
|
||||||
{
|
{
|
||||||
public string? ip { get; set; }
|
public string? ip { get; set; }
|
||||||
public string? clientIp { get; set; }
|
public string? city { get; set; }
|
||||||
public string? ip_addr { get; set; }
|
public string? region { get; set; }
|
||||||
public string? query { get; set; }
|
public string? region_code { 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,10 +1,9 @@
|
||||||
using ReactiveUI;
|
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItem : ReactiveObject
|
public class ProfileItem
|
||||||
{
|
{
|
||||||
public ProfileItem()
|
public ProfileItem()
|
||||||
{
|
{
|
||||||
|
@ -94,5 +93,4 @@ public class ProfileItem : ReactiveObject
|
||||||
public string ShortId { get; set; }
|
public string ShortId { get; set; }
|
||||||
public string SpiderX { get; set; }
|
public string SpiderX { get; set; }
|
||||||
public string Extra { get; set; }
|
public string Extra { get; set; }
|
||||||
public bool? MuxEnabled { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using ReactiveUI.Fody.Helpers;
|
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
@ -7,28 +5,13 @@ 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; }
|
||||||
}
|
}
|
||||||
|
|
9
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
9
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
@ -3201,15 +3201,6 @@ 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>
|
||||||
|
|
|
@ -1416,7 +1416,4 @@
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>صادر کردن سرور</value>
|
<value>صادر کردن سرور</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
|
||||||
<value>URL آزمایش اطلاعات اتصال فعلی</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</root>
|
||||||
|
|
|
@ -1416,7 +1416,4 @@
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>Export server</value>
|
<value>Export server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
|
||||||
<value>Current connection info test URL</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</root>
|
|
@ -1416,7 +1416,4 @@
|
||||||
<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>
|
|
||||||
</root>
|
</root>
|
|
@ -118,16 +118,16 @@
|
||||||
<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>Экспортирование URL в буфер обмена успешно завершено</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>
|
||||||
|
@ -136,13 +136,13 @@
|
||||||
<value>Скорость загрузки</value>
|
<value>Скорость загрузки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
<data name="DownloadYesNo" xml:space="preserve">
|
||||||
<value>Хотите загрузить {0}?</value>
|
<value>Хотите загрузить? {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>Не удалось преобразовать файл конфигурации</value>
|
<value>Не удалось преобразовать файл конфигурации</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedGenDefaultConfiguration" xml:space="preserve">
|
<data name="FailedGenDefaultConfiguration" xml:space="preserve">
|
||||||
<value>Не удалось создать файл конфигурации по умолчанию</value>
|
<value>Не удалось создать файл конфигурации по умолчаниюe</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
||||||
<value>Не удалось получить конфигурацию по умолчанию</value>
|
<value>Не удалось получить конфигурацию по умолчанию</value>
|
||||||
|
@ -154,37 +154,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 +199,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 +214,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 +235,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 +244,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 или Shadowsocks</value>
|
<value>Не является протоколом Vmess или SS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>Файл ядра ({1}) не найден в папке {0}. Скачайте по адресу {2} и поместите его туда</value>
|
<value>Файл Core (имя файла: {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 +286,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 +310,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 +322,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 +337,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>*WebSocket-путь</value>
|
<value>*ws путь</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip2" xml:space="preserve">
|
<data name="TransportPathTip2" xml:space="preserve">
|
||||||
<value>*HTTP2-путь</value>
|
<value>*h2 путь</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</value>
|
<value>*grpc serviceName</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>*WebSocket-хост</value>
|
<value>*ws хост</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||||
<value>*HTTP2-хосты, разделённые запятыми (,)</value>
|
<value>*h2 хосты разделенные запятыми (,)</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>
|
||||||
|
@ -391,10 +391,10 @@
|
||||||
<value>Разгруппировано</value>
|
<value>Разгруппировано</value>
|
||||||
</data>
|
</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 +436,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 +445,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 +571,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 +628,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 +658,10 @@
|
||||||
<value>Шифрования</value>
|
<value>Шифрования</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPreSocksPort" xml:space="preserve">
|
<data name="TbPreSocksPort" xml:space="preserve">
|
||||||
<value>Порт SOCKS</value>
|
<value>txtPreSocksPort</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 +697,7 @@
|
||||||
<value>Разрешить небезопасные</value>
|
<value>Разрешить небезопасные</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve">
|
<data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve">
|
||||||
<value>«Freedom»: стратегия обработки доменов исходящего трафика</value>
|
<value>Outbound Freedom domainStrategy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
||||||
<value>Автоматически регулировать ширину столбца после обновления подписки</value>
|
<value>Автоматически регулировать ширину столбца после обновления подписки</value>
|
||||||
|
@ -712,7 +712,7 @@
|
||||||
<value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value>
|
<value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>Показывать скорость в реальном времени</value>
|
<value>Display real-time speed</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||||
<value>Сохранить старые при удалении дублей</value>
|
<value>Сохранить старые при удалении дублей</value>
|
||||||
|
@ -721,10 +721,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 +733,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>Разрешить loopback для приложений UWP (Win10)</value>
|
<value>Set Win10 UWP Loopback</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>Смешанный порт</value>
|
<value>Mixed Port</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||||
<value>Автозапуск</value>
|
<value>Автозапуск</value>
|
||||||
|
@ -751,7 +751,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 +766,7 @@
|
||||||
<value>Включить UDP</value>
|
<value>Включить UDP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUser" xml:space="preserve">
|
<data name="TbSettingsUser" xml:space="preserve">
|
||||||
<value>Имя пользователя (логин)</value>
|
<value>Auth user</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbClearSystemProxy" xml:space="preserve">
|
<data name="TbClearSystemProxy" xml:space="preserve">
|
||||||
<value>Очистить системный прокси</value>
|
<value>Очистить системный прокси</value>
|
||||||
|
@ -816,9 +816,6 @@
|
||||||
<data name="menuMoveUp" xml:space="preserve">
|
<data name="menuMoveUp" xml:space="preserve">
|
||||||
<value>Вверх (U)</value>
|
<value>Вверх (U)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMoveTo" xml:space="preserve">
|
|
||||||
<value>Переместить вверх/вниз</value>
|
|
||||||
</data>
|
|
||||||
<data name="MsgFilterTitle" xml:space="preserve">
|
<data name="MsgFilterTitle" xml:space="preserve">
|
||||||
<value>Фильтр, поддерживает regex</value>
|
<value>Фильтр, поддерживает regex</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -853,13 +850,13 @@
|
||||||
<value>2.Прямой домен или IP</value>
|
<value>2.Прямой домен или IP</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
<data name="TbRoutingTabProxy" xml:space="preserve">
|
||||||
<value>1.Прокси домен или IP</value>
|
<value>1.Прокси-домен или IP</value>
|
||||||
</data>
|
</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>
|
||||||
|
@ -886,16 +883,16 @@
|
||||||
<value>Удалить правила (Delete)</value>
|
<value>Удалить правила (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
||||||
<value>Детальные настройки правил маршрутизации</value>
|
<value>RoutingRuleDetailsSetting</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</value>
|
<value>Ruleobject Doc</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||||
<value>Поддерживаются DNS-объекты, нажмите для просмотра документации</value>
|
<value>Поддержка DnsObject</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>Необязательное поле</value>
|
<value>Необязательное поле</value>
|
||||||
|
@ -916,16 +913,16 @@
|
||||||
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
|
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTestDelay" xml:space="preserve">
|
<data name="LvTestDelay" xml:space="preserve">
|
||||||
<value>Задержка (мс)</value>
|
<value>Задержка (ms)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTestSpeed" xml:space="preserve">
|
<data name="LvTestSpeed" xml:space="preserve">
|
||||||
<value>Скорость (МБ/с)</value>
|
<value>Скорость (M/s)</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>Фильтр примечаний (Regex)</value>
|
<value>Remarks regular filter</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDisplayLog" xml:space="preserve">
|
<data name="TbDisplayLog" xml:space="preserve">
|
||||||
<value>Показать логи</value>
|
<value>Показать логи</value>
|
||||||
|
@ -937,7 +934,7 @@
|
||||||
<value>Новый порт для локальной сети</value>
|
<value>Новый порт для локальной сети</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>Настройки режима TUN</value>
|
<value>Настройки TunMode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>Перейти в группу</value>
|
<value>Перейти в группу</value>
|
||||||
|
@ -961,22 +958,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 и WebSocket (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>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>Установите это с правами администратора</value>
|
<value>Установите это с правами администратора</value>
|
||||||
|
@ -985,10 +982,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 name="menuMoveTo" xml:space="preserve">
|
||||||
|
<value>Move up and down</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPublicKey" xml:space="preserve">
|
<data name="TbPublicKey" xml:space="preserve">
|
||||||
<value>PublicKey</value>
|
<value>PublicKey</value>
|
||||||
|
@ -1003,19 +1003,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>Отключите при аномальном разрыве соединения</value>
|
<value>Please turn off when there is an abnormal disconnection</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
|
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
|
||||||
<value>Обновления не включены — подписка пропущена</value>
|
<value>Updates are not enabled, skip this subscription</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>Дополнительные URL через запятую, конвертация подписки недоступна</value>
|
<value>More URLs, separated by commas; Subscription conversion will be invalid</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 +1024,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 +1039,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 +1048,88 @@
|
||||||
<value>Стратегия домена для sing-box</value>
|
<value>Стратегия домена для sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
|
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
|
||||||
<value>Протокол Mux для sing-box</value>
|
<value>sing-box Mux Protocol</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
||||||
<value>Полное имя процесса (режим TUN)</value>
|
<value>Full process name (Tun mode)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingRuleIP" xml:space="preserve">
|
<data name="TbRoutingRuleIP" xml:space="preserve">
|
||||||
<value>IP-адрес или сеть CIDR</value>
|
<value>IP or 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 (загрузка/отдача)</value>
|
<value>Hysteria Max bandwidth (Up/Dw)</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>Примечания к предыдущему прокси</value>
|
<value>Previous proxy remarks</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvNextProfile" xml:space="preserve">
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
<value>Примечания к следующему прокси</value>
|
<value>Next proxy remarks</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>Включить дополнительный входящий канал</value>
|
<value>Enable additional Inbound</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>Приватный ключ</value>
|
<value>PrivateKey</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbReserved" xml:space="preserve">
|
<data name="TbReserved" xml:space="preserve">
|
||||||
<value>Зарезервировано (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>Адрес (Ipv4,Ipv6)</value>
|
<value>Адрес(Ipv4,Ipv6)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPath7" xml:space="preserve">
|
<data name="TbPath7" xml:space="preserve">
|
||||||
<value>Пароль obfs</value>
|
<value>obfs password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleMatchingTips" xml:space="preserve">
|
<data name="TbRuleMatchingTips" xml:space="preserve">
|
||||||
<value>(Домен или IP или имя процесса) и порт, и протокол, и InboundTag => OutboundTag</value>
|
<value>(Domain or IP or ProcName) and Port and Protocol and 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>Обновляя подписку, проверять лишь наличие примечаний</value>
|
<value>Updating subscription, only determine remarks exists</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>Используйте Xray и отключите режим TUN, так как он конфликтует с предыдущим прокси-сервером группы</value>
|
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>Включить фрагментацию (Fragment)</value>
|
<value>Включить фрагмент</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 +1138,7 @@
|
||||||
<value>Пользовательский набор правил для sing-box</value>
|
<value>Пользовательский набор правил для sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NeedRebootTips" xml:space="preserve">
|
<data name="NeedRebootTips" xml:space="preserve">
|
||||||
<value>Операция успешна. Перезапустите приложение</value>
|
<value>Successful operation. Click the settings menu to reboot the app.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
||||||
<value>Открыть место хранения</value>
|
<value>Открыть место хранения</value>
|
||||||
|
@ -1147,7 +1147,7 @@
|
||||||
<value>Сортировка</value>
|
<value>Сортировка</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingChain" xml:space="preserve">
|
<data name="TbSortingChain" xml:space="preserve">
|
||||||
<value>Цепочка</value>
|
<value>Chain</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingDefault" xml:space="preserve">
|
<data name="TbSortingDefault" xml:space="preserve">
|
||||||
<value>По умолчанию</value>
|
<value>По умолчанию</value>
|
||||||
|
@ -1159,7 +1159,7 @@
|
||||||
<value>Скорость загрузки</value>
|
<value>Скорость загрузки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingDownTraffic" xml:space="preserve">
|
<data name="TbSortingDownTraffic" xml:space="preserve">
|
||||||
<value>Скачанный трафик</value>
|
<value>Download Traffic</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSortingHost" xml:space="preserve">
|
<data name="TbSortingHost" xml:space="preserve">
|
||||||
<value>Узел</value>
|
<value>Узел</value>
|
||||||
|
@ -1177,10 +1177,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>Отправленный трафик</value>
|
<value>Upload Traffic</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbConnections" xml:space="preserve">
|
<data name="TbConnections" xml:space="preserve">
|
||||||
<value>Соединения</value>
|
<value>Соединения</value>
|
||||||
|
@ -1198,13 +1198,13 @@
|
||||||
<value>Режим правила</value>
|
<value>Режим правила</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeDirect" xml:space="preserve">
|
<data name="menuModeDirect" xml:space="preserve">
|
||||||
<value>Прямое соединение</value>
|
<value>Direct</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeGlobal" xml:space="preserve">
|
<data name="menuModeGlobal" xml:space="preserve">
|
||||||
<value>Глобальный режим</value>
|
<value>Global</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeNothing" xml:space="preserve">
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
<value>Не менять</value>
|
<value>Do not change</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeRule" xml:space="preserve">
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
<value>Правила</value>
|
<value>Правила</value>
|
||||||
|
@ -1213,13 +1213,13 @@
|
||||||
<value>Тест задержки</value>
|
<value>Тест задержки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
<value>Тест задержки выбранных узлов</value>
|
<value>Part Node Latency Test</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 +1234,7 @@
|
||||||
<value>Автоматическая регулировка ширины столбца</value>
|
<value>Автоматическая регулировка ширины столбца</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
||||||
<value>Экспорт ссылок в формате Base64 в буфер обмена</value>
|
<value>Export Base64-encoded Share Links to Clipboard</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>Экспортировать выбранный сервер для полной конфигурации в буфер обмена</value>
|
<value>Экспортировать выбранный сервер для полной конфигурации в буфер обмена</value>
|
||||||
|
@ -1243,7 +1243,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 +1255,28 @@
|
||||||
<value>Восстановить из файла</value>
|
<value>Восстановить из файла</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoteBackup" xml:space="preserve">
|
<data name="menuRemoteBackup" xml:space="preserve">
|
||||||
<value>Резервное копирование на удалённый сервер (WebDAV)</value>
|
<value>Backup to remote (WebDAV)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoteRestore" xml:space="preserve">
|
<data name="menuRemoteRestore" xml:space="preserve">
|
||||||
<value>Восстановить с удалённого сервера (WebDAV)</value>
|
<value>Restore from remote (WebDAV)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||||
<value>Локально</value>
|
<value>Local</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||||
<value>Удалённо (WebDAV)</value>
|
<value>Remote (WebDAV)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavUrl" xml:space="preserve">
|
<data name="LvWebDavUrl" xml:space="preserve">
|
||||||
<value>URL WebDAV</value>
|
<value>WebDav Url</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavUserName" xml:space="preserve">
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
<value>Имя пользователя WebDAV</value>
|
<value>WebDav User Name</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavPassword" xml:space="preserve">
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
<value>Пароль WebDAV</value>
|
<value>WebDav Password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavCheck" xml:space="preserve">
|
<data name="LvWebDavCheck" xml:space="preserve">
|
||||||
<value>Проверить WebDAV</value>
|
<value>WebDav Check</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavDirName" xml:space="preserve">
|
<data name="LvWebDavDirName" xml:space="preserve">
|
||||||
<value>Имя удаленной папки (необязательно)</value>
|
<value>Имя удаленной папки (необязательно)</value>
|
||||||
|
@ -1285,16 +1285,16 @@
|
||||||
<value>Неверный файл резервной копии</value>
|
<value>Неверный файл резервной копии</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
||||||
<value>Фильтр хостов</value>
|
<value>Host filter</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipActiveServer" xml:space="preserve">
|
<data name="TipActiveServer" xml:space="preserve">
|
||||||
<value>Активный</value>
|
<value>Active</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 (необязательно)</value>
|
<value>Источник sing-box srs файлов</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
||||||
<value>Программы для обновления не существует</value>
|
<value>Программы для обновления не существует</value>
|
||||||
|
@ -1315,7 +1315,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 +1324,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 +1333,43 @@
|
||||||
<value>Вы уверены, что хотите выйти?</value>
|
<value>Вы уверены, что хотите выйти?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvMemo" xml:space="preserve">
|
<data name="LvMemo" xml:space="preserve">
|
||||||
<value>Заметка (Memo)</value>
|
<value>Remarks Memo</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
||||||
<value>Пароль sudo системы</value>
|
<value>System sudo password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>Введенный вами пароль не может быть подтвержден, поэтому убедитесь, что вы ввели его правильно. Если приложение не работает должным образом из-за неправильного ввода, то перезапустите его. Пароль не будет сохранен, и вам придется вводить его заново после каждого перезапуска</value>
|
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>Сначала задайте пароль sudo в настройках TUN-режима</value>
|
<value>Please set the sudo password in Tun mode settings first</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
||||||
<value>Не запускайте программу как суперпользователь</value>
|
<value>Пожалуйста, не запускайте программу как суперпользователь.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*XHTTP-режим</value>
|
<value>*xhttp mode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportExtraTip" xml:space="preserve">
|
<data name="TransportExtraTip" xml:space="preserve">
|
||||||
<value>Дополнительный XHTTP сырой JSON, формат: { XHTTPObject }</value>
|
<value>XHTTP Extra raw JSON, format: { 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>Количество одновременно выполняемых тестов при многоэтапном тестировании</value>
|
<value>The number of concurrent during multi-test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>Исключение. Не используйте прокси-сервер для адресов с запятой (,)</value>
|
<value>Исключение. Не используйте прокси-сервер для адресов с запятой (,)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||||
<value>Тип сниффинга</value>
|
<value>Sniffing type</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
||||||
<value>Включить второй смешанный порт</value>
|
<value>Enable second mixed port</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||||
<value>socks: локальный порт, socks2: второй локальный порт, socks3: LAN порт</value>
|
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTheme" xml:space="preserve">
|
<data name="TbSettingsTheme" xml:space="preserve">
|
||||||
<value>Темы</value>
|
<value>Темы</value>
|
||||||
|
@ -1378,7 +1378,7 @@
|
||||||
<value>Копировать команду прокси в буфер обмена</value>
|
<value>Копировать команду прокси в буфер обмена</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>Повторное тестирование неудачных элементов, осталось {0}. Нажмите ESC для остановки…</value>
|
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestServerResult" xml:space="preserve">
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
<value>По результату теста</value>
|
<value>По результату теста</value>
|
||||||
|
@ -1387,36 +1387,33 @@
|
||||||
<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>Заменит указанный порт, перечисляйте через запятую (,)</value>
|
<value>Will cover the port, separate with commas (,)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>От мультиконфигурации к пользовательской конфигурации</value>
|
<value>Multi-server to custom configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
||||||
<value>Случайный (Xray)</value>
|
<value>Multi-server Random by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>Круговой (Xray)</value>
|
<value>Multi-server RoundRobin by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>Минимальное RTT (минимальное время туда-обратно) (Xray)</value>
|
<value>Multi-server LeastPing by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>Минимальная нагрузка (Xray)</value>
|
<value>Multi-server LeastLoad by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>Минимальное RTT (минимальное время туда-обратно) (sing-box)</value>
|
<value>Multi-server LeastPing by sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>Экспортировать конфигурацию</value>
|
<value>Export server</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
|
||||||
<value>URL для тестирования текущего соединения</value>
|
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1413,7 +1413,4 @@
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>导出配置文件</value>
|
<value>导出配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
|
||||||
<value>当前连接信息测试地址</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</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>
|
||||||
|
@ -295,7 +295,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>
|
||||||
|
@ -481,7 +481,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 +517,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>
|
||||||
|
@ -892,7 +892,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 +1003,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>
|
||||||
|
@ -1102,10 +1102,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>
|
||||||
|
@ -1201,7 +1201,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 +1231,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 +1267,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,7 +1336,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>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
|
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
|
||||||
|
@ -1366,7 +1366,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 +1387,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,7 +1413,4 @@
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>匯出設定檔</value>
|
<value>匯出設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
|
||||||
<value>目前連接資訊測試地址</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</root>
|
|
@ -6,10 +6,11 @@
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"address": "1.1.1.1",
|
"address": "1.1.1.1",
|
||||||
"skipFallback": true,
|
|
||||||
"domains": [
|
"domains": [
|
||||||
"domain:googleapis.cn",
|
"geosite:geolocation-!cn"
|
||||||
"domain:gstatic.com"
|
],
|
||||||
|
"expectIPs": [
|
||||||
|
"geoip:!cn"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -22,7 +23,6 @@
|
||||||
"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"
|
||||||
]
|
]
|
||||||
|
|
|
@ -95,21 +95,6 @@ detect_desktop_environment() {
|
||||||
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
|
||||||
|
|
|
@ -336,7 +336,7 @@ public class CoreConfigSingboxService
|
||||||
await GenExperimental(singboxConfig);
|
await GenExperimental(singboxConfig);
|
||||||
singboxConfig.outbounds.RemoveAt(0);
|
singboxConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
var proxyProfiles = new List<ProfileItem>();
|
var tagProxy = new List<string>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
|
@ -370,18 +370,42 @@ public class CoreConfigSingboxService
|
||||||
}
|
}
|
||||||
|
|
||||||
//outbound
|
//outbound
|
||||||
proxyProfiles.Add(item);
|
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
|
await GenOutbound(item, outbound);
|
||||||
|
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||||
|
singboxConfig.outbounds.Insert(0, outbound);
|
||||||
|
tagProxy.Add(outbound.tag);
|
||||||
}
|
}
|
||||||
if (proxyProfiles.Count <= 0)
|
if (tagProxy.Count <= 0)
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
await GenOutboundsList(proxyProfiles, singboxConfig);
|
|
||||||
|
|
||||||
await GenDns(null, singboxConfig);
|
await GenDns(null, singboxConfig);
|
||||||
await ConvertGeo2Ruleset(singboxConfig);
|
await ConvertGeo2Ruleset(singboxConfig);
|
||||||
|
|
||||||
|
//add urltest outbound
|
||||||
|
var outUrltest = new Outbound4Sbox
|
||||||
|
{
|
||||||
|
type = "urltest",
|
||||||
|
tag = $"{Global.ProxyTag}-auto",
|
||||||
|
outbounds = tagProxy,
|
||||||
|
interrupt_exist_connections = false,
|
||||||
|
};
|
||||||
|
singboxConfig.outbounds.Insert(0, outUrltest);
|
||||||
|
|
||||||
|
//add selector outbound
|
||||||
|
var outSelector = new Outbound4Sbox
|
||||||
|
{
|
||||||
|
type = "selector",
|
||||||
|
tag = Global.ProxyTag,
|
||||||
|
outbounds = JsonUtils.DeepCopy(tagProxy),
|
||||||
|
interrupt_exist_connections = false,
|
||||||
|
};
|
||||||
|
outSelector.outbounds.Insert(0, outUrltest.tag);
|
||||||
|
singboxConfig.outbounds.Insert(0, outSelector);
|
||||||
|
|
||||||
ret.Success = true;
|
ret.Success = true;
|
||||||
ret.Data = JsonUtils.Serialize(singboxConfig);
|
ret.Data = JsonUtils.Serialize(singboxConfig);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -751,8 +775,7 @@ public class CoreConfigSingboxService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
|
if (_config.CoreBasicItem.MuxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty())
|
||||||
if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty())
|
|
||||||
{
|
{
|
||||||
var mux = new Multiplex4Sbox()
|
var mux = new Multiplex4Sbox()
|
||||||
{
|
{
|
||||||
|
@ -918,192 +941,37 @@ public class CoreConfigSingboxService
|
||||||
|
|
||||||
//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)
|
||||||
{
|
{
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
var prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
prevOutboundTag = $"prev-{Global.ProxyTag}";
|
prevOutbound.tag = $"{Global.ProxyTag}2";
|
||||||
prevOutbound.tag = prevOutboundTag;
|
|
||||||
singboxConfig.outbounds.Add(prevOutbound);
|
singboxConfig.outbounds.Add(prevOutbound);
|
||||||
}
|
|
||||||
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
|
|
||||||
|
|
||||||
if (nextOutbound is not null)
|
outbound.detour = prevOutbound.tag;
|
||||||
{
|
|
||||||
singboxConfig.outbounds.Insert(0, nextOutbound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Get outbound template and initialize lists
|
|
||||||
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
|
|
||||||
if (txtOutbound.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultOutbounds = new List<Outbound4Sbox>();
|
//Next proxy
|
||||||
var prevOutbounds = new List<Outbound4Sbox>(); // Separate list for prev outbounds
|
|
||||||
var proxyTags = new List<string>(); // For selector and urltest outbounds
|
|
||||||
|
|
||||||
// Cache for chain proxies to avoid duplicate generation
|
|
||||||
var nextProxyCache = new Dictionary<string, Outbound4Sbox?>();
|
|
||||||
var prevProxyTags = new Dictionary<string, string?>(); // Map from profile name to tag
|
|
||||||
int prevIndex = 0; // Index for prev outbounds
|
|
||||||
|
|
||||||
// Process each node
|
|
||||||
int index = 0;
|
|
||||||
foreach (var node in nodes)
|
|
||||||
{
|
|
||||||
index++;
|
|
||||||
|
|
||||||
// Handle proxy chain
|
|
||||||
string? prevTag = null;
|
|
||||||
var currentOutbound = JsonUtils.Deserialize<Outbound4Sbox>(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}";
|
|
||||||
proxyTags.Add(currentOutbound.tag);
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add urltest outbound (auto selection based on latency)
|
|
||||||
if (proxyTags.Count > 0)
|
|
||||||
{
|
|
||||||
var outUrltest = new Outbound4Sbox
|
|
||||||
{
|
|
||||||
type = "urltest",
|
|
||||||
tag = $"{Global.ProxyTag}-auto",
|
|
||||||
outbounds = proxyTags,
|
|
||||||
interrupt_exist_connections = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add selector outbound (manual selection)
|
|
||||||
var outSelector = new Outbound4Sbox
|
|
||||||
{
|
|
||||||
type = "selector",
|
|
||||||
tag = Global.ProxyTag,
|
|
||||||
outbounds = JsonUtils.DeepCopy(proxyTags),
|
|
||||||
interrupt_exist_connections = false,
|
|
||||||
};
|
|
||||||
outSelector.outbounds.Insert(0, outUrltest.tag);
|
|
||||||
|
|
||||||
// Insert these at the beginning
|
|
||||||
resultOutbounds.Insert(0, outUrltest);
|
|
||||||
resultOutbounds.Insert(0, outSelector);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge results: first the selector/urltest/proxies, then other outbounds, and finally prev outbounds
|
|
||||||
resultOutbounds.AddRange(prevOutbounds);
|
|
||||||
resultOutbounds.AddRange(singboxConfig.outbounds);
|
|
||||||
singboxConfig.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<Outbound4Sbox?> GenChainOutbounds(SubItem subItem, Outbound4Sbox outbound, string? prevOutboundTag, Outbound4Sbox? nextOutbound = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
|
|
||||||
|
|
||||||
if (!prevOutboundTag.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
outbound.detour = prevOutboundTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next proxy
|
|
||||||
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
||||||
if (nextNode is not null
|
if (nextNode is not null
|
||||||
&& nextNode.ConfigType != EConfigType.Custom)
|
&& nextNode.ConfigType != EConfigType.Custom)
|
||||||
{
|
{
|
||||||
if (nextOutbound == null)
|
var nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
{
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
nextOutbound.tag = Global.ProxyTag;
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
singboxConfig.outbounds.Insert(0, nextOutbound);
|
||||||
}
|
|
||||||
nextOutbound.tag = outbound.tag;
|
|
||||||
|
|
||||||
outbound.tag = $"mid-{outbound.tag}";
|
outbound.tag = $"{Global.ProxyTag}1";
|
||||||
nextOutbound.detour = outbound.tag;
|
nextOutbound.detour = outbound.tag;
|
||||||
}
|
}
|
||||||
return nextOutbound;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenRouting(SingboxConfig singboxConfig)
|
private async Task<int> GenRouting(SingboxConfig singboxConfig)
|
||||||
|
@ -1111,6 +979,26 @@ public class CoreConfigSingboxService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dnsOutbound = "dns_out";
|
var dnsOutbound = "dns_out";
|
||||||
|
if (!_config.Inbound.First().SniffingEnabled)
|
||||||
|
{
|
||||||
|
singboxConfig.route.rules.Add(new()
|
||||||
|
{
|
||||||
|
port = [53],
|
||||||
|
network = ["udp"],
|
||||||
|
outbound = dnsOutbound
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
singboxConfig.route.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
outbound = Global.DirectTag,
|
||||||
|
clash_mode = ERuleMode.Direct.ToString()
|
||||||
|
});
|
||||||
|
singboxConfig.route.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
outbound = Global.ProxyTag,
|
||||||
|
clash_mode = ERuleMode.Global.ToString()
|
||||||
|
});
|
||||||
|
|
||||||
if (_config.TunModeItem.EnableTun)
|
if (_config.TunModeItem.EnableTun)
|
||||||
{
|
{
|
||||||
|
@ -1137,27 +1025,6 @@ public class CoreConfigSingboxService
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_config.Inbound.First().SniffingEnabled)
|
|
||||||
{
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
port = [53],
|
|
||||||
network = ["udp"],
|
|
||||||
outbound = dnsOutbound
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
outbound = Global.DirectTag,
|
|
||||||
clash_mode = ERuleMode.Direct.ToString()
|
|
||||||
});
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
outbound = Global.ProxyTag,
|
|
||||||
clash_mode = ERuleMode.Global.ToString()
|
|
||||||
});
|
|
||||||
|
|
||||||
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||||
if (routing != null)
|
if (routing != null)
|
||||||
{
|
{
|
||||||
|
@ -1180,30 +1047,28 @@ public class CoreConfigSingboxService
|
||||||
|
|
||||||
private void GenRoutingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe)
|
private void GenRoutingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe)
|
||||||
{
|
{
|
||||||
var dnsExeSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
lstDnsExe = new();
|
||||||
var directExeSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
lstDirectExe = new();
|
||||||
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||||
var coreInfoResult = CoreInfoHandler.Instance.GetCoreInfo();
|
foreach (var it in coreInfo)
|
||||||
|
|
||||||
foreach (var coreConfig in coreInfoResult)
|
|
||||||
{
|
{
|
||||||
if (coreConfig.CoreType == ECoreType.v2rayN)
|
if (it.CoreType == ECoreType.v2rayN)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
foreach (var it2 in it.CoreExes)
|
||||||
foreach (var baseExeName in coreConfig.CoreExes)
|
|
||||||
{
|
{
|
||||||
if (coreConfig.CoreType != ECoreType.sing_box)
|
if (!lstDnsExe.Contains(it2) && it.CoreType != ECoreType.sing_box)
|
||||||
{
|
{
|
||||||
dnsExeSet.Add(Utils.GetExeName(baseExeName));
|
lstDnsExe.Add($"{it2}.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lstDirectExe.Contains(it2))
|
||||||
|
{
|
||||||
|
lstDirectExe.Add($"{it2}.exe");
|
||||||
}
|
}
|
||||||
directExeSet.Add(Utils.GetExeName(baseExeName));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lstDnsExe = new List<string>(dnsExeSet);
|
|
||||||
lstDirectExe = new List<string>(directExeSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
||||||
|
@ -1222,11 +1087,14 @@ public class CoreConfigSingboxService
|
||||||
|
|
||||||
if (item.Port.IsNotEmpty())
|
if (item.Port.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var portRanges = item.Port.Split(',').Where(it => it.Contains('-')).Select(it => it.Replace("-", ":")).ToList();
|
if (item.Port.Contains("-"))
|
||||||
var ports = item.Port.Split(',').Where(it => !it.Contains('-')).Select(it => it.ToInt()).ToList();
|
{
|
||||||
|
rule.port_range = new List<string> { item.Port.Replace("-", ":") };
|
||||||
rule.port_range = portRanges.Count > 0 ? portRanges : null;
|
}
|
||||||
rule.port = ports.Count > 0 ? ports : null;
|
else
|
||||||
|
{
|
||||||
|
rule.port = new List<int> { item.Port.ToInt() };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item.Network.IsNotEmpty())
|
if (item.Network.IsNotEmpty())
|
||||||
{
|
{
|
||||||
|
@ -1283,7 +1151,7 @@ public class CoreConfigSingboxService
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasDomainIp
|
if (!hasDomainIp
|
||||||
&& (rule.port != null || rule.port_range != null || rule.protocol != null || rule.inbound != null || rule.network != null))
|
&& (rule.port != null || rule.port_range != null || rule.protocol != null || rule.inbound != null))
|
||||||
{
|
{
|
||||||
rules.Add(rule);
|
rules.Add(rule);
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class CoreConfigV2rayService
|
||||||
await GenStatistic(v2rayConfig);
|
await GenStatistic(v2rayConfig);
|
||||||
v2rayConfig.outbounds.RemoveAt(0);
|
v2rayConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
var proxyProfiles = new List<ProfileItem>();
|
var tagProxy = new List<string>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
|
@ -151,14 +151,17 @@ public class CoreConfigV2rayService
|
||||||
}
|
}
|
||||||
|
|
||||||
//outbound
|
//outbound
|
||||||
proxyProfiles.Add(item);
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(item, outbound);
|
||||||
|
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||||
|
v2rayConfig.outbounds.Insert(0, outbound);
|
||||||
|
tagProxy.Add(outbound.tag);
|
||||||
}
|
}
|
||||||
if (proxyProfiles.Count <= 0)
|
if (tagProxy.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);
|
||||||
|
@ -325,7 +328,7 @@ public class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
listen = Global.Loopback,
|
listen = Global.Loopback,
|
||||||
port = port,
|
port = port,
|
||||||
protocol = EInboundProtocol.mixed.ToString(),
|
protocol = EInboundProtocol.socks.ToString(),
|
||||||
};
|
};
|
||||||
inbound.tag = inbound.protocol + inbound.port.ToString();
|
inbound.tag = inbound.protocol + inbound.port.ToString();
|
||||||
v2rayConfig.inbounds.Add(inbound);
|
v2rayConfig.inbounds.Add(inbound);
|
||||||
|
@ -400,7 +403,7 @@ public class CoreConfigV2rayService
|
||||||
tag = $"{EInboundProtocol.socks}{port}",
|
tag = $"{EInboundProtocol.socks}{port}",
|
||||||
listen = Global.Loopback,
|
listen = Global.Loopback,
|
||||||
port = port,
|
port = port,
|
||||||
protocol = EInboundProtocol.mixed.ToString(),
|
protocol = EInboundProtocol.socks.ToString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
|
@ -504,7 +507,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.mixed.ToString();
|
inbound.protocol = EInboundProtocol.socks.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;
|
||||||
|
@ -611,7 +614,6 @@ 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);
|
||||||
|
@ -631,7 +633,7 @@ public class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
|
var muxEnabled = _config.CoreBasicItem.MuxEnabled;
|
||||||
switch (node.ConfigType)
|
switch (node.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.VMess:
|
||||||
|
@ -1318,7 +1320,6 @@ 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
|
||||||
|
@ -1326,198 +1327,54 @@ public class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
prevOutboundTag = $"prev-{Global.ProxyTag}";
|
prevOutbound.tag = $"{Global.ProxyTag}2";
|
||||||
prevOutbound.tag = prevOutboundTag;
|
|
||||||
v2rayConfig.outbounds.Add(prevOutbound);
|
v2rayConfig.outbounds.Add(prevOutbound);
|
||||||
}
|
|
||||||
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
|
|
||||||
|
|
||||||
if (nextOutbound is not null)
|
|
||||||
{
|
|
||||||
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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()
|
outbound.streamSettings.sockopt = new()
|
||||||
{
|
{
|
||||||
dialerProxy = prevOutboundTag
|
dialerProxy = prevOutbound.tag
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next proxy
|
//Next proxy
|
||||||
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
||||||
if (nextNode is not null
|
if (nextNode is not null
|
||||||
&& nextNode.ConfigType != EConfigType.Custom
|
&& nextNode.ConfigType != EConfigType.Custom
|
||||||
&& nextNode.ConfigType != EConfigType.Hysteria2
|
&& nextNode.ConfigType != EConfigType.Hysteria2
|
||||||
&& nextNode.ConfigType != EConfigType.TUIC)
|
&& nextNode.ConfigType != EConfigType.TUIC)
|
||||||
{
|
{
|
||||||
if (nextOutbound == null)
|
var nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
{
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
nextOutbound.tag = Global.ProxyTag;
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
||||||
}
|
|
||||||
nextOutbound.tag = outbound.tag;
|
|
||||||
|
|
||||||
outbound.tag = $"mid-{outbound.tag}";
|
outbound.tag = $"{Global.ProxyTag}1";
|
||||||
nextOutbound.streamSettings.sockopt = new()
|
nextOutbound.streamSettings.sockopt = new()
|
||||||
{
|
{
|
||||||
dialerProxy = outbound.tag
|
dialerProxy = outbound.tag
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return nextOutbound;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
||||||
{
|
{
|
||||||
if (multipleLoad == EMultipleLoad.LeastPing)
|
if (multipleLoad is EMultipleLoad.LeastLoad or 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,7 +196,6 @@ public class SpeedtestService
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await Task.Delay(1000);
|
|
||||||
|
|
||||||
var downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
|
|
||||||
|
@ -256,13 +255,9 @@ public class SpeedtestService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
||||||
if (pid < 0)
|
if (pid > 0)
|
||||||
{
|
{
|
||||||
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
await Task.Delay(500);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Task.Delay(1000);
|
|
||||||
var delay = await DoRealPing(downloadHandle, it);
|
var delay = await DoRealPing(downloadHandle, it);
|
||||||
if (blSpeedTest)
|
if (blSpeedTest)
|
||||||
{
|
{
|
||||||
|
@ -276,6 +271,10 @@ public class SpeedtestService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -194,11 +194,11 @@ public class UpdateService
|
||||||
{
|
{
|
||||||
if (Utils.IsBase64String(result2))
|
if (Utils.IsBase64String(result2))
|
||||||
{
|
{
|
||||||
result += Environment.NewLine + Utils.Base64Decode(result2);
|
result += Utils.Base64Decode(result2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result += Environment.NewLine + result2;
|
result += result2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,6 +243,21 @@ 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)
|
||||||
|
@ -485,12 +500,6 @@ 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)
|
||||||
|
|
|
@ -552,7 +552,6 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
await LoadCore();
|
await LoadCore();
|
||||||
await SysProxyHandler.UpdateSysProxy(_config, false);
|
await SysProxyHandler.UpdateSysProxy(_config, false);
|
||||||
await Task.Delay(1000);
|
|
||||||
});
|
});
|
||||||
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,6 @@ 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
|
||||||
|
|
||||||
|
@ -187,7 +186,6 @@ 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
|
||||||
|
|
||||||
|
@ -346,7 +344,6 @@ 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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -320,7 +320,7 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
|
|
||||||
var msg = await Task.Run(async () =>
|
var msg = await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
return await ConnectionHandler.Instance.RunAvailabilityCheck();
|
return await (new UpdateService()).RunAvailabilityCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
NoticeHandler.Instance.SendMessageEx(msg);
|
NoticeHandler.Instance.SendMessageEx(msg);
|
||||||
|
@ -500,16 +500,8 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_config.IsRunningCore(ECoreType.sing_box))
|
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));
|
||||||
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"
|
||||||
Name="v2rayN"
|
|
||||||
x:DataType="vms:StatusBarViewModel"
|
x:DataType="vms:StatusBarViewModel"
|
||||||
|
Name="v2rayN"
|
||||||
RequestedThemeVariant="Default">
|
RequestedThemeVariant="Default">
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<semi:SemiTheme />
|
<semi:SemiTheme />
|
||||||
|
@ -32,8 +32,6 @@
|
||||||
ToolTipText="{Binding RunningServerToolTipText}">
|
ToolTipText="{Binding RunningServerToolTipText}">
|
||||||
<TrayIcon.Menu>
|
<TrayIcon.Menu>
|
||||||
<NativeMenu>
|
<NativeMenu>
|
||||||
<NativeMenuItem Command="{Binding NotifyLeftClickCmd}" Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}" />
|
|
||||||
<NativeMenuItemSeparator />
|
|
||||||
<NativeMenuItem
|
<NativeMenuItem
|
||||||
Command="{Binding SystemProxyClearCmd}"
|
Command="{Binding SystemProxyClearCmd}"
|
||||||
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
||||||
|
@ -57,11 +55,13 @@
|
||||||
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}" />
|
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
||||||
<NativeMenuItemSeparator />
|
<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,6 +11,11 @@ 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;
|
||||||
|
@ -38,7 +43,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!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
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 = 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,17 +14,13 @@ internal class Program
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
if (OnStartup(args) == false)
|
OnStartup(args);
|
||||||
{
|
|
||||||
Environment.Exit(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildAvaloniaApp()
|
BuildAvaloniaApp()
|
||||||
.StartWithClassicDesktopLifetime(args);
|
.StartWithClassicDesktopLifetime(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool OnStartup(string[]? Args)
|
private static void OnStartup(string[]? Args)
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
|
@ -34,7 +30,8 @@ internal class Program
|
||||||
if (!rebootas && !bCreatedNew)
|
if (!rebootas && !bCreatedNew)
|
||||||
{
|
{
|
||||||
ProgramStarted.Set();
|
ProgramStarted.Set();
|
||||||
return false;
|
Environment.Exit(0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -42,30 +39,19 @@ internal class Program
|
||||||
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
||||||
if (!bOnlyOneInstance)
|
if (!bOnlyOneInstance)
|
||||||
{
|
{
|
||||||
return false;
|
Environment.Exit(0);
|
||||||
|
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>()
|
||||||
return AppBuilder.Configure<App>()
|
.UsePlatformDetect()
|
||||||
.UsePlatformDetect()
|
//.WithInterFont()
|
||||||
//.WithInterFont()
|
.WithFontByDefault()
|
||||||
.WithFontByDefault()
|
.LogToTrace()
|
||||||
.LogToTrace()
|
.UseReactiveUI()
|
||||||
#if OS_OSX
|
.With(new MacOSPlatformOptions { ShowInDock = false });
|
||||||
.UseReactiveUI()
|
|
||||||
.With(new MacOSPlatformOptions { ShowInDock = AppHandler.Instance.Config.UiItem.MacOSShowInDock });
|
|
||||||
#else
|
|
||||||
.UseReactiveUI();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 : WindowBase<AddServer2ViewModel>
|
public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
||||||
{
|
{
|
||||||
public AddServer2Window()
|
public AddServer2Window()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -152,26 +152,13 @@
|
||||||
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,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -198,19 +185,6 @@
|
||||||
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"
|
||||||
|
@ -250,7 +224,7 @@
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto,Auto"
|
ColumnDefinitions="180,Auto,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -297,26 +271,13 @@
|
||||||
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,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -343,19 +304,6 @@
|
||||||
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"
|
||||||
|
|
|
@ -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 : WindowBase<AddServerViewModel>
|
public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
{
|
{
|
||||||
public AddServerWindow()
|
public AddServerWindow()
|
||||||
{
|
{
|
||||||
|
@ -150,13 +150,11 @@ public partial class AddServerWindow : WindowBase<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:
|
||||||
|
@ -169,13 +167,11 @@ public partial class AddServerWindow : WindowBase<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:
|
||||||
|
|
|
@ -52,16 +52,9 @@ public partial class ClashConnectionsView : ReactiveUserControl<ClashConnections
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstConnections.Columns)
|
||||||
{
|
{
|
||||||
foreach (var it in lstConnections.Columns)
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("ClashConnectionsView", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TabControl HorizontalContentAlignment="Stretch">
|
<TabControl HorizontalContentAlignment="Left">
|
||||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||||
|
@ -90,18 +90,16 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
|
|
||||||
<HeaderedContentControl
|
<Grid Margin="{StaticResource Margin4}">
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
Header="HTTP/SOCKS">
|
|
||||||
<TextBox
|
<TextBox
|
||||||
Name="txtnormalDNS"
|
x:Name="txtnormalDNS"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
MinLines="10"
|
TextWrapping="Wrap"
|
||||||
TextWrapping="Wrap" />
|
Watermark="HTTP/SOCKS" />
|
||||||
</HeaderedContentControl>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
@ -146,34 +144,31 @@
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
||||||
|
|
||||||
<HeaderedContentControl
|
<TextBox
|
||||||
|
x:Name="txtnormalDNS2"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
BorderBrush="Gray"
|
Width="400"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Header="HTTP/SOCKS">
|
Classes="TextArea"
|
||||||
<TextBox
|
Margin="{StaticResource Margin4}"
|
||||||
Name="txtnormalDNS2"
|
TextWrapping="Wrap"
|
||||||
VerticalAlignment="Stretch"
|
Watermark="HTTP/SOCKS" />
|
||||||
Classes="TextArea"
|
|
||||||
MinLines="10"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</HeaderedContentControl>
|
|
||||||
|
|
||||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||||
|
|
||||||
<HeaderedContentControl
|
<TextBox
|
||||||
|
x:Name="txttunDNS2"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
BorderBrush="Gray"
|
Width="400"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Header="{x:Static resx:ResUI.TbSettingsTunMode}">
|
Classes="TextArea"
|
||||||
<TextBox
|
Margin="{StaticResource Margin4}"
|
||||||
Name="txttunDNS2"
|
TextWrapping="Wrap"
|
||||||
VerticalAlignment="Stretch"
|
Watermark="{x:Static resx:ResUI.TbSettingsTunMode}" />
|
||||||
Classes="TextArea"
|
|
||||||
MinLines="10"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</HeaderedContentControl>
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
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;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
|
|
|
@ -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 : WindowBase<GlobalHotkeySettingViewModel>
|
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
||||||
{
|
{
|
||||||
private readonly List<object> _textBoxKeyEventItem = new();
|
private readonly List<object> _textBoxKeyEventItem = new();
|
||||||
|
|
||||||
|
|
|
@ -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 : WindowBase<MainWindowViewModel>
|
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
private WindowNotificationManager? _manager;
|
private WindowNotificationManager? _manager;
|
||||||
|
@ -29,7 +29,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_config = AppHandler.Instance.Config;
|
_config = AppHandler.Instance.Config;
|
||||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
|
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
|
||||||
|
|
||||||
this.KeyDown += MainWindow_KeyDown;
|
this.KeyDown += MainWindow_KeyDown;
|
||||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||||
|
@ -154,6 +154,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -387,7 +388,7 @@ public partial class MainWindow : WindowBase<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.Yes)
|
if (await UI.ShowYesNo(this, ResUI.menuExitTips) == ButtonResult.No)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -435,14 +436,14 @@ public partial class MainWindow : WindowBase<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)
|
||||||
|
@ -460,15 +461,18 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
|
|
||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
|
_config.UiItem.MainWidth = this.Width;
|
||||||
|
_config.UiItem.MainHeight = this.Height;
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
||||||
|
_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)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
||||||
|
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,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">
|
||||||
|
|
||||||
<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.TbSettingsIPAPIUrl}" />
|
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbIPAPIUrl"
|
x:Name="cmbSubConvertUrl"
|
||||||
Grid.Row="20"
|
Grid.Row="20"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
|
@ -588,41 +588,28 @@
|
||||||
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="22"
|
Grid.Row="21"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
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="23"
|
Grid.Row="22"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -630,19 +617,19 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="23"
|
||||||
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="24"
|
Grid.Row="23"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="23"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -650,25 +637,24 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="25"
|
Grid.Row="24"
|
||||||
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="25"
|
Grid.Row="24"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="25"
|
Grid.Row="24"
|
||||||
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>
|
||||||
|
|
|
@ -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 : WindowBase<OptionSettingViewModel>
|
public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
|
@ -92,10 +92,6 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||||
{
|
{
|
||||||
cmbRoutingRulesSourceUrl.Items.Add(it);
|
cmbRoutingRulesSourceUrl.Items.Add(it);
|
||||||
});
|
});
|
||||||
Global.IPAPIUrls.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbIPAPIUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
||||||
{
|
{
|
||||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
cmbMainGirdOrientation.Items.Add(it.ToString());
|
||||||
|
@ -147,7 +143,6 @@ public partial class OptionSettingWindow : WindowBase<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);
|
||||||
|
|
|
@ -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.Yes)
|
if (await UI.ShowYesNo(_window, ResUI.RemoveServer) == ButtonResult.No)
|
||||||
{
|
{
|
||||||
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,34 +345,9 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstProfiles.Columns)
|
||||||
{
|
{
|
||||||
//First scroll horizontally to the initial position to avoid the control crash bug
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 : WindowBase<RoutingRuleDetailsViewModel>
|
public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetailsViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleDetailsWindow()
|
public RoutingRuleDetailsWindow()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 : WindowBase<RoutingRuleSettingViewModel>
|
public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettingViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleSettingWindow()
|
public RoutingRuleSettingWindow()
|
||||||
{
|
{
|
||||||
|
@ -80,14 +80,14 @@ public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingVie
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) != ButtonResult.Yes)
|
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.AddBatchRoutingRulesYesNo:
|
case EViewAction.AddBatchRoutingRulesYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.AddBatchRoutingRulesYesNo) != ButtonResult.Yes)
|
if (await UI.ShowYesNo(this, ResUI.AddBatchRoutingRulesYesNo) == ButtonResult.No)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,28 @@
|
||||||
<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
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
@ -52,112 +69,58 @@
|
||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid
|
<DockPanel>
|
||||||
Margin="{StaticResource Margin4}"
|
<TabControl x:Name="tabAdvanced">
|
||||||
ColumnDefinitions="Auto,Auto"
|
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||||
DockPanel.Dock="Top"
|
<DataGrid
|
||||||
RowDefinitions="Auto,Auto,Auto">
|
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>
|
||||||
|
|
||||||
<TextBlock
|
<DataGrid.Columns>
|
||||||
Grid.Row="0"
|
<DataGridCheckBoxColumn Width="40" Binding="{Binding IsActive}" />
|
||||||
Grid.Column="0"
|
<DataGridTextColumn
|
||||||
Margin="{StaticResource Margin4}"
|
Width="*"
|
||||||
VerticalAlignment="Center">
|
Binding="{Binding Remarks}"
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy_Click">
|
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
<DataGridTextColumn
|
||||||
</HyperlinkButton>
|
Width="60"
|
||||||
</TextBlock>
|
Binding="{Binding RuleNum}"
|
||||||
<ComboBox
|
Header="{x:Static resx:ResUI.LvCount}" />
|
||||||
x:Name="cmbdomainStrategy"
|
<DataGridTextColumn
|
||||||
Grid.Row="0"
|
Width="60"
|
||||||
Grid.Column="1"
|
Binding="{Binding Sort}"
|
||||||
Width="300"
|
Header="{x:Static resx:ResUI.LvSort}" />
|
||||||
Margin="{StaticResource Margin4}"
|
<DataGridTextColumn
|
||||||
HorizontalAlignment="Left"
|
Width="*"
|
||||||
VerticalAlignment="Center" />
|
Binding="{Binding Url}"
|
||||||
|
Header="{x:Static resx:ResUI.LvUrl}" />
|
||||||
<TextBlock
|
<DataGridTextColumn
|
||||||
Grid.Row="1"
|
Width="300"
|
||||||
Grid.Column="0"
|
Binding="{Binding CustomIcon}"
|
||||||
Margin="{StaticResource Margin4}"
|
Header="{x:Static resx:ResUI.LvCustomIcon}" />
|
||||||
VerticalAlignment="Center"
|
</DataGrid.Columns>
|
||||||
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
</DataGrid>
|
||||||
<ComboBox
|
</TabItem>
|
||||||
x:Name="cmbdomainMatcher"
|
</TabControl>
|
||||||
Grid.Row="1"
|
</DockPanel>
|
||||||
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 : WindowBase<RoutingSettingViewModel>
|
public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveRules) != ButtonResult.Yes)
|
if (await UI.ShowYesNo(this, ResUI.RemoveRules) == ButtonResult.No)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 : WindowBase<SubEditViewModel>
|
public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
||||||
{
|
{
|
||||||
public SubEditWindow()
|
public SubEditWindow()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 : WindowBase<SubSettingViewModel>
|
public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.ShowYesNo:
|
case EViewAction.ShowYesNo:
|
||||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) != ButtonResult.Yes)
|
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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="CanResize" />
|
<Setter Property="ResizeMode" Value="NoResize" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ViewGlobal"
|
x:Key="ViewGlobal"
|
||||||
|
|
|
@ -56,7 +56,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!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
using System.Windows;
|
|
||||||
using ReactiveUI;
|
|
||||||
|
|
||||||
namespace v2rayN.Base;
|
|
||||||
|
|
||||||
public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewModel : class
|
|
||||||
{
|
|
||||||
public WindowBase()
|
|
||||||
{
|
|
||||||
Loaded += OnLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnLoaded(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var sizeItem = ConfigHandler.GetWindowSizeItem(AppHandler.Instance.Config, GetType().Name);
|
|
||||||
if (sizeItem == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Width = Math.Min(sizeItem.Width, SystemParameters.WorkArea.Width);
|
|
||||||
Height = Math.Min(sizeItem.Height, SystemParameters.WorkArea.Height);
|
|
||||||
|
|
||||||
Left = SystemParameters.WorkArea.Left + ((SystemParameters.WorkArea.Width - Width) / 2);
|
|
||||||
Top = SystemParameters.WorkArea.Top + ((SystemParameters.WorkArea.Height - Height) / 2);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
|
||||||
{
|
|
||||||
base.OnClosed(e);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ConfigHandler.SaveWindowSizeItem(AppHandler.Instance.Config, GetType().Name, Width, Height);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.AddServer2Window"
|
x:Class="v2rayN.Views.AddServer2Window"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -199,4 +198,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.AddServerWindow"
|
x:Class="v2rayN.Views.AddServerWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -156,7 +155,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -216,20 +214,6 @@
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSs"
|
x:Name="gridSs"
|
||||||
|
@ -240,7 +224,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -276,20 +259,6 @@
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled3"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSocks"
|
x:Name="gridSocks"
|
||||||
|
@ -345,7 +314,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -405,20 +373,6 @@
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Style="{StaticResource DefTextBox}" />
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled5"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridTrojan"
|
x:Name="gridTrojan"
|
||||||
|
@ -429,7 +383,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -465,20 +418,6 @@
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled6"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridHysteria2"
|
x:Name="gridHysteria2"
|
||||||
|
@ -1072,4 +1011,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -144,13 +144,11 @@ public partial class AddServerWindow
|
||||||
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.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.Text).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.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
|
@ -163,13 +161,11 @@ public partial class AddServerWindow
|
||||||
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.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.Text).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.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled6.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
|
|
|
@ -55,16 +55,9 @@ public partial class ClashConnectionsView
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstConnections.Columns)
|
||||||
{
|
{
|
||||||
foreach (var it in lstConnections.Columns)
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("ClashConnectionsView", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.DNSSettingWindow"
|
x:Class="v2rayN.Views.DNSSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -205,4 +204,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
|
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -170,4 +169,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.MainWindow"
|
x:Class="v2rayN.Views.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -41,8 +40,8 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
KeyboardNavigation.TabNavigation="Continue"
|
Style="{StaticResource MaterialDesignToolBar}"
|
||||||
Style="{StaticResource MaterialDesignToolBar}">
|
KeyboardNavigation.TabNavigation="Continue">
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem Padding="8,0" AutomationProperties.Name="{x:Static resx:ResUI.menuServers}">
|
<MenuItem Padding="8,0" AutomationProperties.Name="{x:Static resx:ResUI.menuServers}">
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
|
@ -433,4 +432,4 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -139,6 +139,7 @@ public partial class MainWindow
|
||||||
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
|
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RestoreUI();
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
|
WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
|
||||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||||
|
@ -394,14 +395,20 @@ public partial class MainWindow
|
||||||
_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxWidth = SystemParameters.WorkArea.Width;
|
||||||
|
var maxHeight = SystemParameters.WorkArea.Height;
|
||||||
|
if (Width > maxWidth)
|
||||||
|
Width = maxWidth;
|
||||||
|
if (Height > maxHeight)
|
||||||
|
Height = maxHeight;
|
||||||
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)
|
||||||
|
@ -419,15 +426,18 @@ public partial class MainWindow
|
||||||
|
|
||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
|
_config.UiItem.MainWidth = this.Width;
|
||||||
|
_config.UiItem.MainHeight = this.Height;
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
||||||
|
_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)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
||||||
|
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.OptionSettingWindow"
|
x:Class="v2rayN.Views.OptionSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -553,7 +552,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
@ -847,26 +845,10 @@
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
|
||||||
<ComboBox
|
|
||||||
x:Name="cmbIPAPIUrl"
|
|
||||||
Grid.Row="20"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="300"
|
|
||||||
Margin="{StaticResource Margin8}"
|
|
||||||
IsEditable="True"
|
|
||||||
Style="{StaticResource DefComboBox}" />
|
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="21"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin8}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSubConvertUrl"
|
x:Name="cmbSubConvertUrl"
|
||||||
Grid.Row="21"
|
Grid.Row="20"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
|
@ -875,7 +857,7 @@
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="21"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -883,14 +865,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="22"
|
Grid.Row="21"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -898,14 +880,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbGetFilesSourceUrl"
|
x:Name="cmbGetFilesSourceUrl"
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -914,7 +896,7 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="23"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -922,14 +904,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSrsFilesSourceUrl"
|
x:Name="cmbSrsFilesSourceUrl"
|
||||||
Grid.Row="24"
|
Grid.Row="23"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="23"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -938,7 +920,7 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="25"
|
Grid.Row="24"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -946,14 +928,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRoutingRulesSourceUrl"
|
x:Name="cmbRoutingRulesSourceUrl"
|
||||||
Grid.Row="25"
|
Grid.Row="24"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="25"
|
Grid.Row="24"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -1230,4 +1212,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -101,10 +101,6 @@ public partial class OptionSettingWindow
|
||||||
{
|
{
|
||||||
cmbRoutingRulesSourceUrl.Items.Add(it);
|
cmbRoutingRulesSourceUrl.Items.Add(it);
|
||||||
});
|
});
|
||||||
Global.IPAPIUrls.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbIPAPIUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
||||||
{
|
{
|
||||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
cmbMainGirdOrientation.Items.Add(it.ToString());
|
||||||
|
@ -166,7 +162,6 @@ public partial class OptionSettingWindow
|
||||||
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.IPAPIUrl, v => v.cmbIPAPIUrl.Text).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.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
||||||
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
||||||
|
<Style x:Key="AccessibleMyChipListBoxItem" TargetType="ListBoxItem" BasedOn="{StaticResource MyChipListBoxItem}">
|
||||||
|
<Setter Property="AutomationProperties.Name" Value="{Binding Remarks}" />
|
||||||
|
</Style>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
|
@ -25,10 +28,10 @@
|
||||||
<ListBox
|
<ListBox
|
||||||
x:Name="lstGroup"
|
x:Name="lstGroup"
|
||||||
MaxHeight="200"
|
MaxHeight="200"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}"
|
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
|
ItemContainerStyle="{StaticResource AccessibleMyChipListBoxItem}"
|
||||||
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding Remarks}" />
|
<TextBlock Text="{Binding Remarks}" />
|
||||||
|
|
|
@ -323,16 +323,9 @@ public partial class ProfilesView
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstProfiles.Columns)
|
||||||
{
|
{
|
||||||
foreach (var it in lstProfiles.Columns)
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("ProfilesView", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
|
x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -243,4 +242,4 @@
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.RoutingRuleSettingWindow"
|
x:Class="v2rayN.Views.RoutingRuleSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -335,4 +334,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.RoutingSettingWindow"
|
x:Class="v2rayN.Views.RoutingSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -30,25 +29,68 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Style="{StaticResource MaterialDesignToolBar}">
|
Style="{StaticResource MaterialDesignToolBar}">
|
||||||
<Button x:Name="menuRoutingAdvancedAdd2">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<MenuItem x:Name="menuRoutingAdvanced" Padding="8,0">
|
||||||
<materialDesign:PackIcon
|
<MenuItem.Header>
|
||||||
Margin="{StaticResource MarginRight8}"
|
<StackPanel Orientation="Horizontal">
|
||||||
VerticalAlignment="Center"
|
<materialDesign:PackIcon
|
||||||
Kind="Plus" />
|
Margin="{StaticResource MarginRight8}"
|
||||||
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
VerticalAlignment="Center"
|
||||||
</StackPanel>
|
Kind="Routes" />
|
||||||
</Button>
|
<TextBlock Text="{x:Static resx:ResUI.menuRoutingAdvanced}" />
|
||||||
|
</StackPanel>
|
||||||
|
</MenuItem.Header>
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRoutingAdvancedAdd2"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRoutingAdvancedImportRules2"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Button x:Name="menuRoutingAdvancedImportRules2">
|
<TextBlock
|
||||||
<StackPanel Orientation="Horizontal">
|
Margin="{StaticResource MarginLeft8}"
|
||||||
<materialDesign:PackIcon
|
VerticalAlignment="Center"
|
||||||
Margin="{StaticResource MarginRight8}"
|
Style="{StaticResource ToolbarTextBlock}">
|
||||||
VerticalAlignment="Center"
|
<Hyperlink Click="linkdomainStrategy_Click">
|
||||||
Kind="Import" />
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||||
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
<materialDesign:PackIcon Kind="Link" />
|
||||||
</StackPanel>
|
</Hyperlink>
|
||||||
</Button>
|
</TextBlock>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy"
|
||||||
|
Width="110"
|
||||||
|
Margin="{StaticResource MarginLeft8}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
<Separator />
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource MarginLeft8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainMatcher"
|
||||||
|
Width="60"
|
||||||
|
Margin="{StaticResource MarginLeft8}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
<Separator />
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource MarginLeft8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}">
|
||||||
|
<Hyperlink Click="linkdomainStrategy4Singbox_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||||
|
<materialDesign:PackIcon Kind="Link" />
|
||||||
|
</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy4Singbox"
|
||||||
|
Width="100"
|
||||||
|
Margin="{StaticResource MarginLeft8}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
</ToolBarTray>
|
</ToolBarTray>
|
||||||
|
|
||||||
|
@ -80,145 +122,82 @@
|
||||||
Style="{StaticResource DefButton}" />
|
Style="{StaticResource DefButton}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin8}" DockPanel.Dock="Top">
|
<DockPanel>
|
||||||
<Grid.RowDefinitions>
|
<TabControl x:Name="tabAdvanced">
|
||||||
<RowDefinition Height="Auto" />
|
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||||
<RowDefinition Height="Auto" />
|
<DataGrid
|
||||||
<RowDefinition Height="Auto" />
|
x:Name="lstRoutings"
|
||||||
</Grid.RowDefinitions>
|
AutoGenerateColumns="False"
|
||||||
<Grid.ColumnDefinitions>
|
BorderThickness="1"
|
||||||
<ColumnDefinition Width="Auto" />
|
CanUserAddRows="False"
|
||||||
<ColumnDefinition Width="Auto" />
|
CanUserResizeRows="False"
|
||||||
</Grid.ColumnDefinitions>
|
CanUserSortColumns="False"
|
||||||
|
EnableRowVirtualization="True"
|
||||||
<TextBlock
|
GridLinesVisibility="All"
|
||||||
Grid.Row="0"
|
HeadersVisibility="Column"
|
||||||
Grid.Column="0"
|
IsReadOnly="True"
|
||||||
Margin="{StaticResource Margin4}"
|
Style="{StaticResource DefDataGrid}">
|
||||||
VerticalAlignment="Center"
|
<DataGrid.ContextMenu>
|
||||||
Style="{StaticResource ToolbarTextBlock}">
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
<Hyperlink Click="linkdomainStrategy_Click">
|
<MenuItem
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
x:Name="menuRoutingAdvancedAdd"
|
||||||
<materialDesign:PackIcon Kind="Link" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
</Hyperlink>
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
</TextBlock>
|
<MenuItem
|
||||||
<ComboBox
|
x:Name="menuRoutingAdvancedRemove"
|
||||||
x:Name="cmbdomainStrategy"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Grid.Row="0"
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" />
|
||||||
Grid.Column="1"
|
<MenuItem
|
||||||
Width="300"
|
x:Name="menuRoutingAdvancedSelectAll"
|
||||||
Margin="{StaticResource Margin4}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||||
|
<MenuItem
|
||||||
<TextBlock
|
x:Name="menuRoutingAdvancedSetDefault"
|
||||||
Grid.Row="1"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Grid.Column="0"
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}" />
|
||||||
Margin="{StaticResource Margin4}"
|
<Separator />
|
||||||
VerticalAlignment="Center"
|
<MenuItem
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
x:Name="menuRoutingAdvancedImportRules"
|
||||||
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<ComboBox
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
x:Name="cmbdomainMatcher"
|
</ContextMenu>
|
||||||
Grid.Row="1"
|
</DataGrid.ContextMenu>
|
||||||
Grid.Column="1"
|
<DataGrid.Resources>
|
||||||
Width="300"
|
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
|
||||||
Margin="{StaticResource Margin4}"
|
<Style.Triggers>
|
||||||
Style="{StaticResource DefComboBox}" />
|
<DataTrigger Binding="{Binding IsActive}" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
<TextBlock
|
<Setter Property="Foreground" Value="Black" />
|
||||||
Grid.Row="2"
|
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
Grid.Column="0"
|
</DataTrigger>
|
||||||
Margin="{StaticResource Margin4}"
|
</Style.Triggers>
|
||||||
VerticalAlignment="Center"
|
</Style>
|
||||||
Style="{StaticResource ToolbarTextBlock}">
|
</DataGrid.Resources>
|
||||||
<Hyperlink Click="linkdomainStrategy4Singbox_Click">
|
<DataGrid.Columns>
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
<DataGridTextColumn
|
||||||
<materialDesign:PackIcon Kind="Link" />
|
Width="*"
|
||||||
</Hyperlink>
|
Binding="{Binding Remarks}"
|
||||||
</TextBlock>
|
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
<ComboBox
|
<DataGridTextColumn
|
||||||
x:Name="cmbdomainStrategy4Singbox"
|
Width="60"
|
||||||
Grid.Row="2"
|
Binding="{Binding RuleNum}"
|
||||||
Grid.Column="1"
|
Header="{x:Static resx:ResUI.LvCount}" />
|
||||||
Width="300"
|
<DataGridTextColumn
|
||||||
Margin="{StaticResource Margin4}"
|
Width="60"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Binding="{Binding Sort}"
|
||||||
</Grid>
|
Header="{x:Static resx:ResUI.LvSort}" />
|
||||||
|
<DataGridTextColumn
|
||||||
<TabControl x:Name="tabAdvanced">
|
Width="*"
|
||||||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
Binding="{Binding Url}"
|
||||||
<DataGrid
|
Header="{x:Static resx:ResUI.LvUrl}" />
|
||||||
x:Name="lstRoutings"
|
<DataGridTextColumn
|
||||||
AutoGenerateColumns="False"
|
Width="300"
|
||||||
BorderThickness="1"
|
Binding="{Binding CustomIcon}"
|
||||||
CanUserAddRows="False"
|
Header="{x:Static resx:ResUI.LvCustomIcon}" />
|
||||||
CanUserResizeRows="False"
|
</DataGrid.Columns>
|
||||||
CanUserSortColumns="False"
|
</DataGrid>
|
||||||
EnableRowVirtualization="True"
|
</TabItem>
|
||||||
GridLinesVisibility="All"
|
</TabControl>
|
||||||
HeadersVisibility="Column"
|
</DockPanel>
|
||||||
IsReadOnly="True"
|
|
||||||
Style="{StaticResource DefDataGrid}">
|
|
||||||
<DataGrid.ContextMenu>
|
|
||||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuRoutingAdvancedAdd"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuRoutingAdvancedRemove"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" />
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuRoutingAdvancedSelectAll"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuRoutingAdvancedSetDefault"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}" />
|
|
||||||
<Separator />
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuRoutingAdvancedImportRules"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
|
||||||
</ContextMenu>
|
|
||||||
</DataGrid.ContextMenu>
|
|
||||||
<DataGrid.Resources>
|
|
||||||
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
|
|
||||||
<Style.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding IsActive}" Value="True">
|
|
||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
|
||||||
<Setter Property="Foreground" Value="Black" />
|
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
|
||||||
</DataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</DataGrid.Resources>
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<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>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
|
@ -93,6 +93,11 @@
|
||||||
DisplayMemberPath="Remarks"
|
DisplayMemberPath="Remarks"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFloatingHintComboBox}">
|
Style="{StaticResource MaterialDesignFloatingHintComboBox}">
|
||||||
|
<ComboBox.ItemContainerStyle>
|
||||||
|
<Style TargetType="ComboBoxItem">
|
||||||
|
<Setter Property="AutomationProperties.Name" Value="{Binding Remarks}" />
|
||||||
|
</Style>
|
||||||
|
</ComboBox.ItemContainerStyle>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
@ -186,6 +191,11 @@
|
||||||
DisplayMemberPath="Remarks"
|
DisplayMemberPath="Remarks"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFilledComboBox}">
|
Style="{StaticResource MaterialDesignFilledComboBox}">
|
||||||
|
<ComboBox.ItemContainerStyle>
|
||||||
|
<Style TargetType="ComboBoxItem">
|
||||||
|
<Setter Property="AutomationProperties.Name" Value="{Binding Remarks}" />
|
||||||
|
</Style>
|
||||||
|
</ComboBox.ItemContainerStyle>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
|
@ -201,6 +211,11 @@
|
||||||
DisplayMemberPath="Text"
|
DisplayMemberPath="Text"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFilledComboBox}">
|
Style="{StaticResource MaterialDesignFilledComboBox}">
|
||||||
|
<ComboBox.ItemContainerStyle>
|
||||||
|
<Style TargetType="ComboBoxItem">
|
||||||
|
<Setter Property="AutomationProperties.Name" Value="{Binding Text}" />
|
||||||
|
</Style>
|
||||||
|
</ComboBox.ItemContainerStyle>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.SubEditWindow"
|
x:Class="v2rayN.Views.SubEditWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -316,4 +315,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.SubSettingWindow"
|
x:Class="v2rayN.Views.SubSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -121,4 +120,4 @@
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
Loading…
Reference in a new issue