Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6500c8d85e | ||
|
|
9866d436da | ||
|
|
0f4884d9d8 | ||
|
|
5a81441351 | ||
|
|
e8721bfb6b | ||
|
|
1b09d95209 | ||
|
|
35f3b5a50e | ||
|
|
ff5203a561 | ||
|
|
c3c1ced309 | ||
|
|
08b1c8ec83 | ||
|
|
1dd3ee4e0a | ||
|
|
06d0c6517d | ||
|
|
4938ce6364 | ||
|
|
25f3fc354f | ||
|
|
ad1a1f8015 | ||
|
|
5c070e2ca8 | ||
|
|
70ea21fca2 | ||
|
|
bc3593871b | ||
|
|
355a424be2 | ||
|
|
0ffa9a0cc8 | ||
|
|
72fecb2b9a | ||
|
|
4e9dfe5478 | ||
|
|
c79e2e3ad4 | ||
|
|
7c33c1c322 | ||
|
|
ea32f75925 | ||
|
|
7eaed21b9a | ||
|
|
cfe8fcd28d | ||
|
|
9f4718af70 | ||
|
|
39faccfd0b | ||
|
|
7545763dae | ||
|
|
c2928be35d | ||
|
|
449bb40d48 | ||
|
|
4caf1a1e63 | ||
|
|
01b205e6f1 | ||
|
|
160d3843a6 | ||
|
|
5efb784115 | ||
|
|
acde5b8384 | ||
|
|
373ee6586a | ||
|
|
215308c329 | ||
|
|
478cadba5e | ||
|
|
f4af4da791 | ||
|
|
22d4f435de |
@@ -9,7 +9,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.27.1" />
|
<PackageReference Include="Google.Protobuf" Version="3.27.2" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.63.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.63.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.64.0">
|
<PackageReference Include="Grpc.Tools" Version="2.64.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<Application
|
<Application
|
||||||
x:Class="v2rayN.App"
|
x:Class="v2rayN.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
|
||||||
ShutdownMode="OnExplicitShutdown"
|
ShutdownMode="OnExplicitShutdown"
|
||||||
StartupUri="Views/MainWindow.xaml">
|
StartupUri="Views/MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace v2rayN
|
|||||||
Init();
|
Init();
|
||||||
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
||||||
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||||
|
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
Logging.ClearLogs();
|
Logging.ClearLogs();
|
||||||
|
|
||||||
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
||||||
|
|||||||
@@ -1,10 +1,38 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static v2rayN.Handler.ProxySetting.InternetConnectionOption;
|
using static v2rayN.Common.ProxySetting.InternetConnectionOption;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Common
|
||||||
{
|
{
|
||||||
internal class ProxySetting
|
internal class ProxySetting
|
||||||
{
|
{
|
||||||
|
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
|
||||||
|
|
||||||
|
private static bool SetProxyFallback(string? strProxy, string? exceptions, int type)
|
||||||
|
{
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyEnable", 0);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
|
||||||
|
}
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyEnable", 1);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
|
||||||
|
}
|
||||||
|
else if (type == 4)
|
||||||
|
{
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyEnable", 0);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
|
||||||
|
Utils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
// set to use no proxy
|
// set to use no proxy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -29,15 +57,24 @@ namespace v2rayN.Handler
|
|||||||
/// <returns>true: one of connection is successfully updated proxy settings</returns>
|
/// <returns>true: one of connection is successfully updated proxy settings</returns>
|
||||||
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
||||||
{
|
{
|
||||||
// set proxy for LAN
|
try
|
||||||
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
|
|
||||||
// set proxy for dial up connections
|
|
||||||
var connections = EnumerateRasEntries();
|
|
||||||
foreach (var connection in connections)
|
|
||||||
{
|
{
|
||||||
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
|
// set proxy for LAN
|
||||||
|
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
|
||||||
|
// set proxy for dial up connections
|
||||||
|
var connections = EnumerateRasEntries();
|
||||||
|
foreach (var connection in connections)
|
||||||
|
{
|
||||||
|
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SetProxyFallback(strProxy, exceptions, type);
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
||||||
@@ -94,25 +131,25 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
list.szConnection = IntPtr.Zero;
|
list.szConnection = nint.Zero;
|
||||||
}
|
}
|
||||||
list.dwOptionCount = options.Length;
|
list.dwOptionCount = options.Length;
|
||||||
list.dwOptionError = 0;
|
list.dwOptionError = 0;
|
||||||
|
|
||||||
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
||||||
// make a pointer out of all that ...
|
// make a pointer out of all that ...
|
||||||
IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
nint optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
||||||
// copy the array over into that spot in memory ...
|
// copy the array over into that spot in memory ...
|
||||||
for (int i = 0; i < options.Length; ++i)
|
for (int i = 0; i < options.Length; ++i)
|
||||||
{
|
{
|
||||||
if (Environment.Is64BitOperatingSystem)
|
if (Environment.Is64BitOperatingSystem)
|
||||||
{
|
{
|
||||||
IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
|
nint opt = new(optionsPtr.ToInt64() + i * optSize);
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
|
nint opt = new(optionsPtr.ToInt32() + i * optSize);
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,11 +157,11 @@ namespace v2rayN.Handler
|
|||||||
list.options = optionsPtr;
|
list.options = optionsPtr;
|
||||||
|
|
||||||
// and then make a pointer out of the whole list
|
// and then make a pointer out of the whole list
|
||||||
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
nint ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
||||||
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
||||||
|
|
||||||
// and finally, call the API method!
|
// and finally, call the API method!
|
||||||
bool isSuccess = NativeMethods.InternetSetOption(IntPtr.Zero,
|
bool isSuccess = NativeMethods.InternetSetOption(nint.Zero,
|
||||||
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
||||||
ipcoListPtr, list.dwSize);
|
ipcoListPtr, list.dwSize);
|
||||||
int returnvalue = 0; // ERROR_SUCCESS
|
int returnvalue = 0; // ERROR_SUCCESS
|
||||||
@@ -135,12 +172,12 @@ namespace v2rayN.Handler
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
||||||
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
|
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
|
||||||
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
|
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FREE the data ASAP
|
// FREE the data ASAP
|
||||||
if (list.szConnection != IntPtr.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
if (list.szConnection != nint.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
||||||
@@ -204,12 +241,12 @@ namespace v2rayN.Handler
|
|||||||
public struct InternetPerConnOptionList
|
public struct InternetPerConnOptionList
|
||||||
{
|
{
|
||||||
public int dwSize; // size of the INTERNET_PER_CONN_OPTION_LIST struct
|
public int dwSize; // size of the INTERNET_PER_CONN_OPTION_LIST struct
|
||||||
public IntPtr szConnection; // connection name to set/query options
|
public nint szConnection; // connection name to set/query options
|
||||||
public int dwOptionCount; // number of options to set/query
|
public int dwOptionCount; // number of options to set/query
|
||||||
public int dwOptionError; // on error, which option failed
|
public int dwOptionError; // on error, which option failed
|
||||||
|
|
||||||
//[MarshalAs(UnmanagedType.)]
|
//[MarshalAs(UnmanagedType.)]
|
||||||
public IntPtr options;
|
public nint options;
|
||||||
};
|
};
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
@@ -236,7 +273,7 @@ namespace v2rayN.Handler
|
|||||||
public int m_Int;
|
public int m_Int;
|
||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public IntPtr m_StringPtr;
|
public nint m_StringPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
@@ -308,7 +345,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength);
|
public static extern bool InternetSetOption(nint hInternet, InternetOption dwOption, nint lpBuffer, int dwBufferLength);
|
||||||
|
|
||||||
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
|
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
|
||||||
public static extern uint RasEnumEntries(
|
public static extern uint RasEnumEntries(
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
using System;
|
using YamlDotNet.Serialization;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using YamlDotNet.Serialization;
|
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
namespace v2rayN.Common
|
namespace v2rayN.Common
|
||||||
@@ -60,4 +55,4 @@ namespace v2rayN.Common
|
|||||||
|
|
||||||
#endregion YAML
|
#endregion YAML
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ namespace v2rayN.Converters
|
|||||||
|
|
||||||
if (delay <= 0)
|
if (delay <= 0)
|
||||||
return new SolidColorBrush(Colors.Red);
|
return new SolidColorBrush(Colors.Red);
|
||||||
if (delay <= 200)
|
if (delay <= 500)
|
||||||
return new SolidColorBrush(Colors.Green);
|
return new SolidColorBrush(Colors.Green);
|
||||||
else
|
else
|
||||||
return new SolidColorBrush(Colors.IndianRed);
|
return new SolidColorBrush(Colors.IndianRed);
|
||||||
|
|||||||
9
v2rayN/v2rayN/Enums/EGirdOrientation.cs
Normal file
9
v2rayN/v2rayN/Enums/EGirdOrientation.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace v2rayN.Enums
|
||||||
|
{
|
||||||
|
public enum EGirdOrientation
|
||||||
|
{
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Tab,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,14 +23,15 @@ namespace v2rayN
|
|||||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||||
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
||||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||||
public const string SingboxRulesetUrlGeosite = @"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/{0}.srs";
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||||
public const string SingboxRulesetUrlGeoip = @"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/srs/{0}.srs";
|
|
||||||
|
|
||||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
public const string CoreConfigFileName = "config.json";
|
public const string CoreConfigFileName = "config.json";
|
||||||
public const string CorePreConfigFileName = "configPre.json";
|
public const string CorePreConfigFileName = "configPre.json";
|
||||||
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
||||||
|
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
||||||
|
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
||||||
public const string V2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
public const string V2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
||||||
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
|
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
|
||||||
public const string V2raySampleHttpRequestFileName = "v2rayN.Sample.SampleHttpRequest";
|
public const string V2raySampleHttpRequestFileName = "v2rayN.Sample.SampleHttpRequest";
|
||||||
@@ -44,6 +45,8 @@ namespace v2rayN
|
|||||||
public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
|
public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
|
||||||
public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
|
public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
|
||||||
public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
|
public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
|
||||||
|
public const string ClashMixinYaml = "v2rayN.Sample.clash_mixin_yaml";
|
||||||
|
public const string ClashTunYaml = "v2rayN.Sample.clash_tun_yaml";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
@@ -71,6 +74,7 @@ namespace v2rayN
|
|||||||
public const string CommandClearMsg = "CommandClearMsg";
|
public const string CommandClearMsg = "CommandClearMsg";
|
||||||
public const string CommandSendMsgView = "CommandSendMsgView";
|
public const string CommandSendMsgView = "CommandSendMsgView";
|
||||||
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
|
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
|
||||||
|
public const string CommandRefreshProfiles = "CommandRefreshProfiles";
|
||||||
public const string DelayUnit = "";
|
public const string DelayUnit = "";
|
||||||
public const string SpeedUnit = "";
|
public const string SpeedUnit = "";
|
||||||
public const int MinFontSize = 10;
|
public const int MinFontSize = 10;
|
||||||
@@ -112,6 +116,7 @@ namespace v2rayN
|
|||||||
|
|
||||||
public static readonly List<string> SpeedPingTestUrls = new() {
|
public static readonly List<string> SpeedPingTestUrls = new() {
|
||||||
@"https://www.google.com/generate_204",
|
@"https://www.google.com/generate_204",
|
||||||
|
@"https://www.gstatic.com/generate_204",
|
||||||
@"https://www.apple.com/library/test/success.html",
|
@"https://www.apple.com/library/test/success.html",
|
||||||
@"http://www.msftconnecttest.com/connecttest.txt",
|
@"http://www.msftconnecttest.com/connecttest.txt",
|
||||||
};
|
};
|
||||||
@@ -170,8 +175,11 @@ namespace v2rayN
|
|||||||
|
|
||||||
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
|
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
|
||||||
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
||||||
|
public static readonly List<string> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" };
|
||||||
|
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"];
|
||||||
|
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"];
|
||||||
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
||||||
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2,http/1.1", "h3,h2", "h2,http/1.1", "" };
|
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2,http/1.1", "h2,h3", "h2,http/1.1", "" };
|
||||||
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
||||||
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
||||||
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.IO;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Handler.CoreConfig;
|
||||||
using v2rayN.Handler.Fmt;
|
using v2rayN.Handler.Fmt;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
@@ -196,6 +197,15 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
config.clashUIItem ??= new();
|
config.clashUIItem ??= new();
|
||||||
|
|
||||||
|
if (config.systemProxyItem == null)
|
||||||
|
{
|
||||||
|
config.systemProxyItem = new()
|
||||||
|
{
|
||||||
|
systemProxyExceptions = config.systemProxyExceptions,
|
||||||
|
systemProxyAdvancedProtocol = config.systemProxyAdvancedProtocol,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
LazyConfig.Instance.SetConfig(config);
|
LazyConfig.Instance.SetConfig(config);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1065,6 +1075,33 @@ namespace v2rayN.Handler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int AddCustomServer4Multiple(Config config, List<ProfileItem> selecteds, ECoreType coreType, out string indexId)
|
||||||
|
{
|
||||||
|
indexId = Utils.GetMD5(Global.CoreMultipleLoadConfigFileName);
|
||||||
|
string configPath = Utils.GetConfigPath(Global.CoreMultipleLoadConfigFileName);
|
||||||
|
if (CoreConfigHandler.GenerateClientMultipleLoadConfig(config, configPath, selecteds, coreType, out string msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileName = configPath;
|
||||||
|
if (!File.Exists(fileName))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var profileItem = LazyConfig.Instance.GetProfileItem(indexId) ?? new();
|
||||||
|
profileItem.indexId = indexId;
|
||||||
|
profileItem.remarks = coreType == ECoreType.sing_box ? Resx.ResUI.menuSetDefaultMultipleServer : Resx.ResUI.menuSetDefaultLoadBalanceServer;
|
||||||
|
profileItem.address = Global.CoreMultipleLoadConfigFileName;
|
||||||
|
profileItem.configType = EConfigType.Custom;
|
||||||
|
profileItem.coreType = coreType;
|
||||||
|
|
||||||
|
AddServerCommon(config, profileItem, true);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Server
|
#endregion Server
|
||||||
|
|
||||||
#region Batch add servers
|
#region Batch add servers
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
/// <param name="fileName"></param>
|
/// <param name="fileName"></param>
|
||||||
/// <param name="msg"></param>
|
/// <param name="msg"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public int GenerateClientConfig(ProfileItem node, string? fileName, out string msg)
|
public int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
|
||||||
{
|
{
|
||||||
if (node == null || fileName is null)
|
if (node == null || fileName is null)
|
||||||
{
|
{
|
||||||
@@ -82,7 +82,8 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
//socks-port
|
//socks-port
|
||||||
fileContent["socks-port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
|
fileContent["socks-port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
//log-level
|
//log-level
|
||||||
fileContent["log-level"] = _config.coreBasicItem.loglevel;
|
fileContent["log-level"] = GetLogLevel(_config.coreBasicItem.loglevel);
|
||||||
|
|
||||||
//external-controller
|
//external-controller
|
||||||
fileContent["external-controller"] = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
fileContent["external-controller"] = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
||||||
//allow-lan
|
//allow-lan
|
||||||
@@ -97,7 +98,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
//ipv6
|
//ipv6
|
||||||
//fileContent["ipv6"] = _config.EnableIpv6;
|
fileContent["ipv6"] = _config.clashUIItem.enableIPv6;
|
||||||
|
|
||||||
//mode
|
//mode
|
||||||
if (!fileContent.ContainsKey("mode"))
|
if (!fileContent.ContainsKey("mode"))
|
||||||
@@ -112,27 +113,27 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////enable tun mode
|
//enable tun mode
|
||||||
//if (config.EnableTun)
|
if (_config.tunModeItem.enableTun)
|
||||||
//{
|
{
|
||||||
// string tun = Utils.GetEmbedText(Global.SampleTun);
|
string tun = Utils.GetEmbedText(Global.ClashTunYaml);
|
||||||
// if (!string.IsNullOrEmpty(tun))
|
if (!string.IsNullOrEmpty(tun))
|
||||||
// {
|
{
|
||||||
// var tunContent = Utils.FromYaml<Dictionary<string, object>>(tun);
|
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
||||||
// if (tunContent != null)
|
if (tunContent != null)
|
||||||
// fileContent["tun"] = tunContent["tun"];
|
fileContent["tun"] = tunContent["tun"];
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
//Mixin
|
//Mixin
|
||||||
//try
|
try
|
||||||
//{
|
{
|
||||||
// MixinContent(fileContent, config, node);
|
MixinContent(fileContent, node);
|
||||||
//}
|
}
|
||||||
//catch (Exception ex)
|
catch (Exception ex)
|
||||||
//{
|
{
|
||||||
// Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
|
Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
|
||||||
//}
|
}
|
||||||
|
|
||||||
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
||||||
File.WriteAllText(fileName, txtFileNew);
|
File.WriteAllText(fileName, txtFileNew);
|
||||||
@@ -156,49 +157,48 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//private static void MixinContent(Dictionary<string, object> fileContent, Config config, ProfileItem node)
|
private void MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
|
||||||
//{
|
{
|
||||||
// if (!config.EnableMixinContent)
|
//if (!_config.clashUIItem.enableMixinContent)
|
||||||
// {
|
//{
|
||||||
// return;
|
// return;
|
||||||
// }
|
//}
|
||||||
|
|
||||||
// var path = Utils.GetConfigPath(Global.mixinConfigFileName);
|
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
|
||||||
// if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
// {
|
{
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.mixinConfigFileName));
|
var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
||||||
// //txtFile = txtFile.Replace("!<str>", "");
|
|
||||||
|
|
||||||
// var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
// if (mixinContent == null)
|
if (mixinContent == null)
|
||||||
// {
|
{
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// foreach (var item in mixinContent)
|
foreach (var item in mixinContent)
|
||||||
// {
|
{
|
||||||
// if (!config.EnableTun && item.Key == "tun")
|
if (!_config.tunModeItem.enableTun && item.Key == "tun")
|
||||||
// {
|
{
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (item.Key.StartsWith("prepend-")
|
if (item.Key.StartsWith("prepend-")
|
||||||
// || item.Key.StartsWith("append-")
|
|| item.Key.StartsWith("append-")
|
||||||
// || item.Key.StartsWith("removed-"))
|
|| item.Key.StartsWith("removed-"))
|
||||||
// {
|
{
|
||||||
// ModifyContentMerge(fileContent, item.Key, item.Value);
|
ModifyContentMerge(fileContent, item.Key, item.Value);
|
||||||
// }
|
}
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// fileContent[item.Key] = item.Value;
|
fileContent[item.Key] = item.Value;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// return;
|
return;
|
||||||
//}
|
}
|
||||||
|
|
||||||
private static void ModifyContentMerge(Dictionary<string, object> fileContent, string key, object value)
|
private void ModifyContentMerge(Dictionary<string, object> fileContent, string key, object value)
|
||||||
{
|
{
|
||||||
bool blPrepend = false;
|
bool blPrepend = false;
|
||||||
bool blRemoved = false;
|
bool blRemoved = false;
|
||||||
@@ -255,5 +255,17 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetLogLevel(string level)
|
||||||
|
{
|
||||||
|
if (level == "none")
|
||||||
|
{
|
||||||
|
return "silent";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,12 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
if (node.coreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
if (node.coreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
||||||
{
|
{
|
||||||
var configGenClash = new CoreConfigClash(config);
|
var configGenClash = new CoreConfigClash(config);
|
||||||
return configGenClash.GenerateClientConfig(node, fileName, out msg);
|
return configGenClash.GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
|
if (node.coreType is ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
var configGenSingbox = new CoreConfigSingbox(config);
|
||||||
|
return configGenSingbox.GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -113,41 +118,6 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//overwrite port
|
|
||||||
if (node.preSocksPort <= 0)
|
|
||||||
{
|
|
||||||
var fileContent = File.ReadAllLines(fileName).ToList();
|
|
||||||
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
|
||||||
switch (coreType)
|
|
||||||
{
|
|
||||||
case ECoreType.v2fly:
|
|
||||||
case ECoreType.SagerNet:
|
|
||||||
case ECoreType.Xray:
|
|
||||||
case ECoreType.v2fly_v5:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ECoreType.clash:
|
|
||||||
case ECoreType.clash_meta:
|
|
||||||
case ECoreType.mihomo:
|
|
||||||
//remove the original
|
|
||||||
var indexPort = fileContent.FindIndex(t => t.Contains("port:"));
|
|
||||||
if (indexPort >= 0)
|
|
||||||
{
|
|
||||||
fileContent.RemoveAt(indexPort);
|
|
||||||
}
|
|
||||||
indexPort = fileContent.FindIndex(t => t.Contains("socks-port:"));
|
|
||||||
if (indexPort >= 0)
|
|
||||||
{
|
|
||||||
fileContent.RemoveAt(indexPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileContent.Add($"port: {LazyConfig.Instance.GetLocalPort(EInboundProtocol.http)}");
|
|
||||||
fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
File.WriteAllLines(fileName, fileContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -179,5 +149,28 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
if (coreType == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
if (new CoreConfigSingbox(config).GenerateClientMultipleLoadConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
|
}
|
||||||
|
else if (coreType == ECoreType.Xray)
|
||||||
|
{
|
||||||
|
if (new CoreConfigV2ray(config).GenerateClientMultipleLoadConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
@@ -16,6 +17,8 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region public gen function
|
||||||
|
|
||||||
public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg)
|
public int GenerateClientConfigContent(ProfileItem node, out SingboxConfig? singboxConfig, out string msg)
|
||||||
{
|
{
|
||||||
singboxConfig = null;
|
singboxConfig = null;
|
||||||
@@ -76,6 +79,347 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
|
||||||
|
{
|
||||||
|
singboxConfig = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
|
||||||
|
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
|
||||||
|
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
|
||||||
|
if (singboxConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
List<IPEndPoint> lstIpEndPoints = new();
|
||||||
|
List<TcpConnectionInformation> lstTcpConns = new();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||||
|
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenLog(singboxConfig);
|
||||||
|
//GenDns(new(), singboxConfig);
|
||||||
|
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
|
||||||
|
singboxConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
|
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||||
|
|
||||||
|
foreach (var it in selecteds)
|
||||||
|
{
|
||||||
|
if (it.configType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.port <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
||||||
|
{
|
||||||
|
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//find unused port
|
||||||
|
var port = httpPort;
|
||||||
|
for (int k = httpPort; k < Global.MaxPort; k++)
|
||||||
|
{
|
||||||
|
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//found
|
||||||
|
port = k;
|
||||||
|
httpPort = port + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Port In Used
|
||||||
|
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it.port = port;
|
||||||
|
it.allowTest = true;
|
||||||
|
|
||||||
|
//inbound
|
||||||
|
Inbound4Sbox inbound = new()
|
||||||
|
{
|
||||||
|
listen = Global.Loopback,
|
||||||
|
listen_port = port,
|
||||||
|
type = EInboundProtocol.http.ToString(),
|
||||||
|
};
|
||||||
|
inbound.tag = inbound.type + inbound.listen_port.ToString();
|
||||||
|
singboxConfig.inbounds.Add(inbound);
|
||||||
|
|
||||||
|
//outbound
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.Shadowsocks
|
||||||
|
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.VLESS
|
||||||
|
&& !Global.Flows.Contains(item.flow))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
|
GenOutbound(item, outbound);
|
||||||
|
outbound.tag = Global.ProxyTag + inbound.listen_port.ToString();
|
||||||
|
singboxConfig.outbounds.Add(outbound);
|
||||||
|
|
||||||
|
//rule
|
||||||
|
Rule4Sbox rule = new()
|
||||||
|
{
|
||||||
|
inbound = new List<string> { inbound.tag },
|
||||||
|
outbound = outbound.tag
|
||||||
|
};
|
||||||
|
singboxConfig.route.rules.Add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenDnsDomains(null, singboxConfig, null);
|
||||||
|
//var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
|
||||||
|
//if (dnsServer != null)
|
||||||
|
//{
|
||||||
|
// dnsServer.detour = singboxConfig.route.rules.LastOrDefault()?.outbound;
|
||||||
|
//}
|
||||||
|
//var dnsRule = singboxConfig.dns?.rules.Where(t => t.outbound != null).FirstOrDefault();
|
||||||
|
//if (dnsRule != null)
|
||||||
|
//{
|
||||||
|
// singboxConfig.dns.rules = [];
|
||||||
|
// singboxConfig.dns.rules.Add(dnsRule);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
|
||||||
|
{
|
||||||
|
singboxConfig = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
|
||||||
|
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
|
||||||
|
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
|
||||||
|
if (singboxConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenLog(singboxConfig);
|
||||||
|
GenInbounds(singboxConfig);
|
||||||
|
GenRouting(singboxConfig);
|
||||||
|
GenExperimental(singboxConfig);
|
||||||
|
singboxConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
|
var tagProxy = new List<string>();
|
||||||
|
foreach (var it in selecteds)
|
||||||
|
{
|
||||||
|
if (it.configType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.port <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(item.id) || !Utils.IsGuidByParse(item.id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.Shadowsocks
|
||||||
|
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.VLESS && !Global.Flows.Contains(item.flow))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//outbound
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
|
GenOutbound(item, outbound);
|
||||||
|
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||||
|
singboxConfig.outbounds.Add(outbound);
|
||||||
|
tagProxy.Add(outbound.tag);
|
||||||
|
}
|
||||||
|
if (tagProxy.Count <= 0)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenDns(null, singboxConfig);
|
||||||
|
ConvertGeo2Ruleset(singboxConfig);
|
||||||
|
|
||||||
|
//add urltest outbound
|
||||||
|
var outUrltest = new Outbound4Sbox
|
||||||
|
{
|
||||||
|
type = "urltest",
|
||||||
|
tag = $"{Global.ProxyTag}-auto",
|
||||||
|
outbounds = tagProxy,
|
||||||
|
interrupt_exist_connections = false,
|
||||||
|
};
|
||||||
|
singboxConfig.outbounds.Add(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.Add(outSelector);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
|
||||||
|
{
|
||||||
|
if (node == null || fileName is null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string addressFileName = node.address;
|
||||||
|
if (string.IsNullOrEmpty(addressFileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!File.Exists(addressFileName))
|
||||||
|
{
|
||||||
|
addressFileName = Path.Combine(Utils.GetConfigPath(), addressFileName);
|
||||||
|
}
|
||||||
|
if (!File.Exists(addressFileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration + "1";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFile = File.ReadAllText(addressFileName);
|
||||||
|
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(txtFile);
|
||||||
|
if (singboxConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenExperimental(singboxConfig);
|
||||||
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
|
|
||||||
|
//check again
|
||||||
|
if (!File.Exists(fileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration + "2";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = string.Format(ResUI.SuccessfulConfiguration, $"{node.GetSummary()}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion public gen function
|
||||||
|
|
||||||
#region private gen function
|
#region private gen function
|
||||||
|
|
||||||
private int GenLog(SingboxConfig singboxConfig)
|
private int GenLog(SingboxConfig singboxConfig)
|
||||||
@@ -559,6 +903,17 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
singboxConfig.route.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
outbound = Global.DirectTag,
|
||||||
|
clash_mode = ERuleMode.Direct.ToString()
|
||||||
|
});
|
||||||
|
singboxConfig.route.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
outbound = Global.ProxyTag,
|
||||||
|
clash_mode = ERuleMode.Global.ToString()
|
||||||
|
});
|
||||||
|
|
||||||
if (_config.tunModeItem.enableTun)
|
if (_config.tunModeItem.enableTun)
|
||||||
{
|
{
|
||||||
singboxConfig.route.auto_detect_interface = true;
|
singboxConfig.route.auto_detect_interface = true;
|
||||||
@@ -803,7 +1158,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GenDns(ProfileItem node, SingboxConfig singboxConfig)
|
private int GenDns(ProfileItem? node, SingboxConfig singboxConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -825,7 +1180,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
singboxConfig.dns = dns4Sbox;
|
singboxConfig.dns = dns4Sbox;
|
||||||
|
|
||||||
GenDnsDomains(node, singboxConfig);
|
GenDnsDomains(node, singboxConfig, item);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -834,7 +1189,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig)
|
private int GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
|
||||||
{
|
{
|
||||||
var dns4Sbox = singboxConfig.dns ?? new();
|
var dns4Sbox = singboxConfig.dns ?? new();
|
||||||
dns4Sbox.servers ??= [];
|
dns4Sbox.servers ??= [];
|
||||||
@@ -844,14 +1199,25 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
dns4Sbox.servers.Add(new()
|
dns4Sbox.servers.Add(new()
|
||||||
{
|
{
|
||||||
tag = tag,
|
tag = tag,
|
||||||
address = "223.5.5.5",
|
address = Utils.IsNullOrEmpty(dNSItem?.domainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.domainDNSAddress,
|
||||||
detour = Global.DirectTag,
|
detour = Global.DirectTag,
|
||||||
//strategy = strategy
|
strategy = Utils.IsNullOrEmpty(dNSItem?.domainStrategy4Freedom) ? null : dNSItem?.domainStrategy4Freedom,
|
||||||
|
});
|
||||||
|
dns4Sbox.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
server = tag,
|
||||||
|
clash_mode = ERuleMode.Direct.ToString()
|
||||||
|
});
|
||||||
|
dns4Sbox.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote",
|
||||||
|
clash_mode = ERuleMode.Global.ToString()
|
||||||
});
|
});
|
||||||
|
|
||||||
var lstDomain = singboxConfig.outbounds
|
var lstDomain = singboxConfig.outbounds
|
||||||
.Where(t => !Utils.IsNullOrEmpty(t.server) && Utils.IsDomain(t.server))
|
.Where(t => !Utils.IsNullOrEmpty(t.server) && Utils.IsDomain(t.server))
|
||||||
.Select(t => t.server)
|
.Select(t => t.server)
|
||||||
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
if (lstDomain != null && lstDomain.Count > 0)
|
if (lstDomain != null && lstDomain.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -966,195 +1332,46 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Local srs files address
|
||||||
|
var localSrss = Utils.GetBinPath("srss");
|
||||||
|
|
||||||
//Add ruleset srs
|
//Add ruleset srs
|
||||||
singboxConfig.route.rule_set = [];
|
singboxConfig.route.rule_set = [];
|
||||||
foreach (var item in new HashSet<string>(ruleSets))
|
foreach (var item in new HashSet<string>(ruleSets))
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(item)) { continue; }
|
if (Utils.IsNullOrEmpty(item)) { continue; }
|
||||||
var customRuleset = customRulesets.FirstOrDefault(t => t.tag != null && t.tag.Equals(item));
|
var customRuleset = customRulesets.FirstOrDefault(t => t.tag != null && t.tag.Equals(item));
|
||||||
if (customRuleset != null)
|
if (customRuleset is null)
|
||||||
{
|
{
|
||||||
singboxConfig.route.rule_set.Add(customRuleset);
|
var pathSrs = Path.Combine(localSrss, $"{item}.srs");
|
||||||
}
|
if (File.Exists(pathSrs))
|
||||||
else
|
|
||||||
{
|
|
||||||
singboxConfig.route.rule_set.Add(new()
|
|
||||||
{
|
{
|
||||||
type = "remote",
|
customRuleset = new()
|
||||||
format = "binary",
|
{
|
||||||
tag = item,
|
type = "local",
|
||||||
url = item.StartsWith(geosite) ?
|
format = "binary",
|
||||||
string.Format(Global.SingboxRulesetUrlGeosite, item) :
|
tag = item,
|
||||||
string.Format(Global.SingboxRulesetUrlGeoip, item.Replace($"{geoip}-", "")),
|
path = pathSrs
|
||||||
download_detour = Global.ProxyTag
|
};
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
customRuleset = new()
|
||||||
|
{
|
||||||
|
type = "remote",
|
||||||
|
format = "binary",
|
||||||
|
tag = item,
|
||||||
|
url = string.Format(Global.SingboxRulesetUrl, item.StartsWith(geosite) ? geosite : geoip, item),
|
||||||
|
download_detour = Global.ProxyTag
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
singboxConfig.route.rule_set.Add(customRuleset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion private gen function
|
#endregion private gen function
|
||||||
|
|
||||||
#region Gen speedtest config
|
|
||||||
|
|
||||||
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
|
|
||||||
{
|
|
||||||
singboxConfig = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_config == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.CheckServerSettings;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = ResUI.InitialConfiguration;
|
|
||||||
|
|
||||||
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
|
|
||||||
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
|
|
||||||
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGetDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
|
|
||||||
if (singboxConfig == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
List<IPEndPoint> lstIpEndPoints = new();
|
|
||||||
List<TcpConnectionInformation> lstTcpConns = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
|
||||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
|
||||||
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
GenLog(singboxConfig);
|
|
||||||
//GenDns(new(), singboxConfig);
|
|
||||||
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
|
|
||||||
singboxConfig.outbounds.RemoveAt(0);
|
|
||||||
|
|
||||||
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
|
||||||
|
|
||||||
foreach (var it in selecteds)
|
|
||||||
{
|
|
||||||
if (it.configType == EConfigType.Custom)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.port <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
|
||||||
{
|
|
||||||
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
|
|
||||||
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//find unused port
|
|
||||||
var port = httpPort;
|
|
||||||
for (int k = httpPort; k < Global.MaxPort; k++)
|
|
||||||
{
|
|
||||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//found
|
|
||||||
port = k;
|
|
||||||
httpPort = port + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port In Used
|
|
||||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
it.port = port;
|
|
||||||
it.allowTest = true;
|
|
||||||
|
|
||||||
//inbound
|
|
||||||
Inbound4Sbox inbound = new()
|
|
||||||
{
|
|
||||||
listen = Global.Loopback,
|
|
||||||
listen_port = port,
|
|
||||||
type = EInboundProtocol.http.ToString(),
|
|
||||||
};
|
|
||||||
inbound.tag = inbound.type + inbound.listen_port.ToString();
|
|
||||||
singboxConfig.inbounds.Add(inbound);
|
|
||||||
|
|
||||||
//outbound
|
|
||||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
|
||||||
if (item is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.configType == EConfigType.Shadowsocks
|
|
||||||
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.configType == EConfigType.VLESS
|
|
||||||
&& !Global.Flows.Contains(item.flow))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
|
||||||
GenOutbound(item, outbound);
|
|
||||||
outbound.tag = Global.ProxyTag + inbound.listen_port.ToString();
|
|
||||||
singboxConfig.outbounds.Add(outbound);
|
|
||||||
|
|
||||||
//rule
|
|
||||||
Rule4Sbox rule = new()
|
|
||||||
{
|
|
||||||
inbound = new List<string> { inbound.tag },
|
|
||||||
outbound = outbound.tag
|
|
||||||
};
|
|
||||||
singboxConfig.route.rules.Add(rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
GenDnsDomains(null, singboxConfig);
|
|
||||||
//var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
|
|
||||||
//if (dnsServer != null)
|
|
||||||
//{
|
|
||||||
// dnsServer.detour = singboxConfig.route.rules.LastOrDefault()?.outbound;
|
|
||||||
//}
|
|
||||||
//var dnsRule = singboxConfig.dns?.rules.Where(t => t.outbound != null).FirstOrDefault();
|
|
||||||
//if (dnsRule != null)
|
|
||||||
//{
|
|
||||||
// singboxConfig.dns.rules = [];
|
|
||||||
// singboxConfig.dns.rules.Add(dnsRule);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Gen speedtest config
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,8 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region public gen function
|
||||||
|
|
||||||
public int GenerateClientConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg)
|
public int GenerateClientConfigContent(ProfileItem node, out V2rayConfig? v2rayConfig, out string msg)
|
||||||
{
|
{
|
||||||
v2rayConfig = null;
|
v2rayConfig = null;
|
||||||
@@ -69,6 +71,276 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds, out V2rayConfig? v2rayConfig, out string msg)
|
||||||
|
{
|
||||||
|
v2rayConfig = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
string result = Utils.GetEmbedText(Global.V2raySampleClient);
|
||||||
|
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
|
||||||
|
if (v2rayConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenLog(v2rayConfig);
|
||||||
|
GenInbounds(v2rayConfig);
|
||||||
|
GenRouting(v2rayConfig);
|
||||||
|
GenDns(null, v2rayConfig);
|
||||||
|
GenStatistic(v2rayConfig);
|
||||||
|
v2rayConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
|
var tagProxy = new List<string>();
|
||||||
|
foreach (var it in selecteds)
|
||||||
|
{
|
||||||
|
if (it.configType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.configType is EConfigType.Hysteria2 or EConfigType.Tuic or EConfigType.Wireguard)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.port <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(item.id) || !Utils.IsGuidByParse(item.id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.Shadowsocks
|
||||||
|
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.VLESS && !Global.Flows.Contains(item.flow))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//outbound
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
GenOutbound(item, outbound);
|
||||||
|
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||||
|
v2rayConfig.outbounds.Add(outbound);
|
||||||
|
tagProxy.Add(outbound.tag);
|
||||||
|
}
|
||||||
|
if (tagProxy.Count <= 0)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//add balancers
|
||||||
|
var balancer = new BalancersItem4Ray
|
||||||
|
{
|
||||||
|
selector = [Global.ProxyTag],
|
||||||
|
strategy = new() { type = "roundRobin" },
|
||||||
|
tag = $"{Global.ProxyTag}-round",
|
||||||
|
};
|
||||||
|
v2rayConfig.routing.balancers = [balancer];
|
||||||
|
|
||||||
|
//add rule
|
||||||
|
var rules = v2rayConfig.routing.rules.Where(t => t.outboundTag == Global.ProxyTag).ToList();
|
||||||
|
if (rules?.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var rule in rules)
|
||||||
|
{
|
||||||
|
rule.outboundTag = null;
|
||||||
|
rule.balancerTag = balancer.tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v2rayConfig.routing.rules.Add(new()
|
||||||
|
{
|
||||||
|
network = "tcp,udp",
|
||||||
|
balancerTag = balancer.tag,
|
||||||
|
type = "field"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out V2rayConfig? v2rayConfig, out string msg)
|
||||||
|
{
|
||||||
|
v2rayConfig = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
string result = Utils.GetEmbedText(Global.V2raySampleClient);
|
||||||
|
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
|
||||||
|
if (v2rayConfig == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
List<IPEndPoint> lstIpEndPoints = new();
|
||||||
|
List<TcpConnectionInformation> lstTcpConns = new();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||||
|
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenLog(v2rayConfig);
|
||||||
|
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
|
||||||
|
v2rayConfig.outbounds.RemoveAt(0);
|
||||||
|
|
||||||
|
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||||
|
|
||||||
|
foreach (var it in selecteds)
|
||||||
|
{
|
||||||
|
if (it.configType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.port <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
||||||
|
{
|
||||||
|
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//find unused port
|
||||||
|
var port = httpPort;
|
||||||
|
for (int k = httpPort; k < Global.MaxPort; k++)
|
||||||
|
{
|
||||||
|
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//found
|
||||||
|
port = k;
|
||||||
|
httpPort = port + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Port In Used
|
||||||
|
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it.port = port;
|
||||||
|
it.allowTest = true;
|
||||||
|
|
||||||
|
//inbound
|
||||||
|
Inbounds4Ray inbound = new()
|
||||||
|
{
|
||||||
|
listen = Global.Loopback,
|
||||||
|
port = port,
|
||||||
|
protocol = EInboundProtocol.http.ToString(),
|
||||||
|
};
|
||||||
|
inbound.tag = inbound.protocol + inbound.port.ToString();
|
||||||
|
v2rayConfig.inbounds.Add(inbound);
|
||||||
|
|
||||||
|
//outbound
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.Shadowsocks
|
||||||
|
&& !Global.SsSecuritiesInXray.Contains(item.security))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (item.configType == EConfigType.VLESS
|
||||||
|
&& !Global.Flows.Contains(item.flow))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
GenOutbound(item, outbound);
|
||||||
|
outbound.tag = Global.ProxyTag + inbound.port.ToString();
|
||||||
|
v2rayConfig.outbounds.Add(outbound);
|
||||||
|
|
||||||
|
//rule
|
||||||
|
RulesItem4Ray rule = new()
|
||||||
|
{
|
||||||
|
inboundTag = new List<string> { inbound.tag },
|
||||||
|
outboundTag = outbound.tag,
|
||||||
|
type = "field"
|
||||||
|
};
|
||||||
|
v2rayConfig.routing.rules.Add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion public gen function
|
||||||
|
|
||||||
#region private gen function
|
#region private gen function
|
||||||
|
|
||||||
private int GenLog(V2rayConfig v2rayConfig)
|
private int GenLog(V2rayConfig v2rayConfig)
|
||||||
@@ -749,7 +1021,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GenDns(ProfileItem node, V2rayConfig v2rayConfig)
|
private int GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -801,7 +1073,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GenDnsDomains(node, obj);
|
GenDnsDomains(node, obj, item);
|
||||||
|
|
||||||
v2rayConfig.dns = obj;
|
v2rayConfig.dns = obj;
|
||||||
}
|
}
|
||||||
@@ -812,8 +1084,10 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GenDnsDomains(ProfileItem node, JsonNode dns)
|
private int GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
|
||||||
{
|
{
|
||||||
|
if (node == null)
|
||||||
|
{ return 0; }
|
||||||
var servers = dns["servers"];
|
var servers = dns["servers"];
|
||||||
if (servers != null)
|
if (servers != null)
|
||||||
{
|
{
|
||||||
@@ -821,7 +1095,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
{
|
{
|
||||||
var dnsServer = new DnsServer4Ray()
|
var dnsServer = new DnsServer4Ray()
|
||||||
{
|
{
|
||||||
address = "223.5.5.5",
|
address = Utils.IsNullOrEmpty(dNSItem?.domainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.domainDNSAddress,
|
||||||
domains = [node.address]
|
domains = [node.address]
|
||||||
};
|
};
|
||||||
servers.AsArray().Insert(0, JsonUtils.SerializeToNode(dnsServer));
|
servers.AsArray().Insert(0, JsonUtils.SerializeToNode(dnsServer));
|
||||||
@@ -973,153 +1247,5 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion private gen function
|
#endregion private gen function
|
||||||
|
|
||||||
#region Gen speedtest config
|
|
||||||
|
|
||||||
public int GenerateClientSpeedtestConfig(List<ServerTestItem> selecteds, out V2rayConfig? v2rayConfig, out string msg)
|
|
||||||
{
|
|
||||||
v2rayConfig = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_config == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.CheckServerSettings;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = ResUI.InitialConfiguration;
|
|
||||||
|
|
||||||
string result = Utils.GetEmbedText(Global.V2raySampleClient);
|
|
||||||
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
|
|
||||||
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGetDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
|
|
||||||
if (v2rayConfig == null)
|
|
||||||
{
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
List<IPEndPoint> lstIpEndPoints = new();
|
|
||||||
List<TcpConnectionInformation> lstTcpConns = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
|
||||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
|
||||||
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
GenLog(v2rayConfig);
|
|
||||||
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
|
|
||||||
v2rayConfig.outbounds.RemoveAt(0);
|
|
||||||
|
|
||||||
int httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
|
||||||
|
|
||||||
foreach (var it in selecteds)
|
|
||||||
{
|
|
||||||
if (it.configType == EConfigType.Custom)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.port <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
|
||||||
{
|
|
||||||
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
|
|
||||||
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//find unused port
|
|
||||||
var port = httpPort;
|
|
||||||
for (int k = httpPort; k < Global.MaxPort; k++)
|
|
||||||
{
|
|
||||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//found
|
|
||||||
port = k;
|
|
||||||
httpPort = port + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port In Used
|
|
||||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
it.port = port;
|
|
||||||
it.allowTest = true;
|
|
||||||
|
|
||||||
//inbound
|
|
||||||
Inbounds4Ray inbound = new()
|
|
||||||
{
|
|
||||||
listen = Global.Loopback,
|
|
||||||
port = port,
|
|
||||||
protocol = EInboundProtocol.http.ToString(),
|
|
||||||
};
|
|
||||||
inbound.tag = inbound.protocol + inbound.port.ToString();
|
|
||||||
v2rayConfig.inbounds.Add(inbound);
|
|
||||||
|
|
||||||
//outbound
|
|
||||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
|
||||||
if (item is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.configType == EConfigType.Shadowsocks
|
|
||||||
&& !Global.SsSecuritiesInXray.Contains(item.security))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.configType == EConfigType.VLESS
|
|
||||||
&& !Global.Flows.Contains(item.flow))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
|
||||||
GenOutbound(item, outbound);
|
|
||||||
outbound.tag = Global.ProxyTag + inbound.port.ToString();
|
|
||||||
v2rayConfig.outbounds.Add(outbound);
|
|
||||||
|
|
||||||
//rule
|
|
||||||
RulesItem4Ray rule = new()
|
|
||||||
{
|
|
||||||
inboundTag = new List<string> { inbound.tag },
|
|
||||||
outboundTag = outbound.tag,
|
|
||||||
type = "field"
|
|
||||||
};
|
|
||||||
v2rayConfig.routing.rules.Add(rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
//msg = string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Gen speedtest config
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,9 +27,8 @@ namespace v2rayN.Handler
|
|||||||
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCore()
|
public void LoadCore(ProfileItem? node)
|
||||||
{
|
{
|
||||||
var node = ConfigHandler.GetDefaultServer(_config);
|
|
||||||
if (node == null)
|
if (node == null)
|
||||||
{
|
{
|
||||||
ShowMsg(false, ResUI.CheckServerSettings);
|
ShowMsg(false, ResUI.CheckServerSettings);
|
||||||
|
|||||||
@@ -286,8 +286,6 @@ namespace v2rayN.Handler
|
|||||||
int responseTime = -1;
|
int responseTime = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Stopwatch timer = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
|
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
|
||||||
using var client = new HttpClient(new SocketsHttpHandler()
|
using var client = new HttpClient(new SocketsHttpHandler()
|
||||||
@@ -295,9 +293,17 @@ namespace v2rayN.Handler
|
|||||||
Proxy = webProxy,
|
Proxy = webProxy,
|
||||||
UseProxy = webProxy != null
|
UseProxy = webProxy != null
|
||||||
});
|
});
|
||||||
await client.GetAsync(url, cts.Token);
|
|
||||||
|
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
List<int> oneTime = [];
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
var timer = Stopwatch.StartNew();
|
||||||
|
await client.GetAsync(url, cts.Token);
|
||||||
|
timer.Stop();
|
||||||
|
oneTime.Add((int)timer.Elapsed.TotalMilliseconds);
|
||||||
|
await Task.Delay(100);
|
||||||
|
}
|
||||||
|
responseTime = oneTime.Where(x => x > 0).OrderBy(x => x).FirstOrDefault();
|
||||||
}
|
}
|
||||||
catch //(Exception ex)
|
catch //(Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ namespace v2rayN.Handler.Fmt
|
|||||||
{
|
{
|
||||||
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
||||||
}
|
}
|
||||||
|
if (item.allowInsecure.Equals("true"))
|
||||||
|
{
|
||||||
|
dicQuery.Add("allowInsecure", "1");
|
||||||
|
}
|
||||||
|
|
||||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||||
|
|
||||||
@@ -137,6 +141,7 @@ namespace v2rayN.Handler.Fmt
|
|||||||
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
||||||
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||||
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||||
|
item.allowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
||||||
|
|
||||||
item.network = query["type"] ?? nameof(ETransport.tcp);
|
item.network = query["type"] ?? nameof(ETransport.tcp);
|
||||||
switch (item.network)
|
switch (item.network)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Text.RegularExpressions;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Enums;
|
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
@@ -7,17 +6,13 @@ namespace v2rayN.Handler.Fmt
|
|||||||
{
|
{
|
||||||
internal class VmessFmt : BaseFmt
|
internal class VmessFmt : BaseFmt
|
||||||
{
|
{
|
||||||
private static readonly Regex StdVmessUserInfo = new(
|
|
||||||
@"^(?<network>[a-z]+)(\+(?<streamSecurity>[a-z]+))?:(?<id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
public static ProfileItem? Resolve(string str, out string msg)
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
ProfileItem? item;
|
ProfileItem? item;
|
||||||
int indexSplit = str.IndexOf("?");
|
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
||||||
if (indexSplit > 0)
|
|
||||||
{
|
{
|
||||||
item = ResolveStdVmess(str) ?? ResolveVmess4Kitsunebi(str);
|
item = ResolveStdVmess(str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -107,7 +102,7 @@ namespace v2rayN.Handler.Fmt
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProfileItem? ResolveStdVmess(string result)
|
public static ProfileItem? ResolveStdVmess(string str)
|
||||||
{
|
{
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
@@ -115,113 +110,15 @@ namespace v2rayN.Handler.Fmt
|
|||||||
security = "auto"
|
security = "auto"
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri u = new(result);
|
Uri url = new(str);
|
||||||
|
|
||||||
item.address = u.IdnHost;
|
item.address = url.IdnHost;
|
||||||
item.port = u.Port;
|
item.port = url.Port;
|
||||||
item.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
var query = Utils.ParseQueryString(u.Query);
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var m = StdVmessUserInfo.Match(u.UserInfo);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
if (!m.Success) return null;
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
item.id = m.Groups["id"].Value;
|
|
||||||
|
|
||||||
if (m.Groups["streamSecurity"].Success)
|
|
||||||
{
|
|
||||||
item.streamSecurity = m.Groups["streamSecurity"].Value;
|
|
||||||
}
|
|
||||||
switch (item.streamSecurity)
|
|
||||||
{
|
|
||||||
case Global.StreamSecurity:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
|
||||||
return null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.network = m.Groups["network"].Value;
|
|
||||||
switch (item.network)
|
|
||||||
{
|
|
||||||
case nameof(ETransport.tcp):
|
|
||||||
string t1 = query["type"] ?? Global.None;
|
|
||||||
item.headerType = t1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.kcp):
|
|
||||||
item.headerType = query["type"] ?? Global.None;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.ws):
|
|
||||||
case nameof(ETransport.httpupgrade):
|
|
||||||
case nameof(ETransport.splithttp):
|
|
||||||
string p1 = query["path"] ?? "/";
|
|
||||||
string h1 = query["host"] ?? "";
|
|
||||||
item.requestHost = Utils.UrlDecode(h1);
|
|
||||||
item.path = p1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.http):
|
|
||||||
case nameof(ETransport.h2):
|
|
||||||
item.network = nameof(ETransport.h2);
|
|
||||||
string p2 = query["path"] ?? "/";
|
|
||||||
string h2 = query["host"] ?? "";
|
|
||||||
item.requestHost = Utils.UrlDecode(h2);
|
|
||||||
item.path = p2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.quic):
|
|
||||||
string s = query["security"] ?? Global.None;
|
|
||||||
string k = query["key"] ?? "";
|
|
||||||
string t3 = query["type"] ?? Global.None;
|
|
||||||
item.headerType = t3;
|
|
||||||
item.requestHost = Utils.UrlDecode(s);
|
|
||||||
item.path = k;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveVmess4Kitsunebi(string result)
|
|
||||||
{
|
|
||||||
ProfileItem item = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.VMess
|
|
||||||
};
|
|
||||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
|
||||||
int indexSplit = result.IndexOf("?");
|
|
||||||
if (indexSplit > 0)
|
|
||||||
{
|
|
||||||
result = result[..indexSplit];
|
|
||||||
}
|
|
||||||
result = Utils.Base64Decode(result);
|
|
||||||
|
|
||||||
string[] arr1 = result.Split('@');
|
|
||||||
if (arr1.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
string[] arr21 = arr1[0].Split(':');
|
|
||||||
string[] arr22 = arr1[1].Split(':');
|
|
||||||
if (arr21.Length != 2 || arr22.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.address = arr22[0];
|
|
||||||
item.port = Utils.ToInt(arr22[1]);
|
|
||||||
item.security = arr21[0];
|
|
||||||
item.id = arr21[1];
|
|
||||||
|
|
||||||
item.network = Global.DefaultNetwork;
|
|
||||||
item.headerType = Global.None;
|
|
||||||
item.remarks = "Alien";
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
using Splat;
|
using Splat;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Handler.CoreConfig;
|
using v2rayN.Handler.CoreConfig;
|
||||||
@@ -19,7 +22,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int index = (int)config.sysProxyType;
|
int index = (int)config.systemProxyItem.sysProxyType;
|
||||||
|
|
||||||
//Load from routing setting
|
//Load from routing setting
|
||||||
var createdIcon = GetNotifyIcon4Routing(config);
|
var createdIcon = GetNotifyIcon4Routing(config);
|
||||||
@@ -53,7 +56,7 @@ namespace v2rayN.Handler
|
|||||||
public System.Windows.Media.ImageSource GetAppIcon(Config config)
|
public System.Windows.Media.ImageSource GetAppIcon(Config config)
|
||||||
{
|
{
|
||||||
int index = 1;
|
int index = 1;
|
||||||
switch (config.sysProxyType)
|
switch (config.systemProxyItem.sysProxyType)
|
||||||
{
|
{
|
||||||
case ESysProxyType.ForcedClear:
|
case ESysProxyType.ForcedClear:
|
||||||
index = 1;
|
index = 1;
|
||||||
@@ -87,7 +90,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
Color color = ColorTranslator.FromHtml("#3399CC");
|
Color color = ColorTranslator.FromHtml("#3399CC");
|
||||||
int index = (int)config.sysProxyType;
|
int index = (int)config.systemProxyItem.sysProxyType;
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
{
|
{
|
||||||
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
|
color = (new[] { Color.Red, Color.Purple, Color.DarkGreen, Color.Orange, Color.DarkSlateBlue, Color.RoyalBlue })[index - 1];
|
||||||
@@ -126,11 +129,6 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (item.configType == EConfigType.Custom)
|
|
||||||
{
|
|
||||||
Locator.Current.GetService<NoticeHandler>()?.Enqueue(ResUI.NonVmessService);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveFileDialog fileDialog = new()
|
SaveFileDialog fileDialog = new()
|
||||||
{
|
{
|
||||||
@@ -228,5 +226,27 @@ namespace v2rayN.Handler
|
|||||||
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
|
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
|
||||||
HotkeyHandler.Instance.Load();
|
HotkeyHandler.Instance.Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RegisterSystemColorSet(Config config, Window window, Action<bool> update)
|
||||||
|
{
|
||||||
|
var helper = new WindowInteropHelper(window);
|
||||||
|
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
|
||||||
|
hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
|
||||||
|
{
|
||||||
|
if (config.uiItem.followSystemTheme)
|
||||||
|
{
|
||||||
|
const int WM_SETTINGCHANGE = 0x001A;
|
||||||
|
if (msg == WM_SETTINGCHANGE)
|
||||||
|
{
|
||||||
|
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
|
||||||
|
{
|
||||||
|
update(!Utils.IsLightTheme());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return IntPtr.Zero;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ namespace v2rayN.Handler
|
|||||||
_snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
|
_snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Enqueue(string content)
|
public void Enqueue(string? content)
|
||||||
{
|
{
|
||||||
if (content.IsNullOrEmpty())
|
if (content.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
@@ -21,18 +21,26 @@ namespace v2rayN.Handler
|
|||||||
_snackbarMessageQueue?.Enqueue(content);
|
_snackbarMessageQueue?.Enqueue(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string msg)
|
public void SendMessage(string? content)
|
||||||
{
|
{
|
||||||
MessageBus.Current.SendMessage(msg, Global.CommandSendMsgView);
|
if (content.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string msg, bool time)
|
public void SendMessage(string? content, bool time)
|
||||||
{
|
{
|
||||||
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {msg}";
|
if (content.IsNullOrEmpty())
|
||||||
SendMessage(msg);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
content = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {content}";
|
||||||
|
SendMessage(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessageAndEnqueue(string msg)
|
public void SendMessageAndEnqueue(string? msg)
|
||||||
{
|
{
|
||||||
Enqueue(msg);
|
Enqueue(msg);
|
||||||
SendMessage(msg);
|
SendMessage(msg);
|
||||||
|
|||||||
@@ -377,19 +377,18 @@ namespace v2rayN.Handler
|
|||||||
ipAddress = ipHostInfo.AddressList[0];
|
ipAddress = ipHostInfo.AddressList[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Stopwatch timer = new();
|
var timer = Stopwatch.StartNew();
|
||||||
timer.Start();
|
|
||||||
|
|
||||||
IPEndPoint endPoint = new(ipAddress, port);
|
IPEndPoint endPoint = new(ipAddress, port);
|
||||||
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
|
||||||
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
|
var result = clientSocket.BeginConnect(endPoint, null, null);
|
||||||
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
||||||
throw new TimeoutException("connect timeout (5s): " + url);
|
throw new TimeoutException("connect timeout (5s): " + url);
|
||||||
clientSocket.EndConnect(result);
|
clientSocket.EndConnect(result);
|
||||||
|
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsHandler
|
internal class StatisticsHandler
|
||||||
{
|
{
|
||||||
|
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
|
||||||
|
public static StatisticsHandler Instance => instance.Value;
|
||||||
|
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private ServerStatItem? _serverStatItem;
|
private ServerStatItem? _serverStatItem;
|
||||||
private List<ServerStatItem> _lstServerStat;
|
private List<ServerStatItem> _lstServerStat;
|
||||||
@@ -12,20 +15,17 @@ namespace v2rayN.Handler
|
|||||||
private StatisticsSingbox? _statisticsSingbox;
|
private StatisticsSingbox? _statisticsSingbox;
|
||||||
|
|
||||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||||
public bool Enable { get; set; }
|
|
||||||
|
|
||||||
public StatisticsHandler(Config config, Action<ServerSpeedItem> update)
|
public void Init(Config config, Action<ServerSpeedItem> update)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
Enable = config.guiItem.enableStatistics;
|
_updateFunc = update;
|
||||||
if (!Enable)
|
if (!config.guiItem.enableStatistics)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateFunc = update;
|
InitData();
|
||||||
|
|
||||||
Init();
|
|
||||||
|
|
||||||
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
||||||
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
||||||
@@ -55,7 +55,10 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
|
if (_lstServerStat != null)
|
||||||
|
{
|
||||||
|
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -63,7 +66,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init()
|
private void InitData()
|
||||||
{
|
{
|
||||||
SQLiteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
|
SQLiteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@ using System.Text;
|
|||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsSingbox
|
internal class StatisticsSingbox
|
||||||
{
|
{
|
||||||
@@ -65,7 +65,7 @@ namespace v2rayN.Handler
|
|||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(_config.runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo))
|
if (!(_config.IsRunningCore(ECoreType.clash)))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using ProtosLib.Statistics;
|
|||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsV2ray
|
internal class StatisticsV2ray
|
||||||
{
|
{
|
||||||
@@ -53,7 +53,7 @@ namespace v2rayN.Handler
|
|||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(_config.runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet))
|
if (!(_config.IsRunningCore(ECoreType.Xray)))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using PacLib;
|
using PacLib;
|
||||||
|
using v2rayN.Common;
|
||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
@@ -6,34 +7,11 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
public static class SysProxyHandle
|
public static class SysProxyHandle
|
||||||
{
|
{
|
||||||
//private const string _userWininetConfigFile = "user-wininet.json";
|
private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
|
||||||
|
|
||||||
//private static string _queryStr;
|
|
||||||
|
|
||||||
// In general, this won't change
|
|
||||||
// format:
|
|
||||||
// <flags><CR-LF>
|
|
||||||
// <proxy-server><CR-LF>
|
|
||||||
// <bypass-list><CR-LF>
|
|
||||||
// <pac-url>
|
|
||||||
|
|
||||||
private enum RET_ERRORS : int
|
|
||||||
{
|
|
||||||
RET_NO_ERROR = 0,
|
|
||||||
INVALID_FORMAT = 1,
|
|
||||||
NO_PERMISSION = 2,
|
|
||||||
SYSCALL_FAILED = 3,
|
|
||||||
NO_MEMORY = 4,
|
|
||||||
INVAILD_OPTION_COUNT = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
static SysProxyHandle()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool UpdateSysProxy(Config config, bool forceDisable)
|
public static bool UpdateSysProxy(Config config, bool forceDisable)
|
||||||
{
|
{
|
||||||
var type = config.sysProxyType;
|
var type = config.systemProxyItem.sysProxyType;
|
||||||
|
|
||||||
if (forceDisable && type != ESysProxyType.Unchanged)
|
if (forceDisable && type != ESysProxyType.Unchanged)
|
||||||
{
|
{
|
||||||
@@ -51,25 +29,29 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (type == ESysProxyType.ForcedChange)
|
if (type == ESysProxyType.ForcedChange)
|
||||||
{
|
{
|
||||||
var strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}";
|
var strExceptions = "";
|
||||||
|
if (config.systemProxyItem.notProxyLocalAddress)
|
||||||
|
{
|
||||||
|
strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyItem.systemProxyExceptions}";
|
||||||
|
}
|
||||||
|
|
||||||
var strProxy = string.Empty;
|
var strProxy = string.Empty;
|
||||||
if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol))
|
if (Utils.IsNullOrEmpty(config.systemProxyItem.systemProxyAdvancedProtocol))
|
||||||
{
|
{
|
||||||
strProxy = $"{Global.Loopback}:{port}";
|
strProxy = $"{Global.Loopback}:{port}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strProxy = config.systemProxyAdvancedProtocol
|
strProxy = config.systemProxyItem.systemProxyAdvancedProtocol
|
||||||
.Replace("{ip}", Global.Loopback)
|
.Replace("{ip}", Global.Loopback)
|
||||||
.Replace("{http_port}", port.ToString())
|
.Replace("{http_port}", port.ToString())
|
||||||
.Replace("{socks_port}", portSocks.ToString());
|
.Replace("{socks_port}", portSocks.ToString());
|
||||||
}
|
}
|
||||||
ProxySetting.SetProxy(strProxy, strExceptions, 2); // set a named proxy
|
ProxySetting.SetProxy(strProxy, strExceptions, 2);
|
||||||
}
|
}
|
||||||
else if (type == ESysProxyType.ForcedClear)
|
else if (type == ESysProxyType.ForcedClear)
|
||||||
{
|
{
|
||||||
ProxySetting.UnsetProxy(); // set to no proxy
|
ProxySetting.UnsetProxy();
|
||||||
}
|
}
|
||||||
else if (type == ESysProxyType.Unchanged)
|
else if (type == ESysProxyType.Unchanged)
|
||||||
{
|
{
|
||||||
@@ -78,7 +60,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
||||||
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
||||||
ProxySetting.SetProxy(strProxy, "", 4); // use pac script url for auto-config proxy
|
ProxySetting.SetProxy(strProxy, "", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != ESysProxyType.Pac)
|
if (type != ESysProxyType.Pac)
|
||||||
@@ -95,14 +77,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
public static void ResetIEProxy4WindowsShutDown()
|
public static void ResetIEProxy4WindowsShutDown()
|
||||||
{
|
{
|
||||||
try
|
ProxySetting.UnsetProxy();
|
||||||
{
|
|
||||||
//TODO To be verified
|
|
||||||
Utils.RegWriteValue(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", "ProxyEnable", 0);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
|
using static v2rayN.Models.ClashProxies;
|
||||||
|
|
||||||
using static v2rayN.Models.ClashProxies;
|
|
||||||
|
|
||||||
namespace v2rayN.Models
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,12 +12,24 @@ namespace v2rayN.Models
|
|||||||
|
|
||||||
public string indexId { get; set; }
|
public string indexId { get; set; }
|
||||||
public string subIndexId { get; set; }
|
public string subIndexId { get; set; }
|
||||||
public ESysProxyType sysProxyType { get; set; }
|
|
||||||
public string systemProxyExceptions { get; set; }
|
public string systemProxyExceptions { get; set; }
|
||||||
public string systemProxyAdvancedProtocol { get; set; }
|
public string systemProxyAdvancedProtocol { get; set; }
|
||||||
|
|
||||||
public ECoreType runningCoreType { get; set; }
|
public ECoreType runningCoreType { get; set; }
|
||||||
|
|
||||||
|
public bool IsRunningCore(ECoreType type)
|
||||||
|
{
|
||||||
|
if (type == ECoreType.Xray && runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (type == ECoreType.clash && runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion property
|
#endregion property
|
||||||
|
|
||||||
#region other entities
|
#region other entities
|
||||||
@@ -34,6 +46,7 @@ namespace v2rayN.Models
|
|||||||
public Mux4SboxItem mux4SboxItem { get; set; }
|
public Mux4SboxItem mux4SboxItem { get; set; }
|
||||||
public HysteriaItem hysteriaItem { get; set; }
|
public HysteriaItem hysteriaItem { get; set; }
|
||||||
public ClashUIItem clashUIItem { get; set; }
|
public ClashUIItem clashUIItem { get; set; }
|
||||||
|
public SystemProxyItem systemProxyItem { get; set; }
|
||||||
public List<InItem> inbound { get; set; }
|
public List<InItem> inbound { get; set; }
|
||||||
public List<KeyEventItem> globalHotkeys { get; set; }
|
public List<KeyEventItem> globalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> coreTypeItem { get; set; }
|
public List<CoreTypeItem> coreTypeItem { get; set; }
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ namespace v2rayN.Models
|
|||||||
public double mainHeight { get; set; }
|
public double mainHeight { get; set; }
|
||||||
public double mainGirdHeight1 { get; set; }
|
public double mainGirdHeight1 { get; set; }
|
||||||
public double mainGirdHeight2 { get; set; }
|
public double mainGirdHeight2 { get; set; }
|
||||||
|
public EGirdOrientation mainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public bool colorModeDark { get; set; }
|
public bool colorModeDark { get; set; }
|
||||||
public bool followSystemTheme { get; set; }
|
public bool followSystemTheme { get; set; }
|
||||||
public string? colorPrimaryName { get; set; }
|
public string? colorPrimaryName { get; set; }
|
||||||
@@ -130,6 +131,7 @@ namespace v2rayN.Models
|
|||||||
public bool autoHideStartup { get; set; }
|
public bool autoHideStartup { get; set; }
|
||||||
public string mainMsgFilter { get; set; }
|
public string mainMsgFilter { get; set; }
|
||||||
public List<ColumnItem> mainColumnItem { get; set; }
|
public List<ColumnItem> mainColumnItem { get; set; }
|
||||||
|
public bool showInTaskbar { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -169,7 +171,7 @@ namespace v2rayN.Models
|
|||||||
public string stack { get; set; }
|
public string stack { get; set; }
|
||||||
public int mtu { get; set; }
|
public int mtu { get; set; }
|
||||||
public bool enableExInbound { get; set; }
|
public bool enableExInbound { get; set; }
|
||||||
public bool enableIPv6Address { get; set; } = true;
|
public bool enableIPv6Address { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -216,7 +218,8 @@ namespace v2rayN.Models
|
|||||||
public class ClashUIItem
|
public class ClashUIItem
|
||||||
{
|
{
|
||||||
public ERuleMode ruleMode { get; set; }
|
public ERuleMode ruleMode { get; set; }
|
||||||
public bool showInTaskbar { get; set; }
|
public bool enableIPv6 { get; set; }
|
||||||
|
public bool enableMixinContent { get; set; }
|
||||||
public int proxiesSorting { get; set; }
|
public int proxiesSorting { get; set; }
|
||||||
public bool proxiesAutoRefresh { get; set; }
|
public bool proxiesAutoRefresh { get; set; }
|
||||||
public int proxiesAutoDelayTestInterval { get; set; } = 10;
|
public int proxiesAutoDelayTestInterval { get; set; } = 10;
|
||||||
@@ -224,4 +227,13 @@ namespace v2rayN.Models
|
|||||||
public bool connectionsAutoRefresh { get; set; }
|
public bool connectionsAutoRefresh { get; set; }
|
||||||
public int connectionsRefreshInterval { get; set; } = 2;
|
public int connectionsRefreshInterval { get; set; } = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class SystemProxyItem
|
||||||
|
{
|
||||||
|
public ESysProxyType sysProxyType { get; set; }
|
||||||
|
public string systemProxyExceptions { get; set; }
|
||||||
|
public bool notProxyLocalAddress { get; set; } = true;
|
||||||
|
public string systemProxyAdvancedProtocol { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,5 +16,6 @@ namespace v2rayN.Models
|
|||||||
public string? normalDNS { get; set; }
|
public string? normalDNS { get; set; }
|
||||||
public string? tunDNS { get; set; }
|
public string? tunDNS { get; set; }
|
||||||
public string? domainStrategy4Freedom { get; set; }
|
public string? domainStrategy4Freedom { get; set; }
|
||||||
|
public string? domainDNSAddress { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ namespace v2rayN.Models
|
|||||||
switch (configType)
|
switch (configType)
|
||||||
{
|
{
|
||||||
case EConfigType.Custom:
|
case EConfigType.Custom:
|
||||||
summary += string.Format("{0}", remarks);
|
summary += string.Format("[{1}]{0}", remarks, coreType.ToString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace v2rayN.Models
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServerSpeedItem : ServerStatItem
|
public class ServerSpeedItem : ServerStatItem
|
||||||
{
|
{
|
||||||
public long proxyUp
|
public long proxyUp
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
public bool? ip_is_private { get; set; }
|
public bool? ip_is_private { get; set; }
|
||||||
public string? client_subnet { get; set; }
|
public string? client_subnet { get; set; }
|
||||||
public bool? invert { get; set; }
|
public bool? invert { get; set; }
|
||||||
|
public string? clash_mode { get; set; }
|
||||||
public List<string>? inbound { get; set; }
|
public List<string>? inbound { get; set; }
|
||||||
public List<string>? protocol { get; set; }
|
public List<string>? protocol { get; set; }
|
||||||
public List<string>? network { get; set; }
|
public List<string>? network { get; set; }
|
||||||
@@ -130,6 +131,8 @@
|
|||||||
public Multiplex4Sbox? multiplex { get; set; }
|
public Multiplex4Sbox? multiplex { get; set; }
|
||||||
public Transport4Sbox? transport { get; set; }
|
public Transport4Sbox? transport { get; set; }
|
||||||
public HyObfs4Sbox? obfs { get; set; }
|
public HyObfs4Sbox? obfs { get; set; }
|
||||||
|
public List<string>? outbounds { get; set; }
|
||||||
|
public bool? interrupt_exist_connections { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Tls4Sbox
|
public class Tls4Sbox
|
||||||
|
|||||||
@@ -392,6 +392,8 @@ namespace v2rayN.Models
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<RulesItem4Ray> rules { get; set; }
|
public List<RulesItem4Ray> rules { get; set; }
|
||||||
|
|
||||||
|
public List<BalancersItem4Ray>? balancers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -406,6 +408,8 @@ namespace v2rayN.Models
|
|||||||
|
|
||||||
public string? outboundTag { get; set; }
|
public string? outboundTag { get; set; }
|
||||||
|
|
||||||
|
public string? balancerTag { get; set; }
|
||||||
|
|
||||||
public List<string>? ip { get; set; }
|
public List<string>? ip { get; set; }
|
||||||
|
|
||||||
public List<string>? domain { get; set; }
|
public List<string>? domain { get; set; }
|
||||||
@@ -413,6 +417,18 @@ namespace v2rayN.Models
|
|||||||
public List<string>? protocol { get; set; }
|
public List<string>? protocol { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BalancersItem4Ray
|
||||||
|
{
|
||||||
|
public List<string>? selector { get; set; }
|
||||||
|
public BalancersStrategy4Ray? strategy { get; set; }
|
||||||
|
public string? tag { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BalancersStrategy4Ray
|
||||||
|
{
|
||||||
|
public string? type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class StreamSettings4Ray
|
public class StreamSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
240
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
240
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
@@ -78,15 +78,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Batch export subscription to clipboard successfully 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string BatchExportSubscriptionSuccessfully {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("BatchExportSubscriptionSuccessfully", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Batch export share URL to clipboard successfully 的本地化字符串。
|
/// 查找类似 Batch export share URL to clipboard successfully 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -222,15 +213,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Please fill in the KCP parameters correctly 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string FillKcpParameters {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("FillKcpParameters", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please fill in the local listening port 的本地化字符串。
|
/// 查找类似 Please fill in the local listening port 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -285,15 +267,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Is not the correct client configuration file, please check 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string IncorrectClientConfiguration {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("IncorrectClientConfiguration", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Is not the correct configuration, please check 的本地化字符串。
|
/// 查找类似 Is not the correct configuration, please check 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -303,15 +276,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Is not the correct server configuration file, please check 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string IncorrectServerConfiguration {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("IncorrectServerConfiguration", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Initial Configuration 的本地化字符串。
|
/// 查找类似 Initial Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -367,7 +331,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Automatic update interval(minutes) 的本地化字符串。
|
/// 查找类似 Automatic update interval (minutes) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvAutoUpdateInterval {
|
public static string LvAutoUpdateInterval {
|
||||||
get {
|
get {
|
||||||
@@ -421,7 +385,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enabled Update 的本地化字符串。
|
/// 查找类似 Enable update 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvEnabled {
|
public static string LvEnabled {
|
||||||
get {
|
get {
|
||||||
@@ -448,7 +412,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 More urls, separated by commas;Subscription conversion will be invalid 的本地化字符串。
|
/// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvMoreUrl {
|
public static string LvMoreUrl {
|
||||||
get {
|
get {
|
||||||
@@ -825,15 +789,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Export subscription (base64) share to clipboard 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuExport2SubContent {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuExport2SubContent", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Global Hotkey Setting 的本地化字符串。
|
/// 查找类似 Global Hotkey Setting 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1014,15 +969,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Set message filters 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuMsgViewFilter {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuMsgViewFilter", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Select all (Ctrl+A) 的本地化字符串。
|
/// 查找类似 Select all (Ctrl+A) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1060,7 +1006,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 All Node Latency Test 的本地化字符串。
|
/// 查找类似 Latency Test 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuProxiesDelaytest {
|
public static string menuProxiesDelaytest {
|
||||||
get {
|
get {
|
||||||
@@ -1078,7 +1024,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Refresh Proxies (F5) 的本地化字符串。
|
/// 查找类似 Refresh Proxies 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuProxiesReload {
|
public static string menuProxiesReload {
|
||||||
get {
|
get {
|
||||||
@@ -1302,6 +1248,24 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Multi-server load balancing 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuSetDefaultLoadBalanceServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuSetDefaultLoadBalanceServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Multi-Server lowest latency 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuSetDefaultMultipleServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuSetDefaultMultipleServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Set as active server (Enter) 的本地化字符串。
|
/// 查找类似 Set as active server (Enter) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1393,7 +1357,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Subscription group 的本地化字符串。
|
/// 查找类似 Subscription Group 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSubscription {
|
public static string menuSubscription {
|
||||||
get {
|
get {
|
||||||
@@ -1420,7 +1384,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Update subscription without proxy 的本地化字符串。
|
/// 查找类似 Update subscriptions without proxy 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSubUpdate {
|
public static string menuSubUpdate {
|
||||||
get {
|
get {
|
||||||
@@ -1429,7 +1393,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Update subscription with proxy 的本地化字符串。
|
/// 查找类似 Update subscriptions with proxy 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSubUpdateViaProxy {
|
public static string menuSubUpdateViaProxy {
|
||||||
get {
|
get {
|
||||||
@@ -1491,15 +1455,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Test current service status 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuTestMe {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuTestMe", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} Website 的本地化字符串。
|
/// 查找类似 {0} Website 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1654,7 +1609,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Update subscription end 的本地化字符串。
|
/// 查找类似 Update subscriptions end 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string MsgUpdateSubscriptionEnd {
|
public static string MsgUpdateSubscriptionEnd {
|
||||||
get {
|
get {
|
||||||
@@ -1663,7 +1618,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Update subscription starts 的本地化字符串。
|
/// 查找类似 Update subscriptions start 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string MsgUpdateSubscriptionStart {
|
public static string MsgUpdateSubscriptionStart {
|
||||||
get {
|
get {
|
||||||
@@ -1707,15 +1662,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Non-standard service, this feature is invalid 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string NonVmessService {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("NonVmessService", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2} 的本地化字符串。
|
/// 查找类似 The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2} 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1942,7 +1888,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Group please leave blank here 的本地化字符串。
|
/// 查找类似 For group please leave blank here 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string SubUrlTips {
|
public static string SubUrlTips {
|
||||||
get {
|
get {
|
||||||
@@ -1987,15 +1933,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 System proxy 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string SystemProxy {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("SystemProxy", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Address 的本地化字符串。
|
/// 查找类似 Address 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2725,6 +2662,15 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Outbound DNS address 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsDomainDNSAddress {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsDomainDNSAddress", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。
|
/// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2734,6 +2680,15 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Default domain strategy for outbound 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsDomainStrategy4Out {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsDomainStrategy4Out", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Double-click server make active 的本地化字符串。
|
/// 查找类似 Double-click server make active 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2941,6 +2896,15 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Main layout orientation(Require restart) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsMainGirdOrientation {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsMainGirdOrientation", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
|
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2977,6 +2941,15 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Do not use proxy servers for local (intranet) addresses 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsNotProxyLocalAddress {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsNotProxyLocalAddress", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Auth pass 的本地化字符串。
|
/// 查找类似 Auth pass 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3032,7 +3005,7 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 HTTP port=SOCKS port+1;Pac port=SOCKS port+4;API port=SOCKS port+5; 的本地化字符串。
|
/// 查找类似 http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6; 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsSocksPortTip {
|
public static string TbSettingsSocksPortTip {
|
||||||
get {
|
get {
|
||||||
@@ -3139,78 +3112,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Bypass Mode 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeBypassMode {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeBypassMode", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Custom Template 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeCustomTemplate {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeCustomTemplate", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Direct IP CIDR, separated by commas (,) 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeDirectIP {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeDirectIP", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Direct Process name, separated by commas (,) 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeDirectProcess {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeDirectProcess", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 DNS object, e.g. {"servers":[]} 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeDNS {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeDNS", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Proxy IP CIDR, separated by commas (,) 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeProxyIP {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeProxyIP", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Proxy Process name, separated by commas (,) 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeProxyProcess {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeProxyProcess", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Show console 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsTunModeShowWindow {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsTunModeShowWindow", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enable UDP 的本地化字符串。
|
/// 查找类似 Enable UDP 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3454,15 +3355,6 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Too many servers, please open the main interface 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TooManyServersTip {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TooManyServersTip", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 *tcp camouflage type 的本地化字符串。
|
/// 查找类似 *tcp camouflage type 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>صادرات دسته ای محتوای اشتراک به کلیپ بورد با موفقیت انجام شد</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>Batch export share URL to clipboard successfully</value>
|
<value>Batch export share URL to clipboard successfully</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>لطفا فرمت صحیح پورت سرور را پر کنید</value>
|
<value>لطفا فرمت صحیح پورت سرور را پر کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>لطفاً پارامترهای KCP را به درستی پر کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>لطفاً پورت گوش دادن محلی را پر کنید</value>
|
<value>لطفاً پورت گوش دادن محلی را پر کنید</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,15 +168,9 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>لطفا شناسه کاربری را وارد کنید</value>
|
<value>لطفا شناسه کاربری را وارد کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value>فایل پیکربندی مشتری صحیح نیست، لطفا بررسی کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>پیکربندی درستی نیست، لطفا بررسی کنید</value>
|
<value>پیکربندی درستی نیست، لطفا بررسی کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<value>فایل پیکربندی سرور صحیح نیست، لطفا بررسی کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>پیکربندی اولیه</value>
|
<value>پیکربندی اولیه</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>Non-VMess or ss protocol</value>
|
<value>Non-VMess or ss protocol</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value> non-standard service, this feature is invalid</value>
|
|
||||||
</data>
|
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
|
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -415,15 +400,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>Please browse to import server configuration</value>
|
<value>Please browse to import server configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>پروکسی سیستم</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>درحال تست کردن...</value>
|
<value>درحال تست کردن...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>تعداد سرورها خیلی زیاد است، لطفا رابط اصلی را باز کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>LAN</value>
|
<value>LAN</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -541,18 +520,12 @@
|
|||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>تست سرورها با tcping (Ctrl+O)</value>
|
<value>تست سرورها با tcping (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestMe" xml:space="preserve">
|
|
||||||
<value>وضعیت سرویس فعلی را تست کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
|
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value>
|
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>اشتراک (base64) را به کلیپ بورد صادر کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>یک سرور پیکربندی سفارشی اضافه شود</value>
|
<value>یک سرور پیکربندی سفارشی اضافه شود</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -583,9 +556,6 @@
|
|||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>کپی همه</value>
|
<value>کپی همه</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<value>فیلترهای پیام را تنظیم کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>انتخاب همه (Ctrl+A)</value>
|
<value>انتخاب همه (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -955,6 +925,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>فقط مسیر</value>
|
<value>فقط مسیر</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>يەرلىك (Intranet) ئادرېسلارغا ۋاكالەتچى مۇلازىمېتىر ئىشلەتمەڭ</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>One-click test Latency and speed (Ctrl+E)</value>
|
<value>One-click test Latency and speed (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -985,15 +958,6 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>تنظیمات TunMode</value>
|
<value>تنظیمات TunMode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>Direct IP CIDR, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>Direct Process name, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>نمایش کنسول</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
||||||
<value>User-Agent</value>
|
<value>User-Agent</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1061,14 +1025,11 @@
|
|||||||
<value>قانون</value>
|
<value>قانون</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytest" xml:space="preserve">
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
<value>All Node Latency Test</value>
|
<value>Latency Test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
<value>Part Node Latency Test</value>
|
<value>Part Node Latency Test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesReload" xml:space="preserve">
|
|
||||||
<value>Refresh Proxies (F5)</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
<value>Select active node (Enter)</value>
|
<value>Select active node (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>Batch export subscription to clipboard successfully</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>Batch export share URL to clipboard successfully</value>
|
<value>Batch export share URL to clipboard successfully</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>Please fill in the correct format server port</value>
|
<value>Please fill in the correct format server port</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>Please fill in the KCP parameters correctly</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>Please fill in the local listening port</value>
|
<value>Please fill in the local listening port</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,15 +168,9 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>Please fill in the user ID</value>
|
<value>Please fill in the user ID</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value>Is not the correct client configuration file, please check</value>
|
|
||||||
</data>
|
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>Is not the correct configuration, please check</value>
|
<value>Is not the correct configuration, please check</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<value>Is not the correct server configuration file, please check</value>
|
|
||||||
</data>
|
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>Initial Configuration</value>
|
<value>Initial Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -253,10 +241,10 @@
|
|||||||
<value>Is unpacking......</value>
|
<value>Is unpacking......</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
|
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
|
||||||
<value>Update subscription end</value>
|
<value>Update subscriptions end</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateSubscriptionStart" xml:space="preserve">
|
<data name="MsgUpdateSubscriptionStart" xml:space="preserve">
|
||||||
<value>Update subscription starts</value>
|
<value>Update subscriptions start</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>Update Core successfully</value>
|
<value>Update Core successfully</value>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>Non-VMess or ss protocol</value>
|
<value>Non-VMess or ss protocol</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value>Non-standard service, this feature is invalid</value>
|
|
||||||
</data>
|
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
|
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -415,15 +400,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>Please browse to import server configuration</value>
|
<value>Please browse to import server configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>System proxy</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>Testing...</value>
|
<value>Testing...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>Too many servers, please open the main interface</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>LAN</value>
|
<value>LAN</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -473,16 +452,16 @@
|
|||||||
<value>Update current subscription with proxy</value>
|
<value>Update current subscription with proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubscription" xml:space="preserve">
|
<data name="menuSubscription" xml:space="preserve">
|
||||||
<value>Subscription group</value>
|
<value>Subscription Group</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubSetting" xml:space="preserve">
|
<data name="menuSubSetting" xml:space="preserve">
|
||||||
<value>Subscription group settings</value>
|
<value>Subscription group settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubUpdate" xml:space="preserve">
|
<data name="menuSubUpdate" xml:space="preserve">
|
||||||
<value>Update subscription without proxy</value>
|
<value>Update subscriptions without proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubUpdateViaProxy" xml:space="preserve">
|
<data name="menuSubUpdateViaProxy" xml:space="preserve">
|
||||||
<value>Update subscription with proxy</value>
|
<value>Update subscriptions with proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSystemproxy" xml:space="preserve">
|
<data name="menuSystemproxy" xml:space="preserve">
|
||||||
<value>System proxy</value>
|
<value>System proxy</value>
|
||||||
@@ -544,18 +523,12 @@
|
|||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>Test servers with tcping (Ctrl+O)</value>
|
<value>Test servers with tcping (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestMe" xml:space="preserve">
|
|
||||||
<value>Test current service status</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>Export selected server for client configuration</value>
|
<value>Export selected server for client configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>Export share URLs to clipboard (Ctrl+C)</value>
|
<value>Export share URLs to clipboard (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>Export subscription (base64) share to clipboard</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>Add a custom configuration server</value>
|
<value>Add a custom configuration server</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -586,9 +559,6 @@
|
|||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>Copy all</value>
|
<value>Copy all</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<value>Set message filters</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>Select all (Ctrl+A)</value>
|
<value>Select all (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -605,7 +575,7 @@
|
|||||||
<value>Share</value>
|
<value>Share</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvEnabled" xml:space="preserve">
|
<data name="LvEnabled" xml:space="preserve">
|
||||||
<value>Enabled Update</value>
|
<value>Enable update</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvSort" xml:space="preserve">
|
<data name="LvSort" xml:space="preserve">
|
||||||
<value>Sort</value>
|
<value>Sort</value>
|
||||||
@@ -947,7 +917,7 @@
|
|||||||
<value>Support DnsObject, Click to view the document</value>
|
<value>Support DnsObject, Click to view the document</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>Group please leave blank here</value>
|
<value>For group please leave blank here</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipChangeRouting" xml:space="preserve">
|
<data name="TipChangeRouting" xml:space="preserve">
|
||||||
<value>Routing setting is changed</value>
|
<value>Routing setting is changed</value>
|
||||||
@@ -958,6 +928,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>RouteOnly</value>
|
<value>RouteOnly</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>Do not use proxy servers for local (intranet) addresses</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>One-click multi test Latency and speed (Ctrl+E)</value>
|
<value>One-click multi test Latency and speed (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -988,21 +961,9 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>TunMode settings</value>
|
<value>TunMode settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>Direct IP CIDR, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>Direct Process name, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>Show console</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>Move to group</value>
|
<value>Move to group</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
|
||||||
<value>Custom Template</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>Enable Server Drag Drop Sort(Require restart)</value>
|
<value>Enable Server Drag Drop Sort(Require restart)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1037,7 +998,7 @@
|
|||||||
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
|
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>HTTP port=SOCKS port+1;Pac port=SOCKS port+4;API port=SOCKS port+5;</value>
|
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>Set this with admin privileges, get admin privileges after startup</value>
|
<value>Set this with admin privileges, get admin privileges after startup</value>
|
||||||
@@ -1045,24 +1006,12 @@
|
|||||||
<data name="TbSettingsFontSize" xml:space="preserve">
|
<data name="TbSettingsFontSize" xml:space="preserve">
|
||||||
<value>Font Size</value>
|
<value>Font Size</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
|
||||||
<value>Proxy IP CIDR, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
|
|
||||||
<value>Proxy Process name, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
|
||||||
<value>Bypass Mode</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||||
<value>SpeedTest Single Timeout Value</value>
|
<value>SpeedTest Single Timeout Value</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
<value>SpeedTest URL</value>
|
<value>SpeedTest URL</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDNS" xml:space="preserve">
|
|
||||||
<value>DNS object, e.g. {"servers":[]}</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveTo" xml:space="preserve">
|
<data name="menuMoveTo" xml:space="preserve">
|
||||||
<value>Move up and down</value>
|
<value>Move up and down</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1091,13 +1040,13 @@
|
|||||||
<value>Restart as Administrator</value>
|
<value>Restart as Administrator</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvMoreUrl" xml:space="preserve">
|
<data name="LvMoreUrl" xml:space="preserve">
|
||||||
<value>More urls, separated by commas;Subscription conversion will be invalid</value>
|
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedDisplayText" xml:space="preserve">
|
<data name="SpeedDisplayText" xml:space="preserve">
|
||||||
<value>{0} : {1}/s↑ | {2}/s↓</value>
|
<value>{0} : {1}/s↑ | {2}/s↓</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAutoUpdateInterval" xml:space="preserve">
|
<data name="LvAutoUpdateInterval" xml:space="preserve">
|
||||||
<value>Automatic update interval(minutes)</value>
|
<value>Automatic update interval (minutes)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
||||||
<value>Enable logging to file</value>
|
<value>Enable logging to file</value>
|
||||||
@@ -1286,15 +1235,30 @@
|
|||||||
<value>Rule</value>
|
<value>Rule</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytest" xml:space="preserve">
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
<value>All Node Latency Test</value>
|
<value>Latency Test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
<value>Part Node Latency Test</value>
|
<value>Part Node Latency Test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesReload" xml:space="preserve">
|
<data name="menuProxiesReload" xml:space="preserve">
|
||||||
<value>Refresh Proxies (F5)</value>
|
<value>Refresh Proxies</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
<value>Select active node (Enter)</value>
|
<value>Select active node (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||||
|
<value>Default domain strategy for outbound</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
|
<value>Multi-Server lowest latency</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
||||||
|
<value>Main layout orientation(Require restart)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
|
||||||
|
<value>Multi-server load balancing</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
||||||
|
<value>Outbound DNS address</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>Экспортирование подписок в буфер обмена успешно завершено</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>Экспортирование URL в буфер обмена успешно завершено</value>
|
<value>Экспортирование URL в буфер обмена успешно завершено</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>Пожалуйста, укажите порт сервера в правильном формате</value>
|
<value>Пожалуйста, укажите порт сервера в правильном формате</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>Пожалуйста, заполните параметры KCP корректно</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>Пожалуйста, укажите локальный порт прослушивания</value>
|
<value>Пожалуйста, укажите локальный порт прослушивания</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,15 +168,9 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните идентификатор пользователя</value>
|
<value>Пожалуйста, заполните идентификатор пользователя</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value>Некорректный файл конфигурации клиента, пожалуйста, проверьте</value>
|
|
||||||
</data>
|
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>Некорректная конфигурация, пожалуйста, проверьте</value>
|
<value>Некорректная конфигурация, пожалуйста, проверьте</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<value>Некорректный файл конфигурации сервера, пожалуйста, проверьте</value>
|
|
||||||
</data>
|
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>Исходная конфигурация</value>
|
<value>Исходная конфигурация</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>Не является протоколом Vmess или SS</value>
|
<value>Не является протоколом Vmess или SS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value> нестандартный сервис, эта функция недействительна</value>
|
|
||||||
</data>
|
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value>
|
<value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -415,15 +400,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера</value>
|
<value>Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>Системный прокси</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>Тестирование...</value>
|
<value>Тестирование...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>Слишком много серверов, пожалуйста, откройте главный интерфейс</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>LAN</value>
|
<value>LAN</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -544,18 +523,12 @@
|
|||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>Тест задержки с tcping (Ctrl+O)</value>
|
<value>Тест задержки с tcping (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestMe" xml:space="preserve">
|
|
||||||
<value>Проверить текущий статус службы</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>Экспортировать выбранный сервер для клиента</value>
|
<value>Экспортировать выбранный сервер для клиента</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value>
|
<value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>Экспортировать ссылку-подписку (base64) в буфер обмена</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>Добавить сервер пользовательской конфигурации</value>
|
<value>Добавить сервер пользовательской конфигурации</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -586,9 +559,6 @@
|
|||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>Скопировать все</value>
|
<value>Скопировать все</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<value>Установить фильтры сообщений</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>Выбрать все (Ctrl+A)</value>
|
<value>Выбрать все (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -964,6 +934,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>Только маршрут</value>
|
<value>Только маршрут</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>Не используйте прокси-серверы для локальных (интранет) адресов</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
|
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -994,21 +967,9 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>Настройки TunMode</value>
|
<value>Настройки TunMode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>Прямой IP CIDR, разделенный запятыми (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>Имя процесса, разделенное запятыми (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>Показать консоль</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>Перейти в группу</value>
|
<value>Перейти в группу</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
|
||||||
<value>Пользовательский шаблон</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>Включить сортировку перетаскиванием сервера (требуется перезагрузка)</value>
|
<value>Включить сортировку перетаскиванием сервера (требуется перезагрузка)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1042,9 +1003,6 @@
|
|||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value>
|
<value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
|
||||||
<value>HTTP port=socks port+1</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>Установите это с правами администратора</value>
|
<value>Установите это с правами администратора</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>批量导出订阅内容至剪贴板成功</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>批量导出分享URL至剪贴板成功</value>
|
<value>批量导出分享URL至剪贴板成功</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>请填写正确格式服务器端口</value>
|
<value>请填写正确格式服务器端口</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>请正确填写KCP参数</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>请填写本地监听端口</value>
|
<value>请填写本地监听端口</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,15 +168,9 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>请填写用户ID</value>
|
<value>请填写用户ID</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value>不是正确的客户端配置文件,请检查</value>
|
|
||||||
</data>
|
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>不是正确的配置,请检查</value>
|
<value>不是正确的配置,请检查</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<value>不是正确的服务端配置文件,请检查</value>
|
|
||||||
</data>
|
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>初始化配置</value>
|
<value>初始化配置</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>非VMess或ss协议</value>
|
<value>非VMess或ss协议</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value>非标准服务,此功能无效</value>
|
|
||||||
</data>
|
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>在文件夹 ({0}) 下未找到Core文件 (文件名:{1}),请下载后放入文件夹,下载地址: {2}</value>
|
<value>在文件夹 ({0}) 下未找到Core文件 (文件名:{1}),请下载后放入文件夹,下载地址: {2}</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -415,15 +400,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>请浏览导入服务器配置</value>
|
<value>请浏览导入服务器配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>系统代理</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>测试中...</value>
|
<value>测试中...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>服务器太多,请打开主界面操作</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>局域网</value>
|
<value>局域网</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -544,18 +523,12 @@
|
|||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>测试服务器延迟Tcping(多选) (Ctrl+O)</value>
|
<value>测试服务器延迟Tcping(多选) (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestMe" xml:space="preserve">
|
|
||||||
<value>测试当前服务状态</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>导出所选服务器为客户端配置</value>
|
<value>导出所选服务器为客户端配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>批量导出分享URL至剪贴板(多选) (Ctrl+C)</value>
|
<value>批量导出分享URL至剪贴板(多选) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>批量导出订阅内容至剪贴板(多选)</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>添加自定义配置服务器</value>
|
<value>添加自定义配置服务器</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -586,9 +559,6 @@
|
|||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>复制所有</value>
|
<value>复制所有</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<value>设置信息过滤器</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>全选 (Ctrl+A)</value>
|
<value>全选 (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -958,6 +928,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>RouteOnly</value>
|
<value>RouteOnly</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>请勿将代理服务器用于本地(Intranet)地址</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>一键多线程测试延迟和速度 (Ctrl+E)</value>
|
<value>一键多线程测试延迟和速度 (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -988,21 +961,9 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>Tun模式设置</value>
|
<value>Tun模式设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>直连的IP CIDR,用逗号(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>直连的进程名,用逗号(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>显示控制台</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>移至订阅分组</value>
|
<value>移至订阅分组</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
|
||||||
<value>自定义配置模板</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>启用服务器拖放排序(需重启)</value>
|
<value>启用服务器拖放排序(需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1037,7 +998,7 @@
|
|||||||
<value>拷贝字体TTF/TTC文件到目录guiFonts,重启设置</value>
|
<value>拷贝字体TTF/TTC文件到目录guiFonts,重启设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>http端口=socks端口+1;Pac端口=socks端口+4;API端口=socks端口+5;</value>
|
<value>http端口= +1;Pac端口= +4;*ray API端口= +5;mihomo API端口= +6;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
||||||
@@ -1045,24 +1006,12 @@
|
|||||||
<data name="TbSettingsFontSize" xml:space="preserve">
|
<data name="TbSettingsFontSize" xml:space="preserve">
|
||||||
<value>字体大小</value>
|
<value>字体大小</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
|
||||||
<value>代理的IP CIDR,用逗号(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
|
|
||||||
<value>代理的进程名,用逗号(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
|
||||||
<value>绕行模式</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||||
<value>测速单个超时值</value>
|
<value>测速单个超时值</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
<value>测速文件地址</value>
|
<value>测速文件地址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDNS" xml:space="preserve">
|
|
||||||
<value>DNS对象,例如 {"servers":[]}</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveTo" xml:space="preserve">
|
<data name="menuMoveTo" xml:space="preserve">
|
||||||
<value>移至上下</value>
|
<value>移至上下</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1283,15 +1232,30 @@
|
|||||||
<value>规则</value>
|
<value>规则</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytest" xml:space="preserve">
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
<value>全部节点延迟测试</value>
|
<value>延迟测试</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
<value>当前部分节点延迟测试</value>
|
<value>当前部分节点延迟测试</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesReload" xml:space="preserve">
|
<data name="menuProxiesReload" xml:space="preserve">
|
||||||
<value>刷新 (F5)</value>
|
<value>刷新</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
<value>设为活动节点 (Enter)</value>
|
<value>设为活动节点 (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||||
|
<value>Outbound默认解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
|
<value>多服务器最低延迟 (多选)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
||||||
|
<value>主界面布局方向(需重启)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
|
||||||
|
<value>多服务器负载均衡 (多选)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
||||||
|
<value>Outbound域名解析地址</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>批次匯出訂閱內容至剪貼簿成功</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>批次匯出分享URL至剪貼簿成功</value>
|
<value>批次匯出分享URL至剪貼簿成功</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>請填寫正確格式伺服器埠</value>
|
<value>請填寫正確格式伺服器埠</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>請正確填寫KCP參數</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>請填寫本機監聽埠</value>
|
<value>請填寫本機監聽埠</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,15 +168,9 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>請填寫使用者ID</value>
|
<value>請填寫使用者ID</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value>不是正確的用戶端配置檔案,請檢查</value>
|
|
||||||
</data>
|
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>不是正確的配置,請檢查</value>
|
<value>不是正確的配置,請檢查</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<value>不是正確的服務端配置檔案,請檢查</value>
|
|
||||||
</data>
|
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>初始化配置</value>
|
<value>初始化配置</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>非VMess或SS協定</value>
|
<value>非VMess或SS協定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value>非標準服務,此功能無效</value>
|
|
||||||
</data>
|
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>在資料夾 ({0}) 下未找到Core文件 (檔案名:{1}),請下載後放入資料夾、,下載網址: {2}</value>
|
<value>在資料夾 ({0}) 下未找到Core文件 (檔案名:{1}),請下載後放入資料夾、,下載網址: {2}</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -414,15 +399,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>請瀏覽匯入伺服器配置</value>
|
<value>請瀏覽匯入伺服器配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>系統代理</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>測試中...</value>
|
<value>測試中...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>伺服器太多,請打開主介面操作</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>區域網路</value>
|
<value>區域網路</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -543,18 +522,12 @@
|
|||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>測試伺服器延遲Tcping(多選) (Ctrl+O)</value>
|
<value>測試伺服器延遲Tcping(多選) (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestMe" xml:space="preserve">
|
|
||||||
<value>測試目前服務狀態</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>匯出所選伺服器為用戶端配置</value>
|
<value>匯出所選伺服器為用戶端配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>批次匯出分享URL至剪貼簿(多選) (Ctrl+C)</value>
|
<value>批次匯出分享URL至剪貼簿(多選) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>批次匯出訂閱內容至剪貼簿(多選)</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>新增自訂配置伺服器</value>
|
<value>新增自訂配置伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -585,9 +558,6 @@
|
|||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>複製所有</value>
|
<value>複製所有</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<value>設定資訊過濾器</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>全選 (Ctrl+A)</value>
|
<value>全選 (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -958,6 +928,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>RouteOnly</value>
|
<value>RouteOnly</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>請勿將代理伺服器用於本機(Intranet)位址</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>一鍵多執行緒測試延遲和速度 (Ctrl+E)</value>
|
<value>一鍵多執行緒測試延遲和速度 (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -988,21 +961,9 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>TUN模式設定</value>
|
<value>TUN模式設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>直連的IP CIDR,用逗號(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>直連的行程名,用逗號(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>顯示控制台</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>移至訂閱分組</value>
|
<value>移至訂閱分組</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
|
||||||
<value>自訂配置模板</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>啟動伺服器拖放排序(需重啟)</value>
|
<value>啟動伺服器拖放排序(需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1037,7 +998,7 @@
|
|||||||
<value>複製字型TTF/TTC文件到目錄guiFonts,重啟設定</value>
|
<value>複製字型TTF/TTC文件到目錄guiFonts,重啟設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>HTTP埠=SOCKS埠+1</value>
|
<value>http端口= +1;Pac端口= +4;*ray API端口= +5;mihomo API端口= +6;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
|
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
|
||||||
@@ -1045,24 +1006,12 @@
|
|||||||
<data name="TbSettingsFontSize" xml:space="preserve">
|
<data name="TbSettingsFontSize" xml:space="preserve">
|
||||||
<value>字型大小</value>
|
<value>字型大小</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
|
||||||
<value>代理的IP CIDR,用逗號(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
|
|
||||||
<value>代理的行程名,用逗號(,)分隔</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
|
||||||
<value>繞行模式</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||||
<value>測速單個超時值</value>
|
<value>測速單個超時值</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
<value>測速檔案位址</value>
|
<value>測速檔案位址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDNS" xml:space="preserve">
|
|
||||||
<value>DNS物件,例如 {"servers":[]}</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveTo" xml:space="preserve">
|
<data name="menuMoveTo" xml:space="preserve">
|
||||||
<value>移至上下</value>
|
<value>移至上下</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
39
v2rayN/v2rayN/Sample/clash_mixin_yaml
Normal file
39
v2rayN/v2rayN/Sample/clash_mixin_yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# 配置文件内容不会被修改,混合行为只会发生在内存中
|
||||||
|
#
|
||||||
|
# 注意下面缩进,请用支持yaml显示的编辑器打开
|
||||||
|
#
|
||||||
|
# 使用clash配置文件关键字则覆盖原配置
|
||||||
|
#
|
||||||
|
# removed-rules 循环匹配rules数组每行,符合则移除当前行 (此规则请放最前面)
|
||||||
|
#
|
||||||
|
# append-rules 数组合并至原配置rules数组后
|
||||||
|
# prepend-rules 数组合并至原配置rules数组前
|
||||||
|
# append-proxies 数组合并至原配置proxies数组后
|
||||||
|
# prepend-proxies 数组合并至原配置proxies数组前
|
||||||
|
# append-proxy-groups 数组合并至原配置proxy-groups数组后
|
||||||
|
# prepend-proxy-groups 数组合并至原配置proxy-groups数组前
|
||||||
|
# append-rule-providers 数组合并至原配置rule-providers数组后
|
||||||
|
# prepend-rule-providers 数组合并至原配置rule-providers数组前
|
||||||
|
#
|
||||||
|
|
||||||
|
dns:
|
||||||
|
enable: true
|
||||||
|
enhanced-mode: fake-ip
|
||||||
|
nameserver:
|
||||||
|
- 114.114.114.114
|
||||||
|
- 223.5.5.5
|
||||||
|
- 8.8.8.8
|
||||||
|
fallback: []
|
||||||
|
fake-ip-filter:
|
||||||
|
- +.stun.*.*
|
||||||
|
- +.stun.*.*.*
|
||||||
|
- +.stun.*.*.*.*
|
||||||
|
- +.stun.*.*.*.*.*
|
||||||
|
- "*.n.n.srv.nintendo.net"
|
||||||
|
- +.stun.playstation.net
|
||||||
|
- xbox.*.*.microsoft.com
|
||||||
|
- "*.*.xboxlive.com"
|
||||||
|
- "*.msftncsi.com"
|
||||||
|
- "*.msftconnecttest.com"
|
||||||
|
- WORKGROUP
|
||||||
7
v2rayN/v2rayN/Sample/clash_tun_yaml
Normal file
7
v2rayN/v2rayN/Sample/clash_tun_yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
tun:
|
||||||
|
enable: true
|
||||||
|
stack: gvisor
|
||||||
|
dns-hijack:
|
||||||
|
- 0.0.0.0:53
|
||||||
|
auto-route: true
|
||||||
|
auto-detect-interface: true
|
||||||
@@ -5,6 +5,11 @@
|
|||||||
"bittorrent"
|
"bittorrent"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"outboundTag": "block",
|
||||||
|
"port": "443",
|
||||||
|
"network": "udp"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"outboundTag": "block",
|
"outboundTag": "block",
|
||||||
"domain": [
|
"domain": [
|
||||||
@@ -15,7 +20,7 @@
|
|||||||
"outboundTag": "proxy",
|
"outboundTag": "proxy",
|
||||||
|
|
||||||
"domain": [
|
"domain": [
|
||||||
"geosite:geolocation-!cn",
|
"geosite:gfw",
|
||||||
"geosite:greatfire"
|
"geosite:greatfire"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"outboundTag": "block",
|
||||||
|
"port": "443",
|
||||||
|
"network": "udp"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"port": "0-65535",
|
"port": "0-65535",
|
||||||
"outboundTag": "proxy"
|
"outboundTag": "proxy"
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
"domain:example-example2.com"
|
"domain:example-example2.com"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"outboundTag": "block",
|
||||||
|
"port": "443",
|
||||||
|
"network": "udp"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"outboundTag": "block",
|
"outboundTag": "block",
|
||||||
"domain": [
|
"domain": [
|
||||||
|
|||||||
@@ -20,9 +20,10 @@
|
|||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
"rule_set": [
|
"rule_set": [
|
||||||
"geosite-geolocation-!cn"
|
"geosite-cn",
|
||||||
|
"geosite-geolocation-cn"
|
||||||
],
|
],
|
||||||
"server": "remote"
|
"server": "local"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule_set": [
|
"rule_set": [
|
||||||
@@ -31,5 +32,5 @@
|
|||||||
"server": "block"
|
"server": "block"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"final": "local"
|
"final": "remote"
|
||||||
}
|
}
|
||||||
@@ -20,9 +20,10 @@
|
|||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
"rule_set": [
|
"rule_set": [
|
||||||
"geosite-geolocation-!cn"
|
"geosite-cn",
|
||||||
|
"geosite-geolocation-cn"
|
||||||
],
|
],
|
||||||
"server": "remote"
|
"server": "local"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule_set": [
|
"rule_set": [
|
||||||
@@ -31,5 +32,5 @@
|
|||||||
"server": "block"
|
"server": "block"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"final": "local"
|
"final": "remote"
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@ using DynamicData;
|
|||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
using Splat;
|
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using v2rayN.Enums;
|
||||||
using v2rayN.Handler;
|
using v2rayN.Handler;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
@@ -15,11 +15,6 @@ namespace v2rayN.ViewModels
|
|||||||
{
|
{
|
||||||
private static Config _config;
|
private static Config _config;
|
||||||
|
|
||||||
static ClashConnectionsViewModel()
|
|
||||||
{
|
|
||||||
_config = LazyConfig.Instance.GetConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IObservableCollection<ClashConnectionModel> _connectionItems = new ObservableCollectionExtended<ClashConnectionModel>();
|
private IObservableCollection<ClashConnectionModel> _connectionItems = new ObservableCollectionExtended<ClashConnectionModel>();
|
||||||
|
|
||||||
public IObservableCollection<ClashConnectionModel> ConnectionItems => _connectionItems;
|
public IObservableCollection<ClashConnectionModel> ConnectionItems => _connectionItems;
|
||||||
@@ -38,6 +33,7 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
public ClashConnectionsViewModel()
|
public ClashConnectionsViewModel()
|
||||||
{
|
{
|
||||||
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
SortingSelected = _config.clashUIItem.connectionsSorting;
|
SortingSelected = _config.clashUIItem.connectionsSorting;
|
||||||
AutoRefresh = _config.clashUIItem.connectionsAutoRefresh;
|
AutoRefresh = _config.clashUIItem.connectionsAutoRefresh;
|
||||||
|
|
||||||
@@ -89,7 +85,7 @@ namespace v2rayN.ViewModels
|
|||||||
Observable.Interval(TimeSpan.FromSeconds(10))
|
Observable.Interval(TimeSpan.FromSeconds(10))
|
||||||
.Subscribe(x =>
|
.Subscribe(x =>
|
||||||
{
|
{
|
||||||
if (!(AutoRefresh && _config.clashUIItem.showInTaskbar))
|
if (!(AutoRefresh && _config.uiItem.showInTaskbar && _config.IsRunningCore(ECoreType.clash)))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ namespace v2rayN.ViewModels
|
|||||||
public void ProxiesReload()
|
public void ProxiesReload()
|
||||||
{
|
{
|
||||||
GetClashProxies(true);
|
GetClashProxies(true);
|
||||||
|
ProxiesDelayTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProxiesClear()
|
public void ProxiesClear()
|
||||||
@@ -166,7 +167,7 @@ namespace v2rayN.ViewModels
|
|||||||
public void ProxiesDelayTest()
|
public void ProxiesDelayTest()
|
||||||
{
|
{
|
||||||
ProxiesDelayTest(true);
|
ProxiesDelayTest(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region proxy function
|
#region proxy function
|
||||||
|
|
||||||
@@ -186,7 +187,7 @@ namespace v2rayN.ViewModels
|
|||||||
{
|
{
|
||||||
ClashApiHandler.Instance.GetClashProxies(_config, (it, it2) =>
|
ClashApiHandler.Instance.GetClashProxies(_config, (it, it2) =>
|
||||||
{
|
{
|
||||||
UpdateHandler(false, "Refresh Clash Proxies");
|
//UpdateHandler(false, "Refresh Clash Proxies");
|
||||||
proxies = it?.proxies;
|
proxies = it?.proxies;
|
||||||
providers = it2?.providers;
|
providers = it2?.providers;
|
||||||
|
|
||||||
@@ -336,7 +337,7 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
private ProxiesItem? TryGetProxy(string name)
|
private ProxiesItem? TryGetProxy(string name)
|
||||||
{
|
{
|
||||||
if(proxies is null)
|
if (proxies is null)
|
||||||
return null;
|
return null;
|
||||||
proxies.TryGetValue(name, out ProxiesItem proxy2);
|
proxies.TryGetValue(name, out ProxiesItem proxy2);
|
||||||
if (proxy2 != null)
|
if (proxy2 != null)
|
||||||
@@ -412,7 +413,7 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
private void ProxiesDelayTest(bool blAll)
|
private void ProxiesDelayTest(bool blAll)
|
||||||
{
|
{
|
||||||
UpdateHandler(false, "Clash Proxies Latency Test");
|
//UpdateHandler(false, "Clash Proxies Latency Test");
|
||||||
|
|
||||||
ClashApiHandler.Instance.ClashProxiesDelayTest(blAll, _proxyDetails.ToList(), (item, result) =>
|
ClashApiHandler.Instance.ClashProxiesDelayTest(blAll, _proxyDetails.ToList(), (item, result) =>
|
||||||
{
|
{
|
||||||
@@ -464,7 +465,7 @@ namespace v2rayN.ViewModels
|
|||||||
Observable.Interval(TimeSpan.FromSeconds(60))
|
Observable.Interval(TimeSpan.FromSeconds(60))
|
||||||
.Subscribe(x =>
|
.Subscribe(x =>
|
||||||
{
|
{
|
||||||
if (!(AutoRefresh && _config.clashUIItem.showInTaskbar))
|
if (!(AutoRefresh && _config.uiItem.showInTaskbar && _config.IsRunningCore(ECoreType.clash)))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -478,7 +479,7 @@ namespace v2rayN.ViewModels
|
|||||||
}
|
}
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion task
|
#endregion task
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
[Reactive] public bool useSystemHosts { get; set; }
|
[Reactive] public bool useSystemHosts { get; set; }
|
||||||
[Reactive] public string domainStrategy4Freedom { get; set; }
|
[Reactive] public string domainStrategy4Freedom { get; set; }
|
||||||
|
[Reactive] public string domainDNSAddress { get; set; }
|
||||||
[Reactive] public string normalDNS { get; set; }
|
[Reactive] public string normalDNS { get; set; }
|
||||||
|
|
||||||
|
[Reactive] public string domainStrategy4Freedom2 { get; set; }
|
||||||
|
[Reactive] public string domainDNSAddress2 { get; set; }
|
||||||
[Reactive] public string normalDNS2 { get; set; }
|
[Reactive] public string normalDNS2 { get; set; }
|
||||||
[Reactive] public string tunDNS2 { get; set; }
|
[Reactive] public string tunDNS2 { get; set; }
|
||||||
|
|
||||||
@@ -34,12 +38,15 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray);
|
var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
useSystemHosts = item.useSystemHosts;
|
useSystemHosts = item.useSystemHosts;
|
||||||
domainStrategy4Freedom = item?.domainStrategy4Freedom!;
|
domainStrategy4Freedom = item?.domainStrategy4Freedom ?? string.Empty;
|
||||||
normalDNS = item?.normalDNS!;
|
domainDNSAddress = item?.domainDNSAddress ?? string.Empty;
|
||||||
|
normalDNS = item?.normalDNS ?? string.Empty;
|
||||||
|
|
||||||
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
||||||
normalDNS2 = item2?.normalDNS!;
|
domainStrategy4Freedom2 = item2?.domainStrategy4Freedom ?? string.Empty;
|
||||||
tunDNS2 = item2?.tunDNS!;
|
domainDNSAddress2 = item2?.domainDNSAddress ?? string.Empty;
|
||||||
|
normalDNS2 = item2?.normalDNS ?? string.Empty;
|
||||||
|
tunDNS2 = item2?.tunDNS ?? string.Empty;
|
||||||
|
|
||||||
SaveCmd = ReactiveCommand.Create(() =>
|
SaveCmd = ReactiveCommand.Create(() =>
|
||||||
{
|
{
|
||||||
@@ -98,13 +105,16 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray);
|
var item = LazyConfig.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
item.domainStrategy4Freedom = domainStrategy4Freedom;
|
item.domainStrategy4Freedom = domainStrategy4Freedom;
|
||||||
|
item.domainDNSAddress = domainDNSAddress;
|
||||||
item.useSystemHosts = useSystemHosts;
|
item.useSystemHosts = useSystemHosts;
|
||||||
item.normalDNS = normalDNS;
|
item.normalDNS = normalDNS;
|
||||||
ConfigHandler.SaveDNSItems(_config, item);
|
ConfigHandler.SaveDNSItems(_config, item);
|
||||||
|
|
||||||
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
||||||
|
item2.domainStrategy4Freedom = domainStrategy4Freedom2;
|
||||||
|
item2.domainDNSAddress = domainDNSAddress2;
|
||||||
item2.normalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(normalDNS2));
|
item2.normalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(normalDNS2));
|
||||||
item2.tunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2));
|
item2.tunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2));;
|
||||||
ConfigHandler.SaveDNSItems(_config, item2);
|
ConfigHandler.SaveDNSItems(_config, item2);
|
||||||
|
|
||||||
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -74,11 +74,13 @@ namespace v2rayN.ViewModels
|
|||||||
[Reactive] public string SpeedPingTestUrl { get; set; }
|
[Reactive] public string SpeedPingTestUrl { get; set; }
|
||||||
[Reactive] public bool EnableHWA { get; set; }
|
[Reactive] public bool EnableHWA { get; set; }
|
||||||
[Reactive] public string SubConvertUrl { get; set; }
|
[Reactive] public string SubConvertUrl { get; set; }
|
||||||
|
[Reactive] public int MainGirdOrientation { get; set; }
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
#region System proxy
|
#region System proxy
|
||||||
|
|
||||||
|
[Reactive] public bool notProxyLocalAddress { get; set; }
|
||||||
[Reactive] public string systemProxyAdvancedProtocol { get; set; }
|
[Reactive] public string systemProxyAdvancedProtocol { get; set; }
|
||||||
[Reactive] public string systemProxyExceptions { get; set; }
|
[Reactive] public string systemProxyExceptions { get; set; }
|
||||||
|
|
||||||
@@ -171,13 +173,15 @@ namespace v2rayN.ViewModels
|
|||||||
SpeedPingTestUrl = _config.speedTestItem.speedPingTestUrl;
|
SpeedPingTestUrl = _config.speedTestItem.speedPingTestUrl;
|
||||||
EnableHWA = _config.guiItem.enableHWA;
|
EnableHWA = _config.guiItem.enableHWA;
|
||||||
SubConvertUrl = _config.constItem.subConvertUrl;
|
SubConvertUrl = _config.constItem.subConvertUrl;
|
||||||
|
MainGirdOrientation = (int)_config.uiItem.mainGirdOrientation;
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
#region System proxy
|
#region System proxy
|
||||||
|
|
||||||
systemProxyAdvancedProtocol = _config.systemProxyAdvancedProtocol;
|
notProxyLocalAddress = _config.systemProxyItem.notProxyLocalAddress;
|
||||||
systemProxyExceptions = _config.systemProxyExceptions;
|
systemProxyAdvancedProtocol = _config.systemProxyItem.systemProxyAdvancedProtocol;
|
||||||
|
systemProxyExceptions = _config.systemProxyItem.systemProxyExceptions;
|
||||||
|
|
||||||
#endregion System proxy
|
#endregion System proxy
|
||||||
|
|
||||||
@@ -333,10 +337,12 @@ namespace v2rayN.ViewModels
|
|||||||
_config.speedTestItem.speedPingTestUrl = SpeedPingTestUrl;
|
_config.speedTestItem.speedPingTestUrl = SpeedPingTestUrl;
|
||||||
_config.guiItem.enableHWA = EnableHWA;
|
_config.guiItem.enableHWA = EnableHWA;
|
||||||
_config.constItem.subConvertUrl = SubConvertUrl;
|
_config.constItem.subConvertUrl = SubConvertUrl;
|
||||||
|
_config.uiItem.mainGirdOrientation = (EGirdOrientation)MainGirdOrientation;
|
||||||
|
|
||||||
//systemProxy
|
//systemProxy
|
||||||
_config.systemProxyExceptions = systemProxyExceptions;
|
_config.systemProxyItem.systemProxyExceptions = systemProxyExceptions;
|
||||||
_config.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
|
_config.systemProxyItem.notProxyLocalAddress = notProxyLocalAddress;
|
||||||
|
_config.systemProxyItem.systemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
|
||||||
|
|
||||||
//tun mode
|
//tun mode
|
||||||
_config.tunModeItem.strictRoute = TunStrictRoute;
|
_config.tunModeItem.strictRoute = TunStrictRoute;
|
||||||
|
|||||||
796
v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs
Normal file
796
v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs
Normal file
@@ -0,0 +1,796 @@
|
|||||||
|
using DynamicData;
|
||||||
|
using DynamicData.Binding;
|
||||||
|
using MaterialDesignThemes.Wpf;
|
||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using Splat;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Handler;
|
||||||
|
using v2rayN.Handler.Fmt;
|
||||||
|
using v2rayN.Handler.Statistics;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
using v2rayN.Views;
|
||||||
|
|
||||||
|
namespace v2rayN.ViewModels
|
||||||
|
{
|
||||||
|
public class ProfilesViewModel : ReactiveObject
|
||||||
|
{
|
||||||
|
#region private prop
|
||||||
|
|
||||||
|
private List<ProfileItem> _lstProfile;
|
||||||
|
private string _serverFilter = string.Empty;
|
||||||
|
private static Config _config;
|
||||||
|
private NoticeHandler? _noticeHandler;
|
||||||
|
private Dictionary<string, bool> _dicHeaderSort = new();
|
||||||
|
private Action<EViewAction> _updateView;
|
||||||
|
|
||||||
|
#endregion private prop
|
||||||
|
|
||||||
|
#region ObservableCollection
|
||||||
|
|
||||||
|
private IObservableCollection<ProfileItemModel> _profileItems = new ObservableCollectionExtended<ProfileItemModel>();
|
||||||
|
public IObservableCollection<ProfileItemModel> ProfileItems => _profileItems;
|
||||||
|
|
||||||
|
private IObservableCollection<SubItem> _subItems = new ObservableCollectionExtended<SubItem>();
|
||||||
|
public IObservableCollection<SubItem> SubItems => _subItems;
|
||||||
|
|
||||||
|
private IObservableCollection<ComboItem> _servers = new ObservableCollectionExtended<ComboItem>();
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public ProfileItemModel SelectedProfile { get; set; }
|
||||||
|
|
||||||
|
public IList<ProfileItemModel> SelectedProfiles { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public SubItem SelectedSub { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public SubItem SelectedMoveToGroup { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public ComboItem SelectedServer { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string ServerFilter { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool BlServers { get; set; }
|
||||||
|
|
||||||
|
#endregion ObservableCollection
|
||||||
|
|
||||||
|
#region Menu
|
||||||
|
|
||||||
|
//servers delete
|
||||||
|
public ReactiveCommand<Unit, Unit> EditServerCmd { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> RemoveServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> RemoveDuplicateServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> CopyServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> SetDefaultServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ShareServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> SetDefaultMultipleServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> SetDefaultLoadBalanceServerCmd { get; }
|
||||||
|
|
||||||
|
//servers move
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveBottomCmd { get; }
|
||||||
|
|
||||||
|
//servers ping
|
||||||
|
public ReactiveCommand<Unit, Unit> MixedTestServerCmd { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> TcpingServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> RealPingServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; }
|
||||||
|
|
||||||
|
//servers export
|
||||||
|
public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> Export2ShareUrlCmd { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> AddSubCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> EditSubCmd { get; }
|
||||||
|
|
||||||
|
#endregion Menu
|
||||||
|
|
||||||
|
#region Init
|
||||||
|
|
||||||
|
public ProfilesViewModel(Action<EViewAction> updateView)
|
||||||
|
{
|
||||||
|
_updateView = updateView;
|
||||||
|
|
||||||
|
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
|
||||||
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
|
MessageBus.Current.Listen<string>(Global.CommandRefreshProfiles).Subscribe(x => RefreshServersBiz());
|
||||||
|
|
||||||
|
SelectedProfile = new();
|
||||||
|
SelectedSub = new();
|
||||||
|
SelectedMoveToGroup = new();
|
||||||
|
SelectedServer = new();
|
||||||
|
|
||||||
|
RefreshSubscriptions();
|
||||||
|
RefreshServers();
|
||||||
|
|
||||||
|
#region WhenAnyValue && ReactiveCommand
|
||||||
|
|
||||||
|
var canEditRemove = this.WhenAnyValue(
|
||||||
|
x => x.SelectedProfile,
|
||||||
|
selectedSource => selectedSource != null && !selectedSource.indexId.IsNullOrEmpty());
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.SelectedSub,
|
||||||
|
y => y != null && !y.remarks.IsNullOrEmpty() && _config.subIndexId != y.id)
|
||||||
|
.Subscribe(c => SubSelectedChanged(c));
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.SelectedMoveToGroup,
|
||||||
|
y => y != null && !y.remarks.IsNullOrEmpty())
|
||||||
|
.Subscribe(c => MoveToGroup(c));
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.SelectedServer,
|
||||||
|
y => y != null && !y.Text.IsNullOrEmpty())
|
||||||
|
.Subscribe(c => ServerSelectedChanged(c));
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.ServerFilter,
|
||||||
|
y => y != null && _serverFilter != y)
|
||||||
|
.Subscribe(c => ServerFilterChanged(c));
|
||||||
|
|
||||||
|
//servers delete
|
||||||
|
EditServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
EditServer(false, EConfigType.Custom);
|
||||||
|
}, canEditRemove);
|
||||||
|
RemoveServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
RemoveServer();
|
||||||
|
}, canEditRemove);
|
||||||
|
RemoveDuplicateServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
RemoveDuplicateServer();
|
||||||
|
});
|
||||||
|
CopyServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
CopyServer();
|
||||||
|
}, canEditRemove);
|
||||||
|
SetDefaultServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
SetDefaultServer();
|
||||||
|
}, canEditRemove);
|
||||||
|
ShareServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ShareServer();
|
||||||
|
}, canEditRemove);
|
||||||
|
SetDefaultMultipleServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
SetDefaultMultipleServer(ECoreType.sing_box);
|
||||||
|
}, canEditRemove);
|
||||||
|
SetDefaultLoadBalanceServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
SetDefaultMultipleServer(ECoreType.Xray);
|
||||||
|
}, canEditRemove);
|
||||||
|
|
||||||
|
//servers move
|
||||||
|
MoveTopCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
MoveServer(EMove.Top);
|
||||||
|
}, canEditRemove);
|
||||||
|
MoveUpCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
MoveServer(EMove.Up);
|
||||||
|
}, canEditRemove);
|
||||||
|
MoveDownCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
MoveServer(EMove.Down);
|
||||||
|
}, canEditRemove);
|
||||||
|
MoveBottomCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
MoveServer(EMove.Bottom);
|
||||||
|
}, canEditRemove);
|
||||||
|
|
||||||
|
//servers ping
|
||||||
|
MixedTestServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ServerSpeedtest(ESpeedActionType.Mixedtest);
|
||||||
|
});
|
||||||
|
TcpingServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ServerSpeedtest(ESpeedActionType.Tcping);
|
||||||
|
}, canEditRemove);
|
||||||
|
RealPingServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ServerSpeedtest(ESpeedActionType.Realping);
|
||||||
|
}, canEditRemove);
|
||||||
|
SpeedServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ServerSpeedtest(ESpeedActionType.Speedtest);
|
||||||
|
}, canEditRemove);
|
||||||
|
SortServerResultCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
SortServer(EServerColName.delayVal.ToString());
|
||||||
|
});
|
||||||
|
//servers export
|
||||||
|
Export2ClientConfigCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
Export2ClientConfig();
|
||||||
|
}, canEditRemove);
|
||||||
|
Export2ShareUrlCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
Export2ShareUrl();
|
||||||
|
}, canEditRemove);
|
||||||
|
|
||||||
|
//Subscription
|
||||||
|
AddSubCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
EditSub(true);
|
||||||
|
});
|
||||||
|
EditSubCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
EditSub(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
#endregion WhenAnyValue && ReactiveCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Init
|
||||||
|
|
||||||
|
#region Actions
|
||||||
|
|
||||||
|
private void Reload()
|
||||||
|
{
|
||||||
|
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSpeedtestHandler(string indexId, string delay, string speed)
|
||||||
|
{
|
||||||
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
SetTestResult(indexId, delay, speed);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetTestResult(string indexId, string delay, string speed)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(indexId))
|
||||||
|
{
|
||||||
|
_noticeHandler?.SendMessage(delay, true);
|
||||||
|
_noticeHandler?.Enqueue(delay);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault();
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(delay))
|
||||||
|
{
|
||||||
|
int.TryParse(delay, out int temp);
|
||||||
|
item.delay = temp;
|
||||||
|
item.delayVal = $"{delay} {Global.DelayUnit}";
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(speed))
|
||||||
|
{
|
||||||
|
item.speedVal = $"{speed} {Global.SpeedUnit}";
|
||||||
|
}
|
||||||
|
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateStatistics(ServerSpeedItem update)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
var item = _profileItems.Where(it => it.indexId == update.indexId).FirstOrDefault();
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
item.todayDown = Utils.HumanFy(update.todayDown);
|
||||||
|
item.todayUp = Utils.HumanFy(update.todayUp);
|
||||||
|
item.totalDown = Utils.HumanFy(update.totalDown);
|
||||||
|
item.totalUp = Utils.HumanFy(update.totalUp);
|
||||||
|
|
||||||
|
if (SelectedProfile?.indexId == item.indexId)
|
||||||
|
{
|
||||||
|
var temp = JsonUtils.DeepCopy(item);
|
||||||
|
_profileItems.Replace(item, temp);
|
||||||
|
SelectedProfile = temp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Actions
|
||||||
|
|
||||||
|
#region Servers && Groups
|
||||||
|
|
||||||
|
private void SubSelectedChanged(bool c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_config.subIndexId = SelectedSub?.id;
|
||||||
|
|
||||||
|
RefreshServers();
|
||||||
|
|
||||||
|
_updateView(EViewAction.ProfilesFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ServerFilterChanged(bool c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_serverFilter = ServerFilter;
|
||||||
|
if (Utils.IsNullOrEmpty(_serverFilter))
|
||||||
|
{
|
||||||
|
RefreshServers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshServers()
|
||||||
|
{
|
||||||
|
MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshServersBiz()
|
||||||
|
{
|
||||||
|
var lstModel = LazyConfig.Instance.ProfileItems(_config.subIndexId, _serverFilter);
|
||||||
|
|
||||||
|
ConfigHandler.SetDefaultServer(_config, lstModel);
|
||||||
|
|
||||||
|
var lstServerStat = (_config.guiItem.enableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
||||||
|
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
|
||||||
|
lstModel = (from t in lstModel
|
||||||
|
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
|
||||||
|
from t22 in t2b.DefaultIfEmpty()
|
||||||
|
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
|
||||||
|
from t33 in t3b.DefaultIfEmpty()
|
||||||
|
select new ProfileItemModel
|
||||||
|
{
|
||||||
|
indexId = t.indexId,
|
||||||
|
configType = t.configType,
|
||||||
|
remarks = t.remarks,
|
||||||
|
address = t.address,
|
||||||
|
port = t.port,
|
||||||
|
security = t.security,
|
||||||
|
network = t.network,
|
||||||
|
streamSecurity = t.streamSecurity,
|
||||||
|
subid = t.subid,
|
||||||
|
subRemarks = t.subRemarks,
|
||||||
|
isActive = t.indexId == _config.indexId,
|
||||||
|
sort = t33 == null ? 0 : t33.sort,
|
||||||
|
delay = t33 == null ? 0 : t33.delay,
|
||||||
|
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
|
||||||
|
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
|
||||||
|
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
|
||||||
|
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
|
||||||
|
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
|
||||||
|
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
|
||||||
|
}).OrderBy(t => t.sort).ToList();
|
||||||
|
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel));
|
||||||
|
|
||||||
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
_profileItems.Clear();
|
||||||
|
_profileItems.AddRange(lstModel);
|
||||||
|
if (lstModel.Count > 0)
|
||||||
|
{
|
||||||
|
var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId);
|
||||||
|
if (selected != null)
|
||||||
|
{
|
||||||
|
SelectedProfile = selected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedProfile = lstModel[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshSubscriptions()
|
||||||
|
{
|
||||||
|
_subItems.Clear();
|
||||||
|
|
||||||
|
_subItems.Add(new SubItem { remarks = ResUI.AllGroupServers });
|
||||||
|
foreach (var item in LazyConfig.Instance.SubItems().OrderBy(t => t.sort))
|
||||||
|
{
|
||||||
|
_subItems.Add(item);
|
||||||
|
}
|
||||||
|
if (_config.subIndexId != null && _subItems.FirstOrDefault(t => t.id == _config.subIndexId) != null)
|
||||||
|
{
|
||||||
|
SelectedSub = _subItems.FirstOrDefault(t => t.id == _config.subIndexId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedSub = _subItems[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Servers && Groups
|
||||||
|
|
||||||
|
#region Add Servers
|
||||||
|
|
||||||
|
private int GetProfileItems(out List<ProfileItem> lstSelecteds, bool latest)
|
||||||
|
{
|
||||||
|
lstSelecteds = new List<ProfileItem>();
|
||||||
|
if (SelectedProfiles == null || SelectedProfiles.Count <= 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var orderProfiles = SelectedProfiles?.OrderBy(t => t.sort);
|
||||||
|
if (latest)
|
||||||
|
{
|
||||||
|
foreach (var profile in orderProfiles)
|
||||||
|
{
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(profile.indexId);
|
||||||
|
if (item is not null)
|
||||||
|
{
|
||||||
|
lstSelecteds.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lstSelecteds = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(orderProfiles));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EditServer(bool blNew, EConfigType eConfigType)
|
||||||
|
{
|
||||||
|
ProfileItem item;
|
||||||
|
if (blNew)
|
||||||
|
{
|
||||||
|
item = new()
|
||||||
|
{
|
||||||
|
subid = _config.subIndexId,
|
||||||
|
configType = eConfigType,
|
||||||
|
isSub = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eConfigType = item.configType;
|
||||||
|
}
|
||||||
|
bool? ret = false;
|
||||||
|
if (eConfigType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
ret = (new AddServer2Window(item)).ShowDialog();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = (new AddServerWindow(item)).ShowDialog();
|
||||||
|
}
|
||||||
|
if (ret == true)
|
||||||
|
{
|
||||||
|
RefreshServers();
|
||||||
|
if (item.indexId == _config.indexId)
|
||||||
|
{
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveServer()
|
||||||
|
{
|
||||||
|
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var exists = lstSelecteds.Exists(t => t.indexId == _config.indexId);
|
||||||
|
|
||||||
|
ConfigHandler.RemoveServer(_config, lstSelecteds);
|
||||||
|
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||||
|
|
||||||
|
RefreshServers();
|
||||||
|
if (exists)
|
||||||
|
{
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveDuplicateServer()
|
||||||
|
{
|
||||||
|
var tuple = ConfigHandler.DedupServerList(_config, _config.subIndexId);
|
||||||
|
RefreshServers();
|
||||||
|
Reload();
|
||||||
|
_noticeHandler?.Enqueue(string.Format(ResUI.RemoveDuplicateServerResult, tuple.Item1, tuple.Item2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CopyServer()
|
||||||
|
{
|
||||||
|
if (GetProfileItems(out List<ProfileItem> lstSelecteds, false) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ConfigHandler.CopyServer(_config, lstSelecteds) == 0)
|
||||||
|
{
|
||||||
|
RefreshServers();
|
||||||
|
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDefaultServer()
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetDefaultServer(SelectedProfile.indexId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetDefaultServer(string indexId)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(indexId))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (indexId == _config.indexId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConfigHandler.SetDefaultServerIndex(_config, indexId) == 0)
|
||||||
|
{
|
||||||
|
RefreshServers();
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ServerSelectedChanged(bool c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SelectedServer == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Utils.IsNullOrEmpty(SelectedServer.ID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetDefaultServer(SelectedServer.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ShareServer()
|
||||||
|
{
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var url = FmtHandler.GetShareUri(item);
|
||||||
|
if (Utils.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var img = QRCodeHelper.GetQRCode(url);
|
||||||
|
var dialog = new QrcodeView()
|
||||||
|
{
|
||||||
|
imgQrcode = { Source = img },
|
||||||
|
txtContent = { Text = url },
|
||||||
|
};
|
||||||
|
|
||||||
|
await DialogHost.Show(dialog, "RootDialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetDefaultMultipleServer(ECoreType coreType)
|
||||||
|
{
|
||||||
|
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConfigHandler.AddCustomServer4Multiple(_config, lstSelecteds, coreType, out string indexId) != 0)
|
||||||
|
{
|
||||||
|
_noticeHandler?.Enqueue(ResUI.OperationFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (indexId == _config.indexId)
|
||||||
|
{
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetDefaultServer(indexId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SortServer(string colName)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(colName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dicHeaderSort.TryAdd(colName, true);
|
||||||
|
_dicHeaderSort.TryGetValue(colName, out bool asc);
|
||||||
|
if (ConfigHandler.SortServers(_config, _config.subIndexId, colName, asc) != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dicHeaderSort[colName] = !asc;
|
||||||
|
RefreshServers();
|
||||||
|
}
|
||||||
|
|
||||||
|
//move server
|
||||||
|
private void MoveToGroup(bool c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigHandler.MoveToGroup(_config, lstSelecteds, SelectedMoveToGroup.id);
|
||||||
|
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||||
|
|
||||||
|
RefreshServers();
|
||||||
|
SelectedMoveToGroup = new();
|
||||||
|
//Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MoveServer(EMove eMove)
|
||||||
|
{
|
||||||
|
var item = _lstProfile.FirstOrDefault(t => t.indexId == SelectedProfile.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = _lstProfile.IndexOf(item);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ConfigHandler.MoveServer(_config, ref _lstProfile, index, eMove) == 0)
|
||||||
|
{
|
||||||
|
RefreshServers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MoveServerTo(int startIndex, ProfileItemModel targetItem)
|
||||||
|
{
|
||||||
|
var targetIndex = _profileItems.IndexOf(targetItem);
|
||||||
|
if (startIndex >= 0 && targetIndex >= 0 && startIndex != targetIndex)
|
||||||
|
{
|
||||||
|
if (ConfigHandler.MoveServer(_config, ref _lstProfile, startIndex, EMove.Position, targetIndex) == 0)
|
||||||
|
{
|
||||||
|
RefreshServers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServerSpeedtest(ESpeedActionType actionType)
|
||||||
|
{
|
||||||
|
if (actionType == ESpeedActionType.Mixedtest)
|
||||||
|
{
|
||||||
|
SelectedProfiles = _profileItems;
|
||||||
|
}
|
||||||
|
if (GetProfileItems(out List<ProfileItem> lstSelecteds, false) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//ClearTestResult();
|
||||||
|
var coreHandler = Locator.Current.GetService<CoreHandler>();
|
||||||
|
if (coreHandler != null)
|
||||||
|
{
|
||||||
|
new SpeedtestHandler(_config, coreHandler, lstSelecteds, actionType, UpdateSpeedtestHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Export2ClientConfig()
|
||||||
|
{
|
||||||
|
var item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MainFormHandler.Instance.Export2ClientConfig(item, _config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Export2ShareUrl()
|
||||||
|
{
|
||||||
|
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new();
|
||||||
|
foreach (var it in lstSelecteds)
|
||||||
|
{
|
||||||
|
var url = FmtHandler.GetShareUri(it);
|
||||||
|
if (Utils.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sb.Append(url);
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
if (sb.Length > 0)
|
||||||
|
{
|
||||||
|
Utils.SetClipboardData(sb.ToString());
|
||||||
|
_noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Add Servers
|
||||||
|
|
||||||
|
#region Subscription
|
||||||
|
|
||||||
|
private void EditSub(bool blNew)
|
||||||
|
{
|
||||||
|
SubItem item;
|
||||||
|
if (blNew)
|
||||||
|
{
|
||||||
|
item = new();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item = LazyConfig.Instance.GetSubItem(_config.subIndexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ret = (new SubEditWindow(item)).ShowDialog();
|
||||||
|
if (ret == true)
|
||||||
|
{
|
||||||
|
RefreshSubscriptions();
|
||||||
|
SubSelectedChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Subscription
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,16 +13,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
this.Loaded += Window_Loaded;
|
||||||
ViewModel = new AddServer2ViewModel(profileItem, this);
|
ViewModel = new AddServer2ViewModel(profileItem, this);
|
||||||
|
|||||||
@@ -16,16 +16,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
this.Loaded += Window_Loaded;
|
||||||
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
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:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:v2rayN.Views"
|
|
||||||
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"
|
||||||
xmlns:reactiveui="http://reactiveui.net"
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
@@ -13,52 +12,52 @@
|
|||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
x:TypeArguments="vms:ClashConnectionsViewModel"
|
x:TypeArguments="vms:ClashConnectionsViewModel"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel>
|
|
||||||
<ToolBarTray Margin="0,8,0,8" DockPanel.Dock="Top">
|
<DockPanel Margin="2">
|
||||||
<ToolBar ClipToBounds="True" Style="{StaticResource MaterialDesignToolBar}">
|
<WrapPanel
|
||||||
<Button Width="1" Visibility="Hidden">
|
Margin="8"
|
||||||
<materialDesign:PackIcon
|
VerticalAlignment="Center"
|
||||||
Margin="0,0,8,0"
|
DockPanel.Dock="Top"
|
||||||
VerticalAlignment="Center"
|
Orientation="Horizontal">
|
||||||
Kind="ContentSave" />
|
|
||||||
</Button>
|
<TextBlock
|
||||||
<TextBlock
|
Margin="8,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSorting}" />
|
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSorting"
|
x:Name="cmbSorting"
|
||||||
Width="100"
|
Width="100"
|
||||||
Margin="8"
|
Margin="8,0"
|
||||||
Style="{StaticResource DefComboBox}">
|
Style="{StaticResource DefComboBox}">
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpSpeed}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpSpeed}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownSpeed}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownSpeed}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingTime}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingTime}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingHost}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingHost}" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
<Separator />
|
|
||||||
<Button x:Name="btnConnectionCloseAll" ToolTip="{x:Static resx:ResUI.menuConnectionCloseAll}">
|
<Button
|
||||||
<StackPanel Orientation="Horizontal">
|
x:Name="btnConnectionCloseAll"
|
||||||
<materialDesign:PackIcon
|
Width="24"
|
||||||
Margin="0,0,8,0"
|
Height="24"
|
||||||
VerticalAlignment="Center"
|
Margin="8,0"
|
||||||
Kind="Close" />
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuConnectionCloseAll}" />
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Close" />
|
||||||
</StackPanel>
|
</Button>
|
||||||
</Button>
|
|
||||||
<Separator />
|
<TextBlock
|
||||||
<TextBlock
|
Margin="8,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
x:Name="togAutoRefresh"
|
x:Name="togAutoRefresh"
|
||||||
Margin="8"
|
Margin="8,0"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
</ToolBar>
|
</WrapPanel>
|
||||||
</ToolBarTray>
|
|
||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstConnections"
|
x:Name="lstConnections"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
@@ -79,21 +78,21 @@
|
|||||||
</DataGrid.ContextMenu>
|
</DataGrid.ContextMenu>
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Width="300"
|
Width="240"
|
||||||
Binding="{Binding host}"
|
Binding="{Binding host}"
|
||||||
Header="{x:Static resx:ResUI.TbSortingHost}" />
|
Header="{x:Static resx:ResUI.TbSortingHost}" />
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Width="100"
|
Width="160"
|
||||||
|
Binding="{Binding chain}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingChain}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="80"
|
||||||
Binding="{Binding network}"
|
Binding="{Binding network}"
|
||||||
Header="{x:Static resx:ResUI.TbSortingNetwork}" />
|
Header="{x:Static resx:ResUI.TbSortingNetwork}" />
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Width="100"
|
Width="100"
|
||||||
Binding="{Binding type}"
|
Binding="{Binding type}"
|
||||||
Header="{x:Static resx:ResUI.TbSortingType}" />
|
Header="{x:Static resx:ResUI.TbSortingType}" />
|
||||||
<DataGridTextColumn
|
|
||||||
Width="200"
|
|
||||||
Binding="{Binding chain}"
|
|
||||||
Header="{x:Static resx:ResUI.TbSortingChain}" />
|
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Width="100"
|
Width="100"
|
||||||
Binding="{Binding uploadTraffic}"
|
Binding="{Binding uploadTraffic}"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using v2rayN.ViewModels;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
using v2rayN.ViewModels;
|
||||||
|
|
||||||
namespace v2rayN.Views
|
namespace v2rayN.Views
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:converters="clr-namespace:v2rayN.Converters"
|
xmlns:converters="clr-namespace:v2rayN.Converters"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:v2rayN.Views"
|
|
||||||
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"
|
||||||
xmlns:reactiveui="http://reactiveui.net"
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
@@ -20,59 +19,71 @@
|
|||||||
<converters:DelayColorConverter x:Key="DelayColorConverter" />
|
<converters:DelayColorConverter x:Key="DelayColorConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<DockPanel>
|
<DockPanel Margin="2">
|
||||||
<ToolBarTray DockPanel.Dock="Top">
|
<WrapPanel
|
||||||
<ToolBar
|
Margin="8"
|
||||||
HorizontalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
DockPanel.Dock="Top"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Margin="8,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Style="{StaticResource MaterialDesignToolBar}">
|
Text="{x:Static resx:ResUI.menuRulemode}" />
|
||||||
<Button Width="1" Visibility="Hidden">
|
<ComboBox
|
||||||
<materialDesign:PackIcon
|
x:Name="cmbRulemode"
|
||||||
Margin="0,0,8,0"
|
Width="80"
|
||||||
VerticalAlignment="Center"
|
Margin="8,0"
|
||||||
Kind="ContentSave" />
|
Style="{StaticResource DefComboBox}">
|
||||||
</Button>
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeRule}" />
|
||||||
<Separator />
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeGlobal}" />
|
||||||
<TextBlock
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeDirect}" />
|
||||||
VerticalAlignment="Center"
|
</ComboBox>
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.menuRulemode}" />
|
<TextBlock
|
||||||
<ComboBox
|
Margin="8,0"
|
||||||
x:Name="cmbRulemode"
|
VerticalAlignment="Center"
|
||||||
Width="80"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Margin="8"
|
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||||
Style="{StaticResource DefComboBox}">
|
<ComboBox
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeRule}" />
|
x:Name="cmbSorting"
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeGlobal}" />
|
Width="60"
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeDirect}" />
|
Margin="8,0"
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeNothing}" />
|
Style="{StaticResource DefComboBox}">
|
||||||
</ComboBox>
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDelay}" />
|
||||||
<Separator />
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingName}" />
|
||||||
<TextBlock
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDefault}" />
|
||||||
VerticalAlignment="Center"
|
</ComboBox>
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSorting}" />
|
<Button
|
||||||
<ComboBox
|
x:Name="menuProxiesReload"
|
||||||
x:Name="cmbSorting"
|
Width="24"
|
||||||
Width="60"
|
Height="24"
|
||||||
Margin="8"
|
Margin="8,0"
|
||||||
Style="{StaticResource DefComboBox}">
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDelay}" />
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Reload" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingName}" />
|
</Button>
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDefault}" />
|
|
||||||
</ComboBox>
|
<Button
|
||||||
<Separator />
|
x:Name="menuProxiesDelaytest"
|
||||||
<TextBlock
|
Width="24"
|
||||||
VerticalAlignment="Center"
|
Height="24"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Margin="8,0"
|
||||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
<ToggleButton
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="LightningBolt" />
|
||||||
x:Name="togAutoRefresh"
|
</Button>
|
||||||
Margin="8"
|
|
||||||
HorizontalAlignment="Left" />
|
<TextBlock
|
||||||
</ToolBar>
|
Margin="8,0"
|
||||||
</ToolBarTray>
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togAutoRefresh"
|
||||||
|
Margin="8,0"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
</WrapPanel>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="lstProxyGroups"
|
x:Name="lstProxyGroups"
|
||||||
@@ -83,12 +94,6 @@
|
|||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||||||
Style="{StaticResource MaterialDesignListView}">
|
Style="{StaticResource MaterialDesignListView}">
|
||||||
<ListView.ContextMenu>
|
|
||||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
|
||||||
<MenuItem x:Name="menuProxiesReload" Header="{x:Static resx:ResUI.menuProxiesReload}" />
|
|
||||||
<MenuItem x:Name="menuProxiesDelaytest" Header="{x:Static resx:ResUI.menuProxiesDelaytest}" />
|
|
||||||
</ContextMenu>
|
|
||||||
</ListView.ContextMenu>
|
|
||||||
<ListView.ItemsPanel>
|
<ListView.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<StackPanel Orientation="Vertical" />
|
<StackPanel Orientation="Vertical" />
|
||||||
@@ -96,20 +101,23 @@
|
|||||||
</ListView.ItemsPanel>
|
</ListView.ItemsPanel>
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Border Width="200" Padding="0">
|
<Border
|
||||||
|
Width="160"
|
||||||
|
Margin="4,0"
|
||||||
|
Padding="0">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Grid Grid.Column="0" Margin="4">
|
<Grid Grid.Column="0" Margin="4">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
<DockPanel Grid.Row="0">
|
||||||
<TextBlock Style="{StaticResource ListItemTitle}" Text="{Binding name}" />
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="8,0,0,0"
|
DockPanel.Dock="Right"
|
||||||
Style="{StaticResource ListItemSubTitle}"
|
Style="{StaticResource ListItemSubTitle}"
|
||||||
Text="{Binding type}" />
|
Text="{Binding type}" />
|
||||||
</StackPanel>
|
<TextBlock Style="{StaticResource ListItemTitle}" Text="{Binding name}" />
|
||||||
|
</DockPanel>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Style="{StaticResource ListItemSubTitle}"
|
Style="{StaticResource ListItemSubTitle}"
|
||||||
@@ -141,7 +149,7 @@
|
|||||||
</ListView.ItemsPanel>
|
</ListView.ItemsPanel>
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Border Width="200" Padding="0">
|
<Border Width="160" Padding="0">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Border
|
<Border
|
||||||
Width="5"
|
Width="5"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using v2rayN.ViewModels;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Splat;
|
using Splat;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using v2rayN.ViewModels;
|
||||||
|
|
||||||
namespace v2rayN.Views
|
namespace v2rayN.Views
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,33 +49,6 @@
|
|||||||
|
|
||||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||||
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
||||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
|
||||||
<TextBlock
|
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
|
|
||||||
<ComboBox
|
|
||||||
x:Name="cmbdomainStrategy4Freedom"
|
|
||||||
Width="200"
|
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
|
||||||
Style="{StaticResource DefComboBox}" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
|
||||||
<TextBlock
|
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
|
|
||||||
<ToggleButton
|
|
||||||
x:Name="togUseSystemHosts"
|
|
||||||
Grid.Row="5"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
@@ -83,7 +56,7 @@
|
|||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
|
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="8,0,0,0"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}">
|
Style="{StaticResource ToolbarTextBlock}">
|
||||||
<Hyperlink Click="linkDnsObjectDoc_Click">
|
<Hyperlink Click="linkDnsObjectDoc_Click">
|
||||||
@@ -93,12 +66,53 @@
|
|||||||
</TextBlock>
|
</TextBlock>
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnImportDefConfig4V2ray"
|
x:Name="btnImportDefConfig4V2ray"
|
||||||
Margin="8,0,0,0"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
Style="{StaticResource DefButton}" />
|
Style="{StaticResource DefButton}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togUseSystemHosts"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy4Freedom"
|
||||||
|
Width="150"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainDNSAddress"
|
||||||
|
Width="150"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
IsEditable="True"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</StackPanel>
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtnormalDNS"
|
x:Name="txtnormalDNS"
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
@@ -116,7 +130,7 @@
|
|||||||
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
||||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="8,0,0,0"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}">
|
Style="{StaticResource ToolbarTextBlock}">
|
||||||
<Hyperlink Click="linkDnsSingboxObjectDoc_Click">
|
<Hyperlink Click="linkDnsSingboxObjectDoc_Click">
|
||||||
@@ -126,12 +140,41 @@
|
|||||||
</TextBlock>
|
</TextBlock>
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnImportDefConfig4Singbox"
|
x:Name="btnImportDefConfig4Singbox"
|
||||||
Margin="8,0,0,0"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
Style="{StaticResource DefButton}" />
|
Style="{StaticResource DefButton}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy4Out"
|
||||||
|
Width="150"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainDNSAddress2"
|
||||||
|
Width="150"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
IsEditable="True"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</StackPanel>
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
<Grid Margin="{StaticResource SettingItemMargin}">
|
<Grid Margin="{StaticResource SettingItemMargin}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="1*" />
|
<ColumnDefinition Width="1*" />
|
||||||
|
|||||||
@@ -15,16 +15,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
_config = LazyConfig.Instance.GetConfig();
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
|
|
||||||
@@ -34,12 +24,28 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
cmbdomainStrategy4Freedom.Items.Add(it);
|
||||||
});
|
});
|
||||||
|
Global.SingboxDomainStrategy4Out.ForEach(it =>
|
||||||
|
{
|
||||||
|
cmbdomainStrategy4Out.Items.Add(it);
|
||||||
|
});
|
||||||
|
Global.DomainDNSAddress.ForEach(it =>
|
||||||
|
{
|
||||||
|
cmbdomainDNSAddress.Items.Add(it);
|
||||||
|
});
|
||||||
|
Global.SingboxDomainDNSAddress.ForEach(it =>
|
||||||
|
{
|
||||||
|
cmbdomainDNSAddress2.Items.Add(it);
|
||||||
|
});
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
this.Bind(ViewModel, vm => vm.useSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.useSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.domainDNSAddress, v => v.cmbdomainDNSAddress.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.normalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.normalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.domainDNSAddress2, v => v.cmbdomainDNSAddress2.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.normalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.normalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.tunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.tunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
|||||||
@@ -18,16 +18,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
_config = LazyConfig.Instance.GetConfig();
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
_config.globalHotkeys ??= new List<KeyEventItem>();
|
_config.globalHotkeys ??= new List<KeyEventItem>();
|
||||||
|
|||||||
@@ -2,10 +2,8 @@
|
|||||||
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:conv="clr-namespace:v2rayN.Converters"
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:v2rayN.Views"
|
|
||||||
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"
|
||||||
xmlns:reactiveui="http://reactiveui.net"
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
@@ -32,7 +30,6 @@
|
|||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
||||||
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
@@ -327,8 +324,7 @@
|
|||||||
x:Name="togDarkMode"
|
x:Name="togDarkMode"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="8"
|
Margin="8" />
|
||||||
IsEnabled="{Binding ElementName=followSystemTheme, Path=IsChecked, Converter={StaticResource InverseBooleanConverter}}" />
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -390,62 +386,6 @@
|
|||||||
</materialDesign:PopupBox>
|
</materialDesign:PopupBox>
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
</ToolBarTray>
|
</ToolBarTray>
|
||||||
<WrapPanel Margin="2" DockPanel.Dock="Top">
|
|
||||||
<ListBox
|
|
||||||
x:Name="lstGroup"
|
|
||||||
MaxHeight="120"
|
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
|
||||||
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
|
|
||||||
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
|
||||||
<ListBox.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Text="{Binding remarks}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ListBox.ItemTemplate>
|
|
||||||
</ListBox>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
x:Name="btnEditSub"
|
|
||||||
Width="30"
|
|
||||||
Height="30"
|
|
||||||
Margin="4,0"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Edit" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
x:Name="btnAddSub"
|
|
||||||
Width="30"
|
|
||||||
Height="30"
|
|
||||||
Margin="4,0"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
x:Name="btnAutofitColumnWidth"
|
|
||||||
Width="30"
|
|
||||||
Height="30"
|
|
||||||
Margin="20,0"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
|
|
||||||
</Button>
|
|
||||||
<TextBox
|
|
||||||
x:Name="txtServerFilter"
|
|
||||||
Width="200"
|
|
||||||
Margin="4,0"
|
|
||||||
VerticalContentAlignment="Center"
|
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
|
||||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
|
||||||
Style="{StaticResource DefTextBox}" />
|
|
||||||
<Button
|
|
||||||
x:Name="btnShowCalshUI"
|
|
||||||
Width="30"
|
|
||||||
Height="30"
|
|
||||||
Margin="20,0"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="EyeOutline" />
|
|
||||||
</Button>
|
|
||||||
</WrapPanel>
|
|
||||||
|
|
||||||
<materialDesign:ColorZone
|
<materialDesign:ColorZone
|
||||||
Height="50"
|
Height="50"
|
||||||
@@ -526,252 +466,154 @@
|
|||||||
</DockPanel>
|
</DockPanel>
|
||||||
</materialDesign:ColorZone>
|
</materialDesign:ColorZone>
|
||||||
|
|
||||||
<Grid x:Name="gridMain">
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid x:Name="gridMain" Visibility="Collapsed">
|
||||||
<RowDefinition Height="1*" />
|
<Grid.ColumnDefinitions>
|
||||||
<RowDefinition Height="10" />
|
<ColumnDefinition Width="1*" />
|
||||||
<RowDefinition Height="1*" />
|
<ColumnDefinition Width="10" />
|
||||||
</Grid.RowDefinitions>
|
<ColumnDefinition Width="1*" />
|
||||||
<DockPanel Grid.Row="0">
|
</Grid.ColumnDefinitions>
|
||||||
<ContentControl x:Name="tabClashUI" DockPanel.Dock="Right" />
|
<ContentControl x:Name="tabProfiles" Grid.Column="0" />
|
||||||
<DataGrid
|
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||||
x:Name="lstProfiles"
|
<TabControl
|
||||||
materialDesign:DataGridAssist.CellPadding="2,2"
|
x:Name="tabMain"
|
||||||
AutoGenerateColumns="False"
|
Grid.Column="2"
|
||||||
BorderThickness="1"
|
HorizontalContentAlignment="Left">
|
||||||
CanUserAddRows="False"
|
<TabItem x:Name="tabMsgView" Header="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||||
CanUserResizeRows="False"
|
<TabItem x:Name="tabClashProxies" Header="{x:Static resx:ResUI.TbProxies}" />
|
||||||
CanUserSortColumns="False"
|
<TabItem x:Name="tabClashConnections" Header="{x:Static resx:ResUI.TbConnections}" />
|
||||||
EnableRowVirtualization="True"
|
</TabControl>
|
||||||
Focusable="True"
|
</Grid>
|
||||||
GridLinesVisibility="All"
|
<Grid x:Name="gridMain1" Visibility="Collapsed">
|
||||||
HeadersVisibility="All"
|
<Grid.RowDefinitions>
|
||||||
IsReadOnly="True"
|
<RowDefinition Height="1*" />
|
||||||
RowHeaderWidth="40"
|
<RowDefinition Height="10" />
|
||||||
Style="{StaticResource DefDataGrid}">
|
<RowDefinition Height="1*" />
|
||||||
<DataGrid.InputBindings>
|
</Grid.RowDefinitions>
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" />
|
<ContentControl x:Name="tabProfiles1" Grid.Row="0" />
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+V" />
|
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" />
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Delete" />
|
<TabControl
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Enter" />
|
x:Name="tabMain1"
|
||||||
</DataGrid.InputBindings>
|
Grid.Row="2"
|
||||||
<DataGrid.ContextMenu>
|
materialDesign:NavigationRailAssist.ShowSelectionBackground="True"
|
||||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
Style="{StaticResource MaterialDesignNavigationRailTabControl}"
|
||||||
<MenuItem
|
TabStripPlacement="Left">
|
||||||
x:Name="menuEditServer"
|
<TabItem x:Name="tabMsgView1">
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<TabItem.Header>
|
||||||
Header="{x:Static resx:ResUI.menuEditServer}" />
|
<StackPanel>
|
||||||
<MenuItem
|
<materialDesign:PackIcon
|
||||||
x:Name="menuSetDefaultServer"
|
Width="24"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="24"
|
||||||
Header="{x:Static resx:ResUI.menuSetDefaultServer}" />
|
HorizontalAlignment="Center"
|
||||||
<MenuItem
|
Kind="MessageTextOutline" />
|
||||||
x:Name="menuRemoveServer"
|
<TextBlock
|
||||||
Height="{StaticResource MenuItemHeight}"
|
HorizontalAlignment="Center"
|
||||||
Header="{x:Static resx:ResUI.menuRemoveServer}" />
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
<MenuItem
|
Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||||
x:Name="menuRemoveDuplicateServer"
|
</StackPanel>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
</TabItem.Header>
|
||||||
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
</TabItem>
|
||||||
<MenuItem
|
<TabItem x:Name="tabClashProxies1">
|
||||||
x:Name="menuCopyServer"
|
<TabItem.Header>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<StackPanel>
|
||||||
Header="{x:Static resx:ResUI.menuCopyServer}" />
|
<materialDesign:PackIcon
|
||||||
<MenuItem
|
Width="24"
|
||||||
x:Name="menuShareServer"
|
Height="24"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
HorizontalAlignment="Center"
|
||||||
Header="{x:Static resx:ResUI.menuShareServer}" />
|
Kind="ArrowDecisionOutline" />
|
||||||
<Separator />
|
<TextBlock
|
||||||
<MenuItem
|
HorizontalAlignment="Center"
|
||||||
x:Name="menuMixedTestServer"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Text="{x:Static resx:ResUI.TbProxies}" />
|
||||||
Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
</StackPanel>
|
||||||
<MenuItem
|
</TabItem.Header>
|
||||||
x:Name="menuTcpingServer"
|
</TabItem>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<TabItem x:Name="tabClashConnections1">
|
||||||
Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
<TabItem.Header>
|
||||||
<MenuItem
|
<StackPanel>
|
||||||
x:Name="menuRealPingServer"
|
<materialDesign:PackIcon
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Width="24"
|
||||||
Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
Height="24"
|
||||||
<MenuItem
|
HorizontalAlignment="Center"
|
||||||
x:Name="menuSpeedServer"
|
Kind="LanConnect" />
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<TextBlock
|
||||||
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
HorizontalAlignment="Center"
|
||||||
<MenuItem
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
x:Name="menuSortServerResult"
|
Text="{x:Static resx:ResUI.TbConnections}" />
|
||||||
Height="{StaticResource MenuItemHeight}"
|
</StackPanel>
|
||||||
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
</TabItem.Header>
|
||||||
<Separator />
|
</TabItem>
|
||||||
<MenuItem
|
</TabControl>
|
||||||
x:Name="menuMoveToGroup"
|
</Grid>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<Grid x:Name="gridMain2" Visibility="Collapsed">
|
||||||
Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
<TabControl
|
||||||
<MenuItem Height="Auto">
|
x:Name="tabMain2"
|
||||||
<MenuItem.Header>
|
materialDesign:NavigationRailAssist.ShowSelectionBackground="True"
|
||||||
<DockPanel>
|
Style="{StaticResource MaterialDesignNavigationRailTabControl}"
|
||||||
<ComboBox
|
TabStripPlacement="Left">
|
||||||
x:Name="cmbMoveToGroup"
|
<TabItem x:Name="tabProfiles2">
|
||||||
Width="200"
|
<TabItem.Header>
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
|
<StackPanel>
|
||||||
DisplayMemberPath="remarks"
|
<materialDesign:PackIcon
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
Width="24"
|
||||||
Style="{StaticResource MaterialDesignFilledComboBox}" />
|
Height="24"
|
||||||
</DockPanel>
|
HorizontalAlignment="Center"
|
||||||
</MenuItem.Header>
|
Kind="Server" />
|
||||||
</MenuItem>
|
<TextBlock
|
||||||
</MenuItem>
|
HorizontalAlignment="Center"
|
||||||
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
<MenuItem
|
Text="{x:Static resx:ResUI.menuServers}" />
|
||||||
x:Name="menuMoveTop"
|
</StackPanel>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
</TabItem.Header>
|
||||||
Header="{x:Static resx:ResUI.menuMoveTop}" />
|
</TabItem>
|
||||||
<MenuItem
|
<TabItem x:Name="tabMsgView2">
|
||||||
x:Name="menuMoveUp"
|
<TabItem.Header>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<StackPanel>
|
||||||
Header="{x:Static resx:ResUI.menuMoveUp}" />
|
<materialDesign:PackIcon
|
||||||
<MenuItem
|
Width="24"
|
||||||
x:Name="menuMoveDown"
|
Height="24"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
HorizontalAlignment="Center"
|
||||||
Header="{x:Static resx:ResUI.menuMoveDown}" />
|
Kind="MessageTextOutline" />
|
||||||
<MenuItem
|
<TextBlock
|
||||||
x:Name="menuMoveBottom"
|
HorizontalAlignment="Center"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Header="{x:Static resx:ResUI.menuMoveBottom}" />
|
Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||||
</MenuItem>
|
</StackPanel>
|
||||||
<MenuItem
|
</TabItem.Header>
|
||||||
x:Name="menuSelectAll"
|
</TabItem>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<TabItem x:Name="tabClashProxies2">
|
||||||
Click="menuSelectAll_Click"
|
<TabItem.Header>
|
||||||
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
<StackPanel>
|
||||||
<Separator />
|
<materialDesign:PackIcon
|
||||||
<MenuItem
|
Width="24"
|
||||||
x:Name="menuExport2ClientConfig"
|
Height="24"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
HorizontalAlignment="Center"
|
||||||
Header="{x:Static resx:ResUI.menuExport2ClientConfig}" />
|
Kind="ArrowDecisionOutline" />
|
||||||
<MenuItem
|
<TextBlock
|
||||||
x:Name="menuExport2ShareUrl"
|
HorizontalAlignment="Center"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Header="{x:Static resx:ResUI.menuExport2ShareUrl}" />
|
Text="{x:Static resx:ResUI.TbProxies}" />
|
||||||
<MenuItem
|
</StackPanel>
|
||||||
x:Name="menuExport2SubContent"
|
</TabItem.Header>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
</TabItem>
|
||||||
Header="{x:Static resx:ResUI.menuExport2SubContent}" />
|
<TabItem x:Name="tabClashConnections2">
|
||||||
</ContextMenu>
|
<TabItem.Header>
|
||||||
</DataGrid.ContextMenu>
|
<StackPanel>
|
||||||
<DataGrid.Resources>
|
<materialDesign:PackIcon
|
||||||
<Style BasedOn="{StaticResource MaterialDesignDataGridRow}" TargetType="DataGridRow">
|
Width="24"
|
||||||
<EventSetter Event="MouseDoubleClick" Handler="LstProfiles_MouseDoubleClick" />
|
Height="24"
|
||||||
</Style>
|
HorizontalAlignment="Center"
|
||||||
<Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
|
Kind="LanConnect" />
|
||||||
<EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" />
|
<TextBlock
|
||||||
</Style>
|
HorizontalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
|
Text="{x:Static resx:ResUI.TbConnections}" />
|
||||||
<Style.Triggers>
|
</StackPanel>
|
||||||
<DataTrigger Binding="{Binding isActive}" Value="True">
|
</TabItem.Header>
|
||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
</TabItem>
|
||||||
<Setter Property="Foreground" Value="Black" />
|
</TabControl>
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
</Grid>
|
||||||
</DataTrigger>
|
<materialDesign:Snackbar x:Name="MainSnackbar" MessageQueue="{materialDesign:MessageQueue}" />
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</DataGrid.Resources>
|
|
||||||
<DataGrid.Columns>
|
|
||||||
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="80"
|
|
||||||
Binding="{Binding configType}"
|
|
||||||
ExName="configType"
|
|
||||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="150"
|
|
||||||
Binding="{Binding remarks}"
|
|
||||||
ExName="remarks"
|
|
||||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="120"
|
|
||||||
Binding="{Binding address}"
|
|
||||||
ExName="address"
|
|
||||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="60"
|
|
||||||
Binding="{Binding port}"
|
|
||||||
ExName="port"
|
|
||||||
Header="{x:Static resx:ResUI.LvPort}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding network}"
|
|
||||||
ExName="network"
|
|
||||||
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding streamSecurity}"
|
|
||||||
ExName="streamSecurity"
|
|
||||||
Header="{x:Static resx:ResUI.LvTLS}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding subRemarks}"
|
|
||||||
ExName="subRemarks"
|
|
||||||
Header="{x:Static resx:ResUI.LvSubscription}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding delayVal}"
|
|
||||||
ExName="delayVal"
|
|
||||||
Header="{x:Static resx:ResUI.LvTestDelay}">
|
|
||||||
<DataGridTextColumn.ElementStyle>
|
|
||||||
<Style TargetType="{x:Type TextBlock}">
|
|
||||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
|
||||||
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
|
|
||||||
</Style>
|
|
||||||
</DataGridTextColumn.ElementStyle>
|
|
||||||
</base:MyDGTextColumn>
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding speedVal}"
|
|
||||||
ExName="speedVal"
|
|
||||||
Header="{x:Static resx:ResUI.LvTestSpeed}">
|
|
||||||
<DataGridTextColumn.ElementStyle>
|
|
||||||
<Style TargetType="{x:Type TextBlock}">
|
|
||||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
|
||||||
</Style>
|
|
||||||
</DataGridTextColumn.ElementStyle>
|
|
||||||
</base:MyDGTextColumn>
|
|
||||||
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
x:Name="colTodayUp"
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding todayUp}"
|
|
||||||
ExName="todayUp"
|
|
||||||
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
x:Name="colTodayDown"
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding todayDown}"
|
|
||||||
ExName="todayDown"
|
|
||||||
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
x:Name="colTotalUp"
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding totalUp}"
|
|
||||||
ExName="totalUp"
|
|
||||||
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
|
|
||||||
<base:MyDGTextColumn
|
|
||||||
x:Name="colTotalDown"
|
|
||||||
Width="100"
|
|
||||||
Binding="{Binding totalDown}"
|
|
||||||
ExName="totalDown"
|
|
||||||
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
</DockPanel>
|
|
||||||
|
|
||||||
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" />
|
|
||||||
<local:MsgView Grid.Row="2" />
|
|
||||||
<materialDesign:Snackbar
|
|
||||||
x:Name="MainSnackbar"
|
|
||||||
Grid.Row="2"
|
|
||||||
MessageQueue="{materialDesign:MessageQueue}" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<tb:TaskbarIcon
|
<tb:TaskbarIcon
|
||||||
|
|||||||
@@ -2,20 +2,16 @@
|
|||||||
using Splat;
|
using Splat;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Controls.Primitives;
|
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Handler;
|
using v2rayN.Handler;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
using v2rayN.ViewModels;
|
using v2rayN.ViewModels;
|
||||||
using Point = System.Windows.Point;
|
|
||||||
|
|
||||||
namespace v2rayN.Views
|
namespace v2rayN.Views
|
||||||
{
|
{
|
||||||
@@ -27,39 +23,13 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
lstGroup.MaxHeight = Math.Floor(SystemParameters.WorkArea.Height * 0.20 / 40) * 40;
|
|
||||||
|
|
||||||
_config = LazyConfig.Instance.GetConfig();
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
|
|
||||||
App.Current.SessionEnding += Current_SessionEnding;
|
App.Current.SessionEnding += Current_SessionEnding;
|
||||||
this.Closing += MainWindow_Closing;
|
this.Closing += MainWindow_Closing;
|
||||||
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
|
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
|
||||||
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
|
||||||
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
|
|
||||||
btnShowCalshUI.Click += BtnShowCalshUI_Click;
|
|
||||||
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
|
|
||||||
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
|
|
||||||
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
|
|
||||||
if (_config.uiItem.enableDragDropSort)
|
|
||||||
{
|
|
||||||
lstProfiles.AllowDrop = true;
|
|
||||||
lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown;
|
|
||||||
lstProfiles.MouseMove += LstProfiles_MouseMove;
|
|
||||||
lstProfiles.DragEnter += LstProfiles_DragEnter;
|
|
||||||
lstProfiles.Drop += LstProfiles_Drop;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler);
|
ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue, null);
|
||||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
|
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
|
||||||
|
|
||||||
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++)
|
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++)
|
||||||
@@ -74,15 +44,6 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
this.OneWayBind(ViewModel, vm => vm.ProfileItems, v => v.lstProfiles.ItemsSource).DisposeWith(disposables);
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedProfile, v => v.lstProfiles.SelectedItem).DisposeWith(disposables);
|
|
||||||
|
|
||||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstGroup.ItemsSource).DisposeWith(disposables);
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables);
|
|
||||||
this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.btnAddSub).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.EditSubCmd, v => v.btnEditSub).DisposeWith(disposables);
|
|
||||||
|
|
||||||
//servers
|
//servers
|
||||||
this.BindCommand(ViewModel, vm => vm.AddVmessServerCmd, v => v.menuAddVmessServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddVmessServerCmd, v => v.menuAddVmessServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddVlessServerCmd, v => v.menuAddVlessServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddVlessServerCmd, v => v.menuAddVlessServer).DisposeWith(disposables);
|
||||||
@@ -97,35 +58,6 @@ namespace v2rayN.Views
|
|||||||
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
||||||
|
|
||||||
//servers delete
|
|
||||||
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.menuEditServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.RemoveServerCmd, v => v.menuRemoveServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.RemoveDuplicateServerCmd, v => v.menuRemoveDuplicateServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables);
|
|
||||||
|
|
||||||
//servers move
|
|
||||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables);
|
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
|
||||||
|
|
||||||
//servers ping
|
|
||||||
this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
|
||||||
|
|
||||||
//servers export
|
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ShareUrlCmd, v => v.menuExport2ShareUrl).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2SubContentCmd, v => v.menuExport2SubContent).DisposeWith(disposables);
|
|
||||||
|
|
||||||
//sub
|
//sub
|
||||||
this.BindCommand(ViewModel, vm => vm.SubSettingCmd, v => v.menuSubSetting).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SubSettingCmd, v => v.menuSubSetting).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate).DisposeWith(disposables);
|
||||||
@@ -183,7 +115,6 @@ namespace v2rayN.Views
|
|||||||
this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables);
|
||||||
this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables);
|
||||||
this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables);
|
||||||
//this.OneWayBind(ViewModel, vm => vm.BlShowTrayTip, v => v.borTrayToolTip.Visibility).DisposeWith(disposables);
|
|
||||||
|
|
||||||
//status bar
|
//status bar
|
||||||
this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables);
|
||||||
@@ -206,63 +137,68 @@ namespace v2rayN.Views
|
|||||||
this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables);
|
||||||
this.OneWayBind(ViewModel, vm => vm.ShowCalshUI, v => v.btnShowCalshUI.Visibility).DisposeWith(disposables);
|
|
||||||
this.OneWayBind(ViewModel, vm => vm.ShowCalshUI, v => v.tabClashUI.Visibility).DisposeWith(disposables);
|
|
||||||
});
|
|
||||||
|
|
||||||
RestoreUI();
|
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
AddHelpMenuItem();
|
{
|
||||||
|
gridMain.Visibility = Visibility.Visible;
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies.Visibility).DisposeWith(disposables);
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections.Visibility).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TabMainSelectedIndex, v => v.tabMain.SelectedIndex).DisposeWith(disposables);
|
||||||
|
}
|
||||||
|
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
|
{
|
||||||
|
gridMain1.Visibility = Visibility.Visible;
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies1.Visibility).DisposeWith(disposables);
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections1.Visibility).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TabMainSelectedIndex, v => v.tabMain1.SelectedIndex).DisposeWith(disposables);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gridMain2.Visibility = Visibility.Visible;
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies2.Visibility).DisposeWith(disposables);
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections2.Visibility).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TabMainSelectedIndex, v => v.tabMain2.SelectedIndex).DisposeWith(disposables);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var IsAdministrator = Utils.IsAdministrator();
|
var IsAdministrator = Utils.IsAdministrator();
|
||||||
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||||
|
|
||||||
//if (_config.uiItem.autoHideStartup)
|
|
||||||
//{
|
|
||||||
// WindowState = WindowState.Minimized;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (!_config.guiItem.enableHWA)
|
if (!_config.guiItem.enableHWA)
|
||||||
{
|
{
|
||||||
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
|
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
var helper = new WindowInteropHelper(this);
|
MainFormHandler.Instance.RegisterSystemColorSet(_config, this, (bool bl) => { ViewModel?.ModifyTheme(bl); });
|
||||||
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
|
|
||||||
hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
|
|
||||||
{
|
|
||||||
if (_config.uiItem.followSystemTheme)
|
|
||||||
{
|
|
||||||
const int WM_SETTINGCHANGE = 0x001A;
|
|
||||||
if (msg == WM_SETTINGCHANGE)
|
|
||||||
{
|
|
||||||
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
|
|
||||||
{
|
|
||||||
ViewModel?.ModifyTheme(!Utils.IsLightTheme());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return IntPtr.Zero;
|
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
});
|
{
|
||||||
|
tabProfiles.Content ??= new ProfilesView();
|
||||||
|
tabMsgView.Content ??= new MsgView();
|
||||||
|
tabClashProxies.Content ??= new ClashProxiesView();
|
||||||
|
tabClashConnections.Content ??= new ClashConnectionsView();
|
||||||
|
}
|
||||||
|
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
|
{
|
||||||
|
tabProfiles1.Content ??= new ProfilesView();
|
||||||
|
tabMsgView1.Content ??= new MsgView();
|
||||||
|
tabClashProxies1.Content ??= new ClashProxiesView();
|
||||||
|
tabClashConnections1.Content ??= new ClashConnectionsView();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tabProfiles2.Content ??= new ProfilesView();
|
||||||
|
tabMsgView2.Content ??= new MsgView();
|
||||||
|
tabClashProxies2.Content ??= new ClashProxiesView();
|
||||||
|
tabClashConnections2.Content ??= new ClashConnectionsView();
|
||||||
|
}
|
||||||
|
|
||||||
|
RestoreUI();
|
||||||
|
AddHelpMenuItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event
|
#region Event
|
||||||
|
|
||||||
private void UpdateViewHandler(EViewAction action)
|
|
||||||
{
|
|
||||||
if (action == EViewAction.AdjustMainLvColWidth)
|
|
||||||
{
|
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
AutofitColumnWidth();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (action == EViewAction.ProfilesFocus)
|
|
||||||
{
|
|
||||||
lstProfiles.Focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MainWindow_Closing(object? sender, CancelEventArgs e)
|
private void MainWindow_Closing(object? sender, CancelEventArgs e)
|
||||||
{
|
{
|
||||||
e.Cancel = true;
|
e.Cancel = true;
|
||||||
@@ -271,6 +207,8 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
private void menuExit_Click(object sender, RoutedEventArgs e)
|
private void menuExit_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
tabProfiles = null;
|
||||||
|
|
||||||
tbNotify.Dispose();
|
tbNotify.Dispose();
|
||||||
StorageUI();
|
StorageUI();
|
||||||
ViewModel?.MyAppExit(false);
|
ViewModel?.MyAppExit(false);
|
||||||
@@ -283,45 +221,6 @@ namespace v2rayN.Views
|
|||||||
ViewModel?.MyAppExit(true);
|
ViewModel?.MyAppExit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
|
||||||
{
|
|
||||||
e.Row.Header = $" {e.Row.GetIndex() + 1}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
if (_config.uiItem.doubleClick2Activate)
|
|
||||||
{
|
|
||||||
ViewModel?.SetDefaultServer();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ViewModel?.EditServer(false, EConfigType.Custom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_ColumnHeader_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var colHeader = sender as DataGridColumnHeader;
|
|
||||||
if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var colName = ((MyDGTextColumn)colHeader.Column).ExName;
|
|
||||||
ViewModel?.SortServer(colName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void menuSelectAll_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
lstProfiles.SelectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||||
@@ -332,25 +231,9 @@ namespace v2rayN.Views
|
|||||||
ViewModel?.AddServerViaClipboard();
|
ViewModel?.AddServerViaClipboard();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Key.O:
|
|
||||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Key.R:
|
|
||||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Realping);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Key.S:
|
case Key.S:
|
||||||
ViewModel?.ScanScreenTaskAsync().ContinueWith(_ => { });
|
ViewModel?.ScanScreenTaskAsync().ContinueWith(_ => { });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Key.T:
|
|
||||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Speedtest);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Key.E:
|
|
||||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Mixedtest);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -359,60 +242,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
ViewModel?.Reload();
|
ViewModel?.Reload();
|
||||||
}
|
}
|
||||||
else if (e.Key == Key.Escape)
|
|
||||||
{
|
|
||||||
MessageBus.Current.SendMessage("true", Global.CommandStopSpeedTest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_PreviewKeyDown(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
|
||||||
{
|
|
||||||
if (e.Key == Key.A)
|
|
||||||
{
|
|
||||||
menuSelectAll_Click(null, null);
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.C)
|
|
||||||
{
|
|
||||||
ViewModel?.Export2ShareUrl();
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.D)
|
|
||||||
{
|
|
||||||
ViewModel?.EditServer(false, EConfigType.Custom);
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.F)
|
|
||||||
{
|
|
||||||
ViewModel?.ShareServer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (e.Key is Key.Enter or Key.Return)
|
|
||||||
{
|
|
||||||
ViewModel?.SetDefaultServer();
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.Delete)
|
|
||||||
{
|
|
||||||
ViewModel?.RemoveServer();
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.T)
|
|
||||||
{
|
|
||||||
ViewModel?.MoveServer(EMove.Top);
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.U)
|
|
||||||
{
|
|
||||||
ViewModel?.MoveServer(EMove.Up);
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.D)
|
|
||||||
{
|
|
||||||
ViewModel?.MoveServer(EMove.Down);
|
|
||||||
}
|
|
||||||
else if (e.Key == Key.B)
|
|
||||||
{
|
|
||||||
ViewModel?.MoveServer(EMove.Bottom);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,48 +266,6 @@ namespace v2rayN.Views
|
|||||||
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
|
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnAutofitColumnWidth_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
AutofitColumnWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
|
||||||
{
|
|
||||||
foreach (var it in lstProfiles.Columns)
|
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TxtServerFilter_PreviewKeyDown(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Key is Key.Enter or Key.Return)
|
|
||||||
{
|
|
||||||
ViewModel?.RefreshServers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool blShowClashUI = false;
|
|
||||||
|
|
||||||
private void BtnShowCalshUI_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (blShowClashUI)
|
|
||||||
{
|
|
||||||
tabClashUI.Visibility = Visibility.Hidden;
|
|
||||||
tabClashUI.Width = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tabClashUI.Visibility = Visibility.Visible;
|
|
||||||
if (tabClashUI.Content is null)
|
|
||||||
{
|
|
||||||
tabClashUI.Content = new ClashProxiesView();
|
|
||||||
}
|
|
||||||
tabClashUI.Width = this.ActualWidth * 5 / 6;
|
|
||||||
}
|
|
||||||
blShowClashUI = !blShowClashUI;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Event
|
#endregion Event
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
@@ -497,44 +284,16 @@ namespace v2rayN.Views
|
|||||||
if (Height > maxHeight) Height = maxHeight;
|
if (Height > maxHeight) Height = maxHeight;
|
||||||
if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0)
|
if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0)
|
||||||
{
|
{
|
||||||
gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
|
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
|
|
||||||
}
|
|
||||||
|
|
||||||
var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList();
|
|
||||||
var displayIndex = 0;
|
|
||||||
foreach (var item in lvColumnItem)
|
|
||||||
{
|
|
||||||
foreach (MyDGTextColumn item2 in lstProfiles.Columns)
|
|
||||||
{
|
{
|
||||||
if (item2.ExName == item.Name)
|
gridMain.ColumnDefinitions[0].Width = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
|
||||||
{
|
gridMain.ColumnDefinitions[2].Width = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
|
||||||
if (item.Width < 0)
|
}
|
||||||
{
|
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
item2.Visibility = Visibility.Hidden;
|
{
|
||||||
}
|
gridMain1.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
|
||||||
else
|
gridMain1.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
|
||||||
{
|
|
||||||
item2.Width = item.Width;
|
|
||||||
item2.DisplayIndex = displayIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!_config.guiItem.enableStatistics)
|
|
||||||
{
|
|
||||||
colTodayUp.Visibility =
|
|
||||||
colTodayDown.Visibility =
|
|
||||||
colTotalUp.Visibility =
|
|
||||||
colTotalDown.Visibility = Visibility.Hidden;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
colTodayUp.Visibility =
|
|
||||||
colTodayDown.Visibility =
|
|
||||||
colTotalUp.Visibility =
|
|
||||||
colTotalDown.Visibility = Visibility.Visible;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,21 +302,16 @@ namespace v2rayN.Views
|
|||||||
_config.uiItem.mainWidth = Utils.ToInt(this.Width);
|
_config.uiItem.mainWidth = Utils.ToInt(this.Width);
|
||||||
_config.uiItem.mainHeight = Utils.ToInt(this.Height);
|
_config.uiItem.mainHeight = Utils.ToInt(this.Height);
|
||||||
|
|
||||||
List<ColumnItem> lvColumnItem = new();
|
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||||
for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
|
||||||
{
|
{
|
||||||
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
|
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
||||||
lvColumnItem.Add(new()
|
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
|
||||||
{
|
}
|
||||||
Name = item2.ExName,
|
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||||
Width = item2.Visibility == Visibility.Visible ? Utils.ToInt(item2.ActualWidth) : -1,
|
{
|
||||||
Index = item2.DisplayIndex
|
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
||||||
});
|
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
||||||
}
|
}
|
||||||
_config.uiItem.mainColumnItem = lvColumnItem;
|
|
||||||
|
|
||||||
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1);
|
|
||||||
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddHelpMenuItem()
|
private void AddHelpMenuItem()
|
||||||
@@ -588,97 +342,5 @@ namespace v2rayN.Views
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
#region Drag and Drop
|
|
||||||
|
|
||||||
private Point startPoint = new();
|
|
||||||
private int startIndex = -1;
|
|
||||||
private string formatData = "ProfileItemModel";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Helper to search up the VisualTree
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="current"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static T? FindAncestor<T>(DependencyObject current) where T : DependencyObject
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (current is T)
|
|
||||||
{
|
|
||||||
return (T)current;
|
|
||||||
}
|
|
||||||
current = VisualTreeHelper.GetParent(current);
|
|
||||||
}
|
|
||||||
while (current != null);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
// Get current mouse position
|
|
||||||
startPoint = e.GetPosition(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_MouseMove(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
// Get the current mouse position
|
|
||||||
Point mousePos = e.GetPosition(null);
|
|
||||||
Vector diff = startPoint - mousePos;
|
|
||||||
|
|
||||||
if (e.LeftButton == MouseButtonState.Pressed &&
|
|
||||||
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
|
||||||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
|
|
||||||
{
|
|
||||||
// Get the dragged Item
|
|
||||||
if (sender is not DataGrid listView) return;
|
|
||||||
var listViewItem = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
|
||||||
if (listViewItem == null) return; // Abort
|
|
||||||
// Find the data behind the ListViewItem
|
|
||||||
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
|
||||||
if (item == null) return; // Abort
|
|
||||||
// Initialize the drag & drop operation
|
|
||||||
startIndex = lstProfiles.SelectedIndex;
|
|
||||||
DataObject dragData = new(formatData, item);
|
|
||||||
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_DragEnter(object sender, DragEventArgs e)
|
|
||||||
{
|
|
||||||
if (!e.Data.GetDataPresent(formatData) || sender != e.Source)
|
|
||||||
{
|
|
||||||
e.Effects = DragDropEffects.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LstProfiles_Drop(object sender, DragEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Data.GetDataPresent(formatData) && sender == e.Source)
|
|
||||||
{
|
|
||||||
// Get the drop Item destination
|
|
||||||
if (sender is not DataGrid listView) return;
|
|
||||||
var listViewItem = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
|
||||||
if (listViewItem == null)
|
|
||||||
{
|
|
||||||
// Abort
|
|
||||||
e.Effects = DragDropEffects.None;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Find the data behind the Item
|
|
||||||
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
|
||||||
if (item == null) return;
|
|
||||||
// Move item into observable collection
|
|
||||||
// (this will be automatically reflected to lstView.ItemsSource)
|
|
||||||
e.Effects = DragDropEffects.Move;
|
|
||||||
|
|
||||||
ViewModel?.MoveServerTo(startIndex, item);
|
|
||||||
|
|
||||||
startIndex = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Drag and Drop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,15 +10,12 @@
|
|||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel Margin="2">
|
<DockPanel Margin="2">
|
||||||
<StackPanel
|
<WrapPanel
|
||||||
|
Margin="8"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
DockPanel.Dock="Top"
|
DockPanel.Dock="Top"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<TextBlock
|
|
||||||
Margin="8,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
|
||||||
Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbMsgFilter"
|
x:Name="cmbMsgFilter"
|
||||||
Width="200"
|
Width="200"
|
||||||
@@ -28,6 +25,24 @@
|
|||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}"
|
Style="{StaticResource DefComboBox}"
|
||||||
TextBoxBase.TextChanged="cmbMsgFilter_TextChanged" />
|
TextBoxBase.TextChanged="cmbMsgFilter_TextChanged" />
|
||||||
|
<Button
|
||||||
|
x:Name="btnCopy"
|
||||||
|
Width="24"
|
||||||
|
Height="24"
|
||||||
|
Margin="8,0"
|
||||||
|
Click="menuMsgViewCopyAll_Click"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ContentCopy" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
x:Name="btnClear"
|
||||||
|
Width="24"
|
||||||
|
Height="24"
|
||||||
|
Margin="8,0"
|
||||||
|
Click="menuMsgViewClear_Click"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Delete" />
|
||||||
|
</Button>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="8,0"
|
Margin="8,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@@ -48,7 +63,7 @@
|
|||||||
Margin="8,0"
|
Margin="8,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
IsChecked="True" />
|
IsChecked="True" />
|
||||||
</StackPanel>
|
</WrapPanel>
|
||||||
<TextBox
|
<TextBox
|
||||||
Name="txtMsg"
|
Name="txtMsg"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
private void DelegateAppendText(string msg)
|
private void DelegateAppendText(string msg)
|
||||||
{
|
{
|
||||||
Dispatcher.BeginInvoke(AppendText, DispatcherPriority.Send, msg);
|
Dispatcher.BeginInvoke(AppendText, DispatcherPriority.ApplicationIdle, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AppendText(string msg)
|
public void AppendText(string msg)
|
||||||
|
|||||||
@@ -528,6 +528,7 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@@ -830,6 +831,21 @@
|
|||||||
materialDesign:HintAssist.Hint="Convert Url"
|
materialDesign:HintAssist.Hint="Convert Url"
|
||||||
IsEditable="True"
|
IsEditable="True"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="21"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbMainGirdOrientation"
|
||||||
|
Grid.Row="21"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -837,19 +853,31 @@
|
|||||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsSystemproxy}">
|
<TabItem Header="{x:Static resx:ResUI.TbSettingsSystemproxy}">
|
||||||
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
<DockPanel Margin="{StaticResource SettingItemMargin}">
|
||||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Vertical">
|
<StackPanel DockPanel.Dock="Bottom" Orientation="Vertical">
|
||||||
<TextBlock
|
<StackPanel Orientation="Horizontal">
|
||||||
Grid.Row="3"
|
<TextBlock
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsAdvancedProtocol}" />
|
Text="{x:Static resx:ResUI.TbSettingsNotProxyLocalAddress}" />
|
||||||
<ComboBox
|
<ToggleButton
|
||||||
x:Name="cmbsystemProxyAdvancedProtocol"
|
x:Name="tognotProxyLocalAddress"
|
||||||
Grid.Row="4"
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
MinWidth="200"
|
HorizontalAlignment="Left" />
|
||||||
Margin="{StaticResource SettingItemMargin}"
|
</StackPanel>
|
||||||
materialDesign:HintAssist.Hint="Protocol"
|
|
||||||
Style="{StaticResource DefComboBox}" />
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsAdvancedProtocol}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbsystemProxyAdvancedProtocol"
|
||||||
|
MinWidth="400"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
materialDesign:HintAssist.Hint="Protocol"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.IO;
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using v2rayN.Enums;
|
||||||
using v2rayN.Handler;
|
using v2rayN.Handler;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
using v2rayN.ViewModels;
|
using v2rayN.ViewModels;
|
||||||
@@ -18,16 +19,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
_config = LazyConfig.Instance.GetConfig();
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
var lstFonts = GetFonts(Utils.GetFontsPath());
|
var lstFonts = GetFonts(Utils.GetFontsPath());
|
||||||
@@ -98,6 +89,10 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
cmbSubConvertUrl.Items.Add(it);
|
cmbSubConvertUrl.Items.Add(it);
|
||||||
});
|
});
|
||||||
|
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
||||||
|
{
|
||||||
|
cmbMainGirdOrientation.Items.Add(it.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
lstFonts.ForEach(it => { cmbcurrentFontFamily.Items.Add(it); });
|
lstFonts.ForEach(it => { cmbcurrentFontFamily.Items.Add(it); });
|
||||||
cmbcurrentFontFamily.Items.Add(string.Empty);
|
cmbcurrentFontFamily.Items.Add(string.Empty);
|
||||||
@@ -153,7 +148,9 @@ namespace v2rayN.Views
|
|||||||
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.EnableHWA, v => v.togEnableHWA.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableHWA, v => v.togEnableHWA.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.systemProxyExceptions, v => v.txtsystemProxyExceptions.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.systemProxyExceptions, v => v.txtsystemProxyExceptions.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
|||||||
308
v2rayN/v2rayN/Views/ProfilesView.xaml
Normal file
308
v2rayN/v2rayN/Views/ProfilesView.xaml
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
<reactiveui:ReactiveUserControl
|
||||||
|
x:Class="v2rayN.Views.ProfilesView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:base="clr-namespace:v2rayN.Base"
|
||||||
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
|
xmlns:resx="clr-namespace:v2rayN.Resx"
|
||||||
|
xmlns:vms="clr-namespace:v2rayN.ViewModels"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
x:TypeArguments="vms:ProfilesViewModel"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
||||||
|
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid>
|
||||||
|
<DockPanel>
|
||||||
|
<WrapPanel Margin="2" DockPanel.Dock="Top">
|
||||||
|
<ListBox
|
||||||
|
x:Name="lstGroup"
|
||||||
|
MaxHeight="200"
|
||||||
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
|
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
|
||||||
|
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding remarks}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
x:Name="btnEditSub"
|
||||||
|
Width="30"
|
||||||
|
Height="30"
|
||||||
|
Margin="4,0"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Edit" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
x:Name="btnAddSub"
|
||||||
|
Width="30"
|
||||||
|
Height="30"
|
||||||
|
Margin="4,0"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
x:Name="btnAutofitColumnWidth"
|
||||||
|
Width="30"
|
||||||
|
Height="30"
|
||||||
|
Margin="20,0"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||||
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
|
||||||
|
</Button>
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtServerFilter"
|
||||||
|
Width="200"
|
||||||
|
Margin="4,0"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
||||||
|
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||||
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
</WrapPanel>
|
||||||
|
<DataGrid
|
||||||
|
x:Name="lstProfiles"
|
||||||
|
materialDesign:DataGridAssist.CellPadding="2,2"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
BorderThickness="1"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
CanUserResizeRows="False"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
EnableRowVirtualization="True"
|
||||||
|
Focusable="True"
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
HeadersVisibility="All"
|
||||||
|
IsReadOnly="True"
|
||||||
|
RowHeaderWidth="40"
|
||||||
|
Style="{StaticResource DefDataGrid}">
|
||||||
|
<DataGrid.InputBindings>
|
||||||
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" />
|
||||||
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+V" />
|
||||||
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Delete" />
|
||||||
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Enter" />
|
||||||
|
</DataGrid.InputBindings>
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuEditServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuEditServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuSetDefaultServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSetDefaultServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRemoveServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRemoveServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRemoveDuplicateServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuCopyServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuCopyServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuShareServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuShareServer}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuSetDefaultMultipleServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSetDefaultMultipleServer}" />
|
||||||
|
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuSetDefaultLoadBalanceServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSetDefaultLoadBalanceServer}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMixedTestServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuTcpingServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRealPingServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuSpeedServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuSortServerResult"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveToGroup"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
||||||
|
<MenuItem Height="Auto">
|
||||||
|
<MenuItem.Header>
|
||||||
|
<DockPanel>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbMoveToGroup"
|
||||||
|
Width="200"
|
||||||
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
|
||||||
|
DisplayMemberPath="remarks"
|
||||||
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
|
Style="{StaticResource MaterialDesignFilledComboBox}" />
|
||||||
|
</DockPanel>
|
||||||
|
</MenuItem.Header>
|
||||||
|
</MenuItem>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveTop"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveTop}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveUp"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveUp}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveDown"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveDown}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveBottom"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveBottom}" />
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuSelectAll"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Click="menuSelectAll_Click"
|
||||||
|
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuExport2ClientConfig"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuExport2ClientConfig}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuExport2ShareUrl"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuExport2ShareUrl}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<Style BasedOn="{StaticResource MaterialDesignDataGridRow}" TargetType="DataGridRow">
|
||||||
|
<EventSetter Event="MouseDoubleClick" Handler="LstProfiles_MouseDoubleClick" />
|
||||||
|
</Style>
|
||||||
|
<Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
|
||||||
|
<EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding isActive}" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
|
<Setter Property="Foreground" Value="Black" />
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="80"
|
||||||
|
Binding="{Binding configType}"
|
||||||
|
ExName="configType"
|
||||||
|
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="150"
|
||||||
|
Binding="{Binding remarks}"
|
||||||
|
ExName="remarks"
|
||||||
|
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="120"
|
||||||
|
Binding="{Binding address}"
|
||||||
|
ExName="address"
|
||||||
|
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="60"
|
||||||
|
Binding="{Binding port}"
|
||||||
|
ExName="port"
|
||||||
|
Header="{x:Static resx:ResUI.LvPort}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding network}"
|
||||||
|
ExName="network"
|
||||||
|
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding streamSecurity}"
|
||||||
|
ExName="streamSecurity"
|
||||||
|
Header="{x:Static resx:ResUI.LvTLS}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding subRemarks}"
|
||||||
|
ExName="subRemarks"
|
||||||
|
Header="{x:Static resx:ResUI.LvSubscription}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding delayVal}"
|
||||||
|
ExName="delayVal"
|
||||||
|
Header="{x:Static resx:ResUI.LvTestDelay}">
|
||||||
|
<DataGridTextColumn.ElementStyle>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
|
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
|
||||||
|
</Style>
|
||||||
|
</DataGridTextColumn.ElementStyle>
|
||||||
|
</base:MyDGTextColumn>
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding speedVal}"
|
||||||
|
ExName="speedVal"
|
||||||
|
Header="{x:Static resx:ResUI.LvTestSpeed}">
|
||||||
|
<DataGridTextColumn.ElementStyle>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
|
</Style>
|
||||||
|
</DataGridTextColumn.ElementStyle>
|
||||||
|
</base:MyDGTextColumn>
|
||||||
|
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
x:Name="colTodayUp"
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding todayUp}"
|
||||||
|
ExName="todayUp"
|
||||||
|
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
x:Name="colTodayDown"
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding todayDown}"
|
||||||
|
ExName="todayDown"
|
||||||
|
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
x:Name="colTotalUp"
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding totalUp}"
|
||||||
|
ExName="totalUp"
|
||||||
|
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
|
||||||
|
<base:MyDGTextColumn
|
||||||
|
x:Name="colTotalDown"
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding totalDown}"
|
||||||
|
ExName="totalDown"
|
||||||
|
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</DockPanel>
|
||||||
|
</Grid>
|
||||||
|
</reactiveui:ReactiveUserControl>
|
||||||
400
v2rayN/v2rayN/Views/ProfilesView.xaml.cs
Normal file
400
v2rayN/v2rayN/Views/ProfilesView.xaml.cs
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
using ReactiveUI;
|
||||||
|
using Splat;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Controls.Primitives;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using v2rayN.Base;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Handler;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.ViewModels;
|
||||||
|
using Point = System.Windows.Point;
|
||||||
|
|
||||||
|
namespace v2rayN.Views
|
||||||
|
{
|
||||||
|
public partial class ProfilesView
|
||||||
|
{
|
||||||
|
private static Config _config;
|
||||||
|
|
||||||
|
public ProfilesView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
lstGroup.MaxHeight = Math.Floor(SystemParameters.WorkArea.Height * 0.20 / 40) * 40;
|
||||||
|
|
||||||
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
|
|
||||||
|
Application.Current.Exit += Current_Exit;
|
||||||
|
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
||||||
|
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
|
||||||
|
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
|
||||||
|
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
|
||||||
|
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
|
||||||
|
if (_config.uiItem.enableDragDropSort)
|
||||||
|
{
|
||||||
|
lstProfiles.AllowDrop = true;
|
||||||
|
lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown;
|
||||||
|
lstProfiles.MouseMove += LstProfiles_MouseMove;
|
||||||
|
lstProfiles.DragEnter += LstProfiles_DragEnter;
|
||||||
|
lstProfiles.Drop += LstProfiles_Drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewModel = new ProfilesViewModel(UpdateViewHandler);
|
||||||
|
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ProfilesViewModel));
|
||||||
|
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ProfileItems, v => v.lstProfiles.ItemsSource).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedProfile, v => v.lstProfiles.SelectedItem).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstGroup.ItemsSource).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.btnAddSub).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.EditSubCmd, v => v.btnEditSub).DisposeWith(disposables);
|
||||||
|
|
||||||
|
//servers delete
|
||||||
|
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.menuEditServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RemoveServerCmd, v => v.menuRemoveServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RemoveDuplicateServerCmd, v => v.menuRemoveDuplicateServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerCmd, v => v.menuSetDefaultMultipleServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.SetDefaultLoadBalanceServerCmd, v => v.menuSetDefaultLoadBalanceServer).DisposeWith(disposables);
|
||||||
|
|
||||||
|
//servers move
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||||
|
|
||||||
|
//servers ping
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
||||||
|
|
||||||
|
//servers export
|
||||||
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.Export2ShareUrlCmd, v => v.menuExport2ShareUrl).DisposeWith(disposables);
|
||||||
|
});
|
||||||
|
|
||||||
|
RestoreUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Event
|
||||||
|
|
||||||
|
private void Current_Exit(object sender, ExitEventArgs e)
|
||||||
|
{
|
||||||
|
StorageUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateViewHandler(EViewAction action)
|
||||||
|
{
|
||||||
|
if (action == EViewAction.AdjustMainLvColWidth)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
AutofitColumnWidth();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (action == EViewAction.ProfilesFocus)
|
||||||
|
{
|
||||||
|
lstProfiles.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
||||||
|
{
|
||||||
|
e.Row.Header = $" {e.Row.GetIndex() + 1}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (_config.uiItem.doubleClick2Activate)
|
||||||
|
{
|
||||||
|
ViewModel?.SetDefaultServer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ViewModel?.EditServer(false, EConfigType.Custom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_ColumnHeader_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var colHeader = sender as DataGridColumnHeader;
|
||||||
|
if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var colName = ((MyDGTextColumn)colHeader.Column).ExName;
|
||||||
|
ViewModel?.SortServer(colName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void menuSelectAll_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
lstProfiles.SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||||
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.A:
|
||||||
|
menuSelectAll_Click(null, null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.C:
|
||||||
|
ViewModel?.Export2ShareUrl();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.D:
|
||||||
|
ViewModel?.EditServer(false, EConfigType.Custom);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.F:
|
||||||
|
ViewModel?.ShareServer();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.O:
|
||||||
|
ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.R:
|
||||||
|
ViewModel?.ServerSpeedtest(ESpeedActionType.Realping);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.T:
|
||||||
|
ViewModel?.ServerSpeedtest(ESpeedActionType.Speedtest);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.E:
|
||||||
|
ViewModel?.ServerSpeedtest(ESpeedActionType.Mixedtest);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (e.Key is Key.Enter or Key.Return)
|
||||||
|
{
|
||||||
|
ViewModel?.SetDefaultServer();
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.Delete)
|
||||||
|
{
|
||||||
|
ViewModel?.RemoveServer();
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.T)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Top);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.U)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Up);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.D)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Down);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.B)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Bottom);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.Escape)
|
||||||
|
{
|
||||||
|
MessageBus.Current.SendMessage("true", Global.CommandStopSpeedTest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BtnAutofitColumnWidth_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
AutofitColumnWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AutofitColumnWidth()
|
||||||
|
{
|
||||||
|
foreach (var it in lstProfiles.Columns)
|
||||||
|
{
|
||||||
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TxtServerFilter_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key is Key.Enter or Key.Return)
|
||||||
|
{
|
||||||
|
ViewModel?.RefreshServers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Event
|
||||||
|
|
||||||
|
#region UI
|
||||||
|
|
||||||
|
private void RestoreUI()
|
||||||
|
{
|
||||||
|
var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList();
|
||||||
|
var displayIndex = 0;
|
||||||
|
foreach (var item in lvColumnItem)
|
||||||
|
{
|
||||||
|
foreach (MyDGTextColumn item2 in lstProfiles.Columns)
|
||||||
|
{
|
||||||
|
if (item2.ExName == item.Name)
|
||||||
|
{
|
||||||
|
if (item.Width < 0)
|
||||||
|
{
|
||||||
|
item2.Visibility = Visibility.Hidden;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item2.Width = item.Width;
|
||||||
|
item2.DisplayIndex = displayIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_config.guiItem.enableStatistics)
|
||||||
|
{
|
||||||
|
colTodayUp.Visibility =
|
||||||
|
colTodayDown.Visibility =
|
||||||
|
colTotalUp.Visibility =
|
||||||
|
colTotalDown.Visibility = Visibility.Hidden;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
colTodayUp.Visibility =
|
||||||
|
colTodayDown.Visibility =
|
||||||
|
colTotalUp.Visibility =
|
||||||
|
colTotalDown.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StorageUI()
|
||||||
|
{
|
||||||
|
List<ColumnItem> lvColumnItem = new();
|
||||||
|
for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
||||||
|
{
|
||||||
|
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
|
||||||
|
lvColumnItem.Add(new()
|
||||||
|
{
|
||||||
|
Name = item2.ExName,
|
||||||
|
Width = item2.Visibility == Visibility.Visible ? Utils.ToInt(item2.ActualWidth) : -1,
|
||||||
|
Index = item2.DisplayIndex
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_config.uiItem.mainColumnItem = lvColumnItem;
|
||||||
|
ConfigHandler.SaveConfig(_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion UI
|
||||||
|
|
||||||
|
#region Drag and Drop
|
||||||
|
|
||||||
|
private Point startPoint = new();
|
||||||
|
private int startIndex = -1;
|
||||||
|
private string formatData = "ProfileItemModel";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to search up the VisualTree
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="current"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static T? FindAncestor<T>(DependencyObject current) where T : DependencyObject
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (current is T)
|
||||||
|
{
|
||||||
|
return (T)current;
|
||||||
|
}
|
||||||
|
current = VisualTreeHelper.GetParent(current);
|
||||||
|
}
|
||||||
|
while (current != null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
// Get current mouse position
|
||||||
|
startPoint = e.GetPosition(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_MouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
// Get the current mouse position
|
||||||
|
Point mousePos = e.GetPosition(null);
|
||||||
|
Vector diff = startPoint - mousePos;
|
||||||
|
|
||||||
|
if (e.LeftButton == MouseButtonState.Pressed &&
|
||||||
|
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
||||||
|
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
|
||||||
|
{
|
||||||
|
// Get the dragged Item
|
||||||
|
if (sender is not DataGrid listView) return;
|
||||||
|
var listViewItem = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
||||||
|
if (listViewItem == null) return; // Abort
|
||||||
|
// Find the data behind the ListViewItem
|
||||||
|
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||||
|
if (item == null) return; // Abort
|
||||||
|
// Initialize the drag & drop operation
|
||||||
|
startIndex = lstProfiles.SelectedIndex;
|
||||||
|
DataObject dragData = new(formatData, item);
|
||||||
|
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_DragEnter(object sender, DragEventArgs e)
|
||||||
|
{
|
||||||
|
if (!e.Data.GetDataPresent(formatData) || sender != e.Source)
|
||||||
|
{
|
||||||
|
e.Effects = DragDropEffects.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LstProfiles_Drop(object sender, DragEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Data.GetDataPresent(formatData) && sender == e.Source)
|
||||||
|
{
|
||||||
|
// Get the drop Item destination
|
||||||
|
if (sender is not DataGrid listView) return;
|
||||||
|
var listViewItem = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
||||||
|
if (listViewItem == null)
|
||||||
|
{
|
||||||
|
// Abort
|
||||||
|
e.Effects = DragDropEffects.None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Find the data behind the Item
|
||||||
|
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||||
|
if (item == null) return;
|
||||||
|
// Move item into observable collection
|
||||||
|
// (this will be automatically reflected to lstView.ItemsSource)
|
||||||
|
e.Effects = DragDropEffects.Move;
|
||||||
|
|
||||||
|
ViewModel?.MoveServerTo(startIndex, item);
|
||||||
|
|
||||||
|
startIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Drag and Drop
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<reactiveui:ReactiveWindow
|
<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:conv="clr-namespace:v2rayN.Converters"
|
|
||||||
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:reactiveui="http://reactiveui.net"
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
xmlns:resx="clr-namespace:v2rayN.Resx"
|
xmlns:resx="clr-namespace:v2rayN.Resx"
|
||||||
xmlns:vms="clr-namespace:v2rayN.ViewModels"
|
xmlns:vms="clr-namespace:v2rayN.ViewModels"
|
||||||
Title="{x:Static resx:ResUI.menuRoutingRuleDetailsSetting}"
|
Title="{x:Static resx:ResUI.menuRoutingRuleDetailsSetting}"
|
||||||
|
|||||||
@@ -12,16 +12,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
this.Loaded += Window_Loaded;
|
||||||
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<reactiveui:ReactiveWindow
|
<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:conv="clr-namespace:v2rayN.Converters"
|
|
||||||
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:reactiveui="http://reactiveui.net"
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
xmlns:resx="clr-namespace:v2rayN.Resx"
|
xmlns:resx="clr-namespace:v2rayN.Resx"
|
||||||
xmlns:vms="clr-namespace:v2rayN.ViewModels"
|
xmlns:vms="clr-namespace:v2rayN.ViewModels"
|
||||||
Title="{x:Static resx:ResUI.menuRoutingRuleSetting}"
|
Title="{x:Static resx:ResUI.menuRoutingRuleSetting}"
|
||||||
|
|||||||
@@ -14,16 +14,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
this.Loaded += Window_Loaded;
|
||||||
this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
|
this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
|
||||||
|
|||||||
@@ -13,16 +13,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
this.Closing += RoutingSettingWindow_Closing;
|
this.Closing += RoutingSettingWindow_Closing;
|
||||||
this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown;
|
this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown;
|
||||||
|
|||||||
@@ -12,16 +12,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
this.Loaded += Window_Loaded;
|
this.Loaded += Window_Loaded;
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,6 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 设置窗口的尺寸不大于屏幕的尺寸
|
|
||||||
if (this.Width > SystemParameters.WorkArea.Width)
|
|
||||||
{
|
|
||||||
this.Width = SystemParameters.WorkArea.Width;
|
|
||||||
}
|
|
||||||
if (this.Height > SystemParameters.WorkArea.Height)
|
|
||||||
{
|
|
||||||
this.Height = SystemParameters.WorkArea.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
|
|
||||||
ViewModel = new SubSettingViewModel(this);
|
ViewModel = new SubSettingViewModel(this);
|
||||||
|
|||||||
@@ -10,15 +10,15 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<ApplicationIcon>v2rayN.ico</ApplicationIcon>
|
<ApplicationIcon>v2rayN.ico</ApplicationIcon>
|
||||||
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
||||||
<FileVersion>6.49</FileVersion>
|
<FileVersion>6.53</FileVersion>
|
||||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Downloader" Version="3.0.6" />
|
<PackageReference Include="Downloader" Version="3.1.2" />
|
||||||
<PackageReference Include="MaterialDesignThemes" Version="5.1.0" />
|
<PackageReference Include="MaterialDesignThemes" Version="5.1.0" />
|
||||||
<PackageReference Include="H.NotifyIcon.Wpf" Version="2.0.131" />
|
<PackageReference Include="H.NotifyIcon.Wpf" Version="2.1.0" />
|
||||||
<PackageReference Include="QRCoder.Xaml" Version="1.5.1" />
|
<PackageReference Include="QRCoder.Xaml" Version="1.6.0" />
|
||||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageReference Include="TaskScheduler" Version="2.11.0" />
|
<PackageReference Include="TaskScheduler" Version="2.11.0" />
|
||||||
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.12" />
|
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.12" />
|
||||||
@@ -26,11 +26,13 @@
|
|||||||
<PackageReference Include="ReactiveUI.Validation" Version="4.0.9" />
|
<PackageReference Include="ReactiveUI.Validation" Version="4.0.9" />
|
||||||
<PackageReference Include="ReactiveUI.WPF" Version="20.1.1" />
|
<PackageReference Include="ReactiveUI.WPF" Version="20.1.1" />
|
||||||
<PackageReference Include="Splat.NLog" Version="15.1.1" />
|
<PackageReference Include="Splat.NLog" Version="15.1.1" />
|
||||||
<PackageReference Include="YamlDotNet" Version="15.3.0" />
|
<PackageReference Include="YamlDotNet" Version="16.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AdditionalFiles Include="app.manifest" />
|
<AdditionalFiles Include="app.manifest" />
|
||||||
|
<EmbeddedResource Include="Sample\clash_mixin_yaml" />
|
||||||
|
<EmbeddedResource Include="Sample\clash_tun_yaml" />
|
||||||
<EmbeddedResource Include="Sample\SingboxSampleOutbound" />
|
<EmbeddedResource Include="Sample\SingboxSampleOutbound" />
|
||||||
<EmbeddedResource Include="Sample\SingboxSampleClientConfig">
|
<EmbeddedResource Include="Sample\SingboxSampleClientConfig">
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
|||||||
Reference in New Issue
Block a user