mirror of
https://github.com/2dust/v2rayN.git
synced 2025-07-05 06:22:10 +00:00
Compare commits
No commits in common. "master" and "7.12.6" have entirely different histories.
52 changed files with 682 additions and 1153 deletions
12
.github/workflows/winget-publish.yml
vendored
12
.github/workflows/winget-publish.yml
vendored
|
@ -22,18 +22,10 @@ jobs:
|
||||||
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
|
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
|
||||||
|
|
||||||
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
|
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
|
||||||
|
$installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip*' | Select -ExpandProperty browser_download_url
|
||||||
$x64InstallerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip' | Select -ExpandProperty browser_download_url
|
|
||||||
$arm64InstallerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-arm64\.zip' | Select -ExpandProperty browser_download_url
|
|
||||||
|
|
||||||
$ver = $targetRelease.tag_name
|
$ver = $targetRelease.tag_name
|
||||||
|
|
||||||
# getting latest wingetcreate file
|
# getting latest wingetcreate file
|
||||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||||
|
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$installerUrl|x64" -t $gitToken
|
||||||
Write-Host "Updating with both x64 and arm64 installers"
|
|
||||||
Write-Host "Version: $ver"
|
|
||||||
Write-Host "x64 URL: $x64InstallerUrl"
|
|
||||||
Write-Host "arm64 URL: $arm64InstallerUrl"
|
|
||||||
|
|
||||||
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$x64InstallerUrl|x64" "$arm64InstallerUrl|arm64" -t $gitToken
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.12.7</Version>
|
<Version>7.12.6</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
100
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
100
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class AesUtils
|
||||||
|
{
|
||||||
|
private const int KeySize = 256; // AES-256
|
||||||
|
private const int IvSize = 16; // AES block size
|
||||||
|
private const int Iterations = 10000;
|
||||||
|
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' '));
|
||||||
|
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Plain text</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Base64 encoded cipher text with IV</returns>
|
||||||
|
public static string Encrypt(string text, string? password = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var plaintext = Encoding.UTF8.GetBytes(text);
|
||||||
|
var key = GetKey(password);
|
||||||
|
var iv = GenerateIv();
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
ms.Write(iv, 0, iv.Length);
|
||||||
|
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(plaintext, 0, plaintext.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
var cipherTextWithIv = ms.ToArray();
|
||||||
|
return Convert.ToBase64String(cipherTextWithIv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Plain text</returns>
|
||||||
|
public static string Decrypt(string cipherTextWithIv, string? password = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(cipherTextWithIv))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
|
||||||
|
var key = GetKey(password);
|
||||||
|
|
||||||
|
var iv = new byte[IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
|
||||||
|
|
||||||
|
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(cipherText, 0, cipherText.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
var plainText = ms.ToArray();
|
||||||
|
return Encoding.UTF8.GetString(plainText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetKey(string? password)
|
||||||
|
{
|
||||||
|
if (password.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
password = DefaultPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
|
||||||
|
return pbkdf2.GetBytes(KeySize / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GenerateIv()
|
||||||
|
{
|
||||||
|
var randomNumber = new byte[IvSize];
|
||||||
|
|
||||||
|
using var rng = RandomNumberGenerator.Create();
|
||||||
|
rng.GetBytes(randomNumber);
|
||||||
|
return randomNumber;
|
||||||
|
}
|
||||||
|
}
|
74
v2rayN/ServiceLib/Common/DesUtils.cs
Normal file
74
v2rayN/ServiceLib/Common/DesUtils.cs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public class DesUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// /// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Encrypt(string? text, string? key = null)
|
||||||
|
{
|
||||||
|
if (text.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
||||||
|
var dsp = DES.Create();
|
||||||
|
using var memStream = new MemoryStream();
|
||||||
|
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
||||||
|
using var sWriter = new StreamWriter(cryStream);
|
||||||
|
sWriter.Write(text);
|
||||||
|
sWriter.Flush();
|
||||||
|
cryStream.FlushFinalBlock();
|
||||||
|
memStream.Flush();
|
||||||
|
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="encryptText"></param>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Decrypt(string? encryptText, string? key = null)
|
||||||
|
{
|
||||||
|
if (encryptText.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
|
||||||
|
var dsp = DES.Create();
|
||||||
|
var buffer = Convert.FromBase64String(encryptText);
|
||||||
|
|
||||||
|
using var memStream = new MemoryStream();
|
||||||
|
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
|
||||||
|
cryStream.Write(buffer, 0, buffer.Length);
|
||||||
|
cryStream.FlushFinalBlock();
|
||||||
|
return Encoding.UTF8.GetString(memStream.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
|
||||||
|
{
|
||||||
|
if (key.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("The key cannot be null");
|
||||||
|
}
|
||||||
|
if (key.Length <= 8)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
|
||||||
|
}
|
||||||
|
|
||||||
|
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
|
||||||
|
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDefaultKey()
|
||||||
|
{
|
||||||
|
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,7 +101,6 @@ public class ConfigHandler
|
||||||
EnableAutoAdjustMainLvColWidth = true
|
EnableAutoAdjustMainLvColWidth = true
|
||||||
};
|
};
|
||||||
config.UiItem.MainColumnItem ??= new();
|
config.UiItem.MainColumnItem ??= new();
|
||||||
config.UiItem.WindowSizeItem ??= new();
|
|
||||||
|
|
||||||
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
@ -247,7 +246,6 @@ public class ConfigHandler
|
||||||
item.ShortId = profileItem.ShortId;
|
item.ShortId = profileItem.ShortId;
|
||||||
item.SpiderX = profileItem.SpiderX;
|
item.SpiderX = profileItem.SpiderX;
|
||||||
item.Extra = profileItem.Extra;
|
item.Extra = profileItem.Extra;
|
||||||
item.MuxEnabled = profileItem.MuxEnabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = item.ConfigType switch
|
var ret = item.ConfigType switch
|
||||||
|
@ -1981,7 +1979,7 @@ public class ConfigHandler
|
||||||
items = await AppHandler.Instance.RoutingItems();
|
items = await AppHandler.Instance.RoutingItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blImportAdvancedRules && items.Count > 0)
|
if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2175,44 +2173,4 @@ public class ConfigHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Regional Presets
|
#endregion Regional Presets
|
||||||
|
|
||||||
#region UIItem
|
|
||||||
|
|
||||||
public static WindowSizeItem? GetWindowSizeItem(Config config, string typeName)
|
|
||||||
{
|
|
||||||
var sizeItem = config?.UiItem?.WindowSizeItem?.FirstOrDefault(t => t.TypeName == typeName);
|
|
||||||
if (sizeItem == null || sizeItem.Width <= 0 || sizeItem.Height <= 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sizeItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int SaveWindowSizeItem(Config config, string typeName, double width, double height)
|
|
||||||
{
|
|
||||||
var sizeItem = config?.UiItem?.WindowSizeItem?.FirstOrDefault(t => t.TypeName == typeName);
|
|
||||||
if (sizeItem == null)
|
|
||||||
{
|
|
||||||
sizeItem = new WindowSizeItem { TypeName = typeName };
|
|
||||||
config.UiItem.WindowSizeItem.Add(sizeItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
sizeItem.Width = (int)width;
|
|
||||||
sizeItem.Height = (int)height;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int SaveMainGirdHeight(Config config, double height1, double height2)
|
|
||||||
{
|
|
||||||
var uiItem = config.UiItem ?? new();
|
|
||||||
|
|
||||||
uiItem.MainGirdHeight1 = (int)(height1 + 0.1);
|
|
||||||
uiItem.MainGirdHeight2 = (int)(height2 + 0.1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion UIItem
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,8 +89,10 @@ public class UIItem
|
||||||
{
|
{
|
||||||
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
||||||
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
||||||
public int MainGirdHeight1 { get; set; }
|
public double MainWidth { get; set; }
|
||||||
public int MainGirdHeight2 { get; set; }
|
public double MainHeight { get; set; }
|
||||||
|
public double MainGirdHeight1 { get; set; }
|
||||||
|
public double MainGirdHeight2 { get; set; }
|
||||||
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public string? ColorPrimaryName { get; set; }
|
public string? ColorPrimaryName { get; set; }
|
||||||
public string? CurrentTheme { get; set; }
|
public string? CurrentTheme { get; set; }
|
||||||
|
@ -101,10 +103,8 @@ public class UIItem
|
||||||
public bool DoubleClick2Activate { get; set; }
|
public bool DoubleClick2Activate { get; set; }
|
||||||
public bool AutoHideStartup { get; set; }
|
public bool AutoHideStartup { get; set; }
|
||||||
public bool Hide2TrayWhenClose { get; set; }
|
public bool Hide2TrayWhenClose { get; set; }
|
||||||
public bool ShowInTaskbar { get; set; }
|
|
||||||
public bool MacOSShowInDock { get; set; }
|
|
||||||
public List<ColumnItem> MainColumnItem { get; set; }
|
public List<ColumnItem> MainColumnItem { get; set; }
|
||||||
public List<WindowSizeItem> WindowSizeItem { get; set; }
|
public bool ShowInTaskbar { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
@ -245,11 +245,3 @@ public class Fragment4RayItem
|
||||||
public string? Length { get; set; }
|
public string? Length { get; set; }
|
||||||
public string? Interval { get; set; }
|
public string? Interval { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class WindowSizeItem
|
|
||||||
{
|
|
||||||
public string TypeName { get; set; }
|
|
||||||
public int Width { get; set; }
|
|
||||||
public int Height { get; set; }
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
using ReactiveUI;
|
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItem : ReactiveObject
|
public class ProfileItem
|
||||||
{
|
{
|
||||||
public ProfileItem()
|
public ProfileItem()
|
||||||
{
|
{
|
||||||
|
@ -94,5 +93,4 @@ public class ProfileItem : ReactiveObject
|
||||||
public string ShortId { get; set; }
|
public string ShortId { get; set; }
|
||||||
public string SpiderX { get; set; }
|
public string SpiderX { get; set; }
|
||||||
public string Extra { get; set; }
|
public string Extra { get; set; }
|
||||||
public bool? MuxEnabled { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using ReactiveUI.Fody.Helpers;
|
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
@ -7,28 +5,13 @@ public class ProfileItemModel : ProfileItem
|
||||||
{
|
{
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
public string SubRemarks { get; set; }
|
public string SubRemarks { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
|
||||||
public int Delay { get; set; }
|
public int Delay { get; set; }
|
||||||
|
|
||||||
public decimal Speed { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
|
||||||
public string DelayVal { get; set; }
|
public string DelayVal { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
|
||||||
public string SpeedVal { get; set; }
|
public string SpeedVal { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
|
||||||
public string TodayUp { get; set; }
|
public string TodayUp { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
|
||||||
public string TodayDown { get; set; }
|
public string TodayDown { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
|
||||||
public string TotalUp { get; set; }
|
public string TotalUp { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
|
||||||
public string TotalDown { get; set; }
|
public string TotalDown { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>匯出分享連結至剪貼簿成功</value>
|
<value>匯出分享链接至剪貼簿成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CheckServerSettings" xml:space="preserve">
|
<data name="CheckServerSettings" xml:space="preserve">
|
||||||
<value>請先檢查設定檔設定</value>
|
<value>請先檢查設定檔設定</value>
|
||||||
|
@ -295,7 +295,7 @@
|
||||||
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>掃描匯入分享連結成功</value>
|
<value>掃描匯入分享链接成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TestMeOutput" xml:space="preserve">
|
<data name="TestMeOutput" xml:space="preserve">
|
||||||
<value>目前延遲: {0} ms,{1}</value>
|
<value>目前延遲: {0} ms,{1}</value>
|
||||||
|
@ -481,7 +481,7 @@
|
||||||
<value>語言 (需重啟)</value>
|
<value>語言 (需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||||
<value>從剪貼簿導入分享連結 (Ctrl+V)</value>
|
<value>從剪貼簿導入分享鏈接 (Ctrl+V)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaScan" xml:space="preserve">
|
<data name="menuAddServerViaScan" xml:space="preserve">
|
||||||
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
||||||
|
@ -517,7 +517,7 @@
|
||||||
<value>匯出所選設定檔完整設定</value>
|
<value>匯出所選設定檔完整設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>匯出分享連結至剪貼簿 (多選) (Ctrl+C)</value>
|
<value>匯出分享链接至剪貼簿 (多選) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>新增自訂設定設定檔</value>
|
<value>新增自訂設定設定檔</value>
|
||||||
|
@ -892,7 +892,7 @@
|
||||||
<value>規則詳細說明檔案</value>
|
<value>規則詳細說明檔案</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||||
<value>支援填寫 DnsObject,JSON 格式,點擊查看說明</value>
|
<value>支援填寫 DnsObject,JSON 格式,點擊查看説明</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>普通分組此處請留空</value>
|
<value>普通分組此處請留空</value>
|
||||||
|
@ -1003,7 +1003,7 @@
|
||||||
<value>啟用硬體加速 (需重啟)</value>
|
<value>啟用硬體加速 (需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingWait" xml:space="preserve">
|
<data name="SpeedtestingWait" xml:space="preserve">
|
||||||
<value>等待測試中(按 ESC 終止)...</value>
|
<value>等待测试中(按 ESC 终止)...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipDisplayLog" xml:space="preserve">
|
<data name="TipDisplayLog" xml:space="preserve">
|
||||||
<value>當有異常斷流時請關閉</value>
|
<value>當有異常斷流時請關閉</value>
|
||||||
|
@ -1102,10 +1102,10 @@
|
||||||
<value>混淆密碼 (obfs password)</value>
|
<value>混淆密碼 (obfs password)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleMatchingTips" xml:space="preserve">
|
<data name="TbRuleMatchingTips" xml:space="preserve">
|
||||||
<value>(Domain 或 IP 或 行程名) 與 Port 與 Protocol 與 InboundTag => OutboundTag</value>
|
<value>(Domain 或 IP 或 行程名) 与 Port 与 Protocol 与 InboundTag => OutboundTag</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
||||||
<value>自動滾動到末尾</value>
|
<value>自动滚动到末尾</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
||||||
<value>真連線測試位址</value>
|
<value>真連線測試位址</value>
|
||||||
|
@ -1201,7 +1201,7 @@
|
||||||
<value>全局</value>
|
<value>全局</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeNothing" xml:space="preserve">
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
<value>隨原配置</value>
|
<value>随原配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuModeRule" xml:space="preserve">
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
<value>規則</value>
|
<value>規則</value>
|
||||||
|
@ -1231,7 +1231,7 @@
|
||||||
<value>自動調整列寬</value>
|
<value>自動調整列寬</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
||||||
<value>匯出分享連結至剪貼簿 (多選) Base64 編碼</value>
|
<value>匯出分享链接至剪貼簿 (多選) Base64 编码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>匯出所選設定檔完整設定至剪貼簿</value>
|
<value>匯出所選設定檔完整設定至剪貼簿</value>
|
||||||
|
@ -1267,7 +1267,7 @@
|
||||||
<value>WebDav 伺服器位址</value>
|
<value>WebDav 伺服器位址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavUserName" xml:space="preserve">
|
<data name="LvWebDavUserName" xml:space="preserve">
|
||||||
<value>WebDav 帳戶</value>
|
<value>WebDav 賬戶</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvWebDavPassword" xml:space="preserve">
|
<data name="LvWebDavPassword" xml:space="preserve">
|
||||||
<value>WebDav 密碼</value>
|
<value>WebDav 密碼</value>
|
||||||
|
@ -1336,7 +1336,7 @@
|
||||||
<value>系統的 sudo 密碼</value>
|
<value>系統的 sudo 密碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會儲存,每次重啟後都需要再次輸入。</value>
|
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會存儲,每次重啟後都需要再次輸入。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
|
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
|
||||||
|
@ -1366,7 +1366,7 @@
|
||||||
<value>開啟第二個本機監聽埠</value>
|
<value>開啟第二個本機監聽埠</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||||
<value>socks:本地埠,socks2:第二個本地埠,socks3:區域網路埠</value>
|
<value>socks:本地端口,socks2:第二個本地端口,socks3:區域網路端口</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTheme" xml:space="preserve">
|
<data name="TbSettingsTheme" xml:space="preserve">
|
||||||
<value>主題</value>
|
<value>主題</value>
|
||||||
|
@ -1387,10 +1387,10 @@
|
||||||
<value>移除無效測試結果 {0} 個。</value>
|
<value>移除無效測試結果 {0} 個。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7" xml:space="preserve">
|
<data name="TbPorts7" xml:space="preserve">
|
||||||
<value>跳躍埠範圍</value>
|
<value>跳躍端口範圍</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7Tips" xml:space="preserve">
|
<data name="TbPorts7Tips" xml:space="preserve">
|
||||||
<value>會覆蓋埠,多組時用逗號 (,) 隔開</value>
|
<value>會覆蓋端口,多組時用逗號 (,) 隔開</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>多設定檔產生自訂配置 (多選)</value>
|
<value>多設定檔產生自訂配置 (多選)</value>
|
||||||
|
|
|
@ -336,7 +336,7 @@ public class CoreConfigSingboxService
|
||||||
await GenExperimental(singboxConfig);
|
await GenExperimental(singboxConfig);
|
||||||
singboxConfig.outbounds.RemoveAt(0);
|
singboxConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
var proxyProfiles = new List<ProfileItem>();
|
var tagProxy = new List<string>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
|
@ -370,18 +370,42 @@ public class CoreConfigSingboxService
|
||||||
}
|
}
|
||||||
|
|
||||||
//outbound
|
//outbound
|
||||||
proxyProfiles.Add(item);
|
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
|
await GenOutbound(item, outbound);
|
||||||
|
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||||
|
singboxConfig.outbounds.Insert(0, outbound);
|
||||||
|
tagProxy.Add(outbound.tag);
|
||||||
}
|
}
|
||||||
if (proxyProfiles.Count <= 0)
|
if (tagProxy.Count <= 0)
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
await GenOutboundsList(proxyProfiles, singboxConfig);
|
|
||||||
|
|
||||||
await GenDns(null, singboxConfig);
|
await GenDns(null, singboxConfig);
|
||||||
await ConvertGeo2Ruleset(singboxConfig);
|
await ConvertGeo2Ruleset(singboxConfig);
|
||||||
|
|
||||||
|
//add urltest outbound
|
||||||
|
var outUrltest = new Outbound4Sbox
|
||||||
|
{
|
||||||
|
type = "urltest",
|
||||||
|
tag = $"{Global.ProxyTag}-auto",
|
||||||
|
outbounds = tagProxy,
|
||||||
|
interrupt_exist_connections = false,
|
||||||
|
};
|
||||||
|
singboxConfig.outbounds.Insert(0, outUrltest);
|
||||||
|
|
||||||
|
//add selector outbound
|
||||||
|
var outSelector = new Outbound4Sbox
|
||||||
|
{
|
||||||
|
type = "selector",
|
||||||
|
tag = Global.ProxyTag,
|
||||||
|
outbounds = JsonUtils.DeepCopy(tagProxy),
|
||||||
|
interrupt_exist_connections = false,
|
||||||
|
};
|
||||||
|
outSelector.outbounds.Insert(0, outUrltest.tag);
|
||||||
|
singboxConfig.outbounds.Insert(0, outSelector);
|
||||||
|
|
||||||
ret.Success = true;
|
ret.Success = true;
|
||||||
ret.Data = JsonUtils.Serialize(singboxConfig);
|
ret.Data = JsonUtils.Serialize(singboxConfig);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -751,8 +775,7 @@ public class CoreConfigSingboxService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
|
if (_config.CoreBasicItem.MuxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty())
|
||||||
if (muxEnabled && _config.Mux4SboxItem.Protocol.IsNotEmpty())
|
|
||||||
{
|
{
|
||||||
var mux = new Multiplex4Sbox()
|
var mux = new Multiplex4Sbox()
|
||||||
{
|
{
|
||||||
|
@ -918,168 +941,15 @@ public class CoreConfigSingboxService
|
||||||
|
|
||||||
//Previous proxy
|
//Previous proxy
|
||||||
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
||||||
string? prevOutboundTag = null;
|
|
||||||
if (prevNode is not null
|
if (prevNode is not null
|
||||||
&& prevNode.ConfigType != EConfigType.Custom)
|
&& prevNode.ConfigType != EConfigType.Custom)
|
||||||
{
|
{
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
var prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
prevOutboundTag = $"prev-{Global.ProxyTag}";
|
prevOutbound.tag = $"{Global.ProxyTag}2";
|
||||||
prevOutbound.tag = prevOutboundTag;
|
|
||||||
singboxConfig.outbounds.Add(prevOutbound);
|
singboxConfig.outbounds.Add(prevOutbound);
|
||||||
}
|
|
||||||
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
|
|
||||||
|
|
||||||
if (nextOutbound is not null)
|
outbound.detour = prevOutbound.tag;
|
||||||
{
|
|
||||||
singboxConfig.outbounds.Insert(0, nextOutbound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, SingboxConfig singboxConfig)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Get outbound template and initialize lists
|
|
||||||
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
|
|
||||||
if (txtOutbound.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultOutbounds = new List<Outbound4Sbox>();
|
|
||||||
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
|
//Next proxy
|
||||||
|
@ -1087,23 +957,21 @@ public class CoreConfigSingboxService
|
||||||
if (nextNode is not null
|
if (nextNode is not null
|
||||||
&& nextNode.ConfigType != EConfigType.Custom)
|
&& nextNode.ConfigType != EConfigType.Custom)
|
||||||
{
|
{
|
||||||
if (nextOutbound == null)
|
var nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
{
|
|
||||||
nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
}
|
nextOutbound.tag = Global.ProxyTag;
|
||||||
nextOutbound.tag = outbound.tag;
|
singboxConfig.outbounds.Insert(0, nextOutbound);
|
||||||
|
|
||||||
outbound.tag = $"mid-{outbound.tag}";
|
outbound.tag = $"{Global.ProxyTag}1";
|
||||||
nextOutbound.detour = outbound.tag;
|
nextOutbound.detour = outbound.tag;
|
||||||
}
|
}
|
||||||
return nextOutbound;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenRouting(SingboxConfig singboxConfig)
|
private async Task<int> GenRouting(SingboxConfig singboxConfig)
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class CoreConfigV2rayService
|
||||||
await GenStatistic(v2rayConfig);
|
await GenStatistic(v2rayConfig);
|
||||||
v2rayConfig.outbounds.RemoveAt(0);
|
v2rayConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
var proxyProfiles = new List<ProfileItem>();
|
var tagProxy = new List<string>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
|
@ -151,14 +151,17 @@ public class CoreConfigV2rayService
|
||||||
}
|
}
|
||||||
|
|
||||||
//outbound
|
//outbound
|
||||||
proxyProfiles.Add(item);
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
await GenOutbound(item, outbound);
|
||||||
|
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||||
|
v2rayConfig.outbounds.Insert(0, outbound);
|
||||||
|
tagProxy.Add(outbound.tag);
|
||||||
}
|
}
|
||||||
if (proxyProfiles.Count <= 0)
|
if (tagProxy.Count <= 0)
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
await GenOutboundsList(proxyProfiles, v2rayConfig);
|
|
||||||
|
|
||||||
//add balancers
|
//add balancers
|
||||||
await GenBalancer(v2rayConfig, multipleLoad);
|
await GenBalancer(v2rayConfig, multipleLoad);
|
||||||
|
@ -631,7 +634,7 @@ public class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
|
var muxEnabled = _config.CoreBasicItem.MuxEnabled;
|
||||||
switch (node.ConfigType)
|
switch (node.ConfigType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.VMess:
|
||||||
|
@ -1318,7 +1321,6 @@ public class CoreConfigV2rayService
|
||||||
|
|
||||||
//Previous proxy
|
//Previous proxy
|
||||||
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
||||||
string? prevOutboundTag = null;
|
|
||||||
if (prevNode is not null
|
if (prevNode is not null
|
||||||
&& prevNode.ConfigType != EConfigType.Custom
|
&& prevNode.ConfigType != EConfigType.Custom
|
||||||
&& prevNode.ConfigType != EConfigType.Hysteria2
|
&& prevNode.ConfigType != EConfigType.Hysteria2
|
||||||
|
@ -1326,138 +1328,12 @@ public class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
prevOutboundTag = $"prev-{Global.ProxyTag}";
|
prevOutbound.tag = $"{Global.ProxyTag}2";
|
||||||
prevOutbound.tag = prevOutboundTag;
|
|
||||||
v2rayConfig.outbounds.Add(prevOutbound);
|
v2rayConfig.outbounds.Add(prevOutbound);
|
||||||
}
|
|
||||||
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
|
|
||||||
|
|
||||||
if (nextOutbound is not null)
|
|
||||||
{
|
|
||||||
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, V2rayConfig v2rayConfig)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Get template and initialize list
|
|
||||||
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
|
||||||
if (txtOutbound.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultOutbounds = new List<Outbounds4Ray>();
|
|
||||||
var prevOutbounds = new List<Outbounds4Ray>(); // Separate list for prev outbounds and fragment
|
|
||||||
|
|
||||||
// Cache for chain proxies to avoid duplicate generation
|
|
||||||
var nextProxyCache = new Dictionary<string, Outbounds4Ray?>();
|
|
||||||
var prevProxyTags = new Dictionary<string, string?>(); // Map from profile name to tag
|
|
||||||
int prevIndex = 0; // Index for prev outbounds
|
|
||||||
|
|
||||||
// Process nodes
|
|
||||||
int index = 0;
|
|
||||||
foreach (var node in nodes)
|
|
||||||
{
|
|
||||||
index++;
|
|
||||||
|
|
||||||
// Handle proxy chain
|
|
||||||
string? prevTag = null;
|
|
||||||
var currentOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
|
||||||
var nextOutbound = nextProxyCache.GetValueOrDefault(node.Subid, null);
|
|
||||||
if (nextOutbound != null)
|
|
||||||
{
|
|
||||||
nextOutbound = JsonUtils.DeepCopy(nextOutbound);
|
|
||||||
}
|
|
||||||
|
|
||||||
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
|
|
||||||
|
|
||||||
// current proxy
|
|
||||||
await GenOutbound(node, currentOutbound);
|
|
||||||
currentOutbound.tag = $"{Global.ProxyTag}-{index}";
|
|
||||||
|
|
||||||
if (!node.Subid.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
if (prevProxyTags.TryGetValue(node.Subid, out var value))
|
|
||||||
{
|
|
||||||
prevTag = value; // maybe null
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
|
||||||
if (prevNode is not null
|
|
||||||
&& prevNode.ConfigType != EConfigType.Custom
|
|
||||||
&& prevNode.ConfigType != EConfigType.Hysteria2
|
|
||||||
&& prevNode.ConfigType != EConfigType.TUIC)
|
|
||||||
{
|
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
|
||||||
prevTag = $"prev-{Global.ProxyTag}-{++prevIndex}";
|
|
||||||
prevOutbound.tag = prevTag;
|
|
||||||
prevOutbounds.Add(prevOutbound);
|
|
||||||
}
|
|
||||||
prevProxyTags[node.Subid] = prevTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag, nextOutbound);
|
|
||||||
if (!nextProxyCache.ContainsKey(node.Subid))
|
|
||||||
{
|
|
||||||
nextProxyCache[node.Subid] = nextOutbound;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextOutbound is not null)
|
|
||||||
{
|
|
||||||
resultOutbounds.Add(nextOutbound);
|
|
||||||
}
|
|
||||||
resultOutbounds.Add(currentOutbound);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge results: first the main chain outbounds, then other outbounds, and finally utility outbounds
|
|
||||||
resultOutbounds.AddRange(prevOutbounds);
|
|
||||||
resultOutbounds.AddRange(v2rayConfig.outbounds);
|
|
||||||
v2rayConfig.outbounds = resultOutbounds;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates a chained outbound configuration for the given subItem and outbound.
|
|
||||||
/// The outbound's tag must be set before calling this method.
|
|
||||||
/// Returns the next proxy's outbound configuration, which may be null if no next proxy exists.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="subItem">The subscription item containing proxy chain information.</param>
|
|
||||||
/// <param name="outbound">The current outbound configuration. Its tag must be set before calling this method.</param>
|
|
||||||
/// <param name="prevOutboundTag">The tag of the previous outbound in the chain, if any.</param>
|
|
||||||
/// <param name="nextOutbound">The outbound for the next proxy in the chain, if already created. If null, will be created inside.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The outbound configuration for the next proxy in the chain, or null if no next proxy exists.
|
|
||||||
/// </returns>
|
|
||||||
private async Task<Outbounds4Ray?> GenChainOutbounds(SubItem subItem, Outbounds4Ray outbound, string? prevOutboundTag, Outbounds4Ray? nextOutbound = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
|
||||||
|
|
||||||
if (!prevOutboundTag.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
outbound.streamSettings.sockopt = new()
|
outbound.streamSettings.sockopt = new()
|
||||||
{
|
{
|
||||||
dialerProxy = prevOutboundTag
|
dialerProxy = prevOutbound.tag
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,26 +1344,24 @@ public class CoreConfigV2rayService
|
||||||
&& nextNode.ConfigType != EConfigType.Hysteria2
|
&& nextNode.ConfigType != EConfigType.Hysteria2
|
||||||
&& nextNode.ConfigType != EConfigType.TUIC)
|
&& nextNode.ConfigType != EConfigType.TUIC)
|
||||||
{
|
{
|
||||||
if (nextOutbound == null)
|
var nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
{
|
|
||||||
nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
}
|
nextOutbound.tag = Global.ProxyTag;
|
||||||
nextOutbound.tag = outbound.tag;
|
v2rayConfig.outbounds.Insert(0, nextOutbound);
|
||||||
|
|
||||||
outbound.tag = $"mid-{outbound.tag}";
|
outbound.tag = $"{Global.ProxyTag}1";
|
||||||
nextOutbound.streamSettings.sockopt = new()
|
nextOutbound.streamSettings.sockopt = new()
|
||||||
{
|
{
|
||||||
dialerProxy = outbound.tag
|
dialerProxy = outbound.tag
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return nextOutbound;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
private async Task<int> GenBalancer(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
||||||
|
|
|
@ -196,7 +196,6 @@ public class SpeedtestService
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await Task.Delay(1000);
|
|
||||||
|
|
||||||
var downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
|
|
||||||
|
@ -256,13 +255,9 @@ public class SpeedtestService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
||||||
if (pid < 0)
|
if (pid > 0)
|
||||||
{
|
{
|
||||||
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
await Task.Delay(500);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Task.Delay(1000);
|
|
||||||
var delay = await DoRealPing(downloadHandle, it);
|
var delay = await DoRealPing(downloadHandle, it);
|
||||||
if (blSpeedTest)
|
if (blSpeedTest)
|
||||||
{
|
{
|
||||||
|
@ -276,6 +271,10 @@ public class SpeedtestService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -552,7 +552,6 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
await LoadCore();
|
await LoadCore();
|
||||||
await SysProxyHandler.UpdateSysProxy(_config, false);
|
await SysProxyHandler.UpdateSysProxy(_config, false);
|
||||||
await Task.Delay(1000);
|
|
||||||
});
|
});
|
||||||
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -499,18 +499,10 @@ 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"
|
||||||
Name="v2rayN"
|
|
||||||
x:DataType="vms:StatusBarViewModel"
|
x:DataType="vms:StatusBarViewModel"
|
||||||
|
Name="v2rayN"
|
||||||
RequestedThemeVariant="Default">
|
RequestedThemeVariant="Default">
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<semi:SemiTheme />
|
<semi:SemiTheme />
|
||||||
|
@ -32,8 +32,6 @@
|
||||||
ToolTipText="{Binding RunningServerToolTipText}">
|
ToolTipText="{Binding RunningServerToolTipText}">
|
||||||
<TrayIcon.Menu>
|
<TrayIcon.Menu>
|
||||||
<NativeMenu>
|
<NativeMenu>
|
||||||
<NativeMenuItem Command="{Binding NotifyLeftClickCmd}" Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}" />
|
|
||||||
<NativeMenuItemSeparator />
|
|
||||||
<NativeMenuItem
|
<NativeMenuItem
|
||||||
Command="{Binding SystemProxyClearCmd}"
|
Command="{Binding SystemProxyClearCmd}"
|
||||||
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
||||||
|
@ -57,11 +55,13 @@
|
||||||
ToggleType="Radio" />
|
ToggleType="Radio" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
||||||
|
<NativeMenuItem Header="{x:Static resx:ResUI.menuAddServerViaScan}" IsVisible="False" />
|
||||||
<NativeMenuItem Command="{Binding SubUpdateCmd}" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
<NativeMenuItem Command="{Binding SubUpdateCmd}" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||||
<NativeMenuItem Command="{Binding SubUpdateViaProxyCmd}" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
<NativeMenuItem Command="{Binding SubUpdateViaProxyCmd}" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
|
<NativeMenuItem Command="{Binding NotifyLeftClickCmd}" Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}" />
|
||||||
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
||||||
</NativeMenu>
|
</NativeMenu>
|
||||||
</TrayIcon.Menu>
|
</TrayIcon.Menu>
|
||||||
|
|
|
@ -11,6 +11,11 @@ public partial class App : Application
|
||||||
{
|
{
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
if (!AppHandler.Instance.InitApp())
|
||||||
|
{
|
||||||
|
Environment.Exit(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Base;
|
|
||||||
|
|
||||||
public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewModel : class
|
|
||||||
{
|
|
||||||
public WindowBase()
|
|
||||||
{
|
|
||||||
Loaded += OnLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReactiveWindowBase_Closed(object? sender, EventArgs e)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnLoaded(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var sizeItem = ConfigHandler.GetWindowSizeItem(AppHandler.Instance.Config, GetType().Name);
|
|
||||||
if (sizeItem == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Width = sizeItem.Width;
|
|
||||||
Height = sizeItem.Height;
|
|
||||||
|
|
||||||
var workingArea = (Screens.ScreenFromWindow(this) ?? Screens.Primary).WorkingArea;
|
|
||||||
var scaling = (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,17 +14,13 @@ internal class Program
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
if (OnStartup(args) == false)
|
OnStartup(args);
|
||||||
{
|
|
||||||
Environment.Exit(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildAvaloniaApp()
|
BuildAvaloniaApp()
|
||||||
.StartWithClassicDesktopLifetime(args);
|
.StartWithClassicDesktopLifetime(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool OnStartup(string[]? Args)
|
private static void OnStartup(string[]? Args)
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
|
@ -34,7 +30,8 @@ internal class Program
|
||||||
if (!rebootas && !bCreatedNew)
|
if (!rebootas && !bCreatedNew)
|
||||||
{
|
{
|
||||||
ProgramStarted.Set();
|
ProgramStarted.Set();
|
||||||
return false;
|
Environment.Exit(0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -42,30 +39,19 @@ internal class Program
|
||||||
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
|
||||||
if (!bOnlyOneInstance)
|
if (!bOnlyOneInstance)
|
||||||
{
|
{
|
||||||
return false;
|
Environment.Exit(0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AppHandler.Instance.InitApp())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
{
|
=> AppBuilder.Configure<App>()
|
||||||
return AppBuilder.Configure<App>()
|
|
||||||
.UsePlatformDetect()
|
.UsePlatformDetect()
|
||||||
//.WithInterFont()
|
//.WithInterFont()
|
||||||
.WithFontByDefault()
|
.WithFontByDefault()
|
||||||
.LogToTrace()
|
.LogToTrace()
|
||||||
#if OS_OSX
|
|
||||||
.UseReactiveUI()
|
.UseReactiveUI()
|
||||||
.With(new MacOSPlatformOptions { ShowInDock = AppHandler.Instance.Config.UiItem.MacOSShowInDock });
|
.With(new MacOSPlatformOptions { ShowInDock = false });
|
||||||
#else
|
|
||||||
.UseReactiveUI();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class AddServer2Window : WindowBase<AddServer2ViewModel>
|
public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
||||||
{
|
{
|
||||||
public AddServer2Window()
|
public AddServer2Window()
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto,Auto"
|
ColumnDefinitions="180,Auto,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -152,26 +152,13 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleSwitch
|
|
||||||
x:Name="togmuxEnabled"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSs"
|
x:Name="gridSs"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto"
|
ColumnDefinitions="180,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -198,19 +185,6 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleSwitch
|
|
||||||
x:Name="togmuxEnabled3"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSocks"
|
x:Name="gridSocks"
|
||||||
|
@ -250,7 +224,7 @@
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto,Auto"
|
ColumnDefinitions="180,Auto,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -297,26 +271,13 @@
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleSwitch
|
|
||||||
x:Name="togmuxEnabled5"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridTrojan"
|
x:Name="gridTrojan"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
ColumnDefinitions="180,Auto"
|
ColumnDefinitions="180,Auto"
|
||||||
IsVisible="False"
|
IsVisible="False"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
@ -343,19 +304,6 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleSwitch
|
|
||||||
x:Name="togmuxEnabled6"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridHysteria2"
|
x:Name="gridHysteria2"
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||||
{
|
{
|
||||||
public AddServerWindow()
|
public AddServerWindow()
|
||||||
{
|
{
|
||||||
|
@ -150,13 +150,11 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Shadowsocks:
|
case EConfigType.Shadowsocks:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
|
@ -169,13 +167,11 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled5.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled6.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TabControl HorizontalContentAlignment="Stretch">
|
<TabControl HorizontalContentAlignment="Left">
|
||||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||||
|
@ -90,18 +90,16 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
|
|
||||||
<HeaderedContentControl
|
<Grid Margin="{StaticResource Margin4}">
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
Header="HTTP/SOCKS">
|
|
||||||
<TextBox
|
<TextBox
|
||||||
Name="txtnormalDNS"
|
x:Name="txtnormalDNS"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
MinLines="10"
|
TextWrapping="Wrap"
|
||||||
TextWrapping="Wrap" />
|
Watermark="HTTP/SOCKS" />
|
||||||
</HeaderedContentControl>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
@ -146,34 +144,31 @@
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
||||||
|
|
||||||
<HeaderedContentControl
|
|
||||||
Grid.Column="0"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
Header="HTTP/SOCKS">
|
|
||||||
<TextBox
|
<TextBox
|
||||||
Name="txtnormalDNS2"
|
x:Name="txtnormalDNS2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Width="400"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
MinLines="10"
|
Margin="{StaticResource Margin4}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap"
|
||||||
</HeaderedContentControl>
|
Watermark="HTTP/SOCKS" />
|
||||||
|
|
||||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||||
|
|
||||||
<HeaderedContentControl
|
|
||||||
Grid.Column="2"
|
|
||||||
BorderBrush="Gray"
|
|
||||||
BorderThickness="1"
|
|
||||||
Header="{x:Static resx:ResUI.TbSettingsTunMode}">
|
|
||||||
<TextBox
|
<TextBox
|
||||||
Name="txttunDNS2"
|
x:Name="txttunDNS2"
|
||||||
|
Grid.Column="2"
|
||||||
|
Width="400"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
MinLines="10"
|
Margin="{StaticResource Margin4}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap"
|
||||||
</HeaderedContentControl>
|
Watermark="{x:Static resx:ResUI.TbSettingsTunMode}" />
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,13 @@ using System.Text;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
using v2rayN.Desktop.Handler;
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingViewModel>
|
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
||||||
{
|
{
|
||||||
private readonly List<object> _textBoxKeyEventItem = new();
|
private readonly List<object> _textBoxKeyEventItem = new();
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,18 @@ using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Controls.Notifications;
|
using Avalonia.Controls.Notifications;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Splat;
|
using Splat;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
using v2rayN.Desktop.Handler;
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class MainWindow : WindowBase<MainWindowViewModel>
|
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
private WindowNotificationManager? _manager;
|
private WindowNotificationManager? _manager;
|
||||||
|
@ -154,6 +154,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
}
|
}
|
||||||
menuAddServerViaScan.IsVisible = false;
|
menuAddServerViaScan.IsVisible = false;
|
||||||
|
|
||||||
|
RestoreUI();
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||||
}
|
}
|
||||||
|
@ -435,14 +436,14 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
_config.UiItem.ShowInTaskbar = bl;
|
_config.UiItem.ShowInTaskbar = bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnLoaded(sender, e);
|
|
||||||
RestoreUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RestoreUI()
|
private void RestoreUI()
|
||||||
{
|
{
|
||||||
|
if (_config.UiItem.MainWidth > 0 && _config.UiItem.MainHeight > 0)
|
||||||
|
{
|
||||||
|
Width = _config.UiItem.MainWidth;
|
||||||
|
Height = _config.UiItem.MainHeight;
|
||||||
|
}
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
||||||
{
|
{
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
|
@ -460,15 +461,18 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
|
|
||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
|
_config.UiItem.MainWidth = this.Width;
|
||||||
|
_config.UiItem.MainHeight = this.Height;
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
||||||
|
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
|
||||||
}
|
}
|
||||||
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
||||||
|
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -575,9 +575,9 @@
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbIPAPIUrl"
|
x:Name="cmbSubConvertUrl"
|
||||||
Grid.Row="20"
|
Grid.Row="20"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
|
@ -588,41 +588,28 @@
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
|
||||||
<ctrls:AutoCompleteBox
|
|
||||||
x:Name="cmbSubConvertUrl"
|
|
||||||
Grid.Row="21"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="300"
|
|
||||||
Margin="{StaticResource Margin4}" />
|
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="22"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="22"
|
Grid.Row="21"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbGetFilesSourceUrl"
|
x:Name="cmbGetFilesSourceUrl"
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -630,13 +617,33 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="23"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSrsFilesSourceUrl"
|
x:Name="cmbSrsFilesSourceUrl"
|
||||||
|
Grid.Row="23"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="23"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="24"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbRoutingRulesSourceUrl"
|
||||||
Grid.Row="24"
|
Grid.Row="24"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
|
@ -654,20 +661,13 @@
|
||||||
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.TbSettingsIPAPIUrl}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRoutingRulesSourceUrl"
|
x:Name="cmbIPAPIUrl"
|
||||||
Grid.Row="25"
|
Grid.Row="25"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
<TextBlock
|
|
||||||
Grid.Row="25"
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
|
|
|
@ -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,24 +347,6 @@ 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);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsViewModel>
|
public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetailsViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleDetailsWindow()
|
public RoutingRuleDetailsWindow()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,14 +2,14 @@ using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingViewModel>
|
public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettingViewModel>
|
||||||
{
|
{
|
||||||
public RoutingRuleSettingWindow()
|
public RoutingRuleSettingWindow()
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,11 +24,28 @@
|
||||||
<MenuItem x:Name="menuRoutingAdvancedAdd2" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
<MenuItem x:Name="menuRoutingAdvancedAdd2" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
<MenuItem x:Name="menuRoutingAdvancedImportRules2" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
<MenuItem x:Name="menuRoutingAdvancedImportRules2" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
|
<TextBlock VerticalAlignment="Center">
|
||||||
|
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</TextBlock>
|
||||||
|
<ComboBox x:Name="cmbdomainStrategy" Width="110" />
|
||||||
|
<Separator />
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
||||||
|
<ComboBox x:Name="cmbdomainMatcher" Width="60" />
|
||||||
|
<Separator />
|
||||||
|
<TextBlock VerticalAlignment="Center">
|
||||||
|
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
|
||||||
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</TextBlock>
|
||||||
|
<ComboBox x:Name="cmbdomainStrategy4Singbox" Width="100" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
@ -52,62 +69,7 @@
|
||||||
IsCancel="True" />
|
IsCancel="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid
|
<DockPanel>
|
||||||
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
|
||||||
|
@ -160,4 +122,5 @@
|
||||||
</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 : WindowBase<RoutingSettingViewModel>
|
public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class SubEditWindow : WindowBase<SubEditViewModel>
|
public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
||||||
{
|
{
|
||||||
public SubEditWindow()
|
public SubEditWindow()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using MsBox.Avalonia.Enums;
|
using MsBox.Avalonia.Enums;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using v2rayN.Desktop.Base;
|
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
namespace v2rayN.Desktop.Views;
|
||||||
|
|
||||||
public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
||||||
{
|
{
|
||||||
private bool _manualClose = false;
|
private bool _manualClose = false;
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@
|
||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
|
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
|
||||||
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
<Setter Property="TextElement.FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||||
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||||
<Setter Property="ResizeMode" Value="CanResize" />
|
<Setter Property="ResizeMode" Value="NoResize" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ViewGlobal"
|
x:Key="ViewGlobal"
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
using System.Windows;
|
|
||||||
using ReactiveUI;
|
|
||||||
|
|
||||||
namespace v2rayN.Base;
|
|
||||||
|
|
||||||
public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewModel : class
|
|
||||||
{
|
|
||||||
public WindowBase()
|
|
||||||
{
|
|
||||||
Loaded += OnLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnLoaded(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var sizeItem = ConfigHandler.GetWindowSizeItem(AppHandler.Instance.Config, GetType().Name);
|
|
||||||
if (sizeItem == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Width = Math.Min(sizeItem.Width, SystemParameters.WorkArea.Width);
|
|
||||||
Height = Math.Min(sizeItem.Height, SystemParameters.WorkArea.Height);
|
|
||||||
|
|
||||||
Left = SystemParameters.WorkArea.Left + ((SystemParameters.WorkArea.Width - Width) / 2);
|
|
||||||
Top = SystemParameters.WorkArea.Top + ((SystemParameters.WorkArea.Height - Height) / 2);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
|
||||||
{
|
|
||||||
base.OnClosed(e);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ConfigHandler.SaveWindowSizeItem(AppHandler.Instance.Config, GetType().Name, Width, Height);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.AddServer2Window"
|
x:Class="v2rayN.Views.AddServer2Window"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -199,4 +198,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.AddServerWindow"
|
x:Class="v2rayN.Views.AddServerWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -156,7 +155,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -216,20 +214,6 @@
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSs"
|
x:Name="gridSs"
|
||||||
|
@ -240,7 +224,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -276,20 +259,6 @@
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled3"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridSocks"
|
x:Name="gridSocks"
|
||||||
|
@ -345,7 +314,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -405,20 +373,6 @@
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Style="{StaticResource DefTextBox}" />
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled5"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridTrojan"
|
x:Name="gridTrojan"
|
||||||
|
@ -429,7 +383,6 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="180" />
|
<ColumnDefinition Width="180" />
|
||||||
|
@ -465,20 +418,6 @@
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togmuxEnabled6"
|
|
||||||
Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridHysteria2"
|
x:Name="gridHysteria2"
|
||||||
|
@ -1072,4 +1011,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -144,13 +144,11 @@ public partial class AddServerWindow
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Shadowsocks:
|
case EConfigType.Shadowsocks:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId3.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity3.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.SOCKS:
|
case EConfigType.SOCKS:
|
||||||
|
@ -163,13 +161,11 @@ public partial class AddServerWindow
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled5.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled6.IsChecked).DisposeWith(disposables);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EConfigType.Hysteria2:
|
case EConfigType.Hysteria2:
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.DNSSettingWindow"
|
x:Class="v2rayN.Views.DNSSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -205,4 +204,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
|
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -170,4 +169,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.MainWindow"
|
x:Class="v2rayN.Views.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -41,8 +40,8 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
KeyboardNavigation.TabNavigation="Continue"
|
Style="{StaticResource MaterialDesignToolBar}"
|
||||||
Style="{StaticResource MaterialDesignToolBar}">
|
KeyboardNavigation.TabNavigation="Continue">
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem Padding="8,0" AutomationProperties.Name="{x:Static resx:ResUI.menuServers}">
|
<MenuItem Padding="8,0" AutomationProperties.Name="{x:Static resx:ResUI.menuServers}">
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
|
@ -433,4 +432,4 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -139,6 +139,7 @@ public partial class MainWindow
|
||||||
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
|
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RestoreUI();
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
|
WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
|
||||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||||
|
@ -394,14 +395,20 @@ public partial class MainWindow
|
||||||
_config.UiItem.ShowInTaskbar = bl;
|
_config.UiItem.ShowInTaskbar = bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnLoaded(sender, e);
|
|
||||||
RestoreUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RestoreUI()
|
private void RestoreUI()
|
||||||
{
|
{
|
||||||
|
if (_config.UiItem.MainWidth > 0 && _config.UiItem.MainHeight > 0)
|
||||||
|
{
|
||||||
|
Width = _config.UiItem.MainWidth;
|
||||||
|
Height = _config.UiItem.MainHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxWidth = SystemParameters.WorkArea.Width;
|
||||||
|
var maxHeight = SystemParameters.WorkArea.Height;
|
||||||
|
if (Width > maxWidth)
|
||||||
|
Width = maxWidth;
|
||||||
|
if (Height > maxHeight)
|
||||||
|
Height = maxHeight;
|
||||||
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
||||||
{
|
{
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
|
@ -419,15 +426,18 @@ public partial class MainWindow
|
||||||
|
|
||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
|
_config.UiItem.MainWidth = this.Width;
|
||||||
|
_config.UiItem.MainHeight = this.Height;
|
||||||
|
|
||||||
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
||||||
|
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
|
||||||
}
|
}
|
||||||
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
{
|
{
|
||||||
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
|
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
||||||
|
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.OptionSettingWindow"
|
x:Class="v2rayN.Views.OptionSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -847,26 +846,10 @@
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
|
||||||
<ComboBox
|
|
||||||
x:Name="cmbIPAPIUrl"
|
|
||||||
Grid.Row="20"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="300"
|
|
||||||
Margin="{StaticResource Margin8}"
|
|
||||||
IsEditable="True"
|
|
||||||
Style="{StaticResource DefComboBox}" />
|
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="21"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin8}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSubConvertUrl"
|
x:Name="cmbSubConvertUrl"
|
||||||
Grid.Row="21"
|
Grid.Row="20"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
|
@ -875,7 +858,7 @@
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="22"
|
Grid.Row="21"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -883,14 +866,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="22"
|
Grid.Row="21"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -898,14 +881,14 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsGeoFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbGetFilesSourceUrl"
|
x:Name="cmbGetFilesSourceUrl"
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="23"
|
Grid.Row="22"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -914,7 +897,7 @@
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="24"
|
Grid.Row="23"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -922,6 +905,30 @@
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsSrsFilesSource}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSrsFilesSourceUrl"
|
x:Name="cmbSrsFilesSourceUrl"
|
||||||
|
Grid.Row="23"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
IsEditable="True"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="23"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="24"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbRoutingRulesSourceUrl"
|
||||||
Grid.Row="24"
|
Grid.Row="24"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
|
@ -943,23 +950,15 @@
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsRoutingRulesSource}" />
|
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRoutingRulesSourceUrl"
|
x:Name="cmbIPAPIUrl"
|
||||||
Grid.Row="25"
|
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
|
|
||||||
Grid.Row="25"
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
@ -1230,4 +1229,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
|
x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -243,4 +242,4 @@
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.RoutingRuleSettingWindow"
|
x:Class="v2rayN.Views.RoutingRuleSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -335,4 +334,4 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.RoutingSettingWindow"
|
x:Class="v2rayN.Views.RoutingSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -30,25 +29,68 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Style="{StaticResource MaterialDesignToolBar}">
|
Style="{StaticResource MaterialDesignToolBar}">
|
||||||
<Button x:Name="menuRoutingAdvancedAdd2">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
|
<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="Plus" />
|
Kind="Routes" />
|
||||||
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
<TextBlock Text="{x:Static resx:ResUI.menuRoutingAdvanced}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</MenuItem.Header>
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRoutingAdvancedAdd2"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRoutingAdvancedImportRules2"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Button x:Name="menuRoutingAdvancedImportRules2">
|
<TextBlock
|
||||||
<StackPanel Orientation="Horizontal">
|
Margin="{StaticResource MarginLeft8}"
|
||||||
<materialDesign:PackIcon
|
|
||||||
Margin="{StaticResource MarginRight8}"
|
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Kind="Import" />
|
Style="{StaticResource ToolbarTextBlock}">
|
||||||
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
<Hyperlink Click="linkdomainStrategy_Click">
|
||||||
</StackPanel>
|
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||||
</Button>
|
<materialDesign:PackIcon Kind="Link" />
|
||||||
|
</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>
|
||||||
|
|
||||||
|
@ -80,71 +122,7 @@
|
||||||
Style="{StaticResource DefButton}" />
|
Style="{StaticResource DefButton}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid Margin="{StaticResource Margin8}" DockPanel.Dock="Top">
|
<DockPanel>
|
||||||
<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
|
||||||
|
@ -221,4 +199,5 @@
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</DockPanel>
|
||||||
|
</reactiveui:ReactiveWindow>
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.SubEditWindow"
|
x:Class="v2rayN.Views.SubEditWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -316,4 +315,4 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<base:WindowBase
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.SubSettingWindow"
|
x:Class="v2rayN.Views.SubSettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:base="clr-namespace:v2rayN.Base"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
@ -121,4 +120,4 @@
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</base:WindowBase>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|
Loading…
Reference in a new issue