mirror of
https://github.com/2dust/v2rayN.git
synced 2025-11-29 19:23:11 +00:00
sync upstream/master
This commit is contained in:
commit
c133f5c533
87 changed files with 1848 additions and 1584 deletions
12
.github/workflows/winget-publish.yml
vendored
12
.github/workflows/winget-publish.yml
vendored
|
|
@ -22,10 +22,18 @@ jobs:
|
||||||
$github = Invoke-RestMethod -uri "https://api.github.com/repos/cg3s/v2rayN/releases"
|
$github = Invoke-RestMethod -uri "https://api.github.com/repos/cg3s/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
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.12.5</Version>
|
<Version>7.13.3</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,24 @@
|
||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.2" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.2" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.2" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.2" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.8.2" />
|
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||||
<PackageVersion Include="Downloader" Version="3.3.4" />
|
<PackageVersion Include="Downloader" Version="4.0.2" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
||||||
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||||
<PackageVersion Include="QRCoder" Version="1.6.0" />
|
<PackageVersion Include="QRCoder" Version="1.6.0" />
|
||||||
<PackageVersion Include="ReactiveUI" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI" Version="20.4.1" />
|
||||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
|
||||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.7" />
|
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.9" />
|
||||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.7" />
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.9" />
|
||||||
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
<PackageVersion Include="Splat.NLog" Version="15.4.1" />
|
||||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
|
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
||||||
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
||||||
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
||||||
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
||||||
|
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace ServiceLib.Common;
|
|
||||||
|
|
||||||
public class AesUtils
|
|
||||||
{
|
|
||||||
private const int KeySize = 256; // AES-256
|
|
||||||
private const int IvSize = 16; // AES block size
|
|
||||||
private const int Iterations = 10000;
|
|
||||||
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' '));
|
|
||||||
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">Plain text</param>
|
|
||||||
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
|
||||||
/// <returns>Base64 encoded cipher text with IV</returns>
|
|
||||||
public static string Encrypt(string text, string? password = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(text))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var plaintext = Encoding.UTF8.GetBytes(text);
|
|
||||||
var key = GetKey(password);
|
|
||||||
var iv = GenerateIv();
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
|
||||||
aes.Key = key;
|
|
||||||
aes.IV = iv;
|
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
ms.Write(iv, 0, iv.Length);
|
|
||||||
|
|
||||||
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cs.Write(plaintext, 0, plaintext.Length);
|
|
||||||
cs.FlushFinalBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
var cipherTextWithIv = ms.ToArray();
|
|
||||||
return Convert.ToBase64String(cipherTextWithIv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
|
|
||||||
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
|
||||||
/// <returns>Plain text</returns>
|
|
||||||
public static string Decrypt(string cipherTextWithIv, string? password = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(cipherTextWithIv))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
|
|
||||||
var key = GetKey(password);
|
|
||||||
|
|
||||||
var iv = new byte[IvSize];
|
|
||||||
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
|
|
||||||
|
|
||||||
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
|
|
||||||
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
|
|
||||||
|
|
||||||
using var aes = Aes.Create();
|
|
||||||
aes.Key = key;
|
|
||||||
aes.IV = iv;
|
|
||||||
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
|
||||||
{
|
|
||||||
cs.Write(cipherText, 0, cipherText.Length);
|
|
||||||
cs.FlushFinalBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
var plainText = ms.ToArray();
|
|
||||||
return Encoding.UTF8.GetString(plainText);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] GetKey(string? password)
|
|
||||||
{
|
|
||||||
if (password.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
password = DefaultPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
|
|
||||||
return pbkdf2.GetBytes(KeySize / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] GenerateIv()
|
|
||||||
{
|
|
||||||
var randomNumber = new byte[IvSize];
|
|
||||||
|
|
||||||
using var rng = RandomNumberGenerator.Create();
|
|
||||||
rng.GetBytes(randomNumber);
|
|
||||||
return randomNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace ServiceLib.Common;
|
|
||||||
|
|
||||||
public class DesUtils
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text"></param>
|
|
||||||
/// /// <param name="key"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Encrypt(string? text, string? key = null)
|
|
||||||
{
|
|
||||||
if (text.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
|
||||||
var dsp = DES.Create();
|
|
||||||
using var memStream = new MemoryStream();
|
|
||||||
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
|
||||||
using var sWriter = new StreamWriter(cryStream);
|
|
||||||
sWriter.Write(text);
|
|
||||||
sWriter.Flush();
|
|
||||||
cryStream.FlushFinalBlock();
|
|
||||||
memStream.Flush();
|
|
||||||
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypt
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptText"></param>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string Decrypt(string? encryptText, string? key = null)
|
|
||||||
{
|
|
||||||
if (encryptText.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
|
||||||
var dsp = DES.Create();
|
|
||||||
var buffer = Convert.FromBase64String(encryptText);
|
|
||||||
|
|
||||||
using var memStream = new MemoryStream();
|
|
||||||
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
|
||||||
cryStream.Write(buffer, 0, buffer.Length);
|
|
||||||
cryStream.FlushFinalBlock();
|
|
||||||
return Encoding.UTF8.GetString(memStream.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
|
|
||||||
{
|
|
||||||
if (key.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("The key cannot be null");
|
|
||||||
}
|
|
||||||
if (key.Length <= 8)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
|
|
||||||
}
|
|
||||||
|
|
||||||
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
|
|
||||||
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetDefaultKey()
|
|
||||||
{
|
|
||||||
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -26,7 +26,7 @@ public class DownloaderHelper
|
||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
MaxTryAgainOnFailover = 2,
|
MaxTryAgainOnFailure = 2,
|
||||||
RequestConfiguration =
|
RequestConfiguration =
|
||||||
{
|
{
|
||||||
Headers = headers,
|
Headers = headers,
|
||||||
|
|
@ -64,7 +64,7 @@ public class DownloaderHelper
|
||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
MaxTryAgainOnFailover = 2,
|
MaxTryAgainOnFailure = 2,
|
||||||
RequestConfiguration =
|
RequestConfiguration =
|
||||||
{
|
{
|
||||||
Timeout= timeout * 1000,
|
Timeout= timeout * 1000,
|
||||||
|
|
@ -135,7 +135,7 @@ public class DownloaderHelper
|
||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
MaxTryAgainOnFailover = 2,
|
MaxTryAgainOnFailure = 2,
|
||||||
RequestConfiguration =
|
RequestConfiguration =
|
||||||
{
|
{
|
||||||
Timeout= timeout * 1000,
|
Timeout= timeout * 1000,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace ServiceLib.Common;
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
public static class StringEx
|
public static class Extension
|
||||||
{
|
{
|
||||||
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
||||||
{
|
{
|
||||||
|
|
@ -79,4 +79,9 @@ public static class StringEx
|
||||||
{
|
{
|
||||||
return int.TryParse(value, out var result) ? result : defaultValue;
|
return int.TryParse(value, out var result) ? result : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<string> AppendEmpty(this IEnumerable<string> source)
|
||||||
|
{
|
||||||
|
return source.Concat(new[] { string.Empty }).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -323,6 +323,14 @@ public class Utils
|
||||||
return text.Replace(",", ",").Replace(Environment.NewLine, ",");
|
return text.Replace(",", ",").Replace(Environment.NewLine, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<string> GetEnumNames<TEnum>() where TEnum : Enum
|
||||||
|
{
|
||||||
|
return Enum.GetValues(typeof(TEnum))
|
||||||
|
.Cast<TEnum>()
|
||||||
|
.Select(e => e.ToString())
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion 转换函数
|
#endregion 转换函数
|
||||||
|
|
||||||
#region 数据检查
|
#region 数据检查
|
||||||
|
|
@ -582,7 +590,7 @@ public class Utils
|
||||||
var result = await cmd.ExecuteBufferedAsync();
|
var result = await cmd.ExecuteBufferedAsync();
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
{
|
{
|
||||||
return result.StandardOutput.ToString();
|
return result.StandardOutput ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.SaveLog(result.ToString() ?? "");
|
Logging.SaveLog(result.ToString() ?? "");
|
||||||
|
|
@ -816,18 +824,6 @@ public class Utils
|
||||||
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
|
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// var id = GetLinuxUserId().Result ?? "1000";
|
|
||||||
// if (int.TryParse(id, out var userId))
|
|
||||||
// {
|
|
||||||
// return userId == 0;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string?> GetLinuxUserId()
|
private static async Task<string?> GetLinuxUserId()
|
||||||
|
|
@ -839,14 +835,46 @@ public class Utils
|
||||||
public static async Task<string?> SetLinuxChmod(string? fileName)
|
public static async Task<string?> SetLinuxChmod(string? fileName)
|
||||||
{
|
{
|
||||||
if (fileName.IsNullOrEmpty())
|
if (fileName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
if (SetUnixFileMode(fileName))
|
||||||
|
{
|
||||||
|
Logging.SaveLog($"Successfully set the file execution permission, {fileName}");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
if (fileName.Contains(' '))
|
if (fileName.Contains(' '))
|
||||||
|
{
|
||||||
fileName = fileName.AppendQuotes();
|
fileName = fileName.AppendQuotes();
|
||||||
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
|
}
|
||||||
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
||||||
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool SetUnixFileMode(string? fileName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (fileName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
var currentMode = File.GetUnixFileMode(fileName);
|
||||||
|
File.SetUnixFileMode(fileName, currentMode | UnixFileMode.UserExecute | UnixFileMode.GroupExecute | UnixFileMode.OtherExecute);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("SetUnixFileMode", ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<string?> GetLinuxFontFamily(string lang)
|
public static async Task<string?> GetLinuxFontFamily(string lang)
|
||||||
{
|
{
|
||||||
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,6 @@ public enum ECoreType
|
||||||
hysteria2 = 26,
|
hysteria2 = 26,
|
||||||
brook = 27,
|
brook = 27,
|
||||||
overtls = 28,
|
overtls = 28,
|
||||||
|
shadowquic = 29,
|
||||||
v2rayN = 99
|
v2rayN = 99
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,7 @@ public class Global
|
||||||
{ ECoreType.juicity, "juicity/juicity" },
|
{ ECoreType.juicity, "juicity/juicity" },
|
||||||
{ ECoreType.brook, "txthinking/brook" },
|
{ ECoreType.brook, "txthinking/brook" },
|
||||||
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" },
|
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" },
|
||||||
|
{ ECoreType.shadowquic, "spongebob888/shadowquic" },
|
||||||
{ ECoreType.v2rayN, "cg3s/v2rayN" },
|
{ ECoreType.v2rayN, "cg3s/v2rayN" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -527,5 +528,12 @@ public class Global
|
||||||
@""
|
@""
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> OutboundTags =
|
||||||
|
[
|
||||||
|
ProxyTag,
|
||||||
|
DirectTag,
|
||||||
|
BlockTag
|
||||||
|
];
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ public class ConfigHandler
|
||||||
EnableAutoAdjustMainLvColWidth = true
|
EnableAutoAdjustMainLvColWidth = true
|
||||||
};
|
};
|
||||||
config.UiItem.MainColumnItem ??= new();
|
config.UiItem.MainColumnItem ??= new();
|
||||||
|
config.UiItem.WindowSizeItem ??= new();
|
||||||
|
|
||||||
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|
@ -250,6 +251,7 @@ 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
|
||||||
|
|
@ -1859,12 +1861,25 @@ public class ConfigHandler
|
||||||
/// <returns>0 if successful</returns>
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
||||||
{
|
{
|
||||||
if (await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(t => t.Id == routingItem.Id).CountAsync() > 0)
|
var items = await AppHandler.Instance.RoutingItems();
|
||||||
|
if (items.Any(t => t.Id == routingItem.Id && t.IsActive == true))
|
||||||
{
|
{
|
||||||
config.RoutingBasicItem.RoutingIndexId = routingItem.Id;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
await SaveConfig(config);
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
if (item.Id == routingItem.Id)
|
||||||
|
{
|
||||||
|
item.IsActive = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.IsActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await SQLiteHelper.Instance.UpdateAllAsync(items);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1877,7 +1892,7 @@ public class ConfigHandler
|
||||||
/// <returns>The default routing item</returns>
|
/// <returns>The default routing item</returns>
|
||||||
public static async Task<RoutingItem> GetDefaultRouting(Config config)
|
public static async Task<RoutingItem> GetDefaultRouting(Config config)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
|
var item = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.IsActive == true);
|
||||||
if (item is null)
|
if (item is null)
|
||||||
{
|
{
|
||||||
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
|
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
|
||||||
|
|
@ -1983,8 +1998,20 @@ public class ConfigHandler
|
||||||
items = await AppHandler.Instance.RoutingItems();
|
items = await AppHandler.Instance.RoutingItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0)
|
if (!blImportAdvancedRules && items.Count > 0)
|
||||||
{
|
{
|
||||||
|
//migrate
|
||||||
|
//TODO Temporary code to be removed later
|
||||||
|
if (config.RoutingBasicItem.RoutingIndexId.IsNotEmpty())
|
||||||
|
{
|
||||||
|
var item = items.FirstOrDefault(t => t.Id == config.RoutingBasicItem.RoutingIndexId);
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
await SetDefaultRouting(config, item);
|
||||||
|
}
|
||||||
|
config.RoutingBasicItem.RoutingIndexId = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2177,4 +2204,44 @@ 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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ public class CoreAdminHandler
|
||||||
private static readonly Lazy<CoreAdminHandler> _instance = new(() => new());
|
private static readonly Lazy<CoreAdminHandler> _instance = new(() => new());
|
||||||
public static CoreAdminHandler Instance => _instance.Value;
|
public static CoreAdminHandler Instance => _instance.Value;
|
||||||
private Config _config;
|
private Config _config;
|
||||||
|
private readonly string _sudoAccessText = "SUDO_ACCESS_VERIFIED";
|
||||||
private Action<bool, string>? _updateFunc;
|
private Action<bool, string>? _updateFunc;
|
||||||
private int _linuxSudoPid = -1;
|
private int _linuxSudoPid = -1;
|
||||||
|
|
||||||
|
|
@ -44,33 +45,35 @@ public class CoreAdminHandler
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
StandardInputEncoding = Encoding.UTF8,
|
|
||||||
StandardOutputEncoding = Encoding.UTF8,
|
StandardOutputEncoding = Encoding.UTF8,
|
||||||
StandardErrorEncoding = Encoding.UTF8,
|
StandardErrorEncoding = Encoding.UTF8,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
var sudoVerified = false;
|
||||||
{
|
DataReceivedEventHandler dataHandler = (sender, e) =>
|
||||||
if (e.Data.IsNotEmpty())
|
|
||||||
{
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
{
|
||||||
if (e.Data.IsNotEmpty())
|
if (e.Data.IsNotEmpty())
|
||||||
{
|
{
|
||||||
|
if (!sudoVerified && e.Data.Contains(_sudoAccessText))
|
||||||
|
{
|
||||||
|
sudoVerified = true;
|
||||||
|
UpdateFunc(false, ResUI.SudoPwdVerfiedSuccessTip + Environment.NewLine);
|
||||||
|
return;
|
||||||
|
}
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
proc.OutputDataReceived += dataHandler;
|
||||||
|
proc.ErrorDataReceived += dataHandler;
|
||||||
|
|
||||||
proc.Start();
|
proc.Start();
|
||||||
proc.BeginOutputReadLine();
|
proc.BeginOutputReadLine();
|
||||||
proc.BeginErrorReadLine();
|
proc.BeginErrorReadLine();
|
||||||
|
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
await proc.StandardInput.WriteLineAsync();
|
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
|
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
|
||||||
|
|
||||||
|
|
@ -115,7 +118,7 @@ public class CoreAdminHandler
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb.AppendLine($"sudo -S {cmdLine}");
|
sb.AppendLine($"sudo -S echo \"{_sudoAccessText}\" && sudo -S {cmdLine}");
|
||||||
}
|
}
|
||||||
|
|
||||||
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
||||||
|
|
|
||||||
|
|
@ -280,20 +280,15 @@ public class CoreHandler
|
||||||
|
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
DataReceivedEventHandler dataHandler = (sender, e) =>
|
||||||
{
|
|
||||||
if (e.Data.IsNotEmpty())
|
|
||||||
{
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
{
|
||||||
if (e.Data.IsNotEmpty())
|
if (e.Data.IsNotEmpty())
|
||||||
{
|
{
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
proc.OutputDataReceived += dataHandler;
|
||||||
|
proc.ErrorDataReceived += dataHandler;
|
||||||
}
|
}
|
||||||
proc.Start();
|
proc.Start();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,15 @@ public sealed class CoreInfoHandler
|
||||||
Arguments = "-r client -c {0}",
|
Arguments = "-r client -c {0}",
|
||||||
Url = GetCoreUrl(ECoreType.overtls),
|
Url = GetCoreUrl(ECoreType.overtls),
|
||||||
AbsolutePath = false,
|
AbsolutePath = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.shadowquic,
|
||||||
|
CoreExes = [ "shadowquic", "shadowquic"],
|
||||||
|
Arguments = "-c {0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.shadowquic),
|
||||||
|
AbsolutePath = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ public class Hysteria2Fmt : BaseFmt
|
||||||
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
||||||
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
||||||
|
|
||||||
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
|
item.Ports = Utils.UrlDecode(query["mport"] ?? "");
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,8 @@ public class UIItem
|
||||||
{
|
{
|
||||||
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
||||||
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
||||||
public double MainWidth { get; set; }
|
public int MainGirdHeight1 { get; set; }
|
||||||
public double MainHeight { get; set; }
|
public int MainGirdHeight2 { get; set; }
|
||||||
public double MainGirdHeight1 { get; set; }
|
|
||||||
public double MainGirdHeight2 { get; set; }
|
|
||||||
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public string? ColorPrimaryName { get; set; }
|
public string? ColorPrimaryName { get; set; }
|
||||||
public string? CurrentTheme { get; set; }
|
public string? CurrentTheme { get; set; }
|
||||||
|
|
@ -103,8 +101,10 @@ public class UIItem
|
||||||
public bool DoubleClick2Activate { get; set; } = true;
|
public bool DoubleClick2Activate { get; set; } = true;
|
||||||
public bool AutoHideStartup { get; set; }
|
public bool AutoHideStartup { get; set; }
|
||||||
public bool Hide2TrayWhenClose { get; set; }
|
public bool Hide2TrayWhenClose { get; set; }
|
||||||
public List<ColumnItem> MainColumnItem { get; set; }
|
|
||||||
public bool ShowInTaskbar { get; set; }
|
public bool ShowInTaskbar { get; set; }
|
||||||
|
public bool MacOSShowInDock { get; set; }
|
||||||
|
public List<ColumnItem> MainColumnItem { get; set; }
|
||||||
|
public List<WindowSizeItem> WindowSizeItem { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
|
@ -245,3 +245,11 @@ 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; }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
using ReactiveUI;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItem
|
public class ProfileItem : ReactiveObject
|
||||||
{
|
{
|
||||||
public ProfileItem()
|
public ProfileItem()
|
||||||
{
|
{
|
||||||
|
|
@ -93,4 +94,5 @@ public class ProfileItem
|
||||||
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,3 +1,5 @@
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
|
@ -5,13 +7,28 @@ public class ProfileItemModel : ProfileItem
|
||||||
{
|
{
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
public string SubRemarks { get; set; }
|
public string SubRemarks { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public int Delay { get; set; }
|
public int Delay { get; set; }
|
||||||
|
|
||||||
public decimal Speed { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string DelayVal { get; set; }
|
public string DelayVal { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string SpeedVal { get; set; }
|
public string SpeedVal { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TodayUp { get; set; }
|
public string TodayUp { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TodayDown { get; set; }
|
public string TodayDown { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TotalUp { get; set; }
|
public string TotalUp { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
public string TotalDown { get; set; }
|
public string TotalDown { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,5 @@ public class RoutingItem
|
||||||
public string DomainStrategy { get; set; }
|
public string DomainStrategy { get; set; }
|
||||||
public string DomainStrategy4Singbox { get; set; }
|
public string DomainStrategy4Singbox { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,4 @@ namespace ServiceLib.Models;
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItemModel : RoutingItem
|
public class RoutingItemModel : RoutingItem
|
||||||
{
|
{
|
||||||
public bool IsActive { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
110
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
110
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -132,24 +132,6 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Download speed 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string downloadSpeed {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("downloadSpeed", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Do you want to download {0}? 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string DownloadYesNo {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("DownloadYesNo", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Failed to convert configuration file 的本地化字符串。
|
/// 查找类似 Failed to convert configuration file 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1338,15 +1320,6 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Advanced Function 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuRoutingAdvanced {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuRoutingAdvanced", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add 的本地化字符串。
|
/// 查找类似 Add 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -2220,6 +2193,24 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Incorrect password, please try again. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string SudoIncorrectPasswordTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SudoIncorrectPasswordTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Sudo password has been verified successfully, please ignore the incorrect password prompts! 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string SudoPwdVerfiedSuccessTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SudoPwdVerfiedSuccessTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Address 的本地化字符串。
|
/// 查找类似 Address 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -2706,33 +2697,6 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 3. Block Domain or IP 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbRoutingTabBlock {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbRoutingTabBlock", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 2. Direct Domain or IP 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbRoutingTabDirect {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbRoutingTabDirect", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 1. Proxy Domain or IP 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbRoutingTabProxy {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbRoutingTabProxy", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Pre-defined Rule Set List 的本地化字符串。
|
/// 查找类似 Pre-defined Rule Set List 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -2769,6 +2733,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Can fill in the configuration remarks, please make sure it exist and are unique 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbRuleOutboundTagTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbRuleOutboundTagTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Encryption method (security) 的本地化字符串。
|
/// 查找类似 Encryption method (security) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -3229,25 +3202,7 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please set the sudo password in Tun mode settings first 的本地化字符串。
|
/// 查找类似 The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart. 的本地化字符串。
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsLinuxSudoPasswordIsEmpty {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordIsEmpty", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Please do not run this app with sudo 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsLinuxSudoPasswordNotSudoRunApp {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordNotSudoRunApp", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 The password 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. 的本地化字符串。
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsLinuxSudoPasswordTip {
|
public static string TbSettingsLinuxSudoPasswordTip {
|
||||||
get {
|
get {
|
||||||
|
|
@ -3939,15 +3894,6 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Ungrouped 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string UngroupedServers {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("UngroupedServers", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Upgrade App does not exist 的本地化字符串。
|
/// 查找类似 Upgrade App does not exist 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -132,12 +132,6 @@
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>درحال دانلود...</value>
|
<value>درحال دانلود...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>دانلود</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>آیا می خواهید {0} را دانلود کنید؟</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>تبدیل فایل پیکربندی انجام نشد</value>
|
<value>تبدیل فایل پیکربندی انجام نشد</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -387,9 +381,6 @@
|
||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>کلید میانبر جهانی {0} با موفقیت ثبت شد</value>
|
<value>کلید میانبر جهانی {0} با موفقیت ثبت شد</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>گروه بندی نشده</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>همه سرورها</value>
|
<value>همه سرورها</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -819,9 +810,6 @@
|
||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} وب سایت</value>
|
<value>{0} وب سایت</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>عملکرد پیشرفته</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>اضافه کردن</value>
|
<value>اضافه کردن</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -840,15 +828,6 @@
|
||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>استراتژی دامنه</value>
|
<value>استراتژی دامنه</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3. مسدود کردن دامنه یا آیپی</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2. دایرکت کردن دامنه یا IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1. پروکسی کردن دامنه یا IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>لیست مجموعه قوانین از پیش تعریف شده</value>
|
<value>لیست مجموعه قوانین از پیش تعریف شده</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -1336,13 +1315,7 @@
|
||||||
<value>رمز عبور sudo سیستم</value>
|
<value>رمز عبور sudo سیستم</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>رمز عبوری که وارد کرده اید تایید نمی شود، بنابراین مطمئن شوید که آن را به درستی وارد کرده اید. اگر برنامه به دلیل ورودی نادرست به درستی کار نمی کند، لطفاً برنامه را مجدداً راه اندازی کنید. رمز عبور ذخیره نمی شود و پس از هر بار راه اندازی مجدد باید آن را دوباره وارد کنید.</value>
|
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>لطفا این برنامه را با sudo اجرا نکنید</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*حالت xhttp</value>
|
<value>*حالت xhttp</value>
|
||||||
|
|
@ -1416,4 +1389,13 @@
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
<value>URL آزمایش اطلاعات اتصال فعلی</value>
|
<value>URL آزمایش اطلاعات اتصال فعلی</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoPwdVerfiedSuccessTip" xml:space="preserve">
|
||||||
|
<value>Sudo password has been verified successfully, please ignore the incorrect password prompts!</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>Incorrect password, please try again.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -132,12 +132,6 @@
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>Letöltés...</value>
|
<value>Letöltés...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>Letöltés</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>Le szeretné tölteni? {0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>Nem sikerült a konfigurációs fájl átalakítása</value>
|
<value>Nem sikerült a konfigurációs fájl átalakítása</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -387,9 +381,6 @@
|
||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>A globális billentyűparancs {0} sikeresen bejegyezve</value>
|
<value>A globális billentyűparancs {0} sikeresen bejegyezve</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>Összegyűjtetlen</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>Összes</value>
|
<value>Összes</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -822,9 +813,6 @@
|
||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} Weboldal</value>
|
<value>{0} Weboldal</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>Fejlett funkció</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>Hozzáadás</value>
|
<value>Hozzáadás</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -843,15 +831,6 @@
|
||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>Domain stratégia</value>
|
<value>Domain stratégia</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3. Domain vagy IP blokkolása</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2. Közvetlen domain vagy IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1. Proxy domain vagy IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>Előre definiált szabálykészletlista</value>
|
<value>Előre definiált szabálykészletlista</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -1339,13 +1318,7 @@
|
||||||
<value>Rendszer sudo jelszó</value>
|
<value>Rendszer sudo jelszó</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<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>
|
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>Kérlek, először állítsd be a sudo jelszót a Tun módban</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>Kérlek, ne futtasd ezt az alkalmazást sudo-ként</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp mód</value>
|
<value>*xhttp mód</value>
|
||||||
|
|
@ -1419,4 +1392,13 @@
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
<value>Current connection info test URL</value>
|
<value>Current connection info test URL</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoPwdVerfiedSuccessTip" xml:space="preserve">
|
||||||
|
<value>Sudo password has been verified successfully, please ignore the incorrect password prompts!</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>Incorrect password, please try again.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -132,12 +132,6 @@
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>Downloading...</value>
|
<value>Downloading...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>Download speed</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>Do you want to download {0}?</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>Failed to convert configuration file</value>
|
<value>Failed to convert configuration file</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -387,9 +381,6 @@
|
||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>Global hotkey {0} registered successfully</value>
|
<value>Global hotkey {0} registered successfully</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>Ungrouped</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>All</value>
|
<value>All</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -819,9 +810,6 @@
|
||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} Website</value>
|
<value>{0} Website</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>Advanced Function</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>Add</value>
|
<value>Add</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -840,15 +828,6 @@
|
||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>Domain strategy</value>
|
<value>Domain strategy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3. Block Domain or IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2. Direct Domain or IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1. Proxy Domain or IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>Pre-defined Rule Set List</value>
|
<value>Pre-defined Rule Set List</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -1336,13 +1315,7 @@
|
||||||
<value>System sudo password</value>
|
<value>System sudo password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>The password 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>
|
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>Please set the sudo password in Tun mode settings first</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>Please do not run this app with sudo</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp mode</value>
|
<value>*xhttp mode</value>
|
||||||
|
|
@ -1416,4 +1389,13 @@
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
<value>Current connection info test URL</value>
|
<value>Current connection info test URL</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoPwdVerfiedSuccessTip" xml:space="preserve">
|
||||||
|
<value>Sudo password has been verified successfully, please ignore the incorrect password prompts!</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>Incorrect password, please try again.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -132,12 +132,6 @@
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>Загрузка...</value>
|
<value>Загрузка...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>Скорость загрузки</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>Хотите загрузить {0}?</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>Не удалось преобразовать файл конфигурации</value>
|
<value>Не удалось преобразовать файл конфигурации</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -387,9 +381,6 @@
|
||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>Глобальная горячая клавиша {0} зарегистрирована успешно</value>
|
<value>Глобальная горячая клавиша {0} зарегистрирована успешно</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>Разгруппировано</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>Все серверы</value>
|
<value>Все серверы</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -822,9 +813,6 @@
|
||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} веб-сайт</value>
|
<value>{0} веб-сайт</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>Расширенная функция</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>Добавить</value>
|
<value>Добавить</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -843,15 +831,6 @@
|
||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>Доменная стратегия</value>
|
<value>Доменная стратегия</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3.Заблокировать домен или IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2.Прямой домен или IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1.Прокси домен или IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>Предустановленный список наборов правил</value>
|
<value>Предустановленный список наборов правил</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -1336,13 +1315,7 @@
|
||||||
<value>Пароль sudo системы</value>
|
<value>Пароль sudo системы</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>Введенный вами пароль не может быть подтвержден, поэтому убедитесь, что вы ввели его правильно. Если приложение не работает должным образом из-за неправильного ввода, то перезапустите его. Пароль не будет сохранен, и вам придется вводить его заново после каждого перезапуска</value>
|
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>Сначала задайте пароль sudo в настройках TUN-режима</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>Не запускайте программу как суперпользователь</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*XHTTP-режим</value>
|
<value>*XHTTP-режим</value>
|
||||||
|
|
@ -1416,4 +1389,13 @@
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
<value>URL для тестирования текущего соединения</value>
|
<value>URL для тестирования текущего соединения</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoPwdVerfiedSuccessTip" xml:space="preserve">
|
||||||
|
<value>Sudo password has been verified successfully, please ignore the incorrect password prompts!</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>Incorrect password, please try again.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -132,12 +132,6 @@
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>下载开始...</value>
|
<value>下载开始...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>下载</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>是否下载?{0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>转换配置文件失败</value>
|
<value>转换配置文件失败</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -387,9 +381,6 @@
|
||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>注册全局热键 {0} 成功</value>
|
<value>注册全局热键 {0} 成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>未分组配置文件</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -709,7 +700,7 @@
|
||||||
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号 (;) 分隔。</value>
|
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号 (;) 分隔。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>显示实时速度(需重启)</value>
|
<value>显示实时速度 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||||
<value>去重时保留序号较小的项</value>
|
<value>去重时保留序号较小的项</value>
|
||||||
|
|
@ -745,7 +736,7 @@
|
||||||
<value>开机启动 (可能会不成功)</value>
|
<value>开机启动 (可能会不成功)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||||
<value>启用流量统计(需重启)</value>
|
<value>启用流量统计 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||||
<value>订阅转换网址 (可选)</value>
|
<value>订阅转换网址 (可选)</value>
|
||||||
|
|
@ -819,9 +810,6 @@
|
||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} 官网</value>
|
<value>{0} 官网</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>高级功能</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>添加规则集</value>
|
<value>添加规则集</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -840,15 +828,6 @@
|
||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>域名解析策略</value>
|
<value>域名解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3.阻止的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2.直连的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1.代理的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>预定义规则集列表</value>
|
<value>预定义规则集列表</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -904,7 +883,7 @@
|
||||||
<value>仅限路由 (routeOnly)</value>
|
<value>仅限路由 (routeOnly)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
<value>请勿将代理服务器用于本地(Intranet)地址</value>
|
<value>请勿将代理服务器用于本地 (Intranet) 地址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>一键多线程测试延迟和速度 (Ctrl+E)</value>
|
<value>一键多线程测试延迟和速度 (Ctrl+E)</value>
|
||||||
|
|
@ -937,7 +916,7 @@
|
||||||
<value>移至订阅分组</value>
|
<value>移至订阅分组</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>启用配置文件拖放排序(需重启)</value>
|
<value>启用配置文件拖放排序 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoRefresh" xml:space="preserve">
|
<data name="TbAutoRefresh" xml:space="preserve">
|
||||||
<value>自动刷新</value>
|
<value>自动刷新</value>
|
||||||
|
|
@ -964,10 +943,10 @@
|
||||||
<value>仅对 tcp/http、ws 协议生效</value>
|
<value>仅对 tcp/http、ws 协议生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
||||||
<value>当前字体(需重启)</value>
|
<value>当前字体 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>拷贝字体 TTF/TTC 文件到目录 guiFonts,重启设置</value>
|
<value>拷贝字体 TTF/TTC 文件到目录 guiFonts,重启生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>Pac 端口 = +3;Xray API 端口 = +4;mihomo API 端口 = +5;</value>
|
<value>Pac 端口 = +3;Xray API 端口 = +4;mihomo API 端口 = +5;</value>
|
||||||
|
|
@ -997,10 +976,10 @@
|
||||||
<value>SpiderX</value>
|
<value>SpiderX</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
||||||
<value>启用硬件加速(需重启)</value>
|
<value>启用硬件加速 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingWait" xml:space="preserve">
|
<data name="SpeedtestingWait" xml:space="preserve">
|
||||||
<value>等待测试中(按 ESC 终止)...</value>
|
<value>等待测试中 (按 ESC 终止)...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipDisplayLog" xml:space="preserve">
|
<data name="TipDisplayLog" xml:space="preserve">
|
||||||
<value>当有异常断流时请关闭</value>
|
<value>当有异常断流时请关闭</value>
|
||||||
|
|
@ -1093,7 +1072,7 @@
|
||||||
<value>Reserved (2,3,4)</value>
|
<value>Reserved (2,3,4)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbLocalAddress" xml:space="preserve">
|
<data name="TbLocalAddress" xml:space="preserve">
|
||||||
<value>Address (Ipv4,Ipv6)</value>
|
<value>Address (IPv4,IPv6)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPath7" xml:space="preserve">
|
<data name="TbPath7" xml:space="preserve">
|
||||||
<value>混淆密码 (obfs password)</value>
|
<value>混淆密码 (obfs password)</value>
|
||||||
|
|
@ -1123,10 +1102,10 @@
|
||||||
<value>使用 Xray 且非 Tun 模式启用,和分组前置代理冲突</value>
|
<value>使用 Xray 且非 Tun 模式启用,和分组前置代理冲突</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
<value>启用分片(Fragment)</value>
|
<value>启用分片 (Fragment)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
<value>启用 sing-box(规则集文件)的缓存文件</value>
|
<value>启用 sing-box (规则集文件) 的缓存文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
||||||
<value>自定义 sing-box rule-set</value>
|
<value>自定义 sing-box rule-set</value>
|
||||||
|
|
@ -1219,7 +1198,7 @@
|
||||||
<value>Outbound 默认解析策略</value>
|
<value>Outbound 默认解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
||||||
<value>主界面布局方向(需重启)</value>
|
<value>主界面布局方向 (需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
||||||
<value>Outbound 域名解析地址</value>
|
<value>Outbound 域名解析地址</value>
|
||||||
|
|
@ -1321,7 +1300,7 @@
|
||||||
<value>请不要使用不安全的 HTTP 协议订阅地址</value>
|
<value>请不要使用不安全的 HTTP 协议订阅地址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||||
<value>安装字体到系统中,选择或填入字体名称,重启设置</value>
|
<value>安装字体到系统中,选择或填入字体名称,重启生效</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExitTips" xml:space="preserve">
|
<data name="menuExitTips" xml:space="preserve">
|
||||||
<value>是否确定退出?</value>
|
<value>是否确定退出?</value>
|
||||||
|
|
@ -1333,16 +1312,10 @@
|
||||||
<value>系统的 sudo 密码</value>
|
<value>系统的 sudo 密码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>输入的密码无法校验,所以请确保输入正确。如果因为输入错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
|
<value>密码将调用命令行校验,如果因为校验错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>请先在 Tun 模式设置中设置 sudo 密码</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>请不要用 sudo 运行本程序</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp 模式</value>
|
<value>*XHTTP 模式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportExtraTip" xml:space="preserve">
|
<data name="TransportExtraTip" xml:space="preserve">
|
||||||
<value>XHTTP Extra 原始 JSON,格式: { XHTTPObject }</value>
|
<value>XHTTP Extra 原始 JSON,格式: { XHTTPObject }</value>
|
||||||
|
|
@ -1363,7 +1336,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>
|
||||||
|
|
@ -1396,13 +1369,13 @@
|
||||||
<value>多配置文件随机 Xray</value>
|
<value>多配置文件随机 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>多配置文件负载均衡 Xray</value>
|
<value>多配置文件负载均衡 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>多配置文件最低延迟 Xray</value>
|
<value>多配置文件最低延迟 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>多配置文件最稳定 Xray</value>
|
<value>多配置文件最稳定 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>多配置文件最低延迟 sing-box</value>
|
<value>多配置文件最低延迟 sing-box</value>
|
||||||
|
|
@ -1413,4 +1386,13 @@
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
<value>当前连接信息测试地址</value>
|
<value>当前连接信息测试地址</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>可以填写配置文件别名,请确保存在并唯一</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoPwdVerfiedSuccessTip" xml:space="preserve">
|
||||||
|
<value>sudo 密码已经验证成功,请忽略错误密码提示!</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" 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>
|
||||||
|
|
@ -132,12 +132,6 @@
|
||||||
<data name="Downloading" xml:space="preserve">
|
<data name="Downloading" xml:space="preserve">
|
||||||
<value>下載開始...</value>
|
<value>下載開始...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="downloadSpeed" xml:space="preserve">
|
|
||||||
<value>下載</value>
|
|
||||||
</data>
|
|
||||||
<data name="DownloadYesNo" xml:space="preserve">
|
|
||||||
<value>是否下載?{0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||||
<value>轉換設定檔失敗</value>
|
<value>轉換設定檔失敗</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -295,7 +289,7 @@
|
||||||
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>掃描匯入分享链接成功</value>
|
<value>掃描匯入分享連結成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TestMeOutput" xml:space="preserve">
|
<data name="TestMeOutput" xml:space="preserve">
|
||||||
<value>目前延遲: {0} ms,{1}</value>
|
<value>目前延遲: {0} ms,{1}</value>
|
||||||
|
|
@ -387,9 +381,6 @@
|
||||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||||
<value>註冊全域快速鍵 {0} 成功</value>
|
<value>註冊全域快速鍵 {0} 成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
|
||||||
<value>未分組設定檔</value>
|
|
||||||
</data>
|
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -478,7 +469,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>
|
||||||
|
|
@ -514,7 +505,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>
|
||||||
|
|
@ -819,9 +810,6 @@
|
||||||
<data name="menuWebsiteItem" xml:space="preserve">
|
<data name="menuWebsiteItem" xml:space="preserve">
|
||||||
<value>{0} 官網</value>
|
<value>{0} 官網</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
|
||||||
<value>進階功能</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||||
<value>新增規則集</value>
|
<value>新增規則集</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -840,15 +828,6 @@
|
||||||
<data name="TbdomainStrategy" xml:space="preserve">
|
<data name="TbdomainStrategy" xml:space="preserve">
|
||||||
<value>域名解析策略</value>
|
<value>域名解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
|
||||||
<value>3.阻止的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
|
||||||
<value>2.直連的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
|
||||||
<value>1.代理的 Domain 或 IP</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||||
<value>預定義規則集列表</value>
|
<value>預定義規則集列表</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -889,7 +868,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>
|
||||||
|
|
@ -1000,7 +979,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>
|
||||||
|
|
@ -1099,10 +1078,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>
|
||||||
|
|
@ -1198,7 +1177,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>
|
||||||
|
|
@ -1228,7 +1207,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>
|
||||||
|
|
@ -1264,7 +1243,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>
|
||||||
|
|
@ -1333,13 +1312,7 @@
|
||||||
<value>系統的 sudo 密碼</value>
|
<value>系統的 sudo 密碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會存儲,每次重啟後都需要再次輸入。</value>
|
<value>密碼將調用命令行校驗,如果因為校驗錯誤導致無法正常運行時,請重啟本應用。密碼不會存儲,每次重啟後都需要再次輸入。</value>
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
|
||||||
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
|
||||||
<value>請不要用 sudo 來運行此 App</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||||
<value>*xhttp 模式</value>
|
<value>*xhttp 模式</value>
|
||||||
|
|
@ -1363,7 +1336,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>
|
||||||
|
|
@ -1384,10 +1357,10 @@
|
||||||
<value>移除無效測試結果 {0} 個。</value>
|
<value>移除無效測試結果 {0} 個。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7" xml:space="preserve">
|
<data name="TbPorts7" xml:space="preserve">
|
||||||
<value>跳躍端口範圍</value>
|
<value>跳躍埠範圍</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7Tips" xml:space="preserve">
|
<data name="TbPorts7Tips" xml:space="preserve">
|
||||||
<value>會覆蓋端口,多組時用逗號 (,) 隔開</value>
|
<value>會覆蓋埠,多組時用逗號 (,) 隔開</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>多設定檔產生自訂配置 (多選)</value>
|
<value>多設定檔產生自訂配置 (多選)</value>
|
||||||
|
|
@ -1413,4 +1386,13 @@
|
||||||
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
<value>目前連接資訊測試地址</value>
|
<value>目前連接資訊測試地址</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbRuleOutboundTagTip" xml:space="preserve">
|
||||||
|
<value>可以填寫設定檔別名,請確保存在並唯一</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoPwdVerfiedSuccessTip" xml:space="preserve">
|
||||||
|
<value>sudo 密碼已經驗證成功,請忽略錯誤密碼提示!</value>
|
||||||
|
</data>
|
||||||
|
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
|
||||||
|
<value>密碼錯誤,請重試。</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -29,9 +29,6 @@ set_gnome_proxy() {
|
||||||
echo "Ignored Hosts: $IGNORE_HOSTS"
|
echo "Ignored Hosts: $IGNORE_HOSTS"
|
||||||
elif [ "$MODE" == "none" ]; then
|
elif [ "$MODE" == "none" ]; then
|
||||||
echo "GNOME: Proxy disabled."
|
echo "GNOME: Proxy disabled."
|
||||||
else
|
|
||||||
echo "GNOME: Invalid mode. Use 'none' or 'manual'."
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,9 +66,6 @@ set_kde_proxy() {
|
||||||
# Disable proxy
|
# Disable proxy
|
||||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 0
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 0
|
||||||
echo "KDE: Proxy disabled."
|
echo "KDE: Proxy disabled."
|
||||||
else
|
|
||||||
echo "KDE: Invalid mode. Use 'none' or 'manual'."
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Apply changes by restarting KDE's network settings
|
# Apply changes by restarting KDE's network settings
|
||||||
|
|
@ -117,6 +111,15 @@ detect_desktop_environment() {
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Fallback to GNOME method if CLI utility is available. This solves the
|
||||||
|
# proxy configuration issues on minimal installation systems, like setups
|
||||||
|
# with only window managers, that borrow some parts from big DEs.
|
||||||
|
if command -v gsettings >/dev/null 2>&1; then
|
||||||
|
echo "gnome"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
echo "unsupported"
|
echo "unsupported"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,6 +137,11 @@ PROXY_IP=$2
|
||||||
PROXY_PORT=$3
|
PROXY_PORT=$3
|
||||||
IGNORE_HOSTS=$4
|
IGNORE_HOSTS=$4
|
||||||
|
|
||||||
|
if ! [[ "$MODE" =~ ^(manual|none)$ ]]; then
|
||||||
|
echo "Invalid mode. Use 'none' or 'manual'." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Detect desktop environment
|
# Detect desktop environment
|
||||||
DE=$(detect_desktop_environment)
|
DE=$(detect_desktop_environment)
|
||||||
|
|
||||||
|
|
@ -144,6 +152,6 @@ elif [ "$DE" == "kde" ]; then
|
||||||
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||||
set_kde_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
set_kde_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||||
else
|
else
|
||||||
echo "Unsupported desktop environment: $DE"
|
echo "Unsupported desktop environment: $DE" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -336,7 +336,7 @@ public class CoreConfigSingboxService
|
||||||
await GenExperimental(singboxConfig);
|
await GenExperimental(singboxConfig);
|
||||||
singboxConfig.outbounds.RemoveAt(0);
|
singboxConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
var tagProxy = new List<string>();
|
var proxyProfiles = new List<ProfileItem>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
|
|
@ -370,42 +370,18 @@ public class CoreConfigSingboxService
|
||||||
}
|
}
|
||||||
|
|
||||||
//outbound
|
//outbound
|
||||||
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
proxyProfiles.Add(item);
|
||||||
await GenOutbound(item, outbound);
|
|
||||||
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
|
||||||
singboxConfig.outbounds.Insert(0, outbound);
|
|
||||||
tagProxy.Add(outbound.tag);
|
|
||||||
}
|
}
|
||||||
if (tagProxy.Count <= 0)
|
if (proxyProfiles.Count <= 0)
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
await GenOutboundsList(proxyProfiles, 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;
|
||||||
|
|
@ -730,12 +706,17 @@ public class CoreConfigSingboxService
|
||||||
|
|
||||||
outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null;
|
outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null;
|
||||||
outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null;
|
outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null;
|
||||||
if (node.Ports.IsNotEmpty())
|
if (node.Ports.IsNotEmpty() && (node.Ports.Contains(':') || node.Ports.Contains('-') || node.Ports.Contains(',')))
|
||||||
{
|
{
|
||||||
outbound.server_port = null;
|
outbound.server_port = null;
|
||||||
outbound.server_ports = node.Ports.Split(',')
|
outbound.server_ports = node.Ports.Split(',')
|
||||||
.Where(p => p.Trim().IsNotEmpty())
|
.Select(p => p.Trim())
|
||||||
.Select(p => p.Replace('-', ':'))
|
.Where(p => p.IsNotEmpty())
|
||||||
|
.Select(p =>
|
||||||
|
{
|
||||||
|
var port = p.Replace('-', ':');
|
||||||
|
return port.Contains(':') ? port : $"{port}:{port}";
|
||||||
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
outbound.hop_interval = _config.HysteriaItem.HopInterval > 0 ? $"{_config.HysteriaItem.HopInterval}s" : null;
|
outbound.hop_interval = _config.HysteriaItem.HopInterval > 0 ? $"{_config.HysteriaItem.HopInterval}s" : null;
|
||||||
}
|
}
|
||||||
|
|
@ -775,7 +756,8 @@ public class CoreConfigSingboxService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_config.CoreBasicItem.MuxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty())
|
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
|
||||||
|
if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var mux = new Multiplex4Sbox()
|
var mux = new Multiplex4Sbox()
|
||||||
{
|
{
|
||||||
|
|
@ -941,29 +923,21 @@ 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);
|
||||||
prevOutbound.tag = $"{Global.ProxyTag}2";
|
prevOutboundTag = $"prev-{Global.ProxyTag}";
|
||||||
|
prevOutbound.tag = prevOutboundTag;
|
||||||
singboxConfig.outbounds.Add(prevOutbound);
|
singboxConfig.outbounds.Add(prevOutbound);
|
||||||
|
|
||||||
outbound.detour = prevOutbound.tag;
|
|
||||||
}
|
}
|
||||||
|
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
|
||||||
|
|
||||||
//Next proxy
|
if (nextOutbound is not null)
|
||||||
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
|
||||||
if (nextNode is not null
|
|
||||||
&& nextNode.ConfigType != EConfigType.Custom)
|
|
||||||
{
|
{
|
||||||
var nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
|
||||||
nextOutbound.tag = Global.ProxyTag;
|
|
||||||
singboxConfig.outbounds.Insert(0, nextOutbound);
|
singboxConfig.outbounds.Insert(0, nextOutbound);
|
||||||
|
|
||||||
outbound.tag = $"{Global.ProxyTag}1";
|
|
||||||
nextOutbound.detour = outbound.tag;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -974,6 +948,169 @@ public class CoreConfigSingboxService
|
||||||
return 0;
|
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>();
|
||||||
|
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);
|
||||||
|
if (nextNode is not null
|
||||||
|
&& nextNode.ConfigType != EConfigType.Custom)
|
||||||
|
{
|
||||||
|
if (nextOutbound == null)
|
||||||
|
{
|
||||||
|
nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
|
}
|
||||||
|
nextOutbound.tag = outbound.tag;
|
||||||
|
|
||||||
|
outbound.tag = $"mid-{outbound.tag}";
|
||||||
|
nextOutbound.detour = outbound.tag;
|
||||||
|
}
|
||||||
|
return nextOutbound;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenRouting(SingboxConfig singboxConfig)
|
private async Task<int> GenRouting(SingboxConfig singboxConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -1034,7 +1171,7 @@ public class CoreConfigSingboxService
|
||||||
{
|
{
|
||||||
if (item.Enabled)
|
if (item.Enabled)
|
||||||
{
|
{
|
||||||
await GenRoutingUserRule(item, singboxConfig.route.rules);
|
await GenRoutingUserRule(item, singboxConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1074,7 +1211,7 @@ public class CoreConfigSingboxService
|
||||||
lstDirectExe = new List<string>(directExeSet);
|
lstDirectExe = new List<string>(directExeSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
private async Task<int> GenRoutingUserRule(RulesItem item, SingboxConfig singboxConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -1082,6 +1219,8 @@ public class CoreConfigSingboxService
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
item.OutboundTag = await GenRoutingUserRuleOutbound(item.OutboundTag, singboxConfig);
|
||||||
|
var rules = singboxConfig.route.rules;
|
||||||
|
|
||||||
var rule = new Rule4Sbox()
|
var rule = new Rule4Sbox()
|
||||||
{
|
{
|
||||||
|
|
@ -1233,6 +1372,29 @@ public class CoreConfigSingboxService
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string?> GenRoutingUserRuleOutbound(string outboundTag, SingboxConfig singboxConfig)
|
||||||
|
{
|
||||||
|
if (Global.OutboundTags.Contains(outboundTag))
|
||||||
|
{
|
||||||
|
return outboundTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
var node = await AppHandler.Instance.GetProfileItemViaRemarks(outboundTag);
|
||||||
|
if (node == null
|
||||||
|
|| node.ConfigType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
|
await GenOutbound(node, outbound);
|
||||||
|
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
|
||||||
|
singboxConfig.outbounds.Add(outbound);
|
||||||
|
|
||||||
|
return outbound.tag;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
|
private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,12 @@ public class CoreConfigV2rayService
|
||||||
|
|
||||||
await GenInbounds(v2rayConfig);
|
await GenInbounds(v2rayConfig);
|
||||||
|
|
||||||
await GenRouting(v2rayConfig);
|
|
||||||
|
|
||||||
await GenOutbound(node, v2rayConfig.outbounds.First());
|
await GenOutbound(node, v2rayConfig.outbounds.First());
|
||||||
|
|
||||||
await GenMoreOutbounds(node, v2rayConfig);
|
await GenMoreOutbounds(node, v2rayConfig);
|
||||||
|
|
||||||
|
await GenRouting(v2rayConfig);
|
||||||
|
|
||||||
await GenDns(node, v2rayConfig);
|
await GenDns(node, v2rayConfig);
|
||||||
|
|
||||||
await GenStatistic(v2rayConfig);
|
await GenStatistic(v2rayConfig);
|
||||||
|
|
@ -113,7 +113,7 @@ public class CoreConfigV2rayService
|
||||||
await GenStatistic(v2rayConfig);
|
await GenStatistic(v2rayConfig);
|
||||||
v2rayConfig.outbounds.RemoveAt(0);
|
v2rayConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
var tagProxy = new List<string>();
|
var proxyProfiles = new List<ProfileItem>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
|
|
@ -151,17 +151,14 @@ public class CoreConfigV2rayService
|
||||||
}
|
}
|
||||||
|
|
||||||
//outbound
|
//outbound
|
||||||
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
proxyProfiles.Add(item);
|
||||||
await GenOutbound(item, outbound);
|
|
||||||
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
|
||||||
v2rayConfig.outbounds.Insert(0, outbound);
|
|
||||||
tagProxy.Add(outbound.tag);
|
|
||||||
}
|
}
|
||||||
if (tagProxy.Count <= 0)
|
if (proxyProfiles.Count <= 0)
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
await GenOutboundsList(proxyProfiles, v2rayConfig);
|
||||||
|
|
||||||
//add balancers
|
//add balancers
|
||||||
await GenBalancer(v2rayConfig, multipleLoad);
|
await GenBalancer(v2rayConfig, multipleLoad);
|
||||||
|
|
@ -559,6 +556,8 @@ public class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
rule.outboundTag = await GenRoutingUserRuleOutbound(rule.outboundTag, v2rayConfig);
|
||||||
|
|
||||||
if (rule.port.IsNullOrEmpty())
|
if (rule.port.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
rule.port = null;
|
rule.port = null;
|
||||||
|
|
@ -630,11 +629,36 @@ public class CoreConfigV2rayService
|
||||||
return await Task.FromResult(0);
|
return await Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string?> GenRoutingUserRuleOutbound(string outboundTag, V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
if (Global.OutboundTags.Contains(outboundTag))
|
||||||
|
{
|
||||||
|
return outboundTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
var node = await AppHandler.Instance.GetProfileItemViaRemarks(outboundTag);
|
||||||
|
if (node == null
|
||||||
|
|| node.ConfigType == EConfigType.Custom
|
||||||
|
|| node.ConfigType == EConfigType.Hysteria2
|
||||||
|
|| node.ConfigType == EConfigType.TUIC)
|
||||||
|
{
|
||||||
|
return Global.ProxyTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(node, outbound);
|
||||||
|
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
|
||||||
|
v2rayConfig.outbounds.Add(outbound);
|
||||||
|
|
||||||
|
return outbound.tag;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
|
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var muxEnabled = _config.CoreBasicItem.MuxEnabled;
|
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
|
||||||
switch (node.ConfigType)
|
switch (node.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.VMess:
|
||||||
|
|
@ -1321,6 +1345,7 @@ 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
|
||||||
|
|
@ -1328,32 +1353,15 @@ public class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
prevOutbound.tag = $"{Global.ProxyTag}2";
|
prevOutboundTag = $"prev-{Global.ProxyTag}";
|
||||||
|
prevOutbound.tag = prevOutboundTag;
|
||||||
v2rayConfig.outbounds.Add(prevOutbound);
|
v2rayConfig.outbounds.Add(prevOutbound);
|
||||||
|
|
||||||
outbound.streamSettings.sockopt = new()
|
|
||||||
{
|
|
||||||
dialerProxy = prevOutbound.tag
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
|
||||||
|
|
||||||
//Next proxy
|
if (nextOutbound is not null)
|
||||||
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
|
||||||
if (nextNode is not null
|
|
||||||
&& nextNode.ConfigType != EConfigType.Custom
|
|
||||||
&& nextNode.ConfigType != EConfigType.Hysteria2
|
|
||||||
&& nextNode.ConfigType != EConfigType.TUIC)
|
|
||||||
{
|
{
|
||||||
var nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
|
||||||
nextOutbound.tag = Global.ProxyTag;
|
|
||||||
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
||||||
|
|
||||||
outbound.tag = $"{Global.ProxyTag}1";
|
|
||||||
nextOutbound.streamSettings.sockopt = new()
|
|
||||||
{
|
|
||||||
dialerProxy = outbound.tag
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -1364,18 +1372,179 @@ public class CoreConfigV2rayService
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, V2rayConfig v2rayConfig)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get template and initialize list
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
if (txtOutbound.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultOutbounds = new List<Outbounds4Ray>();
|
||||||
|
var prevOutbounds = new List<Outbounds4Ray>(); // Separate list for prev outbounds and fragment
|
||||||
|
|
||||||
|
// Cache for chain proxies to avoid duplicate generation
|
||||||
|
var nextProxyCache = new Dictionary<string, Outbounds4Ray?>();
|
||||||
|
var prevProxyTags = new Dictionary<string, string?>(); // Map from profile name to tag
|
||||||
|
int prevIndex = 0; // Index for prev outbounds
|
||||||
|
|
||||||
|
// Process nodes
|
||||||
|
int index = 0;
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
|
||||||
|
// Handle proxy chain
|
||||||
|
string? prevTag = null;
|
||||||
|
var currentOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
var nextOutbound = nextProxyCache.GetValueOrDefault(node.Subid, null);
|
||||||
|
if (nextOutbound != null)
|
||||||
|
{
|
||||||
|
nextOutbound = JsonUtils.DeepCopy(nextOutbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
|
||||||
|
|
||||||
|
// current proxy
|
||||||
|
await GenOutbound(node, currentOutbound);
|
||||||
|
currentOutbound.tag = $"{Global.ProxyTag}-{index}";
|
||||||
|
|
||||||
|
if (!node.Subid.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
if (prevProxyTags.TryGetValue(node.Subid, out var value))
|
||||||
|
{
|
||||||
|
prevTag = value; // maybe null
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
||||||
|
if (prevNode is not null
|
||||||
|
&& prevNode.ConfigType != EConfigType.Custom
|
||||||
|
&& prevNode.ConfigType != EConfigType.Hysteria2
|
||||||
|
&& prevNode.ConfigType != EConfigType.TUIC)
|
||||||
|
{
|
||||||
|
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
|
prevTag = $"prev-{Global.ProxyTag}-{++prevIndex}";
|
||||||
|
prevOutbound.tag = prevTag;
|
||||||
|
prevOutbounds.Add(prevOutbound);
|
||||||
|
}
|
||||||
|
prevProxyTags[node.Subid] = prevTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag, nextOutbound);
|
||||||
|
if (!nextProxyCache.ContainsKey(node.Subid))
|
||||||
|
{
|
||||||
|
nextProxyCache[node.Subid] = nextOutbound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextOutbound is not null)
|
||||||
|
{
|
||||||
|
resultOutbounds.Add(nextOutbound);
|
||||||
|
}
|
||||||
|
resultOutbounds.Add(currentOutbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge results: first the main chain outbounds, then other outbounds, and finally utility outbounds
|
||||||
|
resultOutbounds.AddRange(prevOutbounds);
|
||||||
|
resultOutbounds.AddRange(v2rayConfig.outbounds);
|
||||||
|
v2rayConfig.outbounds = resultOutbounds;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a chained outbound configuration for the given subItem and outbound.
|
||||||
|
/// The outbound's tag must be set before calling this method.
|
||||||
|
/// Returns the next proxy's outbound configuration, which may be null if no next proxy exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="subItem">The subscription item containing proxy chain information.</param>
|
||||||
|
/// <param name="outbound">The current outbound configuration. Its tag must be set before calling this method.</param>
|
||||||
|
/// <param name="prevOutboundTag">The tag of the previous outbound in the chain, if any.</param>
|
||||||
|
/// <param name="nextOutbound">The outbound for the next proxy in the chain, if already created. If null, will be created inside.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The outbound configuration for the next proxy in the chain, or null if no next proxy exists.
|
||||||
|
/// </returns>
|
||||||
|
private async Task<Outbounds4Ray?> GenChainOutbounds(SubItem subItem, Outbounds4Ray outbound, string? prevOutboundTag, Outbounds4Ray? nextOutbound = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
|
||||||
|
if (!prevOutboundTag.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
outbound.streamSettings.sockopt = new()
|
||||||
|
{
|
||||||
|
dialerProxy = prevOutboundTag
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next proxy
|
||||||
|
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
||||||
|
if (nextNode is not null
|
||||||
|
&& nextNode.ConfigType != EConfigType.Custom
|
||||||
|
&& nextNode.ConfigType != EConfigType.Hysteria2
|
||||||
|
&& nextNode.ConfigType != EConfigType.TUIC)
|
||||||
|
{
|
||||||
|
if (nextOutbound == null)
|
||||||
|
{
|
||||||
|
nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
|
}
|
||||||
|
nextOutbound.tag = outbound.tag;
|
||||||
|
|
||||||
|
outbound.tag = $"mid-{outbound.tag}";
|
||||||
|
nextOutbound.streamSettings.sockopt = new()
|
||||||
|
{
|
||||||
|
dialerProxy = outbound.tag
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return nextOutbound;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
||||||
{
|
{
|
||||||
if (multipleLoad is EMultipleLoad.LeastLoad or EMultipleLoad.LeastPing)
|
if (multipleLoad == EMultipleLoad.LeastPing)
|
||||||
{
|
{
|
||||||
var observatory = new Observatory4Ray
|
var observatory = new Observatory4Ray
|
||||||
{
|
{
|
||||||
subjectSelector = [Global.ProxyTag],
|
subjectSelector = [Global.ProxyTag],
|
||||||
probeUrl = AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
probeUrl = AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
||||||
probeInterval = "3m"
|
probeInterval = "3m",
|
||||||
|
enableConcurrency = true,
|
||||||
};
|
};
|
||||||
v2rayConfig.observatory = observatory;
|
v2rayConfig.observatory = observatory;
|
||||||
}
|
}
|
||||||
|
else if (multipleLoad == EMultipleLoad.LeastLoad)
|
||||||
|
{
|
||||||
|
var burstObservatory = new BurstObservatory4Ray
|
||||||
|
{
|
||||||
|
subjectSelector = [Global.ProxyTag],
|
||||||
|
pingConfig = new()
|
||||||
|
{
|
||||||
|
destination = AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
||||||
|
interval = "5m",
|
||||||
|
timeout = "30s",
|
||||||
|
sampling = 2,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
v2rayConfig.burstObservatory = burstObservatory;
|
||||||
|
}
|
||||||
var strategyType = multipleLoad switch
|
var strategyType = multipleLoad switch
|
||||||
{
|
{
|
||||||
EMultipleLoad.Random => "random",
|
EMultipleLoad.Random => "random",
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,7 @@ public class SpeedtestService
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
var downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
|
|
||||||
|
|
@ -255,9 +256,13 @@ public class SpeedtestService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
||||||
if (pid > 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
var delay = await DoRealPing(downloadHandle, it);
|
var delay = await DoRealPing(downloadHandle, it);
|
||||||
if (blSpeedTest)
|
if (blSpeedTest)
|
||||||
{
|
{
|
||||||
|
|
@ -271,10 +276,6 @@ public class SpeedtestService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -485,6 +485,12 @@ public class UpdateService
|
||||||
|
|
||||||
private async Task UpdateOtherFiles(Config config, Action<bool, string> updateFunc)
|
private async Task UpdateOtherFiles(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
|
//If it is not in China area, no update is required
|
||||||
|
if (config.ConstItem.GeoSourceUrl.IsNotEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_updateFunc = updateFunc;
|
_updateFunc = updateFunc;
|
||||||
|
|
||||||
foreach (var url in Global.OtherGeoUrls)
|
foreach (var url in Global.OtherGeoUrls)
|
||||||
|
|
@ -530,6 +536,11 @@ public class UpdateService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//append dns items TODO
|
||||||
|
geoSiteFiles.Add("cn");
|
||||||
|
geoSiteFiles.Add("geolocation-cn");
|
||||||
|
geoSiteFiles.Add("category-ads-all");
|
||||||
|
|
||||||
var path = Utils.GetBinPath("srss");
|
var path = Utils.GetBinPath("srss");
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -552,6 +552,7 @@ 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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -304,7 +304,7 @@ public class ProfilesViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
item.SpeedVal = result.Speed ?? string.Empty;
|
item.SpeedVal = result.Speed ?? string.Empty;
|
||||||
}
|
}
|
||||||
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
//_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateStatistics(ServerSpeedItem update)
|
public void UpdateStatistics(ServerSpeedItem update)
|
||||||
|
|
@ -319,16 +319,16 @@ public class ProfilesViewModel : MyReactiveObject
|
||||||
item.TotalDown = Utils.HumanFy(update.TotalDown);
|
item.TotalDown = Utils.HumanFy(update.TotalDown);
|
||||||
item.TotalUp = Utils.HumanFy(update.TotalUp);
|
item.TotalUp = Utils.HumanFy(update.TotalUp);
|
||||||
|
|
||||||
if (SelectedProfile?.IndexId == item.IndexId)
|
//if (SelectedProfile?.IndexId == item.IndexId)
|
||||||
{
|
//{
|
||||||
var temp = JsonUtils.DeepCopy(item);
|
// var temp = JsonUtils.DeepCopy(item);
|
||||||
_profileItems.Replace(item, temp);
|
// _profileItems.Replace(item, temp);
|
||||||
SelectedProfile = temp;
|
// SelectedProfile = temp;
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
// _profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,9 @@ public class RoutingSettingViewModel : MyReactiveObject
|
||||||
var routings = await AppHandler.Instance.RoutingItems();
|
var routings = await AppHandler.Instance.RoutingItems();
|
||||||
foreach (var item in routings)
|
foreach (var item in routings)
|
||||||
{
|
{
|
||||||
var def = item.Id == _config.RoutingBasicItem.RoutingIndexId;
|
|
||||||
|
|
||||||
var it = new RoutingItemModel()
|
var it = new RoutingItemModel()
|
||||||
{
|
{
|
||||||
IsActive = def,
|
IsActive = item.IsActive,
|
||||||
RuleNum = item.RuleNum,
|
RuleNum = item.RuleNum,
|
||||||
Id = item.Id,
|
Id = item.Id,
|
||||||
Remarks = item.Remarks,
|
Remarks = item.Remarks,
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
public ReactiveCommand<Unit, Unit> SubUpdateViaProxyCmd { get; }
|
public ReactiveCommand<Unit, Unit> SubUpdateViaProxyCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> CopyProxyCmdToClipboardCmd { get; }
|
public ReactiveCommand<Unit, Unit> CopyProxyCmdToClipboardCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; }
|
public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ShowWindowCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> HideWindowCmd { get; }
|
||||||
|
|
||||||
#region System Proxy
|
#region System Proxy
|
||||||
|
|
||||||
|
|
@ -91,6 +93,9 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public bool EnableTun { get; set; }
|
public bool EnableTun { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool BlIsNonWindows { get; set; }
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
public StatusBarViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
public StatusBarViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
||||||
|
|
@ -100,6 +105,7 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
SelectedServer = new();
|
SelectedServer = new();
|
||||||
RunningServerToolTipText = "-";
|
RunningServerToolTipText = "-";
|
||||||
BlSystemProxyPacVisible = Utils.IsWindows();
|
BlSystemProxyPacVisible = Utils.IsWindows();
|
||||||
|
BlIsNonWindows = Utils.IsNonWindows();
|
||||||
|
|
||||||
if (_config.TunModeItem.EnableTun && AllowEnableTun())
|
if (_config.TunModeItem.EnableTun && AllowEnableTun())
|
||||||
{
|
{
|
||||||
|
|
@ -143,6 +149,16 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(null);
|
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(null);
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
ShowWindowCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(true);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
});
|
||||||
|
HideWindowCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(false);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
|
|
@ -372,7 +388,7 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
foreach (var item in routings)
|
foreach (var item in routings)
|
||||||
{
|
{
|
||||||
_routingItems.Add(item);
|
_routingItems.Add(item);
|
||||||
if (item.Id == _config.RoutingBasicItem.RoutingIndexId)
|
if (item.IsActive)
|
||||||
{
|
{
|
||||||
SelectedRouting = item;
|
SelectedRouting = item;
|
||||||
}
|
}
|
||||||
|
|
@ -396,10 +412,6 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_config.RoutingBasicItem.RoutingIndexId == item.Id)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
|
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -424,12 +436,16 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
|
|
||||||
private async Task DoEnableTun(bool c)
|
private async Task DoEnableTun(bool c)
|
||||||
{
|
{
|
||||||
if (_config.TunModeItem.EnableTun != EnableTun)
|
if (_config.TunModeItem.EnableTun == EnableTun)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_config.TunModeItem.EnableTun = EnableTun;
|
_config.TunModeItem.EnableTun = EnableTun;
|
||||||
// When running as a non-administrator, reboot to administrator mode
|
|
||||||
if (EnableTun && AllowEnableTun() == false)
|
if (EnableTun && AllowEnableTun() == false)
|
||||||
{
|
{
|
||||||
|
// When running as a non-administrator, reboot to administrator mode
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
_config.TunModeItem.EnableTun = false;
|
_config.TunModeItem.EnableTun = false;
|
||||||
|
|
@ -438,7 +454,8 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (await _updateView?.Invoke(EViewAction.PasswordInput, null) == false)
|
bool? passwordResult = await _updateView?.Invoke(EViewAction.PasswordInput, null);
|
||||||
|
if (passwordResult == false)
|
||||||
{
|
{
|
||||||
_config.TunModeItem.EnableTun = false;
|
_config.TunModeItem.EnableTun = false;
|
||||||
return;
|
return;
|
||||||
|
|
@ -448,7 +465,6 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
await ConfigHandler.SaveConfig(_config);
|
await ConfigHandler.SaveConfig(_config);
|
||||||
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private bool AllowEnableTun()
|
private bool AllowEnableTun()
|
||||||
{
|
{
|
||||||
|
|
@ -499,10 +515,18 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
public void UpdateStatistics(ServerSpeedItem update)
|
public void UpdateStatistics(ServerSpeedItem update)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
if (_config.IsRunningCore(ECoreType.sing_box))
|
||||||
|
{
|
||||||
|
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));
|
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));
|
SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.DirectTag, Utils.HumanFy(update.DirectUp), Utils.HumanFy(update.DirectDown));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
xmlns:semi="https://irihi.tech/semi"
|
xmlns:semi="https://irihi.tech/semi"
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
x:DataType="vms:StatusBarViewModel"
|
|
||||||
Name="v2rayN"
|
Name="v2rayN"
|
||||||
|
x:DataType="vms:StatusBarViewModel"
|
||||||
RequestedThemeVariant="Default">
|
RequestedThemeVariant="Default">
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<semi:SemiTheme />
|
<semi:SemiTheme />
|
||||||
|
|
@ -32,6 +32,16 @@
|
||||||
ToolTipText="{Binding RunningServerToolTipText}">
|
ToolTipText="{Binding RunningServerToolTipText}">
|
||||||
<TrayIcon.Menu>
|
<TrayIcon.Menu>
|
||||||
<NativeMenu>
|
<NativeMenu>
|
||||||
|
<NativeMenuItem
|
||||||
|
Command="{Binding ShowWindowCmd}"
|
||||||
|
Header="{x:Static resx:ResUI.TbDisplayGUI}"
|
||||||
|
IsVisible="{Binding BlIsNonWindows}" />
|
||||||
|
<NativeMenuItem
|
||||||
|
Command="{Binding NotifyLeftClickCmd}"
|
||||||
|
Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}"
|
||||||
|
IsVisible="{Binding BlIsNonWindows}" />
|
||||||
|
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
||||||
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem
|
<NativeMenuItem
|
||||||
Command="{Binding SystemProxyClearCmd}"
|
Command="{Binding SystemProxyClearCmd}"
|
||||||
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
||||||
|
|
@ -55,13 +65,9 @@
|
||||||
ToggleType="Radio" />
|
ToggleType="Radio" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
||||||
<NativeMenuItem Header="{x:Static resx:ResUI.menuAddServerViaScan}" IsVisible="False" />
|
|
||||||
<NativeMenuItem Command="{Binding SubUpdateCmd}" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
<NativeMenuItem Command="{Binding SubUpdateCmd}" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||||
<NativeMenuItem Command="{Binding SubUpdateViaProxyCmd}" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
<NativeMenuItem Command="{Binding SubUpdateViaProxyCmd}" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
|
||||||
<NativeMenuItemSeparator />
|
|
||||||
<NativeMenuItem Command="{Binding NotifyLeftClickCmd}" Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}" />
|
|
||||||
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
||||||
</NativeMenu>
|
</NativeMenu>
|
||||||
</TrayIcon.Menu>
|
</TrayIcon.Menu>
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,6 @@ public partial class App : Application
|
||||||
{
|
{
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
if (!AppHandler.Instance.InitApp())
|
|
||||||
{
|
|
||||||
Environment.Exit(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
|
|
|
||||||
52
v2rayN/v2rayN.Desktop/Base/WindowBase.cs
Normal file
52
v2rayN/v2rayN.Desktop/Base/WindowBase.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace v2rayN.Desktop.Base;
|
||||||
|
|
||||||
|
public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewModel : class
|
||||||
|
{
|
||||||
|
public WindowBase()
|
||||||
|
{
|
||||||
|
Loaded += OnLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReactiveWindowBase_Closed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sizeItem = ConfigHandler.GetWindowSizeItem(AppHandler.Instance.Config, GetType().Name);
|
||||||
|
if (sizeItem == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Width = sizeItem.Width;
|
||||||
|
Height = sizeItem.Height;
|
||||||
|
|
||||||
|
var workingArea = (Screens.ScreenFromWindow(this) ?? Screens.Primary).WorkingArea;
|
||||||
|
var scaling = (Utils.IsOSX() ? null : VisualRoot?.RenderScaling) ?? 1.0;
|
||||||
|
|
||||||
|
var x = workingArea.X + ((workingArea.Width - (Width * scaling)) / 2);
|
||||||
|
var y = workingArea.Y + ((workingArea.Height - (Height * scaling)) / 2);
|
||||||
|
|
||||||
|
Position = new PixelPoint((int)x, (int)y);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClosed(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnClosed(e);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConfigHandler.SaveWindowSizeItem(AppHandler.Instance.Config, GetType().Name, Width, Height);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,13 +14,17 @@ internal class Program
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
OnStartup(args);
|
if (OnStartup(args) == false)
|
||||||
|
{
|
||||||
|
Environment.Exit(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BuildAvaloniaApp()
|
BuildAvaloniaApp()
|
||||||
.StartWithClassicDesktopLifetime(args);
|
.StartWithClassicDesktopLifetime(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnStartup(string[]? Args)
|
private static bool OnStartup(string[]? Args)
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
|
|
@ -30,8 +34,7 @@ internal class Program
|
||||||
if (!rebootas && !bCreatedNew)
|
if (!rebootas && !bCreatedNew)
|
||||||
{
|
{
|
||||||
ProgramStarted.Set();
|
ProgramStarted.Set();
|
||||||
Environment.Exit(0);
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -39,19 +42,26 @@ internal class Program
|
||||||
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
||||||
if (!bOnlyOneInstance)
|
if (!bOnlyOneInstance)
|
||||||
{
|
{
|
||||||
Environment.Exit(0);
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!AppHandler.Instance.InitApp())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
=> AppBuilder.Configure<App>()
|
{
|
||||||
|
return AppBuilder.Configure<App>()
|
||||||
.UsePlatformDetect()
|
.UsePlatformDetect()
|
||||||
//.WithInterFont()
|
//.WithInterFont()
|
||||||
.WithFontByDefault()
|
.WithFontByDefault()
|
||||||
.LogToTrace()
|
.LogToTrace()
|
||||||
.UseReactiveUI()
|
.UseReactiveUI()
|
||||||
.With(new MacOSPlatformOptions { ShowInDock = false });
|
.With(new MacOSPlatformOptions { ShowInDock = AppHandler.Instance.Config.UiItem.MacOSShowInDock });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
public partial class AddServer2Window : WindowBase<AddServer2ViewModel>
|
||||||
{
|
{
|
||||||
public AddServer2Window()
|
public AddServer2Window()
|
||||||
{
|
{
|
||||||
|
|
@ -21,13 +21,7 @@ public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
foreach (ECoreType it in Enum.GetValues(typeof(ECoreType)))
|
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
|
||||||
{
|
|
||||||
if (it == ECoreType.v2rayN)
|
|
||||||
continue;
|
|
||||||
cmbCoreType.Items.Add(it.ToString());
|
|
||||||
}
|
|
||||||
cmbCoreType.Items.Add(string.Empty);
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto,Auto"
|
ColumnDefinitions="180,Auto,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|
@ -152,13 +152,26 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSs"
|
x:Name="gridSs"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto"
|
ColumnDefinitions="180,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|
@ -185,6 +198,19 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled3"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSocks"
|
x:Name="gridSocks"
|
||||||
|
|
@ -224,7 +250,7 @@
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto,Auto"
|
ColumnDefinitions="180,Auto,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|
@ -271,13 +297,26 @@
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled5"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridTrojan"
|
x:Name="gridTrojan"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto"
|
ColumnDefinitions="180,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|
@ -304,6 +343,19 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togmuxEnabled6"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridHysteria2"
|
x:Name="gridHysteria2"
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
||||||
{
|
{
|
||||||
public AddServerWindow()
|
public AddServerWindow()
|
||||||
{
|
{
|
||||||
|
|
@ -26,41 +26,22 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
|
|
||||||
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
Global.CoreTypes.ForEach(it =>
|
cmbCoreType.ItemsSource = Global.CoreTypes.AppendEmpty();
|
||||||
{
|
cmbNetwork.ItemsSource = Global.Networks;
|
||||||
cmbCoreType.Items.Add(it);
|
cmbFingerprint.ItemsSource = Global.Fingerprints;
|
||||||
});
|
cmbFingerprint2.ItemsSource = Global.Fingerprints;
|
||||||
cmbCoreType.Items.Add(string.Empty);
|
cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
|
||||||
|
cmbAlpn.ItemsSource = Global.Alpns;
|
||||||
|
|
||||||
cmbStreamSecurity.Items.Add(string.Empty);
|
var lstStreamSecurity = new List<string>();
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurity);
|
lstStreamSecurity.Add(string.Empty);
|
||||||
|
lstStreamSecurity.Add(Global.StreamSecurity);
|
||||||
Global.Networks.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbNetwork.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Fingerprints.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbFingerprint.Items.Add(it);
|
|
||||||
cmbFingerprint2.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.AllowInsecure.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbAllowInsecure.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Alpns.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbAlpn.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (profileItem.ConfigType)
|
switch (profileItem.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.VMess:
|
||||||
gridVMess.IsVisible = true;
|
gridVMess.IsVisible = true;
|
||||||
Global.VmessSecurities.ForEach(it =>
|
cmbSecurity.ItemsSource = Global.VmessSecurities;
|
||||||
{
|
|
||||||
cmbSecurity.Items.Add(it);
|
|
||||||
});
|
|
||||||
if (profileItem.Security.IsNullOrEmpty())
|
if (profileItem.Security.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Security = Global.DefaultSecurity;
|
profileItem.Security = Global.DefaultSecurity;
|
||||||
|
|
@ -69,10 +50,7 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
|
|
||||||
case EConfigType.Shadowsocks:
|
case EConfigType.Shadowsocks:
|
||||||
gridSs.IsVisible = true;
|
gridSs.IsVisible = true;
|
||||||
AppHandler.Instance.GetShadowsocksSecurities(profileItem).ForEach(it =>
|
cmbSecurity3.ItemsSource = AppHandler.Instance.GetShadowsocksSecurities(profileItem);
|
||||||
{
|
|
||||||
cmbSecurity3.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
|
|
@ -82,11 +60,8 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
|
|
||||||
case EConfigType.VLESS:
|
case EConfigType.VLESS:
|
||||||
gridVLESS.IsVisible = true;
|
gridVLESS.IsVisible = true;
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||||
Global.Flows.ForEach(it =>
|
cmbFlow5.ItemsSource = Global.Flows;
|
||||||
{
|
|
||||||
cmbFlow5.Items.Add(it);
|
|
||||||
});
|
|
||||||
if (profileItem.Security.IsNullOrEmpty())
|
if (profileItem.Security.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Security = Global.None;
|
profileItem.Security = Global.None;
|
||||||
|
|
@ -95,11 +70,8 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
|
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
gridTrojan.IsVisible = true;
|
gridTrojan.IsVisible = true;
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||||
Global.Flows.ForEach(it =>
|
cmbFlow6.ItemsSource = Global.Flows;
|
||||||
{
|
|
||||||
cmbFlow6.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
|
|
@ -119,10 +91,7 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
cmbFingerprint.IsEnabled = false;
|
cmbFingerprint.IsEnabled = false;
|
||||||
cmbFingerprint.SelectedValue = string.Empty;
|
cmbFingerprint.SelectedValue = string.Empty;
|
||||||
|
|
||||||
Global.TuicCongestionControls.ForEach(it =>
|
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls;
|
||||||
{
|
|
||||||
cmbHeaderType8.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.WireGuard:
|
case EConfigType.WireGuard:
|
||||||
|
|
@ -134,6 +103,7 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
|
||||||
|
|
||||||
gridTlsMore.IsVisible = false;
|
gridTlsMore.IsVisible = false;
|
||||||
|
|
||||||
|
|
@ -150,11 +120,13 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Shadowsocks:
|
case EConfigType.Shadowsocks:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
|
|
@ -167,11 +139,13 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled5.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled6.IsChecked).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
|
|
@ -268,44 +242,41 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
|
|
||||||
private void SetHeaderType()
|
private void SetHeaderType()
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Clear();
|
var lstHeaderType = new List<string>();
|
||||||
|
|
||||||
var network = cmbNetwork.SelectedItem.ToString();
|
var network = cmbNetwork.SelectedItem.ToString();
|
||||||
if (network.IsNullOrEmpty())
|
if (network.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
|
cmbHeaderType.ItemsSource = lstHeaderType;
|
||||||
|
cmbHeaderType.SelectedIndex = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (network == nameof(ETransport.tcp))
|
if (network == nameof(ETransport.tcp))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
|
lstHeaderType.Add(Global.TcpHeaderHttp);
|
||||||
}
|
}
|
||||||
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
|
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
Global.KcpHeaderTypes.ForEach(it =>
|
lstHeaderType.AddRange(Global.KcpHeaderTypes);
|
||||||
{
|
|
||||||
cmbHeaderType.Items.Add(it);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (network is nameof(ETransport.xhttp))
|
else if (network is nameof(ETransport.xhttp))
|
||||||
{
|
{
|
||||||
Global.XhttpMode.ForEach(it =>
|
lstHeaderType.AddRange(Global.XhttpMode);
|
||||||
{
|
|
||||||
cmbHeaderType.Items.Add(it);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (network == nameof(ETransport.grpc))
|
else if (network == nameof(ETransport.grpc))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.GrpcGunMode);
|
lstHeaderType.Add(Global.GrpcGunMode);
|
||||||
cmbHeaderType.Items.Add(Global.GrpcMultiMode);
|
lstHeaderType.Add(Global.GrpcMultiMode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
}
|
}
|
||||||
|
cmbHeaderType.ItemsSource = lstHeaderType;
|
||||||
cmbHeaderType.SelectedIndex = 0;
|
cmbHeaderType.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TabControl HorizontalContentAlignment="Left">
|
<TabControl HorizontalContentAlignment="Stretch">
|
||||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||||
|
|
@ -90,16 +90,18 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin4}">
|
<HeaderedContentControl
|
||||||
<TextBox
|
|
||||||
x:Name="txtnormalDNS"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Stretch"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
|
Header="HTTP/SOCKS">
|
||||||
|
<TextBox
|
||||||
|
Name="txtnormalDNS"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
TextWrapping="Wrap"
|
MinLines="10"
|
||||||
Watermark="HTTP/SOCKS" />
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</HeaderedContentControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
|
@ -144,31 +146,34 @@
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
||||||
|
|
||||||
<TextBox
|
<HeaderedContentControl
|
||||||
x:Name="txtnormalDNS2"
|
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Width="400"
|
BorderBrush="Gray"
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
|
Header="HTTP/SOCKS">
|
||||||
|
<TextBox
|
||||||
|
Name="txtnormalDNS2"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
Margin="{StaticResource Margin4}"
|
MinLines="10"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap" />
|
||||||
Watermark="HTTP/SOCKS" />
|
</HeaderedContentControl>
|
||||||
|
|
||||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||||
|
|
||||||
<TextBox
|
<HeaderedContentControl
|
||||||
x:Name="txttunDNS2"
|
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Width="400"
|
BorderBrush="Gray"
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
|
Header="{x:Static resx:ResUI.TbSettingsTunMode}">
|
||||||
|
<TextBox
|
||||||
|
Name="txttunDNS2"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
Margin="{StaticResource Margin4}"
|
MinLines="10"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap" />
|
||||||
Watermark="{x:Static resx:ResUI.TbSettingsTunMode}" />
|
</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 : ReactiveWindow<DNSSettingViewModel>
|
public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
|
|
@ -17,22 +17,10 @@ public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
Global.DomainStrategy4Freedoms.ForEach(it =>
|
cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms;
|
||||||
{
|
cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out;
|
||||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress;
|
||||||
});
|
cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress;
|
||||||
Global.SingboxDomainStrategy4Out.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Out.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.DomainDNSAddress.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainDNSAddress.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxDomainDNSAddress.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainDNSAddress2.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ using System.Text;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Handler;
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingViewModel>
|
||||||
{
|
{
|
||||||
private readonly List<object> _textBoxKeyEventItem = new();
|
private readonly List<object> _textBoxKeyEventItem = new();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,18 @@ using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Controls.Notifications;
|
using Avalonia.Controls.Notifications;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Splat;
|
using Splat;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
using v2rayN.Desktop.Handler;
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
private WindowNotificationManager? _manager;
|
private WindowNotificationManager? _manager;
|
||||||
|
|
@ -29,7 +29,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_config = AppHandler.Instance.Config;
|
_config = AppHandler.Instance.Config;
|
||||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
|
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
|
||||||
|
|
||||||
this.KeyDown += MainWindow_KeyDown;
|
this.KeyDown += MainWindow_KeyDown;
|
||||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||||
|
|
@ -135,26 +135,23 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Title = $"{Utils.GetVersion()}";
|
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
|
this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||||
|
|
||||||
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||||
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Utils.IsAdministrator())
|
this.Title = $"{Utils.GetVersion()}";
|
||||||
{
|
|
||||||
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
|
|
||||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
|
|
||||||
}
|
|
||||||
menuRebootAsAdmin.IsVisible = false;
|
menuRebootAsAdmin.IsVisible = false;
|
||||||
menuSettingsSetUWP.IsVisible = false;
|
menuSettingsSetUWP.IsVisible = false;
|
||||||
menuGlobalHotkeySetting.IsVisible = false;
|
menuGlobalHotkeySetting.IsVisible = false;
|
||||||
}
|
}
|
||||||
menuAddServerViaScan.IsVisible = false;
|
menuAddServerViaScan.IsVisible = false;
|
||||||
|
|
||||||
RestoreUI();
|
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||||
}
|
}
|
||||||
|
|
@ -436,14 +433,14 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||||
_config.UiItem.ShowInTaskbar = bl;
|
_config.UiItem.ShowInTaskbar = bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreUI()
|
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_config.UiItem.MainWidth > 0 && _config.UiItem.MainHeight > 0)
|
base.OnLoaded(sender, e);
|
||||||
{
|
RestoreUI();
|
||||||
Width = _config.UiItem.MainWidth;
|
|
||||||
Height = _config.UiItem.MainHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RestoreUI()
|
||||||
|
{
|
||||||
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
||||||
{
|
{
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
|
|
@ -461,18 +458,15 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||||
|
|
||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainWidth = this.Width;
|
ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
|
||||||
_config.UiItem.MainHeight = this.Height;
|
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
|
||||||
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
|
|
||||||
}
|
}
|
||||||
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
|
||||||
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -575,9 +575,9 @@
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
||||||
<ctrls:AutoCompleteBox
|
<ComboBox
|
||||||
x:Name="cmbSubConvertUrl"
|
x:Name="cmbIPAPIUrl"
|
||||||
Grid.Row="20"
|
Grid.Row="20"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
|
|
@ -588,28 +588,41 @@
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||||
|
<ctrls:AutoCompleteBox
|
||||||
|
x:Name="cmbSubConvertUrl"
|
||||||
|
Grid.Row="21"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="22"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="21"
|
Grid.Row="22"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbGetFilesSourceUrl"
|
x:Name="cmbGetFilesSourceUrl"
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -617,19 +630,19 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSrsFilesSourceUrl"
|
x:Name="cmbSrsFilesSourceUrl"
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -637,38 +650,25 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRoutingRulesSourceUrl"
|
x:Name="cmbRoutingRulesSourceUrl"
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="25"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
|
||||||
<ComboBox
|
|
||||||
x:Name="cmbIPAPIUrl"
|
|
||||||
Grid.Row="25"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="300"
|
|
||||||
Margin="{StaticResource Margin4}" />
|
|
||||||
|
|
||||||
</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 : ReactiveWindow<OptionSettingViewModel>
|
public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
|
|
@ -19,87 +19,39 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
||||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
||||||
Global.destOverrideProtocols.ForEach(it =>
|
clbdestOverride.ItemsSource = Global.destOverrideProtocols;
|
||||||
{
|
|
||||||
clbdestOverride.Items.Add(it);
|
|
||||||
});
|
|
||||||
_config.Inbound.First().DestOverride?.ForEach(it =>
|
_config.Inbound.First().DestOverride?.ForEach(it =>
|
||||||
{
|
{
|
||||||
clbdestOverride.SelectedItems.Add(it);
|
clbdestOverride.SelectedItems.Add(it);
|
||||||
});
|
});
|
||||||
Global.IEProxyProtocols.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbsystemProxyAdvancedProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.LogLevels.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbloglevel.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Fingerprints.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdefFingerprint.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.UserAgent.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdefUserAgent.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxMuxs.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbmux4SboxProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
Global.TunMtus.ForEach(it =>
|
cmbsystemProxyAdvancedProtocol.ItemsSource = Global.IEProxyProtocols;
|
||||||
{
|
cmbloglevel.ItemsSource = Global.LogLevels;
|
||||||
cmbMtu.Items.Add(it);
|
cmbdefFingerprint.ItemsSource = Global.Fingerprints;
|
||||||
});
|
cmbdefUserAgent.ItemsSource = Global.UserAgent;
|
||||||
Global.TunStacks.ForEach(it =>
|
cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs;
|
||||||
{
|
cmbMtu.ItemsSource = Global.TunMtus;
|
||||||
cmbStack.Items.Add(it);
|
cmbStack.ItemsSource = Global.TunStacks;
|
||||||
});
|
|
||||||
Global.CoreTypes.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbCoreType1.Items.Add(it);
|
|
||||||
cmbCoreType2.Items.Add(it);
|
|
||||||
cmbCoreType3.Items.Add(it);
|
|
||||||
cmbCoreType4.Items.Add(it);
|
|
||||||
cmbCoreType5.Items.Add(it);
|
|
||||||
cmbCoreType6.Items.Add(it);
|
|
||||||
cmbCoreType9.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i = 2; i <= 8; i++)
|
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
||||||
{
|
cmbCoreType2.ItemsSource = Global.CoreTypes;
|
||||||
cmbMixedConcurrencyCount.Items.Add(i);
|
cmbCoreType3.ItemsSource = Global.CoreTypes;
|
||||||
}
|
cmbCoreType4.ItemsSource = Global.CoreTypes;
|
||||||
for (var i = 2; i <= 6; i++)
|
cmbCoreType5.ItemsSource = Global.CoreTypes;
|
||||||
{
|
cmbCoreType6.ItemsSource = Global.CoreTypes;
|
||||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
cmbCoreType9.ItemsSource = Global.CoreTypes;
|
||||||
}
|
|
||||||
|
|
||||||
|
cmbMixedConcurrencyCount.ItemsSource = Enumerable.Range(2, 7).ToList();
|
||||||
|
cmbSpeedTestTimeout.ItemsSource = Enumerable.Range(2, 5).Select(i => i * 5).ToList();
|
||||||
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
||||||
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
||||||
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
||||||
|
cmbGetFilesSourceUrl.ItemsSource = Global.GeoFilesSources;
|
||||||
|
cmbSrsFilesSourceUrl.ItemsSource = Global.SingboxRulesetSources;
|
||||||
|
cmbRoutingRulesSourceUrl.ItemsSource = Global.RoutingRulesSources;
|
||||||
|
cmbIPAPIUrl.ItemsSource = Global.IPAPIUrls;
|
||||||
|
|
||||||
Global.GeoFilesSources.ForEach(it =>
|
cmbMainGirdOrientation.ItemsSource = Utils.GetEnumNames<EGirdOrientation>();
|
||||||
{
|
|
||||||
cmbGetFilesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxRulesetSources.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbSrsFilesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.RoutingRulesSources.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbRoutingRulesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.IPAPIUrls.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbIPAPIUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
|
||||||
{
|
|
||||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
@ -347,6 +347,24 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//First scroll horizontally to the initial position to avoid the control crash bug
|
||||||
|
if (lstProfiles.SelectedIndex >= 0)
|
||||||
|
{
|
||||||
|
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, lstProfiles.Columns[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var model = lstProfiles.ItemsSource.Cast<ProfileItemModel>();
|
||||||
|
if (model.Any())
|
||||||
|
{
|
||||||
|
lstProfiles.ScrollIntoView(model.First(), lstProfiles.Columns[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var it in lstProfiles.Columns)
|
foreach (var it in lstProfiles.Columns)
|
||||||
{
|
{
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
|
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ctrls="clr-namespace:v2rayN.Desktop.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
|
|
@ -22,86 +23,95 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtRemarks"
|
x:Name="txtRemarks"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
HorizontalAlignment="Left"
|
Margin="{StaticResource Margin4}"
|
||||||
Margin="{StaticResource Margin4}" />
|
HorizontalAlignment="Left" />
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
x:Name="togEnabled"
|
x:Name="togEnabled"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Margin="{StaticResource Margin4}" />
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="outboundTag" />
|
Text="outboundTag" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbOutboundTag"
|
Name="cmbOutboundTag"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
MaxDropDownHeight="1000" />
|
Text="{Binding SelectedSource.OutboundTag, Mode=TwoWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbRuleOutboundTagTip}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="port" />
|
Text="port" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtPort"
|
x:Name="txtPort"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
HorizontalAlignment="Left"
|
Margin="{StaticResource Margin4}"
|
||||||
Margin="{StaticResource Margin4}" />
|
HorizontalAlignment="Left" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="{StaticResource Margin4}">
|
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="protocol" />
|
||||||
|
<ListBox
|
||||||
|
x:Name="clbProtocol"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
SelectionMode="Multiple,Toggle"
|
||||||
|
Theme="{DynamicResource CardCheckGroupListBox}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center">
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
|
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
||||||
</HyperlinkButton>
|
</HyperlinkButton>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="3"
|
|
||||||
Grid.Column="0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
Text="protocol" />
|
|
||||||
<ListBox
|
|
||||||
x:Name="clbProtocol"
|
|
||||||
Grid.Row="3"
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
SelectionMode="Multiple,Toggle"
|
|
||||||
Theme="{DynamicResource CardCheckGroupListBox}" />
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="inboundTag" />
|
Text="inboundTag" />
|
||||||
<ListBox
|
<ListBox
|
||||||
x:Name="clbInboundTag"
|
x:Name="clbInboundTag"
|
||||||
|
|
@ -113,35 +123,36 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
|
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
|
||||||
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="network" />
|
Text="network" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbNetwork"
|
x:Name="cmbNetwork"
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
MaxDropDownHeight="1000" />
|
MaxDropDownHeight="1000" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetailsViewModel>
|
public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleDetailsWindow()
|
public RoutingRuleDetailsWindow()
|
||||||
{
|
{
|
||||||
|
|
@ -23,21 +23,11 @@ public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetail
|
||||||
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
||||||
|
|
||||||
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
|
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
|
||||||
cmbOutboundTag.Items.Add(Global.ProxyTag);
|
|
||||||
cmbOutboundTag.Items.Add(Global.DirectTag);
|
cmbOutboundTag.ItemsSource = Global.OutboundTags;
|
||||||
cmbOutboundTag.Items.Add(Global.BlockTag);
|
clbProtocol.ItemsSource = Global.RuleProtocols;
|
||||||
Global.RuleProtocols.ForEach(it =>
|
clbInboundTag.ItemsSource = Global.InboundTags;
|
||||||
{
|
cmbNetwork.ItemsSource = Global.RuleNetworks;
|
||||||
clbProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.InboundTags.ForEach(it =>
|
|
||||||
{
|
|
||||||
clbInboundTag.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.RuleNetworks.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbNetwork.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!rulesItem.Id.IsNullOrEmpty())
|
if (!rulesItem.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|
@ -54,7 +44,7 @@ public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetail
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
|
||||||
|
|
@ -80,7 +70,7 @@ public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetail
|
||||||
|
|
||||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
cmbOutboundTag.Focus();
|
txtRemarks.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettingViewModel>
|
public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleSettingWindow()
|
public RoutingRuleSettingWindow()
|
||||||
{
|
{
|
||||||
|
|
@ -30,15 +30,9 @@ public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettin
|
||||||
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_ClickAsync;
|
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_ClickAsync;
|
||||||
|
|
||||||
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
|
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
|
||||||
Global.DomainStrategies.ForEach(it =>
|
|
||||||
{
|
cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty();
|
||||||
cmbdomainStrategy.Items.Add(it);
|
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
|
||||||
});
|
|
||||||
cmbdomainStrategy.Items.Add(string.Empty);
|
|
||||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,36 +24,13 @@
|
||||||
<MenuItem x:Name="menuRoutingAdvancedAdd2" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
<MenuItem x:Name="menuRoutingAdvancedAdd2" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
<MenuItem x:Name="menuRoutingAdvancedImportRules2" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
<MenuItem x:Name="menuRoutingAdvancedImportRules2" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<TextBlock VerticalAlignment="Center">
|
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy_Click">
|
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
|
||||||
</HyperlinkButton>
|
|
||||||
</TextBlock>
|
|
||||||
<ComboBox x:Name="cmbdomainStrategy" Width="110" />
|
|
||||||
<Separator />
|
|
||||||
<TextBlock VerticalAlignment="Center" Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
|
||||||
<ComboBox x:Name="cmbdomainMatcher" Width="60" />
|
|
||||||
<Separator />
|
|
||||||
<TextBlock VerticalAlignment="Center">
|
|
||||||
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
|
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
|
||||||
</HyperlinkButton>
|
|
||||||
</TextBlock>
|
|
||||||
<ComboBox x:Name="cmbdomainStrategy4Singbox" Width="100" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<StackPanel
|
|
||||||
Width="600"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
|
||||||
</StackPanel>
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnSave"
|
x:Name="btnSave"
|
||||||
Width="100"
|
Width="100"
|
||||||
|
|
@ -69,7 +46,62 @@
|
||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<DockPanel>
|
<Grid
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
ColumnDefinitions="Auto,Auto"
|
||||||
|
DockPanel.Dock="Top"
|
||||||
|
RowDefinitions="Auto,Auto,Auto">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</TextBlock>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainMatcher"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</TextBlock>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy4Singbox"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<TabControl x:Name="tabAdvanced">
|
<TabControl x:Name="tabAdvanced">
|
||||||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||||
<DataGrid
|
<DataGrid
|
||||||
|
|
@ -122,5 +154,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</DockPanel>
|
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewModel>
|
public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
|
|
@ -26,18 +26,9 @@ public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewMod
|
||||||
|
|
||||||
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
|
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
Global.DomainStrategies.ForEach(it =>
|
cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
|
||||||
{
|
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
|
||||||
cmbdomainStrategy.Items.Add(it);
|
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
|
||||||
});
|
|
||||||
Global.DomainMatchers.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainMatcher.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
||||||
|
|
||||||
case EViewAction.PasswordInput:
|
case EViewAction.PasswordInput:
|
||||||
return await PasswordInputAsync();
|
return await PasswordInputAsync();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
@ -105,13 +104,15 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
||||||
{
|
{
|
||||||
var dialog = new SudoPasswordInputView();
|
var dialog = new SudoPasswordInputView();
|
||||||
var obj = await DialogHost.Show(dialog);
|
var obj = await DialogHost.Show(dialog);
|
||||||
if (obj == null)
|
|
||||||
|
var password = obj?.ToString();
|
||||||
|
if (password.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
togEnableTun.IsChecked = false;
|
togEnableTun.IsChecked = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppHandler.Instance.LinuxSudoPwd = obj.ToString() ?? string.Empty;
|
AppHandler.Instance.LinuxSudoPwd = password;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
public partial class SubEditWindow : WindowBase<SubEditViewModel>
|
||||||
{
|
{
|
||||||
public SubEditWindow()
|
public SubEditWindow()
|
||||||
{
|
{
|
||||||
|
|
@ -22,10 +22,7 @@ public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
||||||
|
|
||||||
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
||||||
|
|
||||||
Global.SubConvertTargets.ForEach(it =>
|
cmbConvertTarget.ItemsSource = Global.SubConvertTargets;
|
||||||
{
|
|
||||||
cmbConvertTarget.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Base;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using CliWrap.Buffered;
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
@ -12,22 +13,71 @@ public partial class SudoPasswordInputView : UserControl
|
||||||
|
|
||||||
this.Loaded += (s, e) => txtPassword.Focus();
|
this.Loaded += (s, e) => txtPassword.Focus();
|
||||||
|
|
||||||
btnSave.Click += (_, _) =>
|
btnSave.Click += async (_, _) => await SavePasswordAsync();
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(txtPassword.Text))
|
|
||||||
{
|
|
||||||
txtPassword.Focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
DialogHost.Close(null, txtPassword.Text);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
btnCancel.Click += (_, _) =>
|
btnCancel.Click += (_, _) =>
|
||||||
{
|
{
|
||||||
DialogHost.Close(null);
|
DialogHost.Close(null);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task SavePasswordAsync()
|
||||||
|
{
|
||||||
|
if (txtPassword.Text.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
txtPassword.Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var password = txtPassword.Text;
|
||||||
|
btnSave.IsEnabled = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Verify if the password is correct
|
||||||
|
if (await CheckSudoPasswordAsync(password))
|
||||||
|
{
|
||||||
|
// Password verification successful, return password and close dialog
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
DialogHost.Close(null, password);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Password verification failed, display error and let user try again
|
||||||
|
NoticeHandler.Instance.Enqueue(ResUI.SudoIncorrectPasswordTip);
|
||||||
|
txtPassword.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("SudoPassword", ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
btnSave.IsEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> CheckSudoPasswordAsync(string password)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Use sudo -S echo command to verify password
|
||||||
|
var arg = new List<string>() { "-c", "sudo -S echo SUDO_CHECK" };
|
||||||
|
var result = await CliWrap.Cli
|
||||||
|
.Wrap(Global.LinuxBash)
|
||||||
|
.WithArguments(arg)
|
||||||
|
.WithStandardInputPipe(CliWrap.PipeSource.FromString(password))
|
||||||
|
.ExecuteBufferedAsync();
|
||||||
|
|
||||||
|
return result.ExitCode == 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("CheckSudoPassword", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,9 @@ public partial class ThemeSettingView : ReactiveUserControl<ThemeSettingViewMode
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
ViewModel = new ThemeSettingViewModel();
|
ViewModel = new ThemeSettingViewModel();
|
||||||
|
|
||||||
foreach (ETheme it in Enum.GetValues(typeof(ETheme)))
|
cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>();
|
||||||
{
|
cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, 11).ToList();
|
||||||
cmbCurrentTheme.Items.Add(it.ToString());
|
cmbCurrentLanguage.ItemsSource = Global.Languages;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++)
|
|
||||||
{
|
|
||||||
cmbCurrentFontSize.Items.Add(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Global.Languages.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbCurrentLanguage.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@
|
||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
|
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
|
||||||
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||||
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||||
<Setter Property="ResizeMode" Value="NoResize" />
|
<Setter Property="ResizeMode" Value="CanResize" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ViewGlobal"
|
x:Key="ViewGlobal"
|
||||||
|
|
|
||||||
42
v2rayN/v2rayN/Base/WindowBase.cs
Normal file
42
v2rayN/v2rayN/Base/WindowBase.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
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,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -198,4 +199,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,7 @@ public partial class AddServer2Window
|
||||||
this.Loaded += Window_Loaded;
|
this.Loaded += Window_Loaded;
|
||||||
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
foreach (ECoreType it in Enum.GetValues(typeof(ECoreType)))
|
cmbCoreType.ItemsSource = Utils.GetEnumNames<ECoreType>().Where(t => t != ECoreType.v2rayN.ToString()).ToList().AppendEmpty();
|
||||||
{
|
|
||||||
if (it == ECoreType.v2rayN)
|
|
||||||
continue;
|
|
||||||
cmbCoreType.Items.Add(it.ToString());
|
|
||||||
}
|
|
||||||
cmbCoreType.Items.Add(string.Empty);
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -155,6 +156,7 @@
|
||||||
<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" />
|
||||||
|
|
@ -214,6 +216,20 @@
|
||||||
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"
|
||||||
|
|
@ -224,6 +240,7 @@
|
||||||
<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" />
|
||||||
|
|
@ -259,6 +276,20 @@
|
||||||
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"
|
||||||
|
|
@ -314,6 +345,7 @@
|
||||||
<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" />
|
||||||
|
|
@ -373,6 +405,20 @@
|
||||||
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"
|
||||||
|
|
@ -383,6 +429,7 @@
|
||||||
<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" />
|
||||||
|
|
@ -418,6 +465,20 @@
|
||||||
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"
|
||||||
|
|
@ -1011,4 +1072,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -20,41 +20,22 @@ public partial class AddServerWindow
|
||||||
|
|
||||||
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
Global.CoreTypes.ForEach(it =>
|
cmbCoreType.ItemsSource = Global.CoreTypes.AppendEmpty();
|
||||||
{
|
cmbNetwork.ItemsSource = Global.Networks;
|
||||||
cmbCoreType.Items.Add(it);
|
cmbFingerprint.ItemsSource = Global.Fingerprints;
|
||||||
});
|
cmbFingerprint2.ItemsSource = Global.Fingerprints;
|
||||||
cmbCoreType.Items.Add(string.Empty);
|
cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
|
||||||
|
cmbAlpn.ItemsSource = Global.Alpns;
|
||||||
|
|
||||||
cmbStreamSecurity.Items.Add(string.Empty);
|
var lstStreamSecurity = new List<string>();
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurity);
|
lstStreamSecurity.Add(string.Empty);
|
||||||
|
lstStreamSecurity.Add(Global.StreamSecurity);
|
||||||
Global.Networks.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbNetwork.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Fingerprints.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbFingerprint.Items.Add(it);
|
|
||||||
cmbFingerprint2.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.AllowInsecure.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbAllowInsecure.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Alpns.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbAlpn.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (profileItem.ConfigType)
|
switch (profileItem.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.VMess:
|
||||||
gridVMess.Visibility = Visibility.Visible;
|
gridVMess.Visibility = Visibility.Visible;
|
||||||
Global.VmessSecurities.ForEach(it =>
|
cmbSecurity.ItemsSource = Global.VmessSecurities;
|
||||||
{
|
|
||||||
cmbSecurity.Items.Add(it);
|
|
||||||
});
|
|
||||||
if (profileItem.Security.IsNullOrEmpty())
|
if (profileItem.Security.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Security = Global.DefaultSecurity;
|
profileItem.Security = Global.DefaultSecurity;
|
||||||
|
|
@ -63,10 +44,7 @@ public partial class AddServerWindow
|
||||||
|
|
||||||
case EConfigType.Shadowsocks:
|
case EConfigType.Shadowsocks:
|
||||||
gridSs.Visibility = Visibility.Visible;
|
gridSs.Visibility = Visibility.Visible;
|
||||||
AppHandler.Instance.GetShadowsocksSecurities(profileItem).ForEach(it =>
|
cmbSecurity3.ItemsSource = AppHandler.Instance.GetShadowsocksSecurities(profileItem);
|
||||||
{
|
|
||||||
cmbSecurity3.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
|
|
@ -76,11 +54,8 @@ public partial class AddServerWindow
|
||||||
|
|
||||||
case EConfigType.VLESS:
|
case EConfigType.VLESS:
|
||||||
gridVLESS.Visibility = Visibility.Visible;
|
gridVLESS.Visibility = Visibility.Visible;
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||||
Global.Flows.ForEach(it =>
|
cmbFlow5.ItemsSource = Global.Flows;
|
||||||
{
|
|
||||||
cmbFlow5.Items.Add(it);
|
|
||||||
});
|
|
||||||
if (profileItem.Security.IsNullOrEmpty())
|
if (profileItem.Security.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Security = Global.None;
|
profileItem.Security = Global.None;
|
||||||
|
|
@ -89,11 +64,8 @@ public partial class AddServerWindow
|
||||||
|
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
gridTrojan.Visibility = Visibility.Visible;
|
gridTrojan.Visibility = Visibility.Visible;
|
||||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||||
Global.Flows.ForEach(it =>
|
cmbFlow6.ItemsSource = Global.Flows;
|
||||||
{
|
|
||||||
cmbFlow6.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
|
|
@ -113,10 +85,7 @@ public partial class AddServerWindow
|
||||||
cmbFingerprint.IsEnabled = false;
|
cmbFingerprint.IsEnabled = false;
|
||||||
cmbFingerprint.Text = string.Empty;
|
cmbFingerprint.Text = string.Empty;
|
||||||
|
|
||||||
Global.TuicCongestionControls.ForEach(it =>
|
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls;
|
||||||
{
|
|
||||||
cmbHeaderType8.Items.Add(it);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.WireGuard:
|
case EConfigType.WireGuard:
|
||||||
|
|
@ -128,6 +97,7 @@ public partial class AddServerWindow
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
|
||||||
|
|
||||||
gridTlsMore.Visibility = Visibility.Hidden;
|
gridTlsMore.Visibility = Visibility.Hidden;
|
||||||
|
|
||||||
|
|
@ -144,11 +114,13 @@ 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:
|
||||||
|
|
@ -161,11 +133,13 @@ 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:
|
||||||
|
|
@ -263,44 +237,41 @@ public partial class AddServerWindow
|
||||||
|
|
||||||
private void SetHeaderType()
|
private void SetHeaderType()
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Clear();
|
var lstHeaderType = new List<string>();
|
||||||
|
|
||||||
var network = cmbNetwork.SelectedItem.ToString();
|
var network = cmbNetwork.SelectedItem.ToString();
|
||||||
if (network.IsNullOrEmpty())
|
if (network.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
|
cmbHeaderType.ItemsSource = lstHeaderType;
|
||||||
|
cmbHeaderType.SelectedIndex = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (network == nameof(ETransport.tcp))
|
if (network == nameof(ETransport.tcp))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
|
lstHeaderType.Add(Global.TcpHeaderHttp);
|
||||||
}
|
}
|
||||||
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
|
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
Global.KcpHeaderTypes.ForEach(it =>
|
lstHeaderType.AddRange(Global.KcpHeaderTypes);
|
||||||
{
|
|
||||||
cmbHeaderType.Items.Add(it);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (network is nameof(ETransport.xhttp))
|
else if (network is nameof(ETransport.xhttp))
|
||||||
{
|
{
|
||||||
Global.XhttpMode.ForEach(it =>
|
lstHeaderType.AddRange(Global.XhttpMode);
|
||||||
{
|
|
||||||
cmbHeaderType.Items.Add(it);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (network == nameof(ETransport.grpc))
|
else if (network == nameof(ETransport.grpc))
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.GrpcGunMode);
|
lstHeaderType.Add(Global.GrpcGunMode);
|
||||||
cmbHeaderType.Items.Add(Global.GrpcMultiMode);
|
lstHeaderType.Add(Global.GrpcMultiMode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmbHeaderType.Items.Add(Global.None);
|
lstHeaderType.Add(Global.None);
|
||||||
}
|
}
|
||||||
|
cmbHeaderType.ItemsSource = lstHeaderType;
|
||||||
cmbHeaderType.SelectedIndex = 0;
|
cmbHeaderType.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -204,4 +205,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,10 @@ public partial class DNSSettingWindow
|
||||||
|
|
||||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
Global.DomainStrategy4Freedoms.ForEach(it =>
|
cmbdomainStrategy4Freedom.ItemsSource = Global.DomainStrategy4Freedoms;
|
||||||
{
|
cmbdomainStrategy4Out.ItemsSource = Global.SingboxDomainStrategy4Out;
|
||||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
cmbdomainDNSAddress.ItemsSource = Global.DomainDNSAddress;
|
||||||
});
|
cmbdomainDNSAddress2.ItemsSource = Global.SingboxDomainDNSAddress;
|
||||||
Global.SingboxDomainStrategy4Out.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Out.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.DomainDNSAddress.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainDNSAddress.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxDomainDNSAddress.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainDNSAddress2.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -169,4 +170,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -40,8 +41,8 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Style="{StaticResource MaterialDesignToolBar}"
|
KeyboardNavigation.TabNavigation="Continue"
|
||||||
KeyboardNavigation.TabNavigation="Continue">
|
Style="{StaticResource MaterialDesignToolBar}">
|
||||||
<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>
|
||||||
|
|
@ -432,4 +433,4 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,6 @@ 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);
|
||||||
|
|
@ -395,20 +394,14 @@ public partial class MainWindow
|
||||||
_config.UiItem.ShowInTaskbar = bl;
|
_config.UiItem.ShowInTaskbar = bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreUI()
|
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_config.UiItem.MainWidth > 0 && _config.UiItem.MainHeight > 0)
|
base.OnLoaded(sender, e);
|
||||||
{
|
RestoreUI();
|
||||||
Width = _config.UiItem.MainWidth;
|
|
||||||
Height = _config.UiItem.MainHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxWidth = SystemParameters.WorkArea.Width;
|
private void RestoreUI()
|
||||||
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)
|
||||||
|
|
@ -426,18 +419,15 @@ public partial class MainWindow
|
||||||
|
|
||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainWidth = this.Width;
|
ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
|
||||||
_config.UiItem.MainHeight = this.Height;
|
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
|
||||||
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
|
|
||||||
}
|
}
|
||||||
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
{
|
{
|
||||||
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
|
||||||
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,7 @@ public partial class MsgView
|
||||||
menuMsgViewCopyAll.Click += menuMsgViewCopyAll_Click;
|
menuMsgViewCopyAll.Click += menuMsgViewCopyAll_Click;
|
||||||
menuMsgViewClear.Click += menuMsgViewClear_Click;
|
menuMsgViewClear.Click += menuMsgViewClear_Click;
|
||||||
|
|
||||||
Global.PresetMsgFilters.ForEach(it =>
|
cmbMsgFilter.ItemsSource = Global.PresetMsgFilters;
|
||||||
{
|
|
||||||
cmbMsgFilter.Items.Add(it);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -846,10 +847,26 @@
|
||||||
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="20"
|
Grid.Row="21"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
|
|
@ -858,7 +875,7 @@
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="21"
|
Grid.Row="22"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -866,14 +883,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="21"
|
Grid.Row="22"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -881,14 +898,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbGetFilesSourceUrl"
|
x:Name="cmbGetFilesSourceUrl"
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="23"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -897,7 +914,7 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -905,14 +922,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSrsFilesSourceUrl"
|
x:Name="cmbSrsFilesSourceUrl"
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="24"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -921,7 +938,7 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -929,36 +946,20 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRoutingRulesSourceUrl"
|
x:Name="cmbRoutingRulesSourceUrl"
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="25"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="25"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin8}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
|
||||||
<ComboBox
|
|
||||||
x:Name="cmbIPAPIUrl"
|
|
||||||
Grid.Row="25"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="300"
|
|
||||||
Margin="{StaticResource Margin8}"
|
|
||||||
IsEditable="True"
|
|
||||||
Style="{StaticResource DefComboBox}" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
@ -1229,4 +1230,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -21,94 +21,39 @@ public partial class OptionSettingWindow
|
||||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
||||||
Global.destOverrideProtocols.ForEach(it =>
|
clbdestOverride.ItemsSource = Global.destOverrideProtocols;
|
||||||
{
|
|
||||||
clbdestOverride.Items.Add(it);
|
|
||||||
});
|
|
||||||
_config.Inbound.First().DestOverride?.ForEach(it =>
|
_config.Inbound.First().DestOverride?.ForEach(it =>
|
||||||
{
|
{
|
||||||
clbdestOverride.SelectedItems.Add(it);
|
clbdestOverride.SelectedItems.Add(it);
|
||||||
});
|
});
|
||||||
Global.IEProxyProtocols.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbsystemProxyAdvancedProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.LogLevels.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbloglevel.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.Fingerprints.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdefFingerprint.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.UserAgent.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdefUserAgent.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxMuxs.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbmux4SboxProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
Global.TunMtus.ForEach(it =>
|
cmbsystemProxyAdvancedProtocol.ItemsSource = Global.IEProxyProtocols;
|
||||||
{
|
cmbloglevel.ItemsSource = Global.LogLevels;
|
||||||
cmbMtu.Items.Add(it);
|
cmbdefFingerprint.ItemsSource = Global.Fingerprints;
|
||||||
});
|
cmbdefUserAgent.ItemsSource = Global.UserAgent;
|
||||||
Global.TunStacks.ForEach(it =>
|
cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs;
|
||||||
{
|
cmbMtu.ItemsSource = Global.TunMtus;
|
||||||
cmbStack.Items.Add(it);
|
cmbStack.ItemsSource = Global.TunStacks;
|
||||||
});
|
|
||||||
Global.CoreTypes.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbCoreType1.Items.Add(it);
|
|
||||||
cmbCoreType2.Items.Add(it);
|
|
||||||
cmbCoreType3.Items.Add(it);
|
|
||||||
cmbCoreType4.Items.Add(it);
|
|
||||||
cmbCoreType5.Items.Add(it);
|
|
||||||
cmbCoreType6.Items.Add(it);
|
|
||||||
cmbCoreType9.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i = 2; i <= 8; i++)
|
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
||||||
{
|
cmbCoreType2.ItemsSource = Global.CoreTypes;
|
||||||
cmbMixedConcurrencyCount.Items.Add(i);
|
cmbCoreType3.ItemsSource = Global.CoreTypes;
|
||||||
}
|
cmbCoreType4.ItemsSource = Global.CoreTypes;
|
||||||
for (var i = 2; i <= 6; i++)
|
cmbCoreType5.ItemsSource = Global.CoreTypes;
|
||||||
{
|
cmbCoreType6.ItemsSource = Global.CoreTypes;
|
||||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
cmbCoreType9.ItemsSource = Global.CoreTypes;
|
||||||
}
|
|
||||||
Global.SpeedTestUrls.ForEach(it =>
|
cmbMixedConcurrencyCount.ItemsSource = Enumerable.Range(2, 7).ToList();
|
||||||
{
|
cmbSpeedTestTimeout.ItemsSource = Enumerable.Range(2, 5).Select(i => i * 5).ToList();
|
||||||
cmbSpeedTestUrl.Items.Add(it);
|
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
||||||
});
|
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
||||||
Global.SpeedPingTestUrls.ForEach(it =>
|
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
||||||
{
|
cmbGetFilesSourceUrl.ItemsSource = Global.GeoFilesSources;
|
||||||
cmbSpeedPingTestUrl.Items.Add(it);
|
cmbSrsFilesSourceUrl.ItemsSource = Global.SingboxRulesetSources;
|
||||||
});
|
cmbRoutingRulesSourceUrl.ItemsSource = Global.RoutingRulesSources;
|
||||||
Global.SubConvertUrls.ForEach(it =>
|
cmbIPAPIUrl.ItemsSource = Global.IPAPIUrls;
|
||||||
{
|
|
||||||
cmbSubConvertUrl.Items.Add(it);
|
cmbMainGirdOrientation.ItemsSource = Utils.GetEnumNames<EGirdOrientation>();
|
||||||
});
|
|
||||||
Global.GeoFilesSources.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbGetFilesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SingboxRulesetSources.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbSrsFilesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.RoutingRulesSources.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbRoutingRulesSourceUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.IPAPIUrls.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbIPAPIUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
|
||||||
{
|
|
||||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
@ -209,8 +154,7 @@ public partial class OptionSettingWindow
|
||||||
private async Task InitSettingFont()
|
private async Task InitSettingFont()
|
||||||
{
|
{
|
||||||
var lstFonts = await GetFonts(Utils.GetFontsPath());
|
var lstFonts = await GetFonts(Utils.GetFontsPath());
|
||||||
lstFonts.ForEach(it => { cmbcurrentFontFamily.Items.Add(it); });
|
cmbcurrentFontFamily.ItemsSource = lstFonts.AppendEmpty();
|
||||||
cmbcurrentFontFamily.Items.Add(string.Empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<string>> GetFonts(string path)
|
private async Task<List<string>> GetFonts(string path)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -52,7 +53,8 @@
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|
@ -67,6 +69,7 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
IsEditable="True"
|
||||||
MaxDropDownHeight="1000"
|
MaxDropDownHeight="1000"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
|
@ -74,8 +77,9 @@
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
Text="{x:Static resx:ResUI.TbRuleOutboundTagTip}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
|
|
@ -96,13 +100,10 @@
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}">
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
<Hyperlink Click="linkRuleobjectDoc_Click">
|
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
|
||||||
<materialDesign:PackIcon Kind="Link" />
|
|
||||||
</Hyperlink>
|
|
||||||
</TextBlock>
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
|
|
@ -119,6 +120,17 @@
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
|
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}">
|
||||||
|
<Hyperlink Click="linkRuleobjectDoc_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
||||||
|
<materialDesign:PackIcon Kind="Link" />
|
||||||
|
</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
|
|
@ -139,6 +151,7 @@
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
|
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
|
||||||
|
|
||||||
|
|
@ -163,6 +176,7 @@
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -242,4 +256,4 @@
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -16,21 +16,11 @@ public partial class RoutingRuleDetailsWindow
|
||||||
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
||||||
|
|
||||||
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
|
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
|
||||||
cmbOutboundTag.Items.Add(Global.ProxyTag);
|
|
||||||
cmbOutboundTag.Items.Add(Global.DirectTag);
|
cmbOutboundTag.ItemsSource = Global.OutboundTags;
|
||||||
cmbOutboundTag.Items.Add(Global.BlockTag);
|
clbProtocol.ItemsSource = Global.RuleProtocols;
|
||||||
Global.RuleProtocols.ForEach(it =>
|
clbInboundTag.ItemsSource = Global.InboundTags;
|
||||||
{
|
cmbNetwork.ItemsSource = Global.RuleNetworks;
|
||||||
clbProtocol.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.InboundTags.ForEach(it =>
|
|
||||||
{
|
|
||||||
clbInboundTag.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.RuleNetworks.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbNetwork.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!rulesItem.Id.IsNullOrEmpty())
|
if (!rulesItem.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|
@ -74,7 +64,7 @@ public partial class RoutingRuleDetailsWindow
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
cmbOutboundTag.Focus();
|
txtRemarks.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -334,4 +335,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,9 @@ public partial class RoutingRuleSettingWindow
|
||||||
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_Click;
|
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_Click;
|
||||||
|
|
||||||
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
|
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
|
||||||
Global.DomainStrategies.ForEach(it =>
|
|
||||||
{
|
cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty();
|
||||||
cmbdomainStrategy.Items.Add(it);
|
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
|
||||||
});
|
|
||||||
cmbdomainStrategy.Items.Add(string.Empty);
|
|
||||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -29,68 +30,25 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Style="{StaticResource MaterialDesignToolBar}">
|
Style="{StaticResource MaterialDesignToolBar}">
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Button x:Name="menuRoutingAdvancedAdd2">
|
||||||
<MenuItem x:Name="menuRoutingAdvanced" Padding="8,0">
|
|
||||||
<MenuItem.Header>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
Margin="{StaticResource MarginRight8}"
|
Margin="{StaticResource MarginRight8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Kind="Routes" />
|
Kind="Plus" />
|
||||||
<TextBlock Text="{x:Static resx:ResUI.menuRoutingAdvanced}" />
|
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</MenuItem.Header>
|
</Button>
|
||||||
<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 />
|
||||||
<TextBlock
|
<Button x:Name="menuRoutingAdvancedImportRules2">
|
||||||
Margin="{StaticResource MarginLeft8}"
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon
|
||||||
|
Margin="{StaticResource MarginRight8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}">
|
Kind="Import" />
|
||||||
<Hyperlink Click="linkdomainStrategy_Click">
|
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
</StackPanel>
|
||||||
<materialDesign:PackIcon Kind="Link" />
|
</Button>
|
||||||
</Hyperlink>
|
|
||||||
</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>
|
||||||
|
|
||||||
|
|
@ -99,12 +57,6 @@
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<StackPanel
|
|
||||||
Width="600"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
|
||||||
</StackPanel>
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnSave"
|
x:Name="btnSave"
|
||||||
Width="100"
|
Width="100"
|
||||||
|
|
@ -122,7 +74,71 @@
|
||||||
Style="{StaticResource DefButton}" />
|
Style="{StaticResource DefButton}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<DockPanel>
|
<Grid Margin="{StaticResource Margin8}" DockPanel.Dock="Top">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}">
|
||||||
|
<Hyperlink Click="linkdomainStrategy_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||||
|
<materialDesign:PackIcon Kind="Link" />
|
||||||
|
</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainMatcher"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
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"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<TabControl x:Name="tabAdvanced">
|
<TabControl x:Name="tabAdvanced">
|
||||||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||||
<DataGrid
|
<DataGrid
|
||||||
|
|
@ -199,5 +215,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</DockPanel>
|
</base:WindowBase>
|
||||||
</reactiveui:ReactiveWindow>
|
|
||||||
|
|
|
||||||
|
|
@ -21,18 +21,9 @@ public partial class RoutingSettingWindow
|
||||||
|
|
||||||
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
|
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
Global.DomainStrategies.ForEach(it =>
|
cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
|
||||||
{
|
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
|
||||||
cmbdomainStrategy.Items.Add(it);
|
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
|
||||||
});
|
|
||||||
Global.DomainMatchers.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainMatcher.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -315,4 +316,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,7 @@ public partial class SubEditWindow
|
||||||
|
|
||||||
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
||||||
|
|
||||||
Global.SubConvertTargets.ForEach(it =>
|
cmbConvertTarget.ItemsSource = Global.SubConvertTargets;
|
||||||
{
|
|
||||||
cmbConvertTarget.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<reactiveui:ReactiveWindow
|
<base:WindowBase
|
||||||
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"
|
||||||
|
|
@ -120,4 +121,4 @@
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</reactiveui:ReactiveWindow>
|
</base:WindowBase>
|
||||||
|
|
|
||||||
|
|
@ -13,22 +13,10 @@ public partial class ThemeSettingView
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
ViewModel = new ThemeSettingViewModel();
|
ViewModel = new ThemeSettingViewModel();
|
||||||
foreach (ETheme it in Enum.GetValues(typeof(ETheme)))
|
|
||||||
{
|
|
||||||
if ((int)it > 2)
|
|
||||||
continue;
|
|
||||||
cmbCurrentTheme.Items.Add(it.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++)
|
cmbCurrentTheme.ItemsSource = Utils.GetEnumNames<ETheme>().Take(3).ToList();
|
||||||
{
|
cmbCurrentFontSize.ItemsSource = Enumerable.Range(Global.MinFontSize, 11).ToList();
|
||||||
cmbCurrentFontSize.Items.Add(i.ToString());
|
cmbCurrentLanguage.ItemsSource = Global.Languages;
|
||||||
}
|
|
||||||
|
|
||||||
Global.Languages.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbCurrentLanguage.Items.Add(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue