Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfe8fcd28d | ||
|
|
9f4718af70 | ||
|
|
39faccfd0b | ||
|
|
7545763dae | ||
|
|
c2928be35d | ||
|
|
449bb40d48 | ||
|
|
4caf1a1e63 | ||
|
|
01b205e6f1 | ||
|
|
160d3843a6 | ||
|
|
5efb784115 | ||
|
|
acde5b8384 | ||
|
|
373ee6586a | ||
|
|
215308c329 | ||
|
|
478cadba5e | ||
|
|
f4af4da791 | ||
|
|
22d4f435de | ||
|
|
ccb8cd5c04 | ||
|
|
e963f9e349 | ||
|
|
e3c2a4b8da | ||
|
|
324f46cdad | ||
|
|
691b19b5fd | ||
|
|
63ed2311dc |
@@ -9,7 +9,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.27.1" />
|
<PackageReference Include="Google.Protobuf" Version="3.27.2" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.63.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.63.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.64.0">
|
<PackageReference Include="Grpc.Tools" Version="2.64.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<Application
|
<Application
|
||||||
x:Class="v2rayN.App"
|
x:Class="v2rayN.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
ShutdownMode="OnExplicitShutdown"
|
ShutdownMode="OnExplicitShutdown"
|
||||||
StartupUri="Views/MainWindow.xaml">
|
StartupUri="Views/MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
<system:Double x:Key="StdFontSize1">13</system:Double>
|
<system:Double x:Key="StdFontSize1">13</system:Double>
|
||||||
<system:Double x:Key="StdFontSize2">14</system:Double>
|
<system:Double x:Key="StdFontSize2">14</system:Double>
|
||||||
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
|
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
|
||||||
|
<system:Double x:Key="StdFontSize-1">11</system:Double>
|
||||||
|
|
||||||
<conv:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
<conv:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||||
<Thickness
|
<Thickness
|
||||||
@@ -68,16 +69,21 @@
|
|||||||
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
|
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
|
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
|
||||||
<Setter Property="Height" Value="20" />
|
<Setter Property="Margin" Value="2" />
|
||||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
<Setter Property="Template">
|
||||||
<Style.Triggers>
|
<Setter.Value>
|
||||||
<Trigger Property="IsSelected" Value="true">
|
<ControlTemplate TargetType="ListViewItem">
|
||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
<materialDesign:Card Name="_Card" SnapsToDevicePixels="true">
|
||||||
</Trigger>
|
<ContentPresenter />
|
||||||
<Trigger Property="IsMouseOver" Value="true">
|
</materialDesign:Card>
|
||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary}" />
|
<ControlTemplate.Triggers>
|
||||||
</Trigger>
|
<Trigger Property="IsSelected" Value="true">
|
||||||
</Style.Triggers>
|
<Setter TargetName="_Card" Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="GridViewColumnHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
|
<Style x:Key="GridViewColumnHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
|
||||||
@@ -156,6 +162,27 @@
|
|||||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||||
<Setter Property="Padding" Value="{StaticResource OutlinedTextBoxDefaultPadding}" />
|
<Setter Property="Padding" Value="{StaticResource OutlinedTextBoxDefaultPadding}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style x:Key="ListItemChip" TargetType="{x:Type materialDesign:Chip}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
|
||||||
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="ListItemTitle"
|
||||||
|
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
|
||||||
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="ListItemSubTitle"
|
||||||
|
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||||
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="ListItemSubTitle2"
|
||||||
|
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize-1}" />
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
@@ -43,6 +43,7 @@ namespace v2rayN
|
|||||||
Init();
|
Init();
|
||||||
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
||||||
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||||
|
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
Logging.ClearLogs();
|
Logging.ClearLogs();
|
||||||
|
|
||||||
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -21,6 +22,22 @@ namespace v2rayN
|
|||||||
|
|
||||||
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
|
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
|
||||||
|
|
||||||
|
public async Task<string?> TryGetAsync(string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(url))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage response = await httpClient.GetAsync(url);
|
||||||
|
return await response.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string?> GetAsync(string url)
|
public async Task<string?> GetAsync(string url)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url)) return null;
|
if (Utils.IsNullOrEmpty(url)) return null;
|
||||||
@@ -41,6 +58,21 @@ namespace v2rayN
|
|||||||
var result = await httpClient.PutAsync(url, content);
|
var result = await httpClient.PutAsync(url, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task PatchAsync(string url, Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
var myContent = JsonUtils.Serialize(headers);
|
||||||
|
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
|
||||||
|
var byteContent = new ByteArrayContent(buffer);
|
||||||
|
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
|
||||||
|
await httpClient.PatchAsync(url, byteContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAsync(string url)
|
||||||
|
{
|
||||||
|
await httpClient.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(url);
|
ArgumentNullException.ThrowIfNull(url);
|
||||||
|
|||||||
@@ -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(
|
||||||
58
v2rayN/v2rayN/Common/YamlUtils.cs
Normal file
58
v2rayN/v2rayN/Common/YamlUtils.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using YamlDotNet.Serialization;
|
||||||
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
|
namespace v2rayN.Common
|
||||||
|
{
|
||||||
|
internal class YamlUtils
|
||||||
|
{
|
||||||
|
#region YAML
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 反序列化成对象
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T FromYaml<T>(string str)
|
||||||
|
{
|
||||||
|
var deserializer = new DeserializerBuilder()
|
||||||
|
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
T obj = deserializer.Deserialize<T>(str);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("FromYaml", ex);
|
||||||
|
return deserializer.Deserialize<T>("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToYaml(Object obj)
|
||||||
|
{
|
||||||
|
var serializer = new SerializerBuilder()
|
||||||
|
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
string result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = serializer.Serialize(obj);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion YAML
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ namespace v2rayN.Converters
|
|||||||
|
|
||||||
if (delay <= 0)
|
if (delay <= 0)
|
||||||
return new SolidColorBrush(Colors.Red);
|
return new SolidColorBrush(Colors.Red);
|
||||||
if (delay <= 200)
|
if (delay <= 500)
|
||||||
return new SolidColorBrush(Colors.Green);
|
return new SolidColorBrush(Colors.Green);
|
||||||
else
|
else
|
||||||
return new SolidColorBrush(Colors.IndianRed);
|
return new SolidColorBrush(Colors.IndianRed);
|
||||||
|
|||||||
10
v2rayN/v2rayN/Enums/ERuleMode.cs
Normal file
10
v2rayN/v2rayN/Enums/ERuleMode.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace v2rayN.Enums
|
||||||
|
{
|
||||||
|
public enum ERuleMode
|
||||||
|
{
|
||||||
|
Rule = 0,
|
||||||
|
Global = 1,
|
||||||
|
Direct = 2,
|
||||||
|
Unchanged = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,14 +23,14 @@ 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 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 +44,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";
|
||||||
@@ -170,6 +172,7 @@ 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> 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", "h3,h2", "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" };
|
||||||
@@ -183,6 +186,10 @@ namespace v2rayN
|
|||||||
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
||||||
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
||||||
|
|
||||||
|
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" };
|
||||||
|
public static readonly List<string> notAllowTestType = new List<string> { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
|
||||||
|
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" };
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
218
v2rayN/v2rayN/Handler/ClashApiHandler.cs
Normal file
218
v2rayN/v2rayN/Handler/ClashApiHandler.cs
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
using v2rayN.Models;
|
||||||
|
using static v2rayN.Models.ClashProxies;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler
|
||||||
|
{
|
||||||
|
public sealed class ClashApiHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
|
||||||
|
public static ClashApiHandler Instance => instance.Value;
|
||||||
|
|
||||||
|
private Dictionary<String, ProxiesItem> _proxies;
|
||||||
|
public Dictionary<string, object> ProfileContent { get; set; }
|
||||||
|
|
||||||
|
public void SetProxies(Dictionary<String, ProxiesItem> proxies)
|
||||||
|
{
|
||||||
|
_proxies = proxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<String, ProxiesItem> GetProxies()
|
||||||
|
{
|
||||||
|
return _proxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetClashProxies(Config config, Action<ClashProxies, ClashProviders> update)
|
||||||
|
{
|
||||||
|
Task.Run(() => GetClashProxiesAsync(config, update));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetClashProxiesAsync(Config config, Action<ClashProxies, ClashProviders> update)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/proxies";
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
var clashProxies = JsonUtils.Deserialize<ClashProxies>(result);
|
||||||
|
|
||||||
|
var url2 = $"{GetApiUrl()}/providers/proxies";
|
||||||
|
var result2 = await HttpClientHelper.Instance.TryGetAsync(url2);
|
||||||
|
var clashProviders = JsonUtils.Deserialize<ClashProviders>(result2);
|
||||||
|
|
||||||
|
if (clashProxies != null || clashProviders != null)
|
||||||
|
{
|
||||||
|
update(clashProxies, clashProviders);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
|
update(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> update)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
if (blAll)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
if (GetProxies() != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
|
var proxies = GetProxies();
|
||||||
|
if (proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lstProxy = new List<ClashProxyModel>();
|
||||||
|
foreach (KeyValuePair<string, ProxiesItem> kv in proxies)
|
||||||
|
{
|
||||||
|
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lstProxy.Add(new ClashProxyModel()
|
||||||
|
{
|
||||||
|
name = kv.Value.name,
|
||||||
|
type = kv.Value.type.ToLower(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstProxy == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var urlBase = $"{GetApiUrl()}/proxies";
|
||||||
|
urlBase += @"/{0}/delay?timeout=10000&url=" + LazyConfig.Instance.GetConfig().speedTestItem.speedPingTestUrl;
|
||||||
|
|
||||||
|
List<Task> tasks = new List<Task>();
|
||||||
|
foreach (var it in lstProxy)
|
||||||
|
{
|
||||||
|
if (Global.notAllowTestType.Contains(it.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var name = it.name;
|
||||||
|
var url = string.Format(urlBase, name);
|
||||||
|
tasks.Add(Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
update(it, result);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Task.WaitAll(tasks.ToArray());
|
||||||
|
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
update(null, "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProxiesItem>? GetClashProxyGroups()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileContent = ProfileContent;
|
||||||
|
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonUtils.Deserialize<List<ProxiesItem>>(JsonUtils.Serialize(fileContent["proxy-groups"]));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GetClashProxyGroups", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashSetActiveProxy(string name, string nameNode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/proxies/{name}";
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>();
|
||||||
|
headers.Add("name", nameNode);
|
||||||
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClashConfigUpdate(Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var proxies = GetProxies();
|
||||||
|
if (proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var urlBase = $"{GetApiUrl()}/configs";
|
||||||
|
|
||||||
|
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashConfigReload(string filePath)
|
||||||
|
{
|
||||||
|
ClashConnectionClose("");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/configs?force=true";
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>();
|
||||||
|
headers.Add("path", filePath);
|
||||||
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetClashConnections(Config config, Action<ClashConnections> update)
|
||||||
|
{
|
||||||
|
Task.Run(() => GetClashConnectionsAsync(config, update));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetClashConnectionsAsync(Config config, Action<ClashConnections> update)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/connections";
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
|
||||||
|
|
||||||
|
update(clashConnections);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashConnectionClose(string id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/connections/{id}";
|
||||||
|
await HttpClientHelper.Instance.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetApiUrl()
|
||||||
|
{
|
||||||
|
return $"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -194,6 +194,7 @@ namespace v2rayN.Handler
|
|||||||
down_mbps = 100
|
down_mbps = 100
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
config.clashUIItem ??= new();
|
||||||
|
|
||||||
LazyConfig.Instance.SetConfig(config);
|
LazyConfig.Instance.SetConfig(config);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
271
v2rayN/v2rayN/Handler/CoreConfig/CoreConfigClash.cs
Normal file
271
v2rayN/v2rayN/Handler/CoreConfig/CoreConfigClash.cs
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
using System.IO;
|
||||||
|
using v2rayN.Common;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler.CoreConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Core configuration file processing class
|
||||||
|
/// </summary>
|
||||||
|
internal class CoreConfigClash
|
||||||
|
{
|
||||||
|
private Config _config;
|
||||||
|
|
||||||
|
public CoreConfigClash(Config config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成配置文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
/// <param name="fileName"></param>
|
||||||
|
/// <param name="msg"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int GenerateClientConfig(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
string tagYamlStr1 = "!<str>";
|
||||||
|
string tagYamlStr2 = "__strn__";
|
||||||
|
string tagYamlStr3 = "!!str";
|
||||||
|
var txtFile = File.ReadAllText(addressFileName);
|
||||||
|
txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2);
|
||||||
|
|
||||||
|
var fileContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
|
if (fileContent == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//port
|
||||||
|
fileContent["port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
|
//socks-port
|
||||||
|
fileContent["socks-port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
|
//log-level
|
||||||
|
fileContent["log-level"] = GetLogLevel(_config.coreBasicItem.loglevel);
|
||||||
|
|
||||||
|
//external-controller
|
||||||
|
fileContent["external-controller"] = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
||||||
|
//allow-lan
|
||||||
|
if (_config.inbound[0].allowLANConn)
|
||||||
|
{
|
||||||
|
fileContent["allow-lan"] = "true";
|
||||||
|
fileContent["bind-address"] = "*";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileContent["allow-lan"] = "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
//ipv6
|
||||||
|
fileContent["ipv6"] = _config.clashUIItem.enableIPv6;
|
||||||
|
|
||||||
|
//mode
|
||||||
|
if (!fileContent.ContainsKey("mode"))
|
||||||
|
{
|
||||||
|
fileContent["mode"] = ERuleMode.Rule.ToString().ToLower();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_config.clashUIItem.ruleMode != ERuleMode.Unchanged)
|
||||||
|
{
|
||||||
|
fileContent["mode"] = _config.clashUIItem.ruleMode.ToString().ToLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//enable tun mode
|
||||||
|
if (_config.tunModeItem.enableTun)
|
||||||
|
{
|
||||||
|
string tun = Utils.GetEmbedText(Global.ClashTunYaml);
|
||||||
|
if (!string.IsNullOrEmpty(tun))
|
||||||
|
{
|
||||||
|
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
||||||
|
if (tunContent != null)
|
||||||
|
fileContent["tun"] = tunContent["tun"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mixin
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MixinContent(fileContent, node);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
||||||
|
File.WriteAllText(fileName, txtFileNew);
|
||||||
|
//check again
|
||||||
|
if (!File.Exists(fileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration + "2";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClashApiHandler.Instance.ProfileContent = fileContent;
|
||||||
|
|
||||||
|
msg = string.Format(ResUI.SuccessfulConfiguration, $"{node.GetSummary()}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GenerateClientConfigClash", ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
|
||||||
|
{
|
||||||
|
//if (!_config.clashUIItem.enableMixinContent)
|
||||||
|
//{
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
||||||
|
|
||||||
|
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
|
if (mixinContent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var item in mixinContent)
|
||||||
|
{
|
||||||
|
if (!_config.tunModeItem.enableTun && item.Key == "tun")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Key.StartsWith("prepend-")
|
||||||
|
|| item.Key.StartsWith("append-")
|
||||||
|
|| item.Key.StartsWith("removed-"))
|
||||||
|
{
|
||||||
|
ModifyContentMerge(fileContent, item.Key, item.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileContent[item.Key] = item.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ModifyContentMerge(Dictionary<string, object> fileContent, string key, object value)
|
||||||
|
{
|
||||||
|
bool blPrepend = false;
|
||||||
|
bool blRemoved = false;
|
||||||
|
if (key.StartsWith("prepend-"))
|
||||||
|
{
|
||||||
|
blPrepend = true;
|
||||||
|
key = key.Replace("prepend-", "");
|
||||||
|
}
|
||||||
|
else if (key.StartsWith("append-"))
|
||||||
|
{
|
||||||
|
blPrepend = false;
|
||||||
|
key = key.Replace("append-", "");
|
||||||
|
}
|
||||||
|
else if (key.StartsWith("removed-"))
|
||||||
|
{
|
||||||
|
blRemoved = true;
|
||||||
|
key = key.Replace("removed-", "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blRemoved && !fileContent.ContainsKey(key))
|
||||||
|
{
|
||||||
|
fileContent.Add(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var lstOri = (List<object>)fileContent[key];
|
||||||
|
var lstValue = (List<object>)value;
|
||||||
|
|
||||||
|
if (blRemoved)
|
||||||
|
{
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.RemoveAll(t => t.ToString().StartsWith(item.ToString()));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blPrepend)
|
||||||
|
{
|
||||||
|
lstValue.Reverse();
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.Insert(0, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetLogLevel(string level)
|
||||||
|
{
|
||||||
|
if (level == "none")
|
||||||
|
{
|
||||||
|
return "silent";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,15 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
msg = ResUI.InitialConfiguration;
|
msg = ResUI.InitialConfiguration;
|
||||||
if (node.configType == EConfigType.Custom)
|
if (node.configType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
return GenerateClientCustomConfig(node, fileName, out msg);
|
if (node.coreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
||||||
|
{
|
||||||
|
var configGenClash = new CoreConfigClash(config);
|
||||||
|
return configGenClash.GenerateClientConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -825,7 +826,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
singboxConfig.dns = dns4Sbox;
|
singboxConfig.dns = dns4Sbox;
|
||||||
|
|
||||||
GenDnsDomains(singboxConfig);
|
GenDnsDomains(node, singboxConfig, item?.domainStrategy4Freedom);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -834,33 +835,44 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GenDnsDomains(SingboxConfig singboxConfig)
|
private int GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, string? strategy)
|
||||||
{
|
{
|
||||||
var dns4Sbox = singboxConfig.dns ?? new();
|
var dns4Sbox = singboxConfig.dns ?? new();
|
||||||
dns4Sbox.servers ??= [];
|
dns4Sbox.servers ??= [];
|
||||||
dns4Sbox.rules ??= [];
|
dns4Sbox.rules ??= [];
|
||||||
|
|
||||||
|
var tag = "local_local";
|
||||||
|
dns4Sbox.servers.Add(new()
|
||||||
|
{
|
||||||
|
tag = tag,
|
||||||
|
address = "223.5.5.5",
|
||||||
|
detour = Global.DirectTag,
|
||||||
|
strategy = Utils.IsNullOrEmpty(strategy) ? null : strategy,
|
||||||
|
});
|
||||||
|
|
||||||
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)
|
||||||
.ToList();
|
.ToList();
|
||||||
if (lstDomain != null && lstDomain.Count > 0)
|
if (lstDomain != null && lstDomain.Count > 0)
|
||||||
{
|
{
|
||||||
//var strategy = dns4Sbox.servers.Where(t => !Utils.IsNullOrEmpty(t.strategy)).Select(t => t.strategy).FirstOrDefault();
|
dns4Sbox.rules.Insert(0, new()
|
||||||
var tag = "local_local";
|
|
||||||
dns4Sbox.servers.Add(new()
|
|
||||||
{
|
|
||||||
tag = tag,
|
|
||||||
address = "223.5.5.5",
|
|
||||||
detour = Global.DirectTag,
|
|
||||||
//strategy = strategy
|
|
||||||
});
|
|
||||||
dns4Sbox.rules.Add(new()
|
|
||||||
{
|
{
|
||||||
server = tag,
|
server = tag,
|
||||||
domain = lstDomain
|
domain = lstDomain
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Tun2SocksAddress
|
||||||
|
if (_config.tunModeItem.enableTun && node?.configType == EConfigType.Socks && Utils.IsDomain(node?.sni))
|
||||||
|
{
|
||||||
|
dns4Sbox.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
server = tag,
|
||||||
|
domain = [node?.sni]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
singboxConfig.dns = dns4Sbox;
|
singboxConfig.dns = dns4Sbox;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -955,29 +967,41 @@ 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;
|
||||||
@@ -1120,7 +1144,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
singboxConfig.route.rules.Add(rule);
|
singboxConfig.route.rules.Add(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenDnsDomains(singboxConfig);
|
GenDnsDomains(null, singboxConfig, null);
|
||||||
//var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
|
//var dnsServer = singboxConfig.dns?.servers.FirstOrDefault();
|
||||||
//if (dnsServer != null)
|
//if (dnsServer != null)
|
||||||
//{
|
//{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
@@ -53,7 +54,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
|
|
||||||
GenMoreOutbounds(node, v2rayConfig);
|
GenMoreOutbounds(node, v2rayConfig);
|
||||||
|
|
||||||
GenDns(v2rayConfig);
|
GenDns(node, v2rayConfig);
|
||||||
|
|
||||||
GenStatistic(v2rayConfig);
|
GenStatistic(v2rayConfig);
|
||||||
|
|
||||||
@@ -748,7 +749,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GenDns(V2rayConfig v2rayConfig)
|
private int GenDns(ProfileItem node, V2rayConfig v2rayConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -800,6 +801,8 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GenDnsDomains(node, obj);
|
||||||
|
|
||||||
v2rayConfig.dns = obj;
|
v2rayConfig.dns = obj;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -809,6 +812,24 @@ namespace v2rayN.Handler.CoreConfig
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int GenDnsDomains(ProfileItem node, JsonNode dns)
|
||||||
|
{
|
||||||
|
var servers = dns["servers"];
|
||||||
|
if (servers != null)
|
||||||
|
{
|
||||||
|
if (Utils.IsDomain(node.address))
|
||||||
|
{
|
||||||
|
var dnsServer = new DnsServer4Ray()
|
||||||
|
{
|
||||||
|
address = "223.5.5.5",
|
||||||
|
domains = [node.address]
|
||||||
|
};
|
||||||
|
servers.AsArray().Insert(0, JsonUtils.SerializeToNode(dnsServer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private int GenStatistic(V2rayConfig v2rayConfig)
|
private int GenStatistic(V2rayConfig v2rayConfig)
|
||||||
{
|
{
|
||||||
if (_config.guiItem.enableStatistics)
|
if (_config.guiItem.enableStatistics)
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ namespace v2rayN.Handler
|
|||||||
coreType = preCoreType,
|
coreType = preCoreType,
|
||||||
configType = EConfigType.Socks,
|
configType = EConfigType.Socks,
|
||||||
address = Global.Loopback,
|
address = Global.Loopback,
|
||||||
|
sni = node.address, //Tun2SocksAddress
|
||||||
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
|
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,13 @@ namespace v2rayN.Handler
|
|||||||
Proxy = webProxy,
|
Proxy = webProxy,
|
||||||
UseProxy = webProxy != null
|
UseProxy = webProxy != null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var timer = Stopwatch.StartNew();
|
||||||
|
|
||||||
await client.GetAsync(url, cts.Token);
|
await client.GetAsync(url, cts.Token);
|
||||||
|
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
timer.Stop();
|
||||||
|
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
||||||
}
|
}
|
||||||
catch //(Exception ex)
|
catch //(Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ namespace v2rayN.Handler.Fmt
|
|||||||
{
|
{
|
||||||
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
||||||
}
|
}
|
||||||
|
if (item.allowInsecure.Equals("true"))
|
||||||
|
{
|
||||||
|
dicQuery.Add("allowInsecure", "1");
|
||||||
|
}
|
||||||
|
|
||||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||||
|
|
||||||
@@ -137,6 +141,7 @@ namespace v2rayN.Handler.Fmt
|
|||||||
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
||||||
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||||
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||||
|
item.allowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
||||||
|
|
||||||
item.network = query["type"] ?? nameof(ETransport.tcp);
|
item.network = query["type"] ?? nameof(ETransport.tcp);
|
||||||
switch (item.network)
|
switch (item.network)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Text.RegularExpressions;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Enums;
|
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
@@ -7,17 +6,13 @@ namespace v2rayN.Handler.Fmt
|
|||||||
{
|
{
|
||||||
internal class VmessFmt : BaseFmt
|
internal class VmessFmt : BaseFmt
|
||||||
{
|
{
|
||||||
private static readonly Regex StdVmessUserInfo = new(
|
|
||||||
@"^(?<network>[a-z]+)(\+(?<streamSecurity>[a-z]+))?:(?<id>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
public static ProfileItem? Resolve(string str, out string msg)
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
ProfileItem? item;
|
ProfileItem? item;
|
||||||
int indexSplit = str.IndexOf("?");
|
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
||||||
if (indexSplit > 0)
|
|
||||||
{
|
{
|
||||||
item = ResolveStdVmess(str) ?? ResolveVmess4Kitsunebi(str);
|
item = ResolveStdVmess(str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -107,7 +102,7 @@ namespace v2rayN.Handler.Fmt
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProfileItem? ResolveStdVmess(string result)
|
public static ProfileItem? ResolveStdVmess(string str)
|
||||||
{
|
{
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
@@ -115,113 +110,15 @@ namespace v2rayN.Handler.Fmt
|
|||||||
security = "auto"
|
security = "auto"
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri u = new(result);
|
Uri url = new(str);
|
||||||
|
|
||||||
item.address = u.IdnHost;
|
item.address = url.IdnHost;
|
||||||
item.port = u.Port;
|
item.port = url.Port;
|
||||||
item.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
var query = Utils.ParseQueryString(u.Query);
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var m = StdVmessUserInfo.Match(u.UserInfo);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
if (!m.Success) return null;
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
item.id = m.Groups["id"].Value;
|
|
||||||
|
|
||||||
if (m.Groups["streamSecurity"].Success)
|
|
||||||
{
|
|
||||||
item.streamSecurity = m.Groups["streamSecurity"].Value;
|
|
||||||
}
|
|
||||||
switch (item.streamSecurity)
|
|
||||||
{
|
|
||||||
case Global.StreamSecurity:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
|
||||||
return null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.network = m.Groups["network"].Value;
|
|
||||||
switch (item.network)
|
|
||||||
{
|
|
||||||
case nameof(ETransport.tcp):
|
|
||||||
string t1 = query["type"] ?? Global.None;
|
|
||||||
item.headerType = t1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.kcp):
|
|
||||||
item.headerType = query["type"] ?? Global.None;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.ws):
|
|
||||||
case nameof(ETransport.httpupgrade):
|
|
||||||
case nameof(ETransport.splithttp):
|
|
||||||
string p1 = query["path"] ?? "/";
|
|
||||||
string h1 = query["host"] ?? "";
|
|
||||||
item.requestHost = Utils.UrlDecode(h1);
|
|
||||||
item.path = p1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.http):
|
|
||||||
case nameof(ETransport.h2):
|
|
||||||
item.network = nameof(ETransport.h2);
|
|
||||||
string p2 = query["path"] ?? "/";
|
|
||||||
string h2 = query["host"] ?? "";
|
|
||||||
item.requestHost = Utils.UrlDecode(h2);
|
|
||||||
item.path = p2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case nameof(ETransport.quic):
|
|
||||||
string s = query["security"] ?? Global.None;
|
|
||||||
string k = query["key"] ?? "";
|
|
||||||
string t3 = query["type"] ?? Global.None;
|
|
||||||
item.headerType = t3;
|
|
||||||
item.requestHost = Utils.UrlDecode(s);
|
|
||||||
item.path = k;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProfileItem? ResolveVmess4Kitsunebi(string result)
|
|
||||||
{
|
|
||||||
ProfileItem item = new()
|
|
||||||
{
|
|
||||||
configType = EConfigType.VMess
|
|
||||||
};
|
|
||||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
|
||||||
int indexSplit = result.IndexOf("?");
|
|
||||||
if (indexSplit > 0)
|
|
||||||
{
|
|
||||||
result = result[..indexSplit];
|
|
||||||
}
|
|
||||||
result = Utils.Base64Decode(result);
|
|
||||||
|
|
||||||
string[] arr1 = result.Split('@');
|
|
||||||
if (arr1.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
string[] arr21 = arr1[0].Split(':');
|
|
||||||
string[] arr22 = arr1[1].Split(':');
|
|
||||||
if (arr21.Length != 2 || arr22.Length != 2)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.address = arr22[0];
|
|
||||||
item.port = Utils.ToInt(arr22[1]);
|
|
||||||
item.security = arr21[0];
|
|
||||||
item.id = arr21[1];
|
|
||||||
|
|
||||||
item.network = Global.DefaultNetwork;
|
|
||||||
item.headerType = Global.None;
|
|
||||||
item.remarks = "Alien";
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -377,19 +377,18 @@ namespace v2rayN.Handler
|
|||||||
ipAddress = ipHostInfo.AddressList[0];
|
ipAddress = ipHostInfo.AddressList[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Stopwatch timer = new();
|
var timer = Stopwatch.StartNew();
|
||||||
timer.Start();
|
|
||||||
|
|
||||||
IPEndPoint endPoint = new(ipAddress, port);
|
IPEndPoint endPoint = new(ipAddress, port);
|
||||||
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
|
||||||
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
|
var result = clientSocket.BeginConnect(endPoint, null, null);
|
||||||
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
||||||
throw new TimeoutException("connect timeout (5s): " + url);
|
throw new TimeoutException("connect timeout (5s): " + url);
|
||||||
clientSocket.EndConnect(result);
|
clientSocket.EndConnect(result);
|
||||||
|
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsHandler
|
internal class StatisticsHandler
|
||||||
{
|
{
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using PacLib;
|
using PacLib;
|
||||||
|
using v2rayN.Common;
|
||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
|
|
||||||
@@ -6,30 +7,7 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -65,11 +43,11 @@ namespace v2rayN.Handler
|
|||||||
.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 +56,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 +73,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
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
v2rayN/v2rayN/Models/ClashConnectionModel.cs
Normal file
17
v2rayN/v2rayN/Models/ClashConnectionModel.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashConnectionModel
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string network { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string host { get; set; }
|
||||||
|
public ulong upload { get; set; }
|
||||||
|
public ulong download { get; set; }
|
||||||
|
public string uploadTraffic { get; set; }
|
||||||
|
public string downloadTraffic { get; set; }
|
||||||
|
public double time { get; set; }
|
||||||
|
public string elapsed { get; set; }
|
||||||
|
public string chain { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
37
v2rayN/v2rayN/Models/ClashConnections.cs
Normal file
37
v2rayN/v2rayN/Models/ClashConnections.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashConnections
|
||||||
|
{
|
||||||
|
public ulong downloadTotal { get; set; }
|
||||||
|
public ulong uploadTotal { get; set; }
|
||||||
|
public List<ConnectionItem>? connections { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConnectionItem
|
||||||
|
{
|
||||||
|
public string id { get; set; } = string.Empty;
|
||||||
|
public MetadataItem metadata { get; set; }
|
||||||
|
public ulong upload { get; set; }
|
||||||
|
public ulong download { get; set; }
|
||||||
|
public DateTime start { get; set; }
|
||||||
|
public List<string>? chains { get; set; }
|
||||||
|
public string rule { get; set; }
|
||||||
|
public string rulePayload { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MetadataItem
|
||||||
|
{
|
||||||
|
public string network { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string sourceIP { get; set; }
|
||||||
|
public string destinationIP { get; set; }
|
||||||
|
public string sourcePort { get; set; }
|
||||||
|
public string destinationPort { get; set; }
|
||||||
|
public string host { get; set; }
|
||||||
|
public string nsMode { get; set; }
|
||||||
|
public object uid { get; set; }
|
||||||
|
public string process { get; set; }
|
||||||
|
public string processPath { get; set; }
|
||||||
|
public string remoteDestination { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
17
v2rayN/v2rayN/Models/ClashProviders.cs
Normal file
17
v2rayN/v2rayN/Models/ClashProviders.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using static v2rayN.Models.ClashProxies;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashProviders
|
||||||
|
{
|
||||||
|
public Dictionary<String, ProvidersItem> providers { get; set; }
|
||||||
|
|
||||||
|
public class ProvidersItem
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public ProxiesItem[] proxies { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string vehicleType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
v2rayN/v2rayN/Models/ClashProxies.cs
Normal file
24
v2rayN/v2rayN/Models/ClashProxies.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class ClashProxies
|
||||||
|
{
|
||||||
|
public Dictionary<String, ProxiesItem> proxies { get; set; }
|
||||||
|
|
||||||
|
public class ProxiesItem
|
||||||
|
{
|
||||||
|
public string[] all { get; set; }
|
||||||
|
public List<HistoryItem> history { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public bool udp { get; set; }
|
||||||
|
public string now { get; set; }
|
||||||
|
public int delay { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HistoryItem
|
||||||
|
{
|
||||||
|
public string time { get; set; }
|
||||||
|
public int delay { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
v2rayN/v2rayN/Models/ClashProxyModel.cs
Normal file
26
v2rayN/v2rayN/Models/ClashProxyModel.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class ClashProxyModel
|
||||||
|
{
|
||||||
|
[Reactive]
|
||||||
|
public string name { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string type { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string now { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public int delay { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string delayName { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool isActive { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ namespace v2rayN.Models
|
|||||||
public SpeedTestItem speedTestItem { get; set; }
|
public SpeedTestItem speedTestItem { get; set; }
|
||||||
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 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; }
|
||||||
|
|||||||
@@ -169,7 +169,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]
|
||||||
@@ -211,4 +211,19 @@ namespace v2rayN.Models
|
|||||||
public int up_mbps { get; set; }
|
public int up_mbps { get; set; }
|
||||||
public int down_mbps { get; set; }
|
public int down_mbps { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ClashUIItem
|
||||||
|
{
|
||||||
|
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 bool proxiesAutoRefresh { get; set; }
|
||||||
|
public int proxiesAutoDelayTestInterval { get; set; } = 10;
|
||||||
|
public int connectionsSorting { get; set; }
|
||||||
|
public bool connectionsAutoRefresh { get; set; }
|
||||||
|
public int connectionsRefreshInterval { get; set; } = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -370,6 +370,12 @@ namespace v2rayN.Models
|
|||||||
public List<string> servers { get; set; }
|
public List<string> servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DnsServer4Ray
|
||||||
|
{
|
||||||
|
public string? address { get; set; }
|
||||||
|
public List<string>? domains { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Routing4Ray
|
public class Routing4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -380,7 +386,7 @@ namespace v2rayN.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string domainMatcher { get; set; }
|
public string? domainMatcher { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|||||||
245
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
245
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
@@ -753,6 +753,24 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Close Connection 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuConnectionClose {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuConnectionClose", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Close All Connection 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuConnectionCloseAll {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuConnectionCloseAll", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Clone selected server 的本地化字符串。
|
/// 查找类似 Clone selected server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -879,6 +897,42 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Direct 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuModeDirect {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuModeDirect", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Global 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuModeGlobal {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuModeGlobal", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Do not change 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuModeNothing {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuModeNothing", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Rule 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuModeRule {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuModeRule", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Move to bottom (B) 的本地化字符串。
|
/// 查找类似 Move to bottom (B) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1005,6 +1059,42 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 All Node Latency Test 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuProxiesDelaytest {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuProxiesDelaytest", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Part Node Latency Test 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuProxiesDelaytestPart {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuProxiesDelaytestPart", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Refresh Proxies (F5) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuProxiesReload {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuProxiesReload", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Select active node (Enter) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuProxiesSelectActivity {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuProxiesSelectActivity", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Test servers real delay (Ctrl+R) 的本地化字符串。
|
/// 查找类似 Test servers real delay (Ctrl+R) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1176,6 +1266,15 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Rule mode 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRulemode {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRulemode", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove Rule (Delete) 的本地化字符串。
|
/// 查找类似 Remove Rule (Delete) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1996,6 +2095,15 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Connections 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbConnections {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbConnections", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Core Type 的本地化字符串。
|
/// 查找类似 Core Type 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2266,6 +2374,15 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Proxies 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbProxies {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbProxies", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 PublicKey 的本地化字符串。
|
/// 查找类似 PublicKey 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2617,6 +2734,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>
|
||||||
@@ -2915,7 +3041,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,6 +3265,123 @@ namespace v2rayN.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Sorting 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSorting {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSorting", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Chain 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingChain {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingChain", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Default 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingDefault {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingDefault", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Delay 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingDelay {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingDelay", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Download Speed 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingDownSpeed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingDownSpeed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Download Traffic 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingDownTraffic {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingDownTraffic", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Host 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingHost {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingHost", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Name 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingName {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingName", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Network 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingNetwork {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingNetwork", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Time 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingTime {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingTime", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Type 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingType {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingType", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Upload Speed 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingUpSpeed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingUpSpeed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Upload Traffic 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSortingUpTraffic {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSortingUpTraffic", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 SpiderX 的本地化字符串。
|
/// 查找类似 SpiderX 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1006,4 +1006,70 @@
|
|||||||
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
|
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSorting" xml:space="preserve">
|
||||||
|
<value>مرتب سازی</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDefault" xml:space="preserve">
|
||||||
|
<value>Default</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDelay" xml:space="preserve">
|
||||||
|
<value>تاخیر</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownSpeed" xml:space="preserve">
|
||||||
|
<value>سرعت دانلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownTraffic" xml:space="preserve">
|
||||||
|
<value>ترافیک دانلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingName" xml:space="preserve">
|
||||||
|
<value>نام</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingTime" xml:space="preserve">
|
||||||
|
<value>زمان</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpSpeed" xml:space="preserve">
|
||||||
|
<value>سرعت اپلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpTraffic" xml:space="preserve">
|
||||||
|
<value>ترافیک آپلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConnections" xml:space="preserve">
|
||||||
|
<value>اتصالات</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionClose" xml:space="preserve">
|
||||||
|
<value>بستن اتصال</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionCloseAll" xml:space="preserve">
|
||||||
|
<value>تمام اتصالات را ببندید</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxies" xml:space="preserve">
|
||||||
|
<value>پروکسی</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRulemode" xml:space="preserve">
|
||||||
|
<value>نوع قانون</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeDirect" xml:space="preserve">
|
||||||
|
<value>Direct</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeGlobal" xml:space="preserve">
|
||||||
|
<value>Global</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
|
<value>تغییر نده</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
|
<value>قانون</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
|
<value>All Node Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
|
<value>Part Node Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesReload" xml:space="preserve">
|
||||||
|
<value>Refresh Proxies (F5)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
|
<value>Select active node (Enter)</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1037,7 +1037,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>
|
||||||
@@ -1219,4 +1219,85 @@
|
|||||||
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
||||||
<value>Open the storage location</value>
|
<value>Open the storage location</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSorting" xml:space="preserve">
|
||||||
|
<value>Sorting</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingChain" xml:space="preserve">
|
||||||
|
<value>Chain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDefault" xml:space="preserve">
|
||||||
|
<value>Default</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDelay" xml:space="preserve">
|
||||||
|
<value>Delay</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownSpeed" xml:space="preserve">
|
||||||
|
<value>Download Speed</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownTraffic" xml:space="preserve">
|
||||||
|
<value>Download Traffic</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingHost" xml:space="preserve">
|
||||||
|
<value>Host</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingName" xml:space="preserve">
|
||||||
|
<value>Name</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingNetwork" xml:space="preserve">
|
||||||
|
<value>Network</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingTime" xml:space="preserve">
|
||||||
|
<value>Time</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingType" xml:space="preserve">
|
||||||
|
<value>Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpSpeed" xml:space="preserve">
|
||||||
|
<value>Upload Speed</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpTraffic" xml:space="preserve">
|
||||||
|
<value>Upload Traffic</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConnections" xml:space="preserve">
|
||||||
|
<value>Connections</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionClose" xml:space="preserve">
|
||||||
|
<value>Close Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionCloseAll" xml:space="preserve">
|
||||||
|
<value>Close All Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxies" xml:space="preserve">
|
||||||
|
<value>Proxies</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRulemode" xml:space="preserve">
|
||||||
|
<value>Rule mode</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeDirect" xml:space="preserve">
|
||||||
|
<value>Direct</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeGlobal" xml:space="preserve">
|
||||||
|
<value>Global</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
|
<value>Do not change</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
|
<value>Rule</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
|
<value>All Node Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
|
<value>Part Node Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesReload" xml:space="preserve">
|
||||||
|
<value>Refresh Proxies (F5)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
|
<value>Select active node (Enter)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||||
|
<value>Default domain strategy for outbound</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1042,9 +1042,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>
|
||||||
|
|||||||
@@ -1037,7 +1037,7 @@
|
|||||||
<value>拷贝字体TTF/TTC文件到目录guiFonts,重启设置</value>
|
<value>拷贝字体TTF/TTC文件到目录guiFonts,重启设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>http端口=socks端口+1;Pac端口=socks端口+4;API端口=socks端口+5;</value>
|
<value>http端口= +1;Pac端口= +4;*ray API端口= +5;mihomo API端口= +6;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
||||||
@@ -1216,4 +1216,85 @@
|
|||||||
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
||||||
<value>打开存储所在的位置</value>
|
<value>打开存储所在的位置</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSorting" xml:space="preserve">
|
||||||
|
<value>排序</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingChain" xml:space="preserve">
|
||||||
|
<value>路由链</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDefault" xml:space="preserve">
|
||||||
|
<value>默认</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDelay" xml:space="preserve">
|
||||||
|
<value>延迟</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownSpeed" xml:space="preserve">
|
||||||
|
<value>下载速度</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownTraffic" xml:space="preserve">
|
||||||
|
<value>下载流量</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingHost" xml:space="preserve">
|
||||||
|
<value>主机</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingName" xml:space="preserve">
|
||||||
|
<value>名称</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingNetwork" xml:space="preserve">
|
||||||
|
<value>网络</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingTime" xml:space="preserve">
|
||||||
|
<value>时间</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingType" xml:space="preserve">
|
||||||
|
<value>类型</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpSpeed" xml:space="preserve">
|
||||||
|
<value>上传速度</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpTraffic" xml:space="preserve">
|
||||||
|
<value>上传流量</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConnections" xml:space="preserve">
|
||||||
|
<value>当前连接</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionClose" xml:space="preserve">
|
||||||
|
<value>关闭连接</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionCloseAll" xml:space="preserve">
|
||||||
|
<value>关闭所有连接</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxies" xml:space="preserve">
|
||||||
|
<value>当前代理</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRulemode" xml:space="preserve">
|
||||||
|
<value>规则模式</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeDirect" xml:space="preserve">
|
||||||
|
<value>直连</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeGlobal" xml:space="preserve">
|
||||||
|
<value>全局</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
|
<value>随原配置</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
|
<value>规则</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
|
<value>全部节点延迟测试</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
|
<value>当前部分节点延迟测试</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesReload" xml:space="preserve">
|
||||||
|
<value>刷新 (F5)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
|
<value>设为活动节点 (Enter)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||||
|
<value>Outbound默认解析策略</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1037,7 +1037,7 @@
|
|||||||
<value>複製字型TTF/TTC文件到目錄guiFonts,重啟設定</value>
|
<value>複製字型TTF/TTC文件到目錄guiFonts,重啟設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>HTTP埠=SOCKS埠+1</value>
|
<value>http端口= +1;Pac端口= +4;*ray API端口= +5;mihomo API端口= +6;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
|
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
|
||||||
|
|||||||
39
v2rayN/v2rayN/Sample/clash_mixin_yaml
Normal file
39
v2rayN/v2rayN/Sample/clash_mixin_yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# 配置文件内容不会被修改,混合行为只会发生在内存中
|
||||||
|
#
|
||||||
|
# 注意下面缩进,请用支持yaml显示的编辑器打开
|
||||||
|
#
|
||||||
|
# 使用clash配置文件关键字则覆盖原配置
|
||||||
|
#
|
||||||
|
# removed-rules 循环匹配rules数组每行,符合则移除当前行 (此规则请放最前面)
|
||||||
|
#
|
||||||
|
# append-rules 数组合并至原配置rules数组后
|
||||||
|
# prepend-rules 数组合并至原配置rules数组前
|
||||||
|
# append-proxies 数组合并至原配置proxies数组后
|
||||||
|
# prepend-proxies 数组合并至原配置proxies数组前
|
||||||
|
# append-proxy-groups 数组合并至原配置proxy-groups数组后
|
||||||
|
# prepend-proxy-groups 数组合并至原配置proxy-groups数组前
|
||||||
|
# append-rule-providers 数组合并至原配置rule-providers数组后
|
||||||
|
# prepend-rule-providers 数组合并至原配置rule-providers数组前
|
||||||
|
#
|
||||||
|
|
||||||
|
dns:
|
||||||
|
enable: true
|
||||||
|
enhanced-mode: fake-ip
|
||||||
|
nameserver:
|
||||||
|
- 114.114.114.114
|
||||||
|
- 223.5.5.5
|
||||||
|
- 8.8.8.8
|
||||||
|
fallback: []
|
||||||
|
fake-ip-filter:
|
||||||
|
- +.stun.*.*
|
||||||
|
- +.stun.*.*.*
|
||||||
|
- +.stun.*.*.*.*
|
||||||
|
- +.stun.*.*.*.*.*
|
||||||
|
- "*.n.n.srv.nintendo.net"
|
||||||
|
- +.stun.playstation.net
|
||||||
|
- xbox.*.*.microsoft.com
|
||||||
|
- "*.*.xboxlive.com"
|
||||||
|
- "*.msftncsi.com"
|
||||||
|
- "*.msftconnecttest.com"
|
||||||
|
- WORKGROUP
|
||||||
7
v2rayN/v2rayN/Sample/clash_tun_yaml
Normal file
7
v2rayN/v2rayN/Sample/clash_tun_yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
tun:
|
||||||
|
enable: true
|
||||||
|
stack: gvisor
|
||||||
|
dns-hijack:
|
||||||
|
- 0.0.0.0:53
|
||||||
|
auto-route: true
|
||||||
|
auto-detect-interface: true
|
||||||
@@ -5,6 +5,11 @@
|
|||||||
"bittorrent"
|
"bittorrent"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"outboundTag": "block",
|
||||||
|
"port": "443",
|
||||||
|
"network": "udp"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"outboundTag": "block",
|
"outboundTag": "block",
|
||||||
"domain": [
|
"domain": [
|
||||||
@@ -15,7 +20,7 @@
|
|||||||
"outboundTag": "proxy",
|
"outboundTag": "proxy",
|
||||||
|
|
||||||
"domain": [
|
"domain": [
|
||||||
"geosite:geolocation-!cn",
|
"geosite:gfw",
|
||||||
"geosite:greatfire"
|
"geosite:greatfire"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"outboundTag": "block",
|
||||||
|
"port": "443",
|
||||||
|
"network": "udp"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"port": "0-65535",
|
"port": "0-65535",
|
||||||
"outboundTag": "proxy"
|
"outboundTag": "proxy"
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
"domain:example-example2.com"
|
"domain:example-example2.com"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"outboundTag": "block",
|
||||||
|
"port": "443",
|
||||||
|
"network": "udp"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"outboundTag": "block",
|
"outboundTag": "block",
|
||||||
"domain": [
|
"domain": [
|
||||||
|
|||||||
198
v2rayN/v2rayN/ViewModels/ClashConnectionsViewModel.cs
Normal file
198
v2rayN/v2rayN/ViewModels/ClashConnectionsViewModel.cs
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
using DynamicData;
|
||||||
|
using DynamicData.Binding;
|
||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using v2rayN.Handler;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.ViewModels
|
||||||
|
{
|
||||||
|
public class ClashConnectionsViewModel : ReactiveObject
|
||||||
|
{
|
||||||
|
private static Config _config;
|
||||||
|
|
||||||
|
private IObservableCollection<ClashConnectionModel> _connectionItems = new ObservableCollectionExtended<ClashConnectionModel>();
|
||||||
|
|
||||||
|
public IObservableCollection<ClashConnectionModel> ConnectionItems => _connectionItems;
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public ClashConnectionModel SelectedSource { get; set; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> ConnectionCloseCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ConnectionCloseAllCmd { get; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public int SortingSelected { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool AutoRefresh { get; set; }
|
||||||
|
|
||||||
|
public ClashConnectionsViewModel()
|
||||||
|
{
|
||||||
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
|
SortingSelected = _config.clashUIItem.connectionsSorting;
|
||||||
|
AutoRefresh = _config.clashUIItem.connectionsAutoRefresh;
|
||||||
|
|
||||||
|
var canEditRemove = this.WhenAnyValue(
|
||||||
|
x => x.SelectedSource,
|
||||||
|
selectedSource => selectedSource != null && !string.IsNullOrEmpty(selectedSource.id));
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.SortingSelected,
|
||||||
|
y => y >= 0)
|
||||||
|
.Subscribe(c => DoSortingSelected(c));
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.AutoRefresh,
|
||||||
|
y => y == true)
|
||||||
|
.Subscribe(c => { _config.clashUIItem.connectionsAutoRefresh = AutoRefresh; });
|
||||||
|
|
||||||
|
ConnectionCloseCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ClashConnectionClose(false);
|
||||||
|
}, canEditRemove);
|
||||||
|
|
||||||
|
ConnectionCloseAllCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ClashConnectionClose(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoSortingSelected(bool c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SortingSelected != _config.clashUIItem.connectionsSorting)
|
||||||
|
{
|
||||||
|
_config.clashUIItem.connectionsSorting = SortingSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetClashConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
var lastTime = DateTime.Now;
|
||||||
|
|
||||||
|
Observable.Interval(TimeSpan.FromSeconds(10))
|
||||||
|
.Subscribe(x =>
|
||||||
|
{
|
||||||
|
if (!(AutoRefresh && _config.clashUIItem.showInTaskbar))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var dtNow = DateTime.Now;
|
||||||
|
if (_config.clashUIItem.connectionsRefreshInterval > 0)
|
||||||
|
{
|
||||||
|
if ((dtNow - lastTime).Minutes % _config.clashUIItem.connectionsRefreshInterval == 0)
|
||||||
|
{
|
||||||
|
GetClashConnections();
|
||||||
|
lastTime = dtNow;
|
||||||
|
}
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetClashConnections()
|
||||||
|
{
|
||||||
|
ClashApiHandler.Instance.GetClashConnections(_config, (it) =>
|
||||||
|
{
|
||||||
|
if (it == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
RefreshConnections(it?.connections);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshConnections(List<ConnectionItem>? connections)
|
||||||
|
{
|
||||||
|
_connectionItems.Clear();
|
||||||
|
|
||||||
|
var dtNow = DateTime.Now;
|
||||||
|
var lstModel = new List<ClashConnectionModel>();
|
||||||
|
foreach (var item in connections ?? [])
|
||||||
|
{
|
||||||
|
ClashConnectionModel model = new();
|
||||||
|
|
||||||
|
model.id = item.id;
|
||||||
|
model.network = item.metadata.network;
|
||||||
|
model.type = item.metadata.type;
|
||||||
|
model.host = $"{(string.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}";
|
||||||
|
var sp = (dtNow - item.start);
|
||||||
|
model.time = sp.TotalSeconds < 0 ? 1 : sp.TotalSeconds;
|
||||||
|
model.upload = item.upload;
|
||||||
|
model.download = item.download;
|
||||||
|
model.uploadTraffic = $"{Utils.HumanFy((long)item.upload)}";
|
||||||
|
model.downloadTraffic = $"{Utils.HumanFy((long)item.download)}";
|
||||||
|
model.elapsed = sp.ToString(@"hh\:mm\:ss");
|
||||||
|
model.chain = item.chains?.Count > 0 ? item.chains[0] : String.Empty;
|
||||||
|
|
||||||
|
lstModel.Add(model);
|
||||||
|
}
|
||||||
|
if (lstModel.Count <= 0) { return; }
|
||||||
|
|
||||||
|
//sort
|
||||||
|
switch (SortingSelected)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
lstModel = lstModel.OrderBy(t => t.upload / t.time).ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
lstModel = lstModel.OrderBy(t => t.download / t.time).ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
lstModel = lstModel.OrderBy(t => t.upload).ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
lstModel = lstModel.OrderBy(t => t.download).ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
lstModel = lstModel.OrderBy(t => t.time).ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
lstModel = lstModel.OrderBy(t => t.host).ToList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_connectionItems.AddRange(lstModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClashConnectionClose(bool all)
|
||||||
|
{
|
||||||
|
var id = string.Empty;
|
||||||
|
if (!all)
|
||||||
|
{
|
||||||
|
var item = SelectedSource;
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id = item.id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_connectionItems.Clear();
|
||||||
|
}
|
||||||
|
ClashApiHandler.Instance.ClashConnectionClose(id);
|
||||||
|
GetClashConnections();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
487
v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs
Normal file
487
v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
using DynamicData;
|
||||||
|
using DynamicData.Binding;
|
||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using Splat;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using v2rayN.Enums;
|
||||||
|
using v2rayN.Handler;
|
||||||
|
using v2rayN.Models;
|
||||||
|
using v2rayN.Resx;
|
||||||
|
using static v2rayN.Models.ClashProviders;
|
||||||
|
using static v2rayN.Models.ClashProxies;
|
||||||
|
|
||||||
|
namespace v2rayN.ViewModels
|
||||||
|
{
|
||||||
|
public class ClashProxiesViewModel : ReactiveObject
|
||||||
|
{
|
||||||
|
private static Config _config;
|
||||||
|
private NoticeHandler? _noticeHandler;
|
||||||
|
private Dictionary<String, ProxiesItem>? proxies;
|
||||||
|
private Dictionary<String, ProvidersItem>? providers;
|
||||||
|
private int delayTimeout = 99999999;
|
||||||
|
|
||||||
|
private IObservableCollection<ClashProxyModel> _proxyGroups = new ObservableCollectionExtended<ClashProxyModel>();
|
||||||
|
private IObservableCollection<ClashProxyModel> _proxyDetails = new ObservableCollectionExtended<ClashProxyModel>();
|
||||||
|
|
||||||
|
public IObservableCollection<ClashProxyModel> ProxyGroups => _proxyGroups;
|
||||||
|
public IObservableCollection<ClashProxyModel> ProxyDetails => _proxyDetails;
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public ClashProxyModel SelectedGroup { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public ClashProxyModel SelectedDetail { get; set; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> ProxiesReloadCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ProxiesDelaytestCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ProxiesDelaytestPartCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ProxiesSelectActivityCmd { get; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public int RuleModeSelected { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public int SortingSelected { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool AutoRefresh { get; set; }
|
||||||
|
|
||||||
|
public ClashProxiesViewModel()
|
||||||
|
{
|
||||||
|
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
|
||||||
|
_config = LazyConfig.Instance.GetConfig();
|
||||||
|
|
||||||
|
SelectedGroup = new();
|
||||||
|
SelectedDetail = new();
|
||||||
|
|
||||||
|
AutoRefresh = _config.clashUIItem.proxiesAutoRefresh;
|
||||||
|
SortingSelected = _config.clashUIItem.proxiesSorting;
|
||||||
|
RuleModeSelected = (int)_config.clashUIItem.ruleMode;
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.SelectedGroup,
|
||||||
|
y => y != null && !string.IsNullOrEmpty(y.name))
|
||||||
|
.Subscribe(c => RefreshProxyDetails(c));
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.RuleModeSelected,
|
||||||
|
y => y >= 0)
|
||||||
|
.Subscribe(c => DoRulemodeSelected(c));
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.SortingSelected,
|
||||||
|
y => y >= 0)
|
||||||
|
.Subscribe(c => DoSortingSelected(c));
|
||||||
|
|
||||||
|
this.WhenAnyValue(
|
||||||
|
x => x.AutoRefresh,
|
||||||
|
y => y == true)
|
||||||
|
.Subscribe(c => { _config.clashUIItem.proxiesAutoRefresh = AutoRefresh; });
|
||||||
|
|
||||||
|
ProxiesReloadCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ProxiesReload();
|
||||||
|
});
|
||||||
|
ProxiesDelaytestCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ProxiesDelayTest(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
ProxiesDelaytestPartCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
ProxiesDelayTest(false);
|
||||||
|
});
|
||||||
|
ProxiesSelectActivityCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
SetActiveProxy();
|
||||||
|
});
|
||||||
|
|
||||||
|
ProxiesReload();
|
||||||
|
DelayTestTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoRulemodeSelected(bool c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_config.clashUIItem.ruleMode == (ERuleMode)RuleModeSelected)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetRuleModeCheck((ERuleMode)RuleModeSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetRuleModeCheck(ERuleMode mode)
|
||||||
|
{
|
||||||
|
if (_config.clashUIItem.ruleMode == mode)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetRuleMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoSortingSelected(bool c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SortingSelected != _config.clashUIItem.proxiesSorting)
|
||||||
|
{
|
||||||
|
_config.clashUIItem.proxiesSorting = SortingSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshProxyDetails(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateHandler(bool notify, string msg)
|
||||||
|
{
|
||||||
|
_noticeHandler?.SendMessage(msg, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProxiesReload()
|
||||||
|
{
|
||||||
|
GetClashProxies(true);
|
||||||
|
ProxiesDelayTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProxiesClear()
|
||||||
|
{
|
||||||
|
proxies = null;
|
||||||
|
providers = null;
|
||||||
|
|
||||||
|
ClashApiHandler.Instance.SetProxies(proxies);
|
||||||
|
|
||||||
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
_proxyGroups.Clear();
|
||||||
|
_proxyDetails.Clear();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProxiesDelayTest()
|
||||||
|
{
|
||||||
|
ProxiesDelayTest(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region proxy function
|
||||||
|
|
||||||
|
private void SetRuleMode(ERuleMode mode)
|
||||||
|
{
|
||||||
|
_config.clashUIItem.ruleMode = mode;
|
||||||
|
|
||||||
|
if (mode != ERuleMode.Unchanged)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>();
|
||||||
|
headers.Add("mode", mode.ToString().ToLower());
|
||||||
|
ClashApiHandler.Instance.ClashConfigUpdate(headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetClashProxies(bool refreshUI)
|
||||||
|
{
|
||||||
|
ClashApiHandler.Instance.GetClashProxies(_config, (it, it2) =>
|
||||||
|
{
|
||||||
|
UpdateHandler(false, "Refresh Clash Proxies");
|
||||||
|
proxies = it?.proxies;
|
||||||
|
providers = it2?.providers;
|
||||||
|
|
||||||
|
ClashApiHandler.Instance.SetProxies(proxies);
|
||||||
|
if (proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refreshUI)
|
||||||
|
{
|
||||||
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
RefreshProxyGroups();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshProxyGroups()
|
||||||
|
{
|
||||||
|
var selectedName = SelectedGroup?.name;
|
||||||
|
_proxyGroups.Clear();
|
||||||
|
|
||||||
|
var proxyGroups = ClashApiHandler.Instance.GetClashProxyGroups();
|
||||||
|
if (proxyGroups != null && proxyGroups.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var it in proxyGroups)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(it.name) || !proxies.ContainsKey(it.name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var item = proxies[it.name];
|
||||||
|
if (!Global.allowSelectType.Contains(item.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_proxyGroups.Add(new ClashProxyModel()
|
||||||
|
{
|
||||||
|
now = item.now,
|
||||||
|
name = item.name,
|
||||||
|
type = item.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//from api
|
||||||
|
foreach (KeyValuePair<string, ProxiesItem> kv in proxies)
|
||||||
|
{
|
||||||
|
if (!Global.allowSelectType.Contains(kv.Value.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var item = _proxyGroups.Where(t => t.name == kv.Key).FirstOrDefault();
|
||||||
|
if (item != null && !string.IsNullOrEmpty(item.name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_proxyGroups.Add(new ClashProxyModel()
|
||||||
|
{
|
||||||
|
now = kv.Value.now,
|
||||||
|
name = kv.Key,
|
||||||
|
type = kv.Value.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_proxyGroups != null && _proxyGroups.Count > 0)
|
||||||
|
{
|
||||||
|
if (selectedName != null && _proxyGroups.Any(t => t.name == selectedName))
|
||||||
|
{
|
||||||
|
SelectedGroup = _proxyGroups.FirstOrDefault(t => t.name == selectedName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedGroup = _proxyGroups[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedGroup = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshProxyDetails(bool c)
|
||||||
|
{
|
||||||
|
_proxyDetails.Clear();
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var name = SelectedGroup?.name;
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxies.TryGetValue(name, out ProxiesItem proxy);
|
||||||
|
if (proxy == null || proxy.all == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var lstDetails = new List<ClashProxyModel>();
|
||||||
|
foreach (var item in proxy.all)
|
||||||
|
{
|
||||||
|
var isActive = item == proxy.now;
|
||||||
|
|
||||||
|
var proxy2 = TryGetProxy(item);
|
||||||
|
if (proxy2 == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int delay = -1;
|
||||||
|
if (proxy2.history.Count > 0)
|
||||||
|
{
|
||||||
|
delay = proxy2.history[proxy2.history.Count - 1].delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
lstDetails.Add(new ClashProxyModel()
|
||||||
|
{
|
||||||
|
isActive = isActive,
|
||||||
|
name = item,
|
||||||
|
type = proxy2.type,
|
||||||
|
delay = delay <= 0 ? delayTimeout : delay,
|
||||||
|
delayName = delay <= 0 ? string.Empty : $"{delay}ms",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//sort
|
||||||
|
switch (SortingSelected)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
lstDetails = lstDetails.OrderBy(t => t.delay).ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
lstDetails = lstDetails.OrderBy(t => t.name).ToList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_proxyDetails.AddRange(lstDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProxiesItem? TryGetProxy(string name)
|
||||||
|
{
|
||||||
|
if (proxies is null)
|
||||||
|
return null;
|
||||||
|
proxies.TryGetValue(name, out ProxiesItem proxy2);
|
||||||
|
if (proxy2 != null)
|
||||||
|
{
|
||||||
|
return proxy2;
|
||||||
|
}
|
||||||
|
//from providers
|
||||||
|
if (providers != null)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, ProvidersItem> kv in providers)
|
||||||
|
{
|
||||||
|
if (Global.proxyVehicleType.Contains(kv.Value.vehicleType.ToLower()))
|
||||||
|
{
|
||||||
|
var proxy3 = kv.Value.proxies.FirstOrDefault(t => t.name == name);
|
||||||
|
if (proxy3 != null)
|
||||||
|
{
|
||||||
|
return proxy3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetActiveProxy()
|
||||||
|
{
|
||||||
|
if (SelectedGroup == null || string.IsNullOrEmpty(SelectedGroup.name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SelectedDetail == null || string.IsNullOrEmpty(SelectedDetail.name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var name = SelectedGroup.name;
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var nameNode = SelectedDetail.name;
|
||||||
|
if (string.IsNullOrEmpty(nameNode))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var selectedProxy = TryGetProxy(name);
|
||||||
|
if (selectedProxy == null || selectedProxy.type != "Selector")
|
||||||
|
{
|
||||||
|
_noticeHandler?.Enqueue(ResUI.OperationFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClashApiHandler.Instance.ClashSetActiveProxy(name, nameNode);
|
||||||
|
|
||||||
|
selectedProxy.now = nameNode;
|
||||||
|
var group = _proxyGroups.Where(it => it.name == SelectedGroup.name).FirstOrDefault();
|
||||||
|
if (group != null)
|
||||||
|
{
|
||||||
|
group.now = nameNode;
|
||||||
|
var group2 = JsonUtils.DeepCopy(group);
|
||||||
|
_proxyGroups.Replace(group, group2);
|
||||||
|
|
||||||
|
SelectedGroup = group2;
|
||||||
|
|
||||||
|
//var index = _proxyGroups.IndexOf(group);
|
||||||
|
//_proxyGroups.Remove(group);
|
||||||
|
//_proxyGroups.Insert(index, group);
|
||||||
|
}
|
||||||
|
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||||
|
|
||||||
|
//RefreshProxyDetails(true);
|
||||||
|
//GetClashProxies(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProxiesDelayTest(bool blAll)
|
||||||
|
{
|
||||||
|
UpdateHandler(false, "Clash Proxies Latency Test");
|
||||||
|
|
||||||
|
ClashApiHandler.Instance.ClashProxiesDelayTest(blAll, _proxyDetails.ToList(), (item, result) =>
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
GetClashProxies(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
|
{
|
||||||
|
//UpdateHandler(false, $"{item.name}={result}");
|
||||||
|
var detail = _proxyDetails.Where(it => it.name == item.name).FirstOrDefault();
|
||||||
|
if (detail != null)
|
||||||
|
{
|
||||||
|
var dicResult = JsonUtils.Deserialize<Dictionary<string, object>>(result);
|
||||||
|
if (dicResult != null && dicResult.ContainsKey("delay"))
|
||||||
|
{
|
||||||
|
detail.delay = Convert.ToInt32(dicResult["delay"].ToString());
|
||||||
|
detail.delayName = $"{detail.delay}ms";
|
||||||
|
}
|
||||||
|
else if (dicResult != null && dicResult.ContainsKey("message"))
|
||||||
|
{
|
||||||
|
detail.delay = delayTimeout;
|
||||||
|
detail.delayName = $"{dicResult["message"]}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
detail.delay = delayTimeout;
|
||||||
|
detail.delayName = String.Empty;
|
||||||
|
}
|
||||||
|
_proxyDetails.Replace(detail, JsonUtils.DeepCopy(detail));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion proxy function
|
||||||
|
|
||||||
|
#region task
|
||||||
|
|
||||||
|
public void DelayTestTask()
|
||||||
|
{
|
||||||
|
var lastTime = DateTime.Now;
|
||||||
|
|
||||||
|
Observable.Interval(TimeSpan.FromSeconds(60))
|
||||||
|
.Subscribe(x =>
|
||||||
|
{
|
||||||
|
if (!(AutoRefresh && _config.clashUIItem.showInTaskbar))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var dtNow = DateTime.Now;
|
||||||
|
if (_config.clashUIItem.proxiesAutoDelayTestInterval > 0)
|
||||||
|
{
|
||||||
|
if ((dtNow - lastTime).Minutes % _config.clashUIItem.proxiesAutoDelayTestInterval == 0)
|
||||||
|
{
|
||||||
|
ProxiesDelayTest();
|
||||||
|
lastTime = dtNow;
|
||||||
|
}
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion task
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ namespace v2rayN.ViewModels
|
|||||||
[Reactive] public string normalDNS { get; set; }
|
[Reactive] public string normalDNS { 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; }
|
||||||
|
[Reactive] public string domainStrategy4Freedom2 { get; set; }
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; }
|
public ReactiveCommand<Unit, Unit> ImportDefConfig4V2rayCmd { get; }
|
||||||
@@ -34,12 +35,13 @@ 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!;
|
normalDNS = item?.normalDNS ?? string.Empty;
|
||||||
|
|
||||||
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
||||||
normalDNS2 = item2?.normalDNS!;
|
normalDNS2 = item2?.normalDNS ?? string.Empty;
|
||||||
tunDNS2 = item2?.tunDNS!;
|
tunDNS2 = item2?.tunDNS ?? string.Empty;
|
||||||
|
domainStrategy4Freedom2 = item2?.domainStrategy4Freedom ?? string.Empty;
|
||||||
|
|
||||||
SaveCmd = ReactiveCommand.Create(() =>
|
SaveCmd = ReactiveCommand.Create(() =>
|
||||||
{
|
{
|
||||||
@@ -105,6 +107,7 @@ namespace v2rayN.ViewModels
|
|||||||
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
var item2 = LazyConfig.Instance.GetDNSItem(ECoreType.sing_box);
|
||||||
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));
|
||||||
|
item2.domainStrategy4Freedom = domainStrategy4Freedom2;
|
||||||
ConfigHandler.SaveDNSItems(_config, item2);
|
ConfigHandler.SaveDNSItems(_config, item2);
|
||||||
|
|
||||||
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ using System.Windows.Media;
|
|||||||
using v2rayN.Enums;
|
using v2rayN.Enums;
|
||||||
using v2rayN.Handler;
|
using v2rayN.Handler;
|
||||||
using v2rayN.Handler.Fmt;
|
using v2rayN.Handler.Fmt;
|
||||||
|
using v2rayN.Handler.Statistics;
|
||||||
using v2rayN.Models;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
using v2rayN.Views;
|
using v2rayN.Views;
|
||||||
@@ -150,6 +151,7 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
//CheckUpdate
|
//CheckUpdate
|
||||||
public ReactiveCommand<Unit, Unit> CheckUpdateNCmd { get; }
|
public ReactiveCommand<Unit, Unit> CheckUpdateNCmd { get; }
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> CheckUpdateXrayCoreCmd { get; }
|
public ReactiveCommand<Unit, Unit> CheckUpdateXrayCoreCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> CheckUpdateClashMetaCoreCmd { get; }
|
public ReactiveCommand<Unit, Unit> CheckUpdateClashMetaCoreCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> CheckUpdateSingBoxCoreCmd { get; }
|
public ReactiveCommand<Unit, Unit> CheckUpdateSingBoxCoreCmd { get; }
|
||||||
@@ -243,6 +245,9 @@ namespace v2rayN.ViewModels
|
|||||||
[Reactive]
|
[Reactive]
|
||||||
public string CurrentLanguage { get; set; }
|
public string CurrentLanguage { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool ShowCalshUI { get; set; }
|
||||||
|
|
||||||
#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
#region Init
|
#region Init
|
||||||
@@ -261,9 +266,16 @@ namespace v2rayN.ViewModels
|
|||||||
SelectedMoveToGroup = new();
|
SelectedMoveToGroup = new();
|
||||||
SelectedRouting = new();
|
SelectedRouting = new();
|
||||||
SelectedServer = new();
|
SelectedServer = new();
|
||||||
if (_config.tunModeItem.enableTun && Utils.IsAdministrator())
|
if (_config.tunModeItem.enableTun)
|
||||||
{
|
{
|
||||||
EnableTun = true;
|
if (Utils.IsAdministrator())
|
||||||
|
{
|
||||||
|
EnableTun = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_config.tunModeItem.enableTun = EnableTun = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_subId = _config.subIndexId;
|
_subId = _config.subIndexId;
|
||||||
|
|
||||||
@@ -562,6 +574,7 @@ namespace v2rayN.ViewModels
|
|||||||
AutoHideStartup();
|
AutoHideStartup();
|
||||||
|
|
||||||
_showInTaskbar = true;
|
_showInTaskbar = true;
|
||||||
|
_config.clashUIItem.showInTaskbar = _showInTaskbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
@@ -601,6 +614,10 @@ namespace v2rayN.ViewModels
|
|||||||
|
|
||||||
private void UpdateHandler(bool notify, string msg)
|
private void UpdateHandler(bool notify, string msg)
|
||||||
{
|
{
|
||||||
|
if (!_showInTaskbar)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
_noticeHandler?.SendMessage(msg);
|
_noticeHandler?.SendMessage(msg);
|
||||||
if (notify)
|
if (notify)
|
||||||
{
|
{
|
||||||
@@ -1502,6 +1519,11 @@ namespace v2rayN.ViewModels
|
|||||||
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
{
|
{
|
||||||
BlReloadEnabled = true;
|
BlReloadEnabled = true;
|
||||||
|
ShowCalshUI = (_config.runningCoreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo);
|
||||||
|
if (ShowCalshUI)
|
||||||
|
{
|
||||||
|
Locator.Current.GetService<ClashProxiesViewModel>()?.ProxiesReload();
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1547,7 +1569,7 @@ namespace v2rayN.ViewModels
|
|||||||
private void ChangeSystemProxyStatus(ESysProxyType type, bool blChange)
|
private void ChangeSystemProxyStatus(ESysProxyType type, bool blChange)
|
||||||
{
|
{
|
||||||
SysProxyHandle.UpdateSysProxy(_config, _config.tunModeItem.enableTun ? true : false);
|
SysProxyHandle.UpdateSysProxy(_config, _config.tunModeItem.enableTun ? true : false);
|
||||||
_noticeHandler?.SendMessage(ResUI.TipChangeSystemProxy + _config.sysProxyType.ToString(), true);
|
_noticeHandler?.SendMessage($"{ResUI.TipChangeSystemProxy} - {_config.sysProxyType.ToString()}", true);
|
||||||
|
|
||||||
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||||
{
|
{
|
||||||
@@ -1673,6 +1695,7 @@ namespace v2rayN.ViewModels
|
|||||||
//Utile.RegWriteValue(Global.MyRegPath, Utile.WindowHwndKey, Convert.ToString((long)windowHandle));
|
//Utile.RegWriteValue(Global.MyRegPath, Utile.WindowHwndKey, Convert.ToString((long)windowHandle));
|
||||||
}
|
}
|
||||||
_showInTaskbar = bl;
|
_showInTaskbar = bl;
|
||||||
|
_config.clashUIItem.showInTaskbar = _showInTaskbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreUI()
|
private void RestoreUI()
|
||||||
@@ -1775,6 +1798,7 @@ namespace v2rayN.ViewModels
|
|||||||
Application.Current.Resources["StdFontSize1"] = size + 1;
|
Application.Current.Resources["StdFontSize1"] = size + 1;
|
||||||
Application.Current.Resources["StdFontSize2"] = size + 2;
|
Application.Current.Resources["StdFontSize2"] = size + 2;
|
||||||
Application.Current.Resources["StdFontSizeMsg"] = size - 1;
|
Application.Current.Resources["StdFontSizeMsg"] = size - 1;
|
||||||
|
Application.Current.Resources["StdFontSize-1"] = size - 1;
|
||||||
|
|
||||||
ConfigHandler.SaveConfig(_config);
|
ConfigHandler.SaveConfig(_config);
|
||||||
}
|
}
|
||||||
|
|||||||
112
v2rayN/v2rayN/Views/ClashConnectionsView.xaml
Normal file
112
v2rayN/v2rayN/Views/ClashConnectionsView.xaml
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<reactiveui:ReactiveUserControl
|
||||||
|
x:Class="v2rayN.Views.ClashConnectionsView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:v2rayN.Views"
|
||||||
|
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:ClashConnectionsViewModel"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<DockPanel>
|
||||||
|
<ToolBarTray Margin="0,8,0,8" DockPanel.Dock="Top">
|
||||||
|
<ToolBar ClipToBounds="True" Style="{StaticResource MaterialDesignToolBar}">
|
||||||
|
<Button Width="1" Visibility="Hidden">
|
||||||
|
<materialDesign:PackIcon
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Kind="ContentSave" />
|
||||||
|
</Button>
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbSorting"
|
||||||
|
Width="100"
|
||||||
|
Margin="8"
|
||||||
|
Style="{StaticResource DefComboBox}">
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpSpeed}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownSpeed}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingTime}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingHost}" />
|
||||||
|
</ComboBox>
|
||||||
|
<Separator />
|
||||||
|
<Button x:Name="btnConnectionCloseAll" ToolTip="{x:Static resx:ResUI.menuConnectionCloseAll}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Kind="Close" />
|
||||||
|
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuConnectionCloseAll}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Separator />
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togAutoRefresh"
|
||||||
|
Margin="8"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
</ToolBar>
|
||||||
|
</ToolBarTray>
|
||||||
|
<DataGrid
|
||||||
|
x:Name="lstConnections"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
BorderThickness="1"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
CanUserResizeRows="False"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
EnableRowVirtualization="True"
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
IsReadOnly="True"
|
||||||
|
Style="{StaticResource DefDataGrid}">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
|
<MenuItem x:Name="menuConnectionClose" Header="{x:Static resx:ResUI.menuConnectionClose}" />
|
||||||
|
<MenuItem x:Name="menuConnectionCloseAll" Header="{x:Static resx:ResUI.menuConnectionCloseAll}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="300"
|
||||||
|
Binding="{Binding host}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingHost}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding network}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingNetwork}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding type}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingType}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="200"
|
||||||
|
Binding="{Binding chain}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingChain}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding uploadTraffic}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding downloadTraffic}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding elapsed}"
|
||||||
|
Header="{x:Static resx:ResUI.TbSortingTime}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</DockPanel>
|
||||||
|
</reactiveui:ReactiveUserControl>
|
||||||
36
v2rayN/v2rayN/Views/ClashConnectionsView.xaml.cs
Normal file
36
v2rayN/v2rayN/Views/ClashConnectionsView.xaml.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using ReactiveUI;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using v2rayN.ViewModels;
|
||||||
|
|
||||||
|
namespace v2rayN.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ConnectionsView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ClashConnectionsView
|
||||||
|
{
|
||||||
|
public ClashConnectionsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
ViewModel = new ClashConnectionsViewModel();
|
||||||
|
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ConnectionItems, v => v.lstConnections.ItemsSource).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstConnections.SelectedItem).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnClose_Click(object sender, System.Windows.RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ViewModel?.ClashConnectionClose(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
179
v2rayN/v2rayN/Views/ClashProxiesView.xaml
Normal file
179
v2rayN/v2rayN/Views/ClashProxiesView.xaml
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<reactiveui:ReactiveUserControl
|
||||||
|
x:Class="v2rayN.Views.ClashProxiesView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
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:converters="clr-namespace:v2rayN.Converters"
|
||||||
|
xmlns:resx="clr-namespace:v2rayN.Resx"
|
||||||
|
xmlns:vms="clr-namespace:v2rayN.ViewModels"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
x:TypeArguments="vms:ClashProxiesViewModel"
|
||||||
|
KeyDown="ProxiesView_KeyDown"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
||||||
|
<converters:DelayColorConverter x:Key="DelayColorConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<DockPanel>
|
||||||
|
<ToolBarTray DockPanel.Dock="Top">
|
||||||
|
<ToolBar
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
ClipToBounds="True"
|
||||||
|
Style="{StaticResource MaterialDesignToolBar}">
|
||||||
|
<Button Width="1" Visibility="Hidden">
|
||||||
|
<materialDesign:PackIcon
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Kind="ContentSave" />
|
||||||
|
</Button>
|
||||||
|
<Separator />
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.menuRulemode}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbRulemode"
|
||||||
|
Width="80"
|
||||||
|
Margin="8"
|
||||||
|
Style="{StaticResource DefComboBox}">
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeRule}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeGlobal}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeDirect}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeNothing}" />
|
||||||
|
</ComboBox>
|
||||||
|
<Separator />
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbSorting"
|
||||||
|
Width="60"
|
||||||
|
Margin="8"
|
||||||
|
Style="{StaticResource DefComboBox}">
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDelay}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingName}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDefault}" />
|
||||||
|
</ComboBox>
|
||||||
|
<Separator />
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togAutoRefresh"
|
||||||
|
Margin="8"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
</ToolBar>
|
||||||
|
</ToolBarTray>
|
||||||
|
<DockPanel>
|
||||||
|
<ListView
|
||||||
|
x:Name="lstProxyGroups"
|
||||||
|
Margin="0,0,5,0"
|
||||||
|
BorderThickness="0"
|
||||||
|
DockPanel.Dock="Left"
|
||||||
|
ItemContainerStyle="{StaticResource lvItemSelected}"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||||||
|
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>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Vertical" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ListView.ItemsPanel>
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Width="200" Padding="0">
|
||||||
|
<DockPanel>
|
||||||
|
<Grid Grid.Column="0" Margin="4">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
||||||
|
<TextBlock Style="{StaticResource ListItemTitle}" Text="{Binding name}" />
|
||||||
|
<TextBlock
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
Style="{StaticResource ListItemSubTitle}"
|
||||||
|
Text="{Binding type}" />
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Style="{StaticResource ListItemSubTitle}"
|
||||||
|
Text="{Binding now}" />
|
||||||
|
</Grid>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
x:Name="lstProxyDetails"
|
||||||
|
BorderThickness="0"
|
||||||
|
ItemContainerStyle="{StaticResource lvItemSelected}"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||||||
|
Style="{StaticResource MaterialDesignListView}">
|
||||||
|
<ListView.ContextMenu>
|
||||||
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
|
<MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" />
|
||||||
|
<MenuItem x:Name="menuProxiesSelectActivity" Header="{x:Static resx:ResUI.menuProxiesSelectActivity}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</ListView.ContextMenu>
|
||||||
|
<ListView.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<WrapPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ListView.ItemsPanel>
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Width="200" Padding="0">
|
||||||
|
<DockPanel>
|
||||||
|
<Border
|
||||||
|
Width="5"
|
||||||
|
Height="auto"
|
||||||
|
Margin="0,1"
|
||||||
|
Background="{DynamicResource MaterialDesign.Brush.Primary.Light}"
|
||||||
|
CornerRadius="4"
|
||||||
|
DockPanel.Dock="Left"
|
||||||
|
Visibility="{Binding Path=isActive, Converter={StaticResource BoolToVisConverter}}" />
|
||||||
|
<Grid Margin="4">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="2*" />
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Style="{StaticResource ListItemSubTitle}"
|
||||||
|
Text="{Binding name}"
|
||||||
|
TextWrapping="WrapWithOverflow" />
|
||||||
|
<DockPanel Grid.Row="1">
|
||||||
|
<TextBlock
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
Foreground="{Binding Path=delay, Converter={StaticResource DelayColorConverter}}"
|
||||||
|
Style="{StaticResource ListItemSubTitle2}"
|
||||||
|
Text="{Binding delayName}" />
|
||||||
|
<TextBlock Style="{StaticResource ListItemSubTitle2}" Text="{Binding type}" />
|
||||||
|
</DockPanel>
|
||||||
|
</Grid>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
</DockPanel>
|
||||||
|
</DockPanel>
|
||||||
|
</reactiveui:ReactiveUserControl>
|
||||||
60
v2rayN/v2rayN/Views/ClashProxiesView.xaml.cs
Normal file
60
v2rayN/v2rayN/Views/ClashProxiesView.xaml.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using ReactiveUI;
|
||||||
|
using Splat;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using v2rayN.ViewModels;
|
||||||
|
|
||||||
|
namespace v2rayN.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ProxiesView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ClashProxiesView
|
||||||
|
{
|
||||||
|
public ClashProxiesView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
ViewModel = new ClashProxiesViewModel();
|
||||||
|
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ClashProxiesViewModel));
|
||||||
|
lstProxyDetails.PreviewMouseDoubleClick += lstProxyDetails_PreviewMouseDoubleClick;
|
||||||
|
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ProxyGroups, v => v.lstProxyGroups.ItemsSource).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedGroup, v => v.lstProxyGroups.SelectedItem).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ProxyDetails, v => v.lstProxyDetails.ItemsSource).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedDetail, v => v.lstProxyDetails.SelectedItem).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ProxiesReloadCmd, v => v.menuProxiesReload).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ProxiesDelaytestCmd, v => v.menuProxiesDelaytest).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ProxiesDelaytestPartCmd, v => v.menuProxiesDelaytestPart).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.ProxiesSelectActivityCmd, v => v.menuProxiesSelectActivity).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.Bind(ViewModel, vm => vm.RuleModeSelected, v => v.cmbRulemode.SelectedIndex).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProxiesView_KeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.F5:
|
||||||
|
ViewModel?.ProxiesReload();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Key.Enter:
|
||||||
|
ViewModel?.SetActiveProxy();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lstProxyDetails_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
ViewModel?.SetActiveProxy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -132,6 +132,19 @@
|
|||||||
Style="{StaticResource DefButton}" />
|
Style="{StaticResource DefButton}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbdomainStrategy4Out"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource SettingItemMargin}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<Grid Margin="{StaticResource SettingItemMargin}">
|
<Grid Margin="{StaticResource SettingItemMargin}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="1*" />
|
<ColumnDefinition Width="1*" />
|
||||||
|
|||||||
@@ -34,12 +34,17 @@ namespace v2rayN.Views
|
|||||||
{
|
{
|
||||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
cmbdomainStrategy4Freedom.Items.Add(it);
|
||||||
});
|
});
|
||||||
|
Global.SingboxDomainStrategy4Out.ForEach(it =>
|
||||||
|
{
|
||||||
|
cmbdomainStrategy4Out.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.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.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);
|
||||||
|
|
||||||
|
|||||||
@@ -437,6 +437,14 @@
|
|||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
||||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||||
Style="{StaticResource DefTextBox}" />
|
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>
|
</WrapPanel>
|
||||||
|
|
||||||
<materialDesign:ColorZone
|
<materialDesign:ColorZone
|
||||||
@@ -524,237 +532,240 @@
|
|||||||
<RowDefinition Height="10" />
|
<RowDefinition Height="10" />
|
||||||
<RowDefinition Height="1*" />
|
<RowDefinition Height="1*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<DataGrid
|
<DockPanel Grid.Row="0">
|
||||||
x:Name="lstProfiles"
|
<ContentControl x:Name="tabClashUI" DockPanel.Dock="Right" />
|
||||||
Grid.Row="0"
|
<DataGrid
|
||||||
materialDesign:DataGridAssist.CellPadding="2,2"
|
x:Name="lstProfiles"
|
||||||
AutoGenerateColumns="False"
|
materialDesign:DataGridAssist.CellPadding="2,2"
|
||||||
BorderThickness="1"
|
AutoGenerateColumns="False"
|
||||||
CanUserAddRows="False"
|
BorderThickness="1"
|
||||||
CanUserResizeRows="False"
|
CanUserAddRows="False"
|
||||||
CanUserSortColumns="False"
|
CanUserResizeRows="False"
|
||||||
EnableRowVirtualization="True"
|
CanUserSortColumns="False"
|
||||||
Focusable="True"
|
EnableRowVirtualization="True"
|
||||||
GridLinesVisibility="All"
|
Focusable="True"
|
||||||
HeadersVisibility="All"
|
GridLinesVisibility="All"
|
||||||
IsReadOnly="True"
|
HeadersVisibility="All"
|
||||||
RowHeaderWidth="40"
|
IsReadOnly="True"
|
||||||
Style="{StaticResource DefDataGrid}">
|
RowHeaderWidth="40"
|
||||||
<DataGrid.InputBindings>
|
Style="{StaticResource DefDataGrid}">
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" />
|
<DataGrid.InputBindings>
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+V" />
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" />
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Delete" />
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+V" />
|
||||||
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Enter" />
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Delete" />
|
||||||
</DataGrid.InputBindings>
|
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Enter" />
|
||||||
<DataGrid.ContextMenu>
|
</DataGrid.InputBindings>
|
||||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
<DataGrid.ContextMenu>
|
||||||
<MenuItem
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
x:Name="menuEditServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuEditServer"
|
||||||
Header="{x:Static resx:ResUI.menuEditServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuEditServer}" />
|
||||||
x:Name="menuSetDefaultServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuSetDefaultServer"
|
||||||
Header="{x:Static resx:ResUI.menuSetDefaultServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuSetDefaultServer}" />
|
||||||
x:Name="menuRemoveServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuRemoveServer"
|
||||||
Header="{x:Static resx:ResUI.menuRemoveServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuRemoveServer}" />
|
||||||
x:Name="menuRemoveDuplicateServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuRemoveDuplicateServer"
|
||||||
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
||||||
x:Name="menuCopyServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuCopyServer"
|
||||||
Header="{x:Static resx:ResUI.menuCopyServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuCopyServer}" />
|
||||||
x:Name="menuShareServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuShareServer"
|
||||||
Header="{x:Static resx:ResUI.menuShareServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<Separator />
|
Header="{x:Static resx:ResUI.menuShareServer}" />
|
||||||
<MenuItem
|
<Separator />
|
||||||
x:Name="menuMixedTestServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuMixedTestServer"
|
||||||
Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
||||||
x:Name="menuTcpingServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuTcpingServer"
|
||||||
Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
||||||
x:Name="menuRealPingServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuRealPingServer"
|
||||||
Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
||||||
x:Name="menuSpeedServer"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuSpeedServer"
|
||||||
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem
|
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||||
x:Name="menuSortServerResult"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuSortServerResult"
|
||||||
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<Separator />
|
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||||
<MenuItem
|
<Separator />
|
||||||
x:Name="menuMoveToGroup"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuMoveToGroup"
|
||||||
Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
Height="{StaticResource MenuItemHeight}"
|
||||||
<MenuItem Height="Auto">
|
Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
||||||
<MenuItem.Header>
|
<MenuItem Height="Auto">
|
||||||
<DockPanel>
|
<MenuItem.Header>
|
||||||
<ComboBox
|
<DockPanel>
|
||||||
x:Name="cmbMoveToGroup"
|
<ComboBox
|
||||||
Width="200"
|
x:Name="cmbMoveToGroup"
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
|
Width="200"
|
||||||
DisplayMemberPath="remarks"
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
DisplayMemberPath="remarks"
|
||||||
Style="{StaticResource MaterialDesignFilledComboBox}" />
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
</DockPanel>
|
Style="{StaticResource MaterialDesignFilledComboBox}" />
|
||||||
</MenuItem.Header>
|
</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>
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuMoveTop"
|
x:Name="menuSelectAll"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuMoveTop}" />
|
Click="menuSelectAll_Click"
|
||||||
|
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||||
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuMoveUp"
|
x:Name="menuExport2ClientConfig"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuMoveUp}" />
|
Header="{x:Static resx:ResUI.menuExport2ClientConfig}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuMoveDown"
|
x:Name="menuExport2ShareUrl"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuMoveDown}" />
|
Header="{x:Static resx:ResUI.menuExport2ShareUrl}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuMoveBottom"
|
x:Name="menuExport2SubContent"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuMoveBottom}" />
|
Header="{x:Static resx:ResUI.menuExport2SubContent}" />
|
||||||
</MenuItem>
|
</ContextMenu>
|
||||||
<MenuItem
|
</DataGrid.ContextMenu>
|
||||||
x:Name="menuSelectAll"
|
<DataGrid.Resources>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
<Style BasedOn="{StaticResource MaterialDesignDataGridRow}" TargetType="DataGridRow">
|
||||||
Click="menuSelectAll_Click"
|
<EventSetter Event="MouseDoubleClick" Handler="LstProfiles_MouseDoubleClick" />
|
||||||
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
</Style>
|
||||||
<Separator />
|
<Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
|
||||||
<MenuItem
|
<EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" />
|
||||||
x:Name="menuExport2ClientConfig"
|
</Style>
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuExport2ClientConfig}" />
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuExport2ShareUrl"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuExport2ShareUrl}" />
|
|
||||||
<MenuItem
|
|
||||||
x:Name="menuExport2SubContent"
|
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
Header="{x:Static resx:ResUI.menuExport2SubContent}" />
|
|
||||||
</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 BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding isActive}" Value="True">
|
<DataTrigger Binding="{Binding isActive}" Value="True">
|
||||||
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
<Setter Property="Foreground" Value="Black" />
|
<Setter Property="Foreground" Value="Black" />
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</DataGrid.Resources>
|
</DataGrid.Resources>
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
|
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="80"
|
Width="80"
|
||||||
Binding="{Binding configType}"
|
Binding="{Binding configType}"
|
||||||
ExName="configType"
|
ExName="configType"
|
||||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="150"
|
Width="150"
|
||||||
Binding="{Binding remarks}"
|
Binding="{Binding remarks}"
|
||||||
ExName="remarks"
|
ExName="remarks"
|
||||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="120"
|
Width="120"
|
||||||
Binding="{Binding address}"
|
Binding="{Binding address}"
|
||||||
ExName="address"
|
ExName="address"
|
||||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="60"
|
Width="60"
|
||||||
Binding="{Binding port}"
|
Binding="{Binding port}"
|
||||||
ExName="port"
|
ExName="port"
|
||||||
Header="{x:Static resx:ResUI.LvPort}" />
|
Header="{x:Static resx:ResUI.LvPort}" />
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="100"
|
Width="100"
|
||||||
Binding="{Binding network}"
|
Binding="{Binding network}"
|
||||||
ExName="network"
|
ExName="network"
|
||||||
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
|
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="100"
|
Width="100"
|
||||||
Binding="{Binding streamSecurity}"
|
Binding="{Binding streamSecurity}"
|
||||||
ExName="streamSecurity"
|
ExName="streamSecurity"
|
||||||
Header="{x:Static resx:ResUI.LvTLS}" />
|
Header="{x:Static resx:ResUI.LvTLS}" />
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="100"
|
Width="100"
|
||||||
Binding="{Binding subRemarks}"
|
Binding="{Binding subRemarks}"
|
||||||
ExName="subRemarks"
|
ExName="subRemarks"
|
||||||
Header="{x:Static resx:ResUI.LvSubscription}" />
|
Header="{x:Static resx:ResUI.LvSubscription}" />
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="100"
|
Width="100"
|
||||||
Binding="{Binding delayVal}"
|
Binding="{Binding delayVal}"
|
||||||
ExName="delayVal"
|
ExName="delayVal"
|
||||||
Header="{x:Static resx:ResUI.LvTestDelay}">
|
Header="{x:Static resx:ResUI.LvTestDelay}">
|
||||||
<DataGridTextColumn.ElementStyle>
|
<DataGridTextColumn.ElementStyle>
|
||||||
<Style TargetType="{x:Type TextBlock}">
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
|
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
|
||||||
</Style>
|
</Style>
|
||||||
</DataGridTextColumn.ElementStyle>
|
</DataGridTextColumn.ElementStyle>
|
||||||
</base:MyDGTextColumn>
|
</base:MyDGTextColumn>
|
||||||
<base:MyDGTextColumn
|
<base:MyDGTextColumn
|
||||||
Width="100"
|
Width="100"
|
||||||
Binding="{Binding speedVal}"
|
Binding="{Binding speedVal}"
|
||||||
ExName="speedVal"
|
ExName="speedVal"
|
||||||
Header="{x:Static resx:ResUI.LvTestSpeed}">
|
Header="{x:Static resx:ResUI.LvTestSpeed}">
|
||||||
<DataGridTextColumn.ElementStyle>
|
<DataGridTextColumn.ElementStyle>
|
||||||
<Style TargetType="{x:Type TextBlock}">
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
</Style>
|
</Style>
|
||||||
</DataGridTextColumn.ElementStyle>
|
</DataGridTextColumn.ElementStyle>
|
||||||
</base:MyDGTextColumn>
|
</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>
|
||||||
|
|
||||||
<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>
|
|
||||||
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" />
|
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" />
|
||||||
<local:MsgView Grid.Row="2" />
|
<local:MsgView Grid.Row="2" />
|
||||||
<materialDesign:Snackbar
|
<materialDesign:Snackbar
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ namespace v2rayN.Views
|
|||||||
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
|
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
|
||||||
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
||||||
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
|
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
|
||||||
|
btnShowCalshUI.Click += BtnShowCalshUI_Click;
|
||||||
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
|
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
|
||||||
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
|
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
|
||||||
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
|
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
|
||||||
@@ -205,6 +206,8 @@ 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();
|
RestoreUI();
|
||||||
@@ -455,6 +458,27 @@ namespace v2rayN.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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.48</FileVersion>
|
<FileVersion>6.51</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,10 +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" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AdditionalFiles Include="app.manifest" />
|
<AdditionalFiles Include="app.manifest" />
|
||||||
|
<EmbeddedResource Include="Sample\clash_mixin_yaml" />
|
||||||
|
<EmbeddedResource Include="Sample\clash_tun_yaml" />
|
||||||
<EmbeddedResource Include="Sample\SingboxSampleOutbound" />
|
<EmbeddedResource Include="Sample\SingboxSampleOutbound" />
|
||||||
<EmbeddedResource Include="Sample\SingboxSampleClientConfig">
|
<EmbeddedResource Include="Sample\SingboxSampleClientConfig">
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
|||||||
Reference in New Issue
Block a user