Compare commits

..

42 Commits
6.49 ... 6.53

Author SHA1 Message Date
2dust
6500c8d85e up 6.53 2024-07-26 11:05:53 +08:00
2dust
9866d436da Add Outbound DNS address
https://github.com/2dust/v2rayN/issues/5387
2024-07-26 11:00:07 +08:00
2dust
0f4884d9d8 Improve and refactor the code 2024-07-25 10:26:39 +08:00
2dust
5a81441351 Adjust resx 2024-07-24 20:14:07 +08:00
2dust
e8721bfb6b Default dns changed to whitelist 2024-07-24 20:01:26 +08:00
2dust
1b09d95209 Improve UI 2024-07-24 19:51:13 +08:00
Jabin Kong
35f3b5a50e 1 (#5394) 2024-07-23 20:41:00 +08:00
2dust
ff5203a561 alpn h2,h3 2024-07-23 20:33:02 +08:00
2dust
c3c1ced309 up 6.52 2024-07-21 15:15:51 +08:00
2dust
08b1c8ec83 Improve latency testing 2024-07-21 15:15:00 +08:00
NagisaEfi
1dd3ee4e0a Update English translations (#5381)
* Update ResUI.resx

* Update ResUI.resx
2024-07-21 11:48:55 +08:00
Random Guy
06d0c6517d fix: add real delay test for custom config (#5377) 2024-07-21 11:44:12 +08:00
2dust
4938ce6364 Code clean 2024-07-21 11:37:11 +08:00
2dust
25f3fc354f Add multi-server load balancing 2024-07-21 11:26:10 +08:00
2dust
ad1a1f8015 Main window layout orientation setting 2024-07-19 20:31:07 +08:00
2dust
5c070e2ca8 Improve UI 2024-07-19 10:51:14 +08:00
2dust
70ea21fca2 Improve UI 2024-07-18 19:59:46 +08:00
2dust
bc3593871b Refactor the main interface 2024-07-18 17:39:11 +08:00
2dust
355a424be2 Code clean 2024-07-18 17:31:49 +08:00
2dust
0ffa9a0cc8 Remove unused resx
Remove Batch export subscription to clipboard
2024-07-15 20:17:55 +08:00
2dust
72fecb2b9a Add clash_mode to rule 2024-07-14 20:17:48 +08:00
2dust
4e9dfe5478 Improve 2024-07-14 17:16:07 +08:00
2dust
c79e2e3ad4 Add functionality multi-server set as active
Implemented using sing-box Selector, which can be switched using the clash api
2024-07-14 16:13:28 +08:00
2dust
7c33c1c322 Add reload for ClashProxiesView 2024-07-14 14:28:45 +08:00
2dust
ea32f75925 Code clean 2024-07-14 11:00:22 +08:00
2dust
7eaed21b9a Improve 2024-07-14 10:59:36 +08:00
2dust
cfe8fcd28d up 6.51 2024-07-12 14:23:29 +08:00
2dust
9f4718af70 Code clean
Add allowInsecure to Share
2024-07-11 14:42:01 +08:00
2dust
39faccfd0b Bug fix 2024-07-10 17:32:26 +08:00
2dust
7545763dae Default domain strategy for resolving the outbound domain names -- singbox 2024-07-08 18:45:29 +08:00
2dust
c2928be35d Log messages are not displayed when in the background 2024-07-08 17:16:49 +08:00
2dust
449bb40d48 sing-box prioritizes the use of local srs 2024-07-08 14:20:41 +08:00
2dust
4caf1a1e63 Improve and refactor the code 2024-07-08 09:52:11 +08:00
2dust
01b205e6f1 Adjust information DispatcherPriority 2024-07-07 21:11:04 +08:00
2dust
160d3843a6 Bug fix 2024-07-05 15:28:28 +08:00
2dust
5efb784115 up 6.50 2024-07-05 11:18:36 +08:00
2dust
acde5b8384 Bug fix 2024-07-05 11:18:14 +08:00
2dust
373ee6586a Optimize system proxy code 2024-07-04 17:07:05 +08:00
2dust
215308c329 Change srs source
https://github.com/2dust/sing-box-rules
2024-07-04 16:27:44 +08:00
2dust
478cadba5e Bug fix 2024-06-30 20:43:06 +08:00
2dust
f4af4da791 Adjust res 2024-06-30 10:00:28 +08:00
2dust
22d4f435de Add tun and mixin functions to clash 2024-06-28 20:29:44 +08:00
76 changed files with 3386 additions and 2800 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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(

View File

@@ -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
} }
} }

View File

@@ -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);

View File

@@ -0,0 +1,9 @@
namespace v2rayN.Enums
{
public enum EGirdOrientation
{
Horizontal,
Vertical,
Tab,
}
}

View File

@@ -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" };

View File

@@ -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

View File

@@ -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;
}
}
} }
} }

View File

@@ -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;
}
} }
} }

View File

@@ -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
} }
} }

View File

@@ -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
} }
} }

View File

@@ -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);

View File

@@ -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)
{ {

View File

@@ -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)

View File

@@ -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;
} }

View File

@@ -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;
});
}
} }
} }

View File

@@ -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);

View File

@@ -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)
{ {

View File

@@ -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 )");

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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
{
}
} }
} }
} }

View File

@@ -1,6 +1,4 @@
 using static v2rayN.Models.ClashProxies;
using static v2rayN.Models.ClashProxies;
namespace v2rayN.Models namespace v2rayN.Models
{ {

View File

@@ -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; }

View File

@@ -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; }
}
} }

View File

@@ -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; }
} }
} }

View File

@@ -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:

View File

@@ -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
{ {

View File

@@ -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

View File

@@ -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>

View File

@@ -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. {&quot;servers&quot;:[]} 的本地化字符串。
/// </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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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端口+1Pac端口=socks端口+4API端口=socks端口+5</value> <value>http端口= +1Pac端口= +4*ray API端口= +5mihomo 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>

View File

@@ -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端口= +1Pac端口= +4*ray API端口= +5mihomo 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>

View 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

View File

@@ -0,0 +1,7 @@
tun:
enable: true
stack: gvisor
dns-hijack:
- 0.0.0.0:53
auto-route: true
auto-detect-interface: true

View File

@@ -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"
] ]
}, },

View File

@@ -1,4 +1,9 @@
[ [
{
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{ {
"port": "0-65535", "port": "0-65535",
"outboundTag": "proxy" "outboundTag": "proxy"

View File

@@ -6,6 +6,11 @@
"domain:example-example2.com" "domain:example-example2.com"
] ]
}, },
{
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{ {
"outboundTag": "block", "outboundTag": "block",
"domain": [ "domain": [

View File

@@ -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"
} }

View File

@@ -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"
} }

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View 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
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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}"

View File

@@ -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
{ {

View File

@@ -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"

View File

@@ -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
{ {

View File

@@ -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*" />

View File

@@ -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);

View File

@@ -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>();

View File

@@ -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

View File

@@ -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
} }
} }

View File

@@ -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"

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View 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>

View 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
}
}

View File

@@ -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}"

View File

@@ -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;

View File

@@ -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}"

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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>