Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aac2b4aaf0 | ||
|
|
fe070b306f | ||
|
|
ecfadf8a23 | ||
|
|
653af71596 | ||
|
|
6a89be2e89 | ||
|
|
b84bad4e1a | ||
|
|
0f8d86f081 | ||
|
|
d44f311ba1 | ||
|
|
6f5428ca61 | ||
|
|
b0bee3ca1a | ||
|
|
7908194d27 | ||
|
|
b27c7fb2dd | ||
|
|
a23cb95a10 | ||
|
|
fc137f9b1c | ||
|
|
84780bf9ef | ||
|
|
1321037c52 | ||
|
|
de1da12d45 | ||
|
|
6d4cbacd50 | ||
|
|
bf9f7ca990 | ||
|
|
ca334104d7 | ||
|
|
c3e00ba31b | ||
|
|
ea3a9cc70e | ||
|
|
7ad22e0a73 | ||
|
|
ca1abb58eb | ||
|
|
3e353944b2 | ||
|
|
007a250f55 | ||
|
|
e9bb6a9951 | ||
|
|
82f236e07b | ||
|
|
17bfe74ecf | ||
|
|
b77827df90 | ||
|
|
a359a508ae | ||
|
|
3a740118f0 | ||
|
|
58d9bcbd14 | ||
|
|
24be7b2180 | ||
|
|
f4c9ca8dff | ||
|
|
9b8181b72b | ||
|
|
1ff1962425 | ||
|
|
9b05736746 | ||
|
|
dec722e693 | ||
|
|
49fa0a4c67 | ||
|
|
0cdc69e1e8 | ||
|
|
0494cc4ce7 | ||
|
|
30d82947d6 | ||
|
|
ec59249d79 | ||
|
|
7eb869ab1d | ||
|
|
d014724a2d | ||
|
|
dfb6cef364 | ||
|
|
0ebf8c9349 | ||
|
|
9dfd89c90d | ||
|
|
f6972125cd | ||
|
|
6e366bf55a | ||
|
|
5e2e45c673 | ||
|
|
f879235564 | ||
|
|
b00aee2ae7 | ||
|
|
28c2159ec3 | ||
|
|
33dcef2285 | ||
|
|
b9acd0ec28 | ||
|
|
7989d5180b | ||
|
|
238086942e | ||
|
|
a704a30242 | ||
|
|
26dd0d0ea5 | ||
|
|
e31a4bcaa9 | ||
|
|
1722dc570b | ||
|
|
3575e69b43 | ||
|
|
373d89874c | ||
|
|
976087ce97 | ||
|
|
69a45788ee | ||
|
|
92e4de12fb | ||
|
|
ea7fdb9b3d | ||
|
|
fe1c043b8e | ||
|
|
146f597a0b | ||
|
|
d2bef312ce | ||
|
|
61f297215d | ||
|
|
639a9fd540 | ||
|
|
3d0428c518 | ||
|
|
f40f926ce1 | ||
|
|
d6db4f0e4c | ||
|
|
fcbc9471aa | ||
|
|
b147e05794 | ||
|
|
47e6eb546d | ||
|
|
8ba05cb4ed | ||
|
|
84b91e9649 | ||
|
|
703e17478d | ||
|
|
8584e15c32 | ||
|
|
46be7aadab | ||
|
|
a5871f6cba | ||
|
|
917dc1803c | ||
|
|
c0c0961b2b | ||
|
|
0995ac6f9a | ||
|
|
b7f40e4cbf | ||
|
|
754cbb9eaa | ||
|
|
7052b56069 | ||
|
|
decdee825b | ||
|
|
5f66afc399 | ||
|
|
5ceb638edf | ||
|
|
688b9ef5ee | ||
|
|
4909a557d5 | ||
|
|
75f63afadc | ||
|
|
e90a624c9a | ||
|
|
dd85ccd3f8 | ||
|
|
fc54e19ce2 | ||
|
|
118a920e57 | ||
|
|
975a335538 | ||
|
|
c6ec4f38b0 | ||
|
|
5a5d686be1 | ||
|
|
8fc430d124 | ||
|
|
721eb40a8a | ||
|
|
f18103751f | ||
|
|
9d30bb669e | ||
|
|
ab6f5c21c8 | ||
|
|
4fc2ed32d2 | ||
|
|
00ab4f2a7d | ||
|
|
cb5d8b405b | ||
|
|
7b28aa8500 | ||
|
|
97a369df0a | ||
|
|
73a817c1cb | ||
|
|
c16053f0e5 | ||
|
|
3dfd108fc4 | ||
|
|
576696b25e | ||
|
|
781fab5aab | ||
|
|
0f099a19cd | ||
|
|
43b96ea4e5 | ||
|
|
8cbf6bfffa | ||
|
|
52debcdcb3 | ||
|
|
9d38d89c25 | ||
|
|
837f0ca393 | ||
|
|
42fd5b6eb2 | ||
|
|
7bdf76a665 | ||
|
|
784ef278ea |
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.App"
|
||||
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:local="clr-namespace:v2rayN"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
ShutdownMode="OnExplicitShutdown"
|
||||
@@ -16,6 +17,10 @@
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<system:Double x:Key="MenuItemHeight">26</system:Double>
|
||||
<system:Double x:Key="StdFontSize">12</system:Double>
|
||||
<system:Double x:Key="StdFontSize1">13</system:Double>
|
||||
<system:Double x:Key="StdFontSize2">14</system:Double>
|
||||
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
|
||||
<Thickness
|
||||
x:Key="ServerItemMargin"
|
||||
Bottom="4"
|
||||
@@ -32,19 +37,19 @@
|
||||
x:Key="ModuleTitle"
|
||||
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||
TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize2}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="ToolbarTextBlock"
|
||||
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||
TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="StatusbarItem"
|
||||
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||
TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
<Style TargetType="{x:Type TextElement}">
|
||||
@@ -57,7 +62,7 @@
|
||||
</Style>
|
||||
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
|
||||
<Setter Property="Height" Value="20" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="true">
|
||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
|
||||
@@ -75,44 +80,69 @@
|
||||
x:Key="ListItemCheckBox"
|
||||
BasedOn="{StaticResource MaterialDesignUserForegroundCheckBox}"
|
||||
TargetType="{x:Type CheckBox}">
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
</Style>
|
||||
<Style x:Key="ListItemChip" TargetType="{x:Type materialDesign:Chip}">
|
||||
<Setter Property="FontSize" Value="11" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="DefButton"
|
||||
BasedOn="{StaticResource MaterialDesignRaisedButton}"
|
||||
TargetType="{x:Type ButtonBase}">
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="DefContextMenu"
|
||||
BasedOn="{StaticResource MaterialDesignContextMenu}"
|
||||
TargetType="{x:Type ContextMenu}">
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
|
||||
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="ToolbarMenu"
|
||||
BasedOn="{StaticResource MaterialDesignMenu}"
|
||||
TargetType="{x:Type Menu}">
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
|
||||
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="DefComboBox"
|
||||
BasedOn="{StaticResource MaterialDesignComboBox}"
|
||||
TargetType="{x:Type ComboBox}">
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="DefDataGrid"
|
||||
BasedOn="{StaticResource MaterialDesignDataGrid}"
|
||||
TargetType="{x:Type DataGrid}">
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="DefTextBox"
|
||||
BasedOn="{StaticResource MaterialDesignTextBox}"
|
||||
TargetType="{x:Type TextBox}">
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="MyOutlinedTextBox"
|
||||
BasedOn="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||
TargetType="{x:Type TextBox}">
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="MyGroupBox"
|
||||
BasedOn="{StaticResource MaterialDesignGroupBox}"
|
||||
TargetType="{x:Type GroupBox}">
|
||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="MyChipListBoxItem"
|
||||
BasedOn="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBoxItem}"
|
||||
TargetType="{x:Type ListBoxItem}">
|
||||
<Setter Property="Margin" Value="-2,0" />
|
||||
</Style>
|
||||
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
</Application.Resources>
|
||||
|
||||
187
v2rayN/v2rayN/Base/DownloaderHelper.cs
Normal file
187
v2rayN/v2rayN/Base/DownloaderHelper.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using Downloader;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace v2rayN.Base
|
||||
{
|
||||
internal class DownloaderHelper
|
||||
{
|
||||
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
|
||||
public static DownloaderHelper Instance => _instance.Value;
|
||||
|
||||
public async Task<string?> DownloadStringAsync(IWebProxy webProxy, string url, string? userAgent, int timeout)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cancellationToken = new CancellationTokenSource();
|
||||
cancellationToken.CancelAfter(timeout * 1000);
|
||||
|
||||
Uri uri = new(url);
|
||||
//Authorization Header
|
||||
var headers = new WebHeaderCollection();
|
||||
if (!Utils.IsNullOrEmpty(uri.UserInfo))
|
||||
{
|
||||
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
||||
}
|
||||
|
||||
var downloadOpt = new DownloadConfiguration()
|
||||
{
|
||||
Timeout = timeout * 1000,
|
||||
MaxTryAgainOnFailover = 2,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Headers = headers,
|
||||
UserAgent = userAgent,
|
||||
Timeout = timeout * 1000,
|
||||
Proxy = webProxy
|
||||
}
|
||||
};
|
||||
|
||||
using var downloader = new DownloadService(downloadOpt);
|
||||
downloader.DownloadFileCompleted += (sender, value) =>
|
||||
{
|
||||
if (value.Error != null)
|
||||
{
|
||||
throw new Exception(string.Format("{0}", value.Error.Message));
|
||||
}
|
||||
};
|
||||
using var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
|
||||
using StreamReader reader = new(stream);
|
||||
|
||||
downloadOpt = null;
|
||||
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
|
||||
|
||||
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
}
|
||||
|
||||
var cancellationToken = new CancellationTokenSource();
|
||||
cancellationToken.CancelAfter(timeout * 1000);
|
||||
|
||||
var downloadOpt = new DownloadConfiguration()
|
||||
{
|
||||
Timeout = timeout * 1000,
|
||||
MaxTryAgainOnFailover = 2,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Timeout= timeout * 1000,
|
||||
Proxy = webProxy
|
||||
}
|
||||
};
|
||||
|
||||
DateTime totalDatetime = DateTime.Now;
|
||||
int totalSecond = 0;
|
||||
var hasValue = false;
|
||||
double maxSpeed = 0;
|
||||
using var downloader = new DownloadService(downloadOpt);
|
||||
//downloader.DownloadStarted += (sender, value) =>
|
||||
//{
|
||||
// if (progress != null)
|
||||
// {
|
||||
// progress.Report("Start download data...");
|
||||
// }
|
||||
//};
|
||||
downloader.DownloadProgressChanged += (sender, value) =>
|
||||
{
|
||||
TimeSpan ts = (DateTime.Now - totalDatetime);
|
||||
if (progress != null && ts.Seconds > totalSecond)
|
||||
{
|
||||
hasValue = true;
|
||||
totalSecond = ts.Seconds;
|
||||
if (value.BytesPerSecondSpeed > maxSpeed)
|
||||
{
|
||||
maxSpeed = value.BytesPerSecondSpeed;
|
||||
var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
|
||||
progress.Report(speed);
|
||||
}
|
||||
}
|
||||
};
|
||||
downloader.DownloadFileCompleted += (sender, value) =>
|
||||
{
|
||||
if (progress != null)
|
||||
{
|
||||
if (!hasValue && value.Error != null)
|
||||
{
|
||||
progress.Report(value.Error?.Message);
|
||||
}
|
||||
}
|
||||
};
|
||||
progress.Report("......");
|
||||
|
||||
await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
|
||||
|
||||
downloadOpt = null;
|
||||
}
|
||||
|
||||
public async Task DownloadFileAsync(IWebProxy webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fileName));
|
||||
}
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
File.Delete(fileName);
|
||||
}
|
||||
|
||||
var cancellationToken = new CancellationTokenSource();
|
||||
cancellationToken.CancelAfter(timeout * 1000);
|
||||
|
||||
var downloadOpt = new DownloadConfiguration()
|
||||
{
|
||||
Timeout = timeout * 1000,
|
||||
MaxTryAgainOnFailover = 2,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Timeout= timeout * 1000,
|
||||
Proxy = webProxy
|
||||
}
|
||||
};
|
||||
|
||||
var progressPercentage = 0;
|
||||
var hasValue = false;
|
||||
using var downloader = new DownloadService(downloadOpt);
|
||||
downloader.DownloadStarted += (sender, value) =>
|
||||
{
|
||||
progress?.Report(0);
|
||||
};
|
||||
downloader.DownloadProgressChanged += (sender, value) =>
|
||||
{
|
||||
hasValue = true;
|
||||
var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
|
||||
if (progressPercentage != percent && percent % 10 == 0)
|
||||
{
|
||||
progressPercentage = percent;
|
||||
progress.Report(percent);
|
||||
}
|
||||
};
|
||||
downloader.DownloadFileCompleted += (sender, value) =>
|
||||
{
|
||||
if (progress != null)
|
||||
{
|
||||
if (hasValue && value.Error == null)
|
||||
{
|
||||
progress.Report(101);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await downloader.DownloadFileTaskAsync(url, fileName, cancellationToken: cancellationToken.Token);
|
||||
|
||||
downloadOpt = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,14 +26,14 @@ namespace v2rayN.Base
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpClientHelper httpClientHelper = new HttpClientHelper();
|
||||
HttpClientHelper httpClientHelper = new();
|
||||
|
||||
HttpClientHandler handler = new HttpClientHandler() { UseCookies = false };
|
||||
HttpClientHandler handler = new() { UseCookies = false };
|
||||
httpClientHelper.httpClient = new HttpClient(handler);
|
||||
return httpClientHelper;
|
||||
}
|
||||
}
|
||||
public async Task<string> GetAsync(string url)
|
||||
public async Task<string?> GetAsync(string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace v2rayN.Base
|
||||
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
public async Task<string> GetAsync(HttpClient client, string url, CancellationToken token)
|
||||
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
@@ -54,7 +54,7 @@ namespace v2rayN.Base
|
||||
{
|
||||
throw new Exception(string.Format("{0}", response.StatusCode));
|
||||
}
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
return await response.Content.ReadAsStringAsync(token);
|
||||
}
|
||||
|
||||
public async Task PutAsync(string url, Dictionary<string, string> headers)
|
||||
@@ -71,11 +71,11 @@ namespace v2rayN.Base
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
throw new ArgumentNullException("url");
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
throw new ArgumentNullException("fileName");
|
||||
throw new ArgumentNullException(nameof(fileName));
|
||||
}
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
@@ -89,56 +89,51 @@ namespace v2rayN.Base
|
||||
throw new Exception(string.Format("{0}", response.StatusCode));
|
||||
}
|
||||
|
||||
var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
|
||||
var total = response.Content.Headers.ContentLength ?? -1L;
|
||||
var canReportProgress = total != -1 && progress != null;
|
||||
|
||||
using (var stream = await response.Content.ReadAsStreamAsync())
|
||||
using var stream = await response.Content.ReadAsStreamAsync(token);
|
||||
using var file = File.Create(fileName);
|
||||
var totalRead = 0L;
|
||||
var buffer = new byte[1024 * 1024];
|
||||
var isMoreToRead = true;
|
||||
var progressPercentage = 0;
|
||||
|
||||
do
|
||||
{
|
||||
using (var file = File.Create(fileName))
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
var read = await stream.ReadAsync(buffer, token);
|
||||
|
||||
if (read == 0)
|
||||
{
|
||||
var totalRead = 0L;
|
||||
var buffer = new byte[1024 * 1024];
|
||||
var isMoreToRead = true;
|
||||
var progressPercentage = 0;
|
||||
isMoreToRead = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = new byte[read];
|
||||
buffer.ToList().CopyTo(0, data, 0, read);
|
||||
|
||||
do
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
// TODO: put here the code to write the file to disk
|
||||
file.Write(data, 0, read);
|
||||
|
||||
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
|
||||
totalRead += read;
|
||||
|
||||
if (read == 0)
|
||||
{
|
||||
isMoreToRead = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = new byte[read];
|
||||
buffer.ToList().CopyTo(0, data, 0, read);
|
||||
|
||||
// TODO: put here the code to write the file to disk
|
||||
file.Write(data, 0, read);
|
||||
|
||||
totalRead += read;
|
||||
|
||||
if (canReportProgress)
|
||||
{
|
||||
var percent = Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
|
||||
if (progressPercentage != percent && percent % 10 == 0)
|
||||
{
|
||||
progressPercentage = percent;
|
||||
progress.Report(percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (isMoreToRead);
|
||||
file.Close();
|
||||
if (canReportProgress)
|
||||
{
|
||||
progress.Report(101);
|
||||
|
||||
var percent = Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
|
||||
if (progressPercentage != percent && percent % 10 == 0)
|
||||
{
|
||||
progressPercentage = percent;
|
||||
progress.Report(percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (isMoreToRead);
|
||||
if (canReportProgress)
|
||||
{
|
||||
progress.Report(101);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +141,7 @@ namespace v2rayN.Base
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
throw new ArgumentNullException("url");
|
||||
throw new ArgumentNullException(nameof(url));
|
||||
}
|
||||
|
||||
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
||||
@@ -159,57 +154,55 @@ namespace v2rayN.Base
|
||||
//var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
|
||||
//var canReportProgress = total != -1 && progress != null;
|
||||
|
||||
using (var stream = await response.Content.ReadAsStreamAsync())
|
||||
using var stream = await response.Content.ReadAsStreamAsync(token);
|
||||
var totalRead = 0L;
|
||||
var buffer = new byte[1024 * 64];
|
||||
var isMoreToRead = true;
|
||||
string progressSpeed = string.Empty;
|
||||
DateTime totalDatetime = DateTime.Now;
|
||||
int totalSecond = 0;
|
||||
|
||||
do
|
||||
{
|
||||
var totalRead = 0L;
|
||||
var buffer = new byte[1024 * 64];
|
||||
var isMoreToRead = true;
|
||||
string progressSpeed = string.Empty;
|
||||
DateTime totalDatetime = DateTime.Now;
|
||||
int totalSecond = 0;
|
||||
|
||||
do
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
if (totalRead > 0)
|
||||
{
|
||||
if (totalRead > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
|
||||
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
|
||||
|
||||
if (read == 0)
|
||||
{
|
||||
isMoreToRead = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = new byte[read];
|
||||
buffer.ToList().CopyTo(0, data, 0, read);
|
||||
token.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
totalRead += read;
|
||||
var read = await stream.ReadAsync(buffer, token);
|
||||
|
||||
TimeSpan ts = (DateTime.Now - totalDatetime);
|
||||
if (progress != null && ts.Seconds > totalSecond)
|
||||
if (read == 0)
|
||||
{
|
||||
isMoreToRead = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = new byte[read];
|
||||
buffer.ToList().CopyTo(0, data, 0, read);
|
||||
|
||||
// TODO:
|
||||
totalRead += read;
|
||||
|
||||
TimeSpan ts = (DateTime.Now - totalDatetime);
|
||||
if (progress != null && ts.Seconds > totalSecond)
|
||||
{
|
||||
totalSecond = ts.Seconds;
|
||||
var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
|
||||
if (progressSpeed != speed)
|
||||
{
|
||||
totalSecond = ts.Seconds;
|
||||
var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
|
||||
if (progressSpeed != speed)
|
||||
{
|
||||
progressSpeed = speed;
|
||||
progress.Report(speed);
|
||||
}
|
||||
progressSpeed = speed;
|
||||
progress.Report(speed);
|
||||
}
|
||||
}
|
||||
} while (isMoreToRead);
|
||||
}
|
||||
}
|
||||
} while (isMoreToRead);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace v2rayN.Base
|
||||
{
|
||||
public sealed class SqliteHelper
|
||||
{
|
||||
private static readonly Lazy<SqliteHelper> _instance = new Lazy<SqliteHelper>(() => new());
|
||||
private static readonly Lazy<SqliteHelper> _instance = new(() => new());
|
||||
public static SqliteHelper Instance => _instance.Value;
|
||||
private string _connstr;
|
||||
public SQLiteConnection _db;
|
||||
@@ -34,7 +34,7 @@ namespace v2rayN.Base
|
||||
|
||||
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
|
||||
{
|
||||
string line;
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.IsWhiteSpace()) continue;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace v2rayN.Converters
|
||||
return new SolidColorBrush(Colors.IndianRed);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
public object? ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
27
v2rayN/v2rayN/Converters/MaterialDesignFonts.cs
Normal file
27
v2rayN/v2rayN/Converters/MaterialDesignFonts.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Windows.Media;
|
||||
using v2rayN.Handler;
|
||||
|
||||
namespace v2rayN.Converters
|
||||
{
|
||||
public class MaterialDesignFonts
|
||||
{
|
||||
public static FontFamily MyFont { get; }
|
||||
|
||||
static MaterialDesignFonts()
|
||||
{
|
||||
try
|
||||
{
|
||||
var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
|
||||
if (!string.IsNullOrEmpty(fontFamily))
|
||||
{
|
||||
var fontPath = Utils.GetFontsPath();
|
||||
MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
MyFont ??= new FontFamily("Microsoft YaHei");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
class Global
|
||||
{
|
||||
#region const
|
||||
public const string githubUrl = "https://github.com";
|
||||
public const string githubApiUrl = "https://api.github.com/repos";
|
||||
public const string v2rayWebsiteUrl = @"https://www.v2fly.org/";
|
||||
public const string AboutUrl = @"https://github.com/2dust/v2rayN";
|
||||
public const string UpdateUrl = AboutUrl + @"/releases";
|
||||
@@ -12,12 +14,11 @@
|
||||
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
|
||||
public const string clashCoreUrl = "https://github.com/Dreamacro/clash/releases";
|
||||
public const string clashMetaCoreUrl = "https://github.com/MetaCubeX/Clash.Meta/releases";
|
||||
public const string hysteriaCoreUrl = "https://github.com/HyNetwork/hysteria/releases";
|
||||
public const string hysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
|
||||
public const string naiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
|
||||
public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
|
||||
public const string singboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
|
||||
public const string geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
||||
public const string SpeedTestUrl = @"http://cachefly.cachefly.net/10mb.test";
|
||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||
|
||||
@@ -77,34 +78,46 @@
|
||||
public const string CommandClearMsg = "CommandClearMsg";
|
||||
public const string DelayUnit = "";
|
||||
public const string SpeedUnit = "";
|
||||
public const int MinFontSize = 10;
|
||||
|
||||
public static readonly List<string> IEProxyProtocols = new List<string> {
|
||||
public static readonly List<string> IEProxyProtocols = new() {
|
||||
"{ip}:{http_port}",
|
||||
"socks={ip}:{socks_port}",
|
||||
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
||||
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
||||
""
|
||||
};
|
||||
public static readonly List<string> vmessSecuritys = new List<string> { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
||||
public static readonly List<string> ssSecuritys = new List<string> { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
||||
public static readonly List<string> ssSecuritysInSagerNet = new List<string> { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
|
||||
public static readonly List<string> ssSecuritysInXray = new List<string> { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
||||
public static readonly List<string> xtlsFlows = new List<string> { "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||
public static readonly List<string> networks = new List<string> { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
|
||||
public static readonly List<string> kcpHeaderTypes = new List<string> { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||
public static readonly List<string> coreTypes = new List<string> { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
|
||||
public static readonly List<string> domainStrategys = new List<string> { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
||||
public static readonly List<string> domainMatchers = new List<string> { "linear", "mph", "" };
|
||||
public static readonly List<string> fingerprints = new List<string> { "chrome", "firefox", "safari", "randomized", "" };
|
||||
public static readonly List<string> allowInsecures = new List<string> { "true", "false", "" };
|
||||
public static readonly List<string> domainStrategy4Freedoms = new List<string> { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
||||
public static readonly List<string> Languages = new List<string> { "zh-Hans", "en" ,"fa-Ir" };
|
||||
public static readonly List<string> alpns = new List<string> { "h2", "http/1.1", "h2,http/1.1", "" };
|
||||
public static readonly List<string> LogLevel = new List<string> { "debug", "info", "warning", "error", "none" };
|
||||
public static readonly List<string> InboundTags = new List<string> { "socks", "http", "socks2", "http2" };
|
||||
public static readonly List<string> Protocols = new List<string> { "http", "tls", "bittorrent" };
|
||||
public static readonly List<string> TunMtus = new List<string> { "9000", "1500" };
|
||||
public static readonly List<string> TunStacks = new List<string> { "gvisor", "system" };
|
||||
public static readonly List<string> vmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
||||
public static readonly List<string> ssSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
||||
public static readonly List<string> ssSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
|
||||
public static readonly List<string> ssSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
||||
public static readonly List<string> xtlsFlows = new() { "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||
public static readonly List<string> networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
|
||||
public static readonly List<string> kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||
public static readonly List<string> coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
|
||||
public static readonly List<string> domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
||||
public static readonly List<string> domainMatchers = new() { "linear", "mph", "" };
|
||||
public static readonly List<string> fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
|
||||
public static readonly List<string> userAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
|
||||
public static readonly Dictionary<string, string> userAgentTxt = new()
|
||||
{
|
||||
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
|
||||
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
||||
{"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" },
|
||||
{"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" },
|
||||
{"none",""}
|
||||
};
|
||||
public static readonly List<string> allowInsecures = new() { "true", "false", "" };
|
||||
public static readonly List<string> domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
||||
public static readonly List<string> Languages = new() { "zh-Hans", "en", "fa-Ir", "ru" };
|
||||
public static readonly List<string> alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" };
|
||||
public static readonly List<string> LogLevel = new() { "debug", "info", "warning", "error", "none" };
|
||||
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
||||
public static readonly List<string> Protocols = new() { "http", "tls", "bittorrent" };
|
||||
public static readonly List<string> TunMtus = new() { "9000", "1500" };
|
||||
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
||||
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
||||
public static readonly List<string> SpeedTestUrls = new() { @"http://cachefly.cachefly.net/100mb.test", @"http://cachefly.cachefly.net/10mb.test" };
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace v2rayN.Handler
|
||||
class ConfigHandler
|
||||
{
|
||||
private static string configRes = Global.ConfigFileName;
|
||||
private static readonly object objLock = new object();
|
||||
private static readonly object objLock = new();
|
||||
|
||||
#region ConfigHandler
|
||||
|
||||
@@ -43,18 +43,17 @@ namespace v2rayN.Handler
|
||||
if (config == null)
|
||||
{
|
||||
config = new Config
|
||||
{
|
||||
};
|
||||
}
|
||||
if (config.coreBasicItem == null)
|
||||
{
|
||||
config.coreBasicItem = new()
|
||||
{
|
||||
logEnabled = false,
|
||||
loglevel = "warning",
|
||||
|
||||
//Mux
|
||||
muxEnabled = false,
|
||||
|
||||
enableStatistics = false,
|
||||
|
||||
statisticsFreshRate = 1,
|
||||
|
||||
enableRoutingAdvanced = true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ namespace v2rayN.Handler
|
||||
if (config.inbound == null)
|
||||
{
|
||||
config.inbound = new List<InItem>();
|
||||
InItem inItem = new InItem
|
||||
InItem inItem = new()
|
||||
{
|
||||
protocol = Global.InboundSocks,
|
||||
localPort = 10808,
|
||||
@@ -87,10 +86,17 @@ namespace v2rayN.Handler
|
||||
config.inbound[0].protocol = Global.InboundSocks;
|
||||
}
|
||||
}
|
||||
//路由规则
|
||||
if (Utils.IsNullOrEmpty(config.domainStrategy))
|
||||
if (config.routingBasicItem == null)
|
||||
{
|
||||
config.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch";
|
||||
config.routingBasicItem = new()
|
||||
{
|
||||
enableRoutingAdvanced = true
|
||||
};
|
||||
}
|
||||
//路由规则
|
||||
if (Utils.IsNullOrEmpty(config.routingBasicItem.domainStrategy))
|
||||
{
|
||||
config.routingBasicItem.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch";
|
||||
}
|
||||
//if (Utils.IsNullOrEmpty(config.domainMatcher))
|
||||
//{
|
||||
@@ -130,6 +136,14 @@ namespace v2rayN.Handler
|
||||
mtu = 9000,
|
||||
};
|
||||
}
|
||||
if (config.guiItem == null)
|
||||
{
|
||||
config.guiItem = new()
|
||||
{
|
||||
enableStatistics = false,
|
||||
statisticsFreshRate = 1,
|
||||
};
|
||||
}
|
||||
if (config.uiItem == null)
|
||||
{
|
||||
config.uiItem = new UIItem()
|
||||
@@ -150,14 +164,6 @@ namespace v2rayN.Handler
|
||||
{
|
||||
config.constItem = new ConstItem();
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(config.constItem.speedTestUrl))
|
||||
{
|
||||
config.constItem.speedTestUrl = Global.SpeedTestUrl;
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(config.constItem.speedPingTestUrl))
|
||||
{
|
||||
config.constItem.speedPingTestUrl = Global.SpeedPingTestUrl;
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions))
|
||||
{
|
||||
config.constItem.defIEProxyExceptions = Global.IEProxyExceptions;
|
||||
@@ -167,9 +173,26 @@ namespace v2rayN.Handler
|
||||
// config.remoteDNS = "1.1.1.1";
|
||||
//}
|
||||
|
||||
if (config.statisticsFreshRate > 100 || config.statisticsFreshRate < 1)
|
||||
if (config.speedTestItem == null)
|
||||
{
|
||||
config.statisticsFreshRate = 1;
|
||||
config.speedTestItem = new();
|
||||
}
|
||||
if (config.speedTestItem.speedTestTimeout < 10)
|
||||
{
|
||||
config.speedTestItem.speedTestTimeout = 10;
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(config.speedTestItem.speedTestUrl))
|
||||
{
|
||||
config.speedTestItem.speedTestUrl = Global.SpeedTestUrls[0];
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(config.speedTestItem.speedPingTestUrl))
|
||||
{
|
||||
config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl;
|
||||
}
|
||||
|
||||
if (config.guiItem.statisticsFreshRate is > 100 or < 1)
|
||||
{
|
||||
config.guiItem.statisticsFreshRate = 1;
|
||||
}
|
||||
|
||||
if (config == null)
|
||||
@@ -182,7 +205,7 @@ namespace v2rayN.Handler
|
||||
|
||||
}
|
||||
|
||||
LazyConfig.Instance.SetConfig(ref config);
|
||||
LazyConfig.Instance.SetConfig(config);
|
||||
return 0;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -288,20 +311,45 @@ namespace v2rayN.Handler
|
||||
}
|
||||
|
||||
config = Utils.FromJson<Config>(Utils.ToJson(configOld));
|
||||
if (config.tunModeItem == null)
|
||||
|
||||
if (config.coreBasicItem == null)
|
||||
{
|
||||
config.tunModeItem = new TunModeItem
|
||||
config.coreBasicItem = new()
|
||||
{
|
||||
enableTun = false,
|
||||
showWindow = true,
|
||||
mtu = 9000,
|
||||
logEnabled = configOld.logEnabled,
|
||||
loglevel = configOld.loglevel,
|
||||
muxEnabled = configOld.muxEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
if (config.routingBasicItem == null)
|
||||
{
|
||||
config.routingBasicItem = new()
|
||||
{
|
||||
enableRoutingAdvanced = configOld.enableRoutingAdvanced,
|
||||
domainStrategy = configOld.domainStrategy
|
||||
};
|
||||
}
|
||||
|
||||
if (config.guiItem == null)
|
||||
{
|
||||
config.guiItem = new()
|
||||
{
|
||||
enableStatistics = configOld.enableStatistics,
|
||||
statisticsFreshRate = configOld.statisticsFreshRate,
|
||||
keepOlderDedupl = configOld.keepOlderDedupl,
|
||||
ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
|
||||
autoUpdateInterval = configOld.autoUpdateInterval,
|
||||
checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
|
||||
enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
|
||||
trayMenuServersLimit = configOld.trayMenuServersLimit,
|
||||
};
|
||||
}
|
||||
|
||||
GetDefaultServer(ref config);
|
||||
GetDefaultRouting(ref config);
|
||||
SaveConfig(ref config);
|
||||
LazyConfig.Instance.SetConfig(ref config);
|
||||
LoadConfig(ref config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -390,14 +438,14 @@ namespace v2rayN.Handler
|
||||
/// <param name="config"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public static int SetDefaultServer(ref Config config, ProfileItem item)
|
||||
public static int SetDefaultServerIndex(ref Config config, string? indexId)
|
||||
{
|
||||
if (item == null)
|
||||
if (Utils.IsNullOrEmpty(indexId))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
config.indexId = item.indexId;
|
||||
config.indexId = indexId;
|
||||
Global.reloadCore = true;
|
||||
|
||||
ToJsonFile(config);
|
||||
@@ -405,34 +453,34 @@ namespace v2rayN.Handler
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int SetDefaultServer(Config config, List<ProfileItem> lstProfile)
|
||||
public static int SetDefaultServer(Config config, List<ProfileItemModel> lstProfile)
|
||||
{
|
||||
if (lstProfile.Exists(t => t.indexId == config.indexId))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.indexId == config.indexId).Count() > 0)
|
||||
var allItems = LazyConfig.Instance.ProfileItemIndexs("");
|
||||
if (allItems.Where(t => t == config.indexId).Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (lstProfile.Count > 0)
|
||||
{
|
||||
return SetDefaultServer(ref config, lstProfile[0]);
|
||||
return SetDefaultServerIndex(ref config, lstProfile[0].indexId);
|
||||
}
|
||||
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
|
||||
if (allItems.Count > 0)
|
||||
{
|
||||
return SetDefaultServer(ref config, SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault());
|
||||
return SetDefaultServerIndex(ref config, allItems.FirstOrDefault());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public static ProfileItem GetDefaultServer(ref Config config)
|
||||
public static ProfileItem? GetDefaultServer(ref Config config)
|
||||
{
|
||||
var item = LazyConfig.Instance.GetProfileItem(config.indexId);
|
||||
if (item is null)
|
||||
{
|
||||
var item2 = SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault();
|
||||
SetDefaultServer(ref config, item2);
|
||||
SetDefaultServerIndex(ref config, item2?.indexId);
|
||||
return item2;
|
||||
}
|
||||
|
||||
@@ -457,9 +505,10 @@ namespace v2rayN.Handler
|
||||
|
||||
for (int i = 0; i < lstProfile.Count; i++)
|
||||
{
|
||||
lstProfile[i].sort = (i + 1) * 10;
|
||||
ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
|
||||
}
|
||||
|
||||
var sort = 0;
|
||||
switch (eMove)
|
||||
{
|
||||
case EMove.Top:
|
||||
@@ -468,7 +517,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
lstProfile[index].sort = lstProfile[0].sort - 1;
|
||||
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -478,7 +527,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
lstProfile[index].sort = lstProfile[index - 1].sort - 1;
|
||||
sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -489,7 +538,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
lstProfile[index].sort = lstProfile[index + 1].sort + 1;
|
||||
sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -499,18 +548,16 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
lstProfile[index].sort = lstProfile[lstProfile.Count - 1].sort + 1;
|
||||
sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1;
|
||||
|
||||
break;
|
||||
}
|
||||
case EMove.Position:
|
||||
lstProfile[index].sort = pos * 10 + 1;
|
||||
sort = pos * 10 + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
SqliteHelper.Instance.UpdateAll(lstProfile);
|
||||
|
||||
|
||||
ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -638,7 +685,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
|
||||
{
|
||||
profileItem.allowInsecure = config.defAllowInsecure.ToString();
|
||||
profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
|
||||
}
|
||||
|
||||
AddServerCommon(ref config, profileItem);
|
||||
@@ -650,11 +697,29 @@ namespace v2rayN.Handler
|
||||
public static int SortServers(ref Config config, string subId, EServerColName name, bool asc)
|
||||
{
|
||||
var lstModel = LazyConfig.Instance.ProfileItems(subId, "");
|
||||
var lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
|
||||
if (lstProfile.Count <= 0)
|
||||
if (lstModel.Count <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
|
||||
var lstProfile = (from t in lstModel
|
||||
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
|
||||
from t33 in t3b.DefaultIfEmpty()
|
||||
select new ProfileItemModel
|
||||
{
|
||||
indexId = t.indexId,
|
||||
configType = t.configType,
|
||||
remarks = t.remarks,
|
||||
address = t.address,
|
||||
port = t.port,
|
||||
security = t.security,
|
||||
network = t.network,
|
||||
streamSecurity = t.streamSecurity,
|
||||
delay = t33 == null ? 0 : t33.delay,
|
||||
speed = t33 == null ? 0 : t33.speed,
|
||||
sort = t33 == null ? 0 : t33.sort
|
||||
}).ToList();
|
||||
|
||||
var propertyName = string.Empty;
|
||||
switch (name)
|
||||
{
|
||||
@@ -688,10 +753,30 @@ namespace v2rayN.Handler
|
||||
}
|
||||
for (int i = 0; i < lstProfile.Count; i++)
|
||||
{
|
||||
lstProfile[i].sort = (i + 1) * 10;
|
||||
ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
|
||||
}
|
||||
if (name == EServerColName.delay)
|
||||
{
|
||||
var maxSort = lstProfile.Max(t => t.sort) + 10;
|
||||
foreach (var item in lstProfile)
|
||||
{
|
||||
if (item.delay <= 0)
|
||||
{
|
||||
ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name == EServerColName.speed)
|
||||
{
|
||||
var maxSort = lstProfile.Max(t => t.sort) + 10;
|
||||
foreach (var item in lstProfile)
|
||||
{
|
||||
if (item.speed <= 0)
|
||||
{
|
||||
ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SqliteHelper.Instance.UpdateAll(lstProfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -723,9 +808,9 @@ namespace v2rayN.Handler
|
||||
public static int DedupServerList(ref Config config, ref List<ProfileItem> lstProfile)
|
||||
{
|
||||
List<ProfileItem> source = lstProfile;
|
||||
bool keepOlder = config.keepOlderDedupl;
|
||||
bool keepOlder = config.guiItem.keepOlderDedupl;
|
||||
|
||||
List<ProfileItem> list = new List<ProfileItem>();
|
||||
List<ProfileItem> list = new();
|
||||
if (!keepOlder) source.Reverse(); // Remove the early items first
|
||||
|
||||
foreach (ProfileItem item in source)
|
||||
@@ -750,7 +835,7 @@ namespace v2rayN.Handler
|
||||
profileItem.configVersion = 2;
|
||||
if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
|
||||
{
|
||||
profileItem.allowInsecure = config.defAllowInsecure.ToString();
|
||||
profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network))
|
||||
{
|
||||
@@ -760,15 +845,8 @@ namespace v2rayN.Handler
|
||||
if (Utils.IsNullOrEmpty(profileItem.indexId))
|
||||
{
|
||||
profileItem.indexId = Utils.GetGUID(false);
|
||||
if (profileItem.sort <= 0)
|
||||
{
|
||||
var maxSort = 0;
|
||||
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
|
||||
{
|
||||
maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t == null ? 0 : t.sort);
|
||||
}
|
||||
profileItem.sort = maxSort + 1;
|
||||
}
|
||||
var maxSort = ProfileExHandler.Instance.GetMaxSort();
|
||||
ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
|
||||
}
|
||||
else if (profileItem.indexId == config.indexId)
|
||||
{
|
||||
@@ -859,11 +937,11 @@ namespace v2rayN.Handler
|
||||
}
|
||||
|
||||
int countServers = 0;
|
||||
var maxSort = 0;
|
||||
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
|
||||
{
|
||||
maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort);
|
||||
}
|
||||
//var maxSort = 0;
|
||||
//if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
|
||||
//{
|
||||
// maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort);
|
||||
//}
|
||||
string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray());
|
||||
foreach (string str in arrData)
|
||||
{
|
||||
@@ -901,7 +979,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
profileItem.subid = subid;
|
||||
profileItem.isSub = isSub;
|
||||
profileItem.sort = maxSort + countServers + 1;
|
||||
//profileItem.sort = maxSort + countServers + 1;
|
||||
|
||||
if (profileItem.configType == EConfigType.VMess)
|
||||
{
|
||||
@@ -951,9 +1029,19 @@ namespace v2rayN.Handler
|
||||
return -1;
|
||||
}
|
||||
|
||||
ProfileItem profileItem = new ProfileItem();
|
||||
//判断str是否包含s的任意一个字符串
|
||||
static bool Containss(string str, params string[] s)
|
||||
{
|
||||
foreach (var item in s)
|
||||
{
|
||||
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ProfileItem profileItem = new();
|
||||
//Is v2ray configuration
|
||||
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData);
|
||||
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData);
|
||||
if (v2rayConfig != null
|
||||
&& v2rayConfig.inbounds != null
|
||||
&& v2rayConfig.inbounds.Count > 0
|
||||
@@ -968,9 +1056,7 @@ namespace v2rayN.Handler
|
||||
profileItem.remarks = "v2ray_custom";
|
||||
}
|
||||
//Is Clash configuration
|
||||
else if (clipboardData.IndexOf("port") >= 0
|
||||
&& clipboardData.IndexOf("socks-port") >= 0
|
||||
&& clipboardData.IndexOf("proxies") >= 0)
|
||||
else if (Containss(clipboardData, "port", "socks-port", "proxies"))
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
|
||||
File.WriteAllText(fileName, clipboardData);
|
||||
@@ -980,12 +1066,7 @@ namespace v2rayN.Handler
|
||||
profileItem.remarks = "clash_custom";
|
||||
}
|
||||
//Is hysteria configuration
|
||||
else if (clipboardData.IndexOf("server") >= 0
|
||||
&& clipboardData.IndexOf("up") >= 0
|
||||
&& clipboardData.IndexOf("down") >= 0
|
||||
&& clipboardData.IndexOf("listen") >= 0
|
||||
&& clipboardData.IndexOf("<html>") < 0
|
||||
&& clipboardData.IndexOf("<body>") < 0)
|
||||
else if (Containss(clipboardData, "server", "up", "down", "listen", "<html>", "<body>"))
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
||||
File.WriteAllText(fileName, clipboardData);
|
||||
@@ -995,10 +1076,7 @@ namespace v2rayN.Handler
|
||||
profileItem.remarks = "hysteria_custom";
|
||||
}
|
||||
//Is naiveproxy configuration
|
||||
else if (clipboardData.IndexOf("listen") >= 0
|
||||
&& clipboardData.IndexOf("proxy") >= 0
|
||||
&& clipboardData.IndexOf("<html>") < 0
|
||||
&& clipboardData.IndexOf("<body>") < 0)
|
||||
else if (Containss(clipboardData, "listen", "proxy", "<html>", "<body>"))
|
||||
{
|
||||
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
||||
File.WriteAllText(fileName, clipboardData);
|
||||
@@ -1098,7 +1176,7 @@ namespace v2rayN.Handler
|
||||
|
||||
public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub)
|
||||
{
|
||||
List<ProfileItem> lstOriSub = null;
|
||||
List<ProfileItem>? lstOriSub = null;
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
{
|
||||
lstOriSub = LazyConfig.Instance.ProfileItems(subid);
|
||||
@@ -1143,7 +1221,7 @@ namespace v2rayN.Handler
|
||||
return 0;
|
||||
}
|
||||
|
||||
SubItem subItem = new SubItem
|
||||
SubItem subItem = new()
|
||||
{
|
||||
id = string.Empty,
|
||||
remarks = "import_sub",
|
||||
@@ -1194,11 +1272,11 @@ namespace v2rayN.Handler
|
||||
}
|
||||
if (isSub)
|
||||
{
|
||||
SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = {subid}");
|
||||
SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = {subid}");
|
||||
SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1217,6 +1295,22 @@ namespace v2rayN.Handler
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int MoveToGroup(Config config, List<ProfileItem> lstProfile, string subid)
|
||||
{
|
||||
foreach (var it in lstProfile)
|
||||
{
|
||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||
if (item is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.subid = subid;
|
||||
SqliteHelper.Instance.Update(item);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UI
|
||||
@@ -1399,7 +1493,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
if (SqliteHelper.Instance.Table<RoutingItem>().Where(t => t.id == routingItem.id).Count() > 0)
|
||||
{
|
||||
config.routingIndexId = routingItem.id;
|
||||
config.routingBasicItem.routingIndexId = routingItem.id;
|
||||
}
|
||||
|
||||
Global.reloadCore = true;
|
||||
@@ -1410,7 +1504,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
public static RoutingItem GetDefaultRouting(ref Config config)
|
||||
{
|
||||
var item = LazyConfig.Instance.GetRoutingItem(config.routingIndexId);
|
||||
var item = LazyConfig.Instance.GetRoutingItem(config.routingBasicItem.routingIndexId);
|
||||
if (item is null)
|
||||
{
|
||||
var item2 = SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(t => t.locked == false);
|
||||
@@ -1423,13 +1517,16 @@ namespace v2rayN.Handler
|
||||
|
||||
public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false)
|
||||
{
|
||||
if (blImportAdvancedRules || LazyConfig.Instance.RoutingItems().Count <= 0)
|
||||
var items = LazyConfig.Instance.RoutingItems();
|
||||
if (blImportAdvancedRules || items.Count <= 0)
|
||||
{
|
||||
var maxSort = items.Count;
|
||||
//Bypass the mainland
|
||||
var item2 = new RoutingItem()
|
||||
{
|
||||
remarks = "绕过大陆(Whitelist)",
|
||||
url = string.Empty,
|
||||
sort = maxSort + 1,
|
||||
};
|
||||
AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
|
||||
|
||||
@@ -1438,6 +1535,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
remarks = "黑名单(Blacklist)",
|
||||
url = string.Empty,
|
||||
sort = maxSort + 2,
|
||||
};
|
||||
AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
|
||||
|
||||
@@ -1446,6 +1544,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
remarks = "全局(Global)",
|
||||
url = string.Empty,
|
||||
sort = maxSort + 3,
|
||||
};
|
||||
AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace v2rayN.Handler
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
public static int GenerateClientConfig(ProfileItem node, string fileName, out string msg, out string content)
|
||||
public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
|
||||
{
|
||||
content = string.Empty;
|
||||
try
|
||||
@@ -43,7 +43,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
else
|
||||
{
|
||||
V2rayConfig v2rayConfig = null;
|
||||
V2rayConfig? v2rayConfig = null;
|
||||
if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0)
|
||||
{
|
||||
return -1;
|
||||
@@ -73,28 +73,29 @@ namespace v2rayN.Handler
|
||||
{
|
||||
if (blExport)
|
||||
{
|
||||
if (config.logEnabled)
|
||||
if (config.coreBasicItem.logEnabled)
|
||||
{
|
||||
v2rayConfig.log.loglevel = config.loglevel;
|
||||
v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
v2rayConfig.log.loglevel = config.loglevel;
|
||||
v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
|
||||
v2rayConfig.log.access = "";
|
||||
v2rayConfig.log.error = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (config.logEnabled)
|
||||
if (config.coreBasicItem.logEnabled)
|
||||
{
|
||||
v2rayConfig.log.loglevel = config.loglevel;
|
||||
v2rayConfig.log.access = Utils.GetLogPath(v2rayConfig.log.access);
|
||||
v2rayConfig.log.error = Utils.GetLogPath(v2rayConfig.log.error);
|
||||
var dtNow = DateTime.Now;
|
||||
v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
|
||||
v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
|
||||
v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
|
||||
}
|
||||
else
|
||||
{
|
||||
v2rayConfig.log.loglevel = config.loglevel;
|
||||
v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
|
||||
v2rayConfig.log.access = "";
|
||||
v2rayConfig.log.error = "";
|
||||
}
|
||||
@@ -113,11 +114,11 @@ namespace v2rayN.Handler
|
||||
{
|
||||
v2rayConfig.inbounds = new List<Inbounds>();
|
||||
|
||||
Inbounds inbound = GetInbound(config.inbound[0], Global.InboundSocks, 0, true);
|
||||
Inbounds? inbound = GetInbound(config.inbound[0], Global.InboundSocks, 0, true);
|
||||
v2rayConfig.inbounds.Add(inbound);
|
||||
|
||||
//http
|
||||
Inbounds inbound2 = GetInbound(config.inbound[0], Global.InboundHttp, 1, false);
|
||||
Inbounds? inbound2 = GetInbound(config.inbound[0], Global.InboundHttp, 1, false);
|
||||
v2rayConfig.inbounds.Add(inbound2);
|
||||
|
||||
if (config.inbound[0].allowLANConn)
|
||||
@@ -156,7 +157,7 @@ namespace v2rayN.Handler
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static Inbounds GetInbound(InItem inItem, string tag, int offset, bool bSocks)
|
||||
private static Inbounds? GetInbound(InItem inItem, string tag, int offset, bool bSocks)
|
||||
{
|
||||
string result = Utils.GetEmbedText(Global.v2raySampleInbound);
|
||||
if (Utils.IsNullOrEmpty(result))
|
||||
@@ -186,10 +187,10 @@ namespace v2rayN.Handler
|
||||
if (v2rayConfig.routing != null
|
||||
&& v2rayConfig.routing.rules != null)
|
||||
{
|
||||
v2rayConfig.routing.domainStrategy = config.domainStrategy;
|
||||
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.domainMatcher) ? null : config.domainMatcher;
|
||||
v2rayConfig.routing.domainStrategy = config.routingBasicItem.domainStrategy;
|
||||
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.routingBasicItem.domainMatcher) ? null : config.routingBasicItem.domainMatcher;
|
||||
|
||||
if (config.enableRoutingAdvanced)
|
||||
if (config.routingBasicItem.enableRoutingAdvanced)
|
||||
{
|
||||
var routing = ConfigHandler.GetDefaultRouting(ref config);
|
||||
if (routing != null)
|
||||
@@ -347,8 +348,8 @@ namespace v2rayN.Handler
|
||||
}
|
||||
|
||||
//Mux
|
||||
outbound.mux.enabled = config.muxEnabled;
|
||||
outbound.mux.concurrency = config.muxEnabled ? 8 : -1;
|
||||
outbound.mux.enabled = config.coreBasicItem.muxEnabled;
|
||||
outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
|
||||
|
||||
boundStreamSettings(node, "out", outbound.streamSettings);
|
||||
|
||||
@@ -404,7 +405,7 @@ namespace v2rayN.Handler
|
||||
if (!Utils.IsNullOrEmpty(node.security)
|
||||
&& !Utils.IsNullOrEmpty(node.id))
|
||||
{
|
||||
SocksUsersItem socksUsersItem = new SocksUsersItem
|
||||
SocksUsersItem socksUsersItem = new()
|
||||
{
|
||||
user = node.security,
|
||||
pass = node.id,
|
||||
@@ -451,8 +452,8 @@ namespace v2rayN.Handler
|
||||
usersItem.encryption = node.security;
|
||||
|
||||
//Mux
|
||||
outbound.mux.enabled = config.muxEnabled;
|
||||
outbound.mux.concurrency = config.muxEnabled ? 8 : -1;
|
||||
outbound.mux.enabled = config.coreBasicItem.muxEnabled;
|
||||
outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
|
||||
|
||||
boundStreamSettings(node, "out", outbound.streamSettings);
|
||||
|
||||
@@ -546,17 +547,29 @@ namespace v2rayN.Handler
|
||||
streamSettings.network = node.GetNetwork();
|
||||
string host = node.requestHost.TrimEx();
|
||||
string sni = node.sni;
|
||||
string useragent = "";
|
||||
if (!config.coreBasicItem.defUserAgent.IsNullOrEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
useragent = Global.userAgentTxt[config.coreBasicItem.defUserAgent];
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
useragent = config.coreBasicItem.defUserAgent;
|
||||
}
|
||||
}
|
||||
|
||||
//if tls
|
||||
if (node.streamSecurity == Global.StreamSecurity)
|
||||
{
|
||||
streamSettings.security = node.streamSecurity;
|
||||
|
||||
TlsSettings tlsSettings = new TlsSettings
|
||||
TlsSettings tlsSettings = new()
|
||||
{
|
||||
allowInsecure = Utils.ToBool(node.allowInsecure),
|
||||
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
|
||||
alpn = node.GetAlpn(),
|
||||
fingerprint = node.fingerprint
|
||||
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(sni))
|
||||
{
|
||||
@@ -574,11 +587,11 @@ namespace v2rayN.Handler
|
||||
{
|
||||
streamSettings.security = node.streamSecurity;
|
||||
|
||||
TlsSettings xtlsSettings = new TlsSettings
|
||||
TlsSettings xtlsSettings = new()
|
||||
{
|
||||
allowInsecure = Utils.ToBool(node.allowInsecure),
|
||||
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
|
||||
alpn = node.GetAlpn(),
|
||||
fingerprint = node.fingerprint
|
||||
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(sni))
|
||||
{
|
||||
@@ -595,7 +608,7 @@ namespace v2rayN.Handler
|
||||
switch (node.GetNetwork())
|
||||
{
|
||||
case "kcp":
|
||||
KcpSettings kcpSettings = new KcpSettings
|
||||
KcpSettings kcpSettings = new()
|
||||
{
|
||||
mtu = config.kcpItem.mtu,
|
||||
tti = config.kcpItem.tti
|
||||
@@ -631,22 +644,21 @@ namespace v2rayN.Handler
|
||||
break;
|
||||
//ws
|
||||
case "ws":
|
||||
WsSettings wsSettings = new WsSettings
|
||||
{
|
||||
};
|
||||
|
||||
WsSettings wsSettings = new();
|
||||
wsSettings.headers = new Headers();
|
||||
string path = node.path;
|
||||
if (!string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
wsSettings.headers = new Headers
|
||||
{
|
||||
Host = host
|
||||
};
|
||||
wsSettings.headers.Host = host;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
wsSettings.path = path;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(useragent))
|
||||
{
|
||||
wsSettings.headers.UserAgent = useragent;
|
||||
}
|
||||
streamSettings.wsSettings = wsSettings;
|
||||
|
||||
//TlsSettings tlsSettings = new TlsSettings();
|
||||
@@ -659,7 +671,7 @@ namespace v2rayN.Handler
|
||||
break;
|
||||
//h2
|
||||
case "h2":
|
||||
HttpSettings httpSettings = new HttpSettings();
|
||||
HttpSettings httpSettings = new();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
@@ -675,7 +687,7 @@ namespace v2rayN.Handler
|
||||
break;
|
||||
//quic
|
||||
case "quic":
|
||||
QuicSettings quicsettings = new QuicSettings
|
||||
QuicSettings quicsettings = new()
|
||||
{
|
||||
security = host,
|
||||
key = node.path,
|
||||
@@ -698,7 +710,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
break;
|
||||
case "grpc":
|
||||
var grpcSettings = new GrpcSettings
|
||||
GrpcSettings grpcSettings = new()
|
||||
{
|
||||
serviceName = node.path,
|
||||
multiMode = (node.headerType == Global.GrpcmultiMode),
|
||||
@@ -714,7 +726,7 @@ namespace v2rayN.Handler
|
||||
//tcp
|
||||
if (node.headerType.Equals(Global.TcpHeaderHttp))
|
||||
{
|
||||
TcpSettings tcpSettings = new TcpSettings
|
||||
TcpSettings tcpSettings = new()
|
||||
{
|
||||
header = new Header
|
||||
{
|
||||
@@ -730,7 +742,7 @@ namespace v2rayN.Handler
|
||||
string host2 = string.Join("\",\"", arrHost);
|
||||
request = request.Replace("$requestHost$", $"\"{host2}\"");
|
||||
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost()));
|
||||
|
||||
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
|
||||
//Path
|
||||
string pathHttp = @"/";
|
||||
if (!Utils.IsNullOrEmpty(node.path))
|
||||
@@ -783,7 +795,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> servers = new List<string>();
|
||||
List<string> servers = new();
|
||||
|
||||
string[] arrDNS = config.remoteDNS.Split(',');
|
||||
foreach (string str in arrDNS)
|
||||
@@ -809,12 +821,12 @@ namespace v2rayN.Handler
|
||||
|
||||
private static int statistic(Config config, ref V2rayConfig v2rayConfig)
|
||||
{
|
||||
if (config.enableStatistics)
|
||||
if (config.guiItem.enableStatistics)
|
||||
{
|
||||
string tag = Global.InboundAPITagName;
|
||||
API apiObj = new API();
|
||||
Policy policyObj = new Policy();
|
||||
SystemPolicy policySystemSetting = new SystemPolicy();
|
||||
API apiObj = new();
|
||||
Policy policyObj = new();
|
||||
SystemPolicy policySystemSetting = new();
|
||||
|
||||
string[] services = { "StatsService" };
|
||||
|
||||
@@ -831,8 +843,8 @@ namespace v2rayN.Handler
|
||||
|
||||
if (!v2rayConfig.inbounds.Exists(item => item.tag == tag))
|
||||
{
|
||||
Inbounds apiInbound = new Inbounds();
|
||||
Inboundsettings apiInboundSettings = new Inboundsettings();
|
||||
Inbounds apiInbound = new();
|
||||
Inboundsettings apiInboundSettings = new();
|
||||
apiInbound.tag = tag;
|
||||
apiInbound.listen = Global.Loopback;
|
||||
apiInbound.port = Global.statePort;
|
||||
@@ -844,7 +856,7 @@ namespace v2rayN.Handler
|
||||
|
||||
if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag))
|
||||
{
|
||||
RulesItem apiRoutingRule = new RulesItem
|
||||
RulesItem apiRoutingRule = new()
|
||||
{
|
||||
inboundTag = new List<string> { tag },
|
||||
outboundTag = tag,
|
||||
@@ -941,7 +953,7 @@ namespace v2rayN.Handler
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GenerateClientConfigContent(ProfileItem node, bool blExport, ref V2rayConfig v2rayConfig, out string msg)
|
||||
public static int GenerateClientConfigContent(ProfileItem node, bool blExport, ref V2rayConfig? v2rayConfig, out string msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1018,7 +1030,7 @@ namespace v2rayN.Handler
|
||||
return -1;
|
||||
}
|
||||
|
||||
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
if (v2rayConfig == null)
|
||||
{
|
||||
msg = ResUI.FailedGenDefaultConfiguration;
|
||||
@@ -1107,10 +1119,10 @@ namespace v2rayN.Handler
|
||||
|
||||
#region Import (export) client/server configuration
|
||||
|
||||
public static ProfileItem ImportFromClientConfig(string fileName, out string msg)
|
||||
public static ProfileItem? ImportFromClientConfig(string fileName, out string msg)
|
||||
{
|
||||
msg = string.Empty;
|
||||
ProfileItem profileItem = new ProfileItem();
|
||||
ProfileItem profileItem = new();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -1121,7 +1133,7 @@ namespace v2rayN.Handler
|
||||
return null;
|
||||
}
|
||||
|
||||
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
if (v2rayConfig == null)
|
||||
{
|
||||
msg = ResUI.FailedConversionConfiguration;
|
||||
@@ -1246,10 +1258,10 @@ namespace v2rayN.Handler
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
public static ProfileItem ImportFromServerConfig(string fileName, out string msg)
|
||||
public static ProfileItem? ImportFromServerConfig(string fileName, out string msg)
|
||||
{
|
||||
msg = string.Empty;
|
||||
ProfileItem profileItem = new ProfileItem();
|
||||
ProfileItem profileItem = new();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -1260,7 +1272,7 @@ namespace v2rayN.Handler
|
||||
return null;
|
||||
}
|
||||
|
||||
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
if (v2rayConfig == null)
|
||||
{
|
||||
msg = ResUI.FailedConversionConfiguration;
|
||||
@@ -1385,7 +1397,7 @@ namespace v2rayN.Handler
|
||||
|
||||
public static int Export2ClientConfig(ProfileItem node, string fileName, out string msg)
|
||||
{
|
||||
V2rayConfig v2rayConfig = null;
|
||||
V2rayConfig? v2rayConfig = null;
|
||||
if (GenerateClientConfigContent(node, true, ref v2rayConfig, out msg) != 0)
|
||||
{
|
||||
return -1;
|
||||
@@ -1424,14 +1436,14 @@ namespace v2rayN.Handler
|
||||
return "";
|
||||
}
|
||||
|
||||
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
|
||||
if (v2rayConfig == null)
|
||||
{
|
||||
msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return "";
|
||||
}
|
||||
List<IPEndPoint> lstIpEndPoints = new List<IPEndPoint>();
|
||||
List<TcpConnectionInformation> lstTcpConns = new List<TcpConnectionInformation>();
|
||||
List<IPEndPoint> lstIpEndPoints = new();
|
||||
List<TcpConnectionInformation> lstTcpConns = new();
|
||||
try
|
||||
{
|
||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||
@@ -1461,10 +1473,10 @@ namespace v2rayN.Handler
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (it.configType == EConfigType.VMess || it.configType == EConfigType.VLESS)
|
||||
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
||||
{
|
||||
var item2 = LazyConfig.Instance.GetProfileItem(config.indexId);
|
||||
if (item2 is null || !Utils.IsGuidByParse(item2.id))
|
||||
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1497,7 +1509,7 @@ namespace v2rayN.Handler
|
||||
it.allowTest = true;
|
||||
|
||||
//inbound
|
||||
Inbounds inbound = new Inbounds
|
||||
Inbounds inbound = new()
|
||||
{
|
||||
listen = Global.Loopback,
|
||||
port = port,
|
||||
@@ -1507,7 +1519,7 @@ namespace v2rayN.Handler
|
||||
v2rayConfig.inbounds.Add(inbound);
|
||||
|
||||
//outbound
|
||||
V2rayConfig v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
|
||||
V2rayConfig? v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
|
||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||
if (item is null)
|
||||
{
|
||||
@@ -1524,7 +1536,7 @@ namespace v2rayN.Handler
|
||||
v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]);
|
||||
|
||||
//rule
|
||||
RulesItem rule = new RulesItem
|
||||
RulesItem rule = new()
|
||||
{
|
||||
inboundTag = new List<string> { inbound.tag },
|
||||
outboundTag = v2rayConfigCopy.outbounds[0].tag,
|
||||
|
||||
@@ -12,14 +12,17 @@ namespace v2rayN.Handler
|
||||
class CoreHandler
|
||||
{
|
||||
private static string _coreCConfigRes = Global.coreConfigFileName;
|
||||
private CoreInfo _coreInfo;
|
||||
private CoreInfo? _coreInfo;
|
||||
private int _processId = 0;
|
||||
private Process _process;
|
||||
private Process? _process;
|
||||
Action<bool, string> _updateFunc;
|
||||
|
||||
public CoreHandler(Action<bool, string> update)
|
||||
{
|
||||
_updateFunc = update;
|
||||
|
||||
Environment.SetEnvironmentVariable("v2ray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
}
|
||||
|
||||
public void LoadCore(Config config)
|
||||
@@ -105,7 +108,7 @@ namespace v2rayN.Handler
|
||||
Process[] existing = Process.GetProcessesByName(vName);
|
||||
foreach (Process p in existing)
|
||||
{
|
||||
string path = p.MainModule.FileName;
|
||||
string? path = p.MainModule?.FileName;
|
||||
if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe")
|
||||
{
|
||||
KillProcess(p);
|
||||
@@ -170,7 +173,8 @@ namespace v2rayN.Handler
|
||||
string fileName = CoreFindexe(_coreInfo);
|
||||
if (fileName == "") return;
|
||||
|
||||
Process p = new Process
|
||||
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
||||
Process p = new()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
@@ -178,18 +182,18 @@ namespace v2rayN.Handler
|
||||
Arguments = _coreInfo.arguments,
|
||||
WorkingDirectory = Utils.GetConfigPath(),
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = node.displayLog,
|
||||
RedirectStandardError = node.displayLog,
|
||||
RedirectStandardOutput = displayLog,
|
||||
RedirectStandardError = displayLog,
|
||||
CreateNoWindow = true,
|
||||
StandardOutputEncoding = node.displayLog ? Encoding.UTF8 : null,
|
||||
StandardErrorEncoding = node.displayLog ? Encoding.UTF8 : null,
|
||||
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
|
||||
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
||||
}
|
||||
};
|
||||
if (node.displayLog)
|
||||
if (displayLog)
|
||||
{
|
||||
p.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (!String.IsNullOrEmpty(e.Data))
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
string msg = e.Data + Environment.NewLine;
|
||||
ShowMsg(false, msg);
|
||||
@@ -197,7 +201,7 @@ namespace v2rayN.Handler
|
||||
};
|
||||
}
|
||||
p.Start();
|
||||
if (node.displayLog)
|
||||
if (displayLog)
|
||||
{
|
||||
p.BeginOutputReadLine();
|
||||
}
|
||||
@@ -205,7 +209,7 @@ namespace v2rayN.Handler
|
||||
|
||||
if (p.WaitForExit(1000))
|
||||
{
|
||||
throw new Exception(node.displayLog ? p.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)");
|
||||
throw new Exception(displayLog ? p.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)");
|
||||
}
|
||||
|
||||
Global.processJob.AddProcess(p.Handle);
|
||||
@@ -228,7 +232,7 @@ namespace v2rayN.Handler
|
||||
string fileName = CoreFindexe(coreInfo);
|
||||
if (fileName == "") return -1;
|
||||
|
||||
Process p = new Process
|
||||
Process p = new()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
public event EventHandler<ResultEventArgs> UpdateCompleted;
|
||||
|
||||
public event ErrorEventHandler Error;
|
||||
public event ErrorEventHandler? Error;
|
||||
|
||||
|
||||
public class ResultEventArgs : EventArgs
|
||||
@@ -33,20 +33,13 @@ namespace v2rayN.Handler
|
||||
|
||||
public async Task<int> DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action<bool, string> update)
|
||||
{
|
||||
var hasValue = false;
|
||||
try
|
||||
{
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13);
|
||||
|
||||
var client = new HttpClient(new SocketsHttpHandler()
|
||||
{
|
||||
Proxy = webProxy
|
||||
});
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
||||
|
||||
var progress = new Progress<string>();
|
||||
progress.ProgressChanged += (sender, value) =>
|
||||
{
|
||||
hasValue = true;
|
||||
if (update != null)
|
||||
{
|
||||
string msg = $"{value}";
|
||||
@@ -54,22 +47,17 @@ namespace v2rayN.Handler
|
||||
}
|
||||
};
|
||||
|
||||
var cancellationToken = new CancellationTokenSource();
|
||||
cancellationToken.CancelAfter(downloadTimeout * 1000);
|
||||
await HttpClientHelper.GetInstance().DownloadDataAsync4Speed(client,
|
||||
await DownloaderHelper.Instance.DownloadDataAsync4Speed(webProxy,
|
||||
url,
|
||||
progress,
|
||||
cancellationToken.Token);
|
||||
downloadTimeout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!hasValue)
|
||||
update(false, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
update(false, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
update(false, ex.InnerException.Message);
|
||||
}
|
||||
update(false, ex.InnerException.Message);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -79,30 +67,25 @@ namespace v2rayN.Handler
|
||||
{
|
||||
try
|
||||
{
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13);
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
||||
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading));
|
||||
|
||||
var client = new HttpClient(new SocketsHttpHandler()
|
||||
{
|
||||
Proxy = GetWebProxy(blProxy)
|
||||
});
|
||||
|
||||
var progress = new Progress<double>();
|
||||
progress.ProgressChanged += (sender, value) =>
|
||||
{
|
||||
if (UpdateCompleted != null)
|
||||
{
|
||||
string msg = $"...{value}%";
|
||||
UpdateCompleted(this, new ResultEventArgs(value > 100 ? true : false, msg));
|
||||
UpdateCompleted(this, new ResultEventArgs(value > 100, msg));
|
||||
}
|
||||
};
|
||||
|
||||
var cancellationToken = new CancellationTokenSource();
|
||||
_ = HttpClientHelper.GetInstance().DownloadFileAsync(client,
|
||||
url,
|
||||
Utils.GetTempPath(Utils.GetDownloadFileName(url)),
|
||||
progress,
|
||||
cancellationToken.Token);
|
||||
var webProxy = GetWebProxy(blProxy);
|
||||
_ = DownloaderHelper.Instance.DownloadFileAsync(webProxy,
|
||||
url,
|
||||
Utils.GetTempPath(Utils.GetDownloadFileName(url)),
|
||||
progress,
|
||||
downloadTimeout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -116,20 +99,20 @@ namespace v2rayN.Handler
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> UrlRedirectAsync(string url, bool blProxy)
|
||||
public async Task<string?> UrlRedirectAsync(string url, bool blProxy)
|
||||
{
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13);
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
||||
var webRequestHandler = new SocketsHttpHandler
|
||||
{
|
||||
AllowAutoRedirect = false,
|
||||
Proxy = GetWebProxy(blProxy)
|
||||
};
|
||||
HttpClient client = new HttpClient(webRequestHandler);
|
||||
HttpClient client = new(webRequestHandler);
|
||||
|
||||
HttpResponseMessage response = await client.GetAsync(url);
|
||||
if (response.StatusCode.ToString() == "Redirect")
|
||||
{
|
||||
return response.Headers.Location.ToString();
|
||||
return response.Headers.Location?.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -138,15 +121,77 @@ namespace v2rayN.Handler
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string?> TryDownloadString(string url, bool blProxy, string userAgent)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result1 = await DownloadStringAsync(url, blProxy, userAgent);
|
||||
if (!Utils.IsNullOrEmpty(result1))
|
||||
{
|
||||
return result1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result2 = await DownloadStringViaDownloader(url, blProxy, userAgent);
|
||||
if (!Utils.IsNullOrEmpty(result2))
|
||||
{
|
||||
return result2;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var wc = new WebClient();
|
||||
wc.Proxy = GetWebProxy(blProxy);
|
||||
var result3 = await wc.DownloadStringTaskAsync(url);
|
||||
if (!Utils.IsNullOrEmpty(result3))
|
||||
{
|
||||
return result3;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DownloadString
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
public async Task<string> DownloadStringAsync(string url, bool blProxy, string userAgent)
|
||||
public async Task<string?> DownloadStringAsync(string url, bool blProxy, string userAgent)
|
||||
{
|
||||
try
|
||||
{
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13);
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
||||
var client = new HttpClient(new SocketsHttpHandler()
|
||||
{
|
||||
Proxy = GetWebProxy(blProxy)
|
||||
@@ -158,7 +203,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent);
|
||||
|
||||
Uri uri = new Uri(url);
|
||||
Uri uri = new(url);
|
||||
//Authorization Header
|
||||
if (!Utils.IsNullOrEmpty(uri.UserInfo))
|
||||
{
|
||||
@@ -183,7 +228,39 @@ namespace v2rayN.Handler
|
||||
return null;
|
||||
}
|
||||
|
||||
public int RunAvailabilityCheck(WebProxy webProxy)
|
||||
/// <summary>
|
||||
/// DownloadString
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
public async Task<string?> DownloadStringViaDownloader(string url, bool blProxy, string userAgent)
|
||||
{
|
||||
try
|
||||
{
|
||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
||||
|
||||
var webProxy = GetWebProxy(blProxy);
|
||||
|
||||
if (Utils.IsNullOrEmpty(userAgent))
|
||||
{
|
||||
userAgent = $"{Utils.GetVersion(false)}";
|
||||
}
|
||||
var result = await DownloaderHelper.Instance.DownloadStringAsync(webProxy, url, userAgent, 30);
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public int RunAvailabilityCheck(WebProxy? webProxy)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -195,7 +272,8 @@ namespace v2rayN.Handler
|
||||
|
||||
try
|
||||
{
|
||||
string status = GetRealPingTime(Global.SpeedPingTestUrl, webProxy, 10, out int responseTime);
|
||||
var config = LazyConfig.Instance.GetConfig();
|
||||
string status = GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
|
||||
bool noError = Utils.IsNullOrEmpty(status);
|
||||
return noError ? responseTime : -1;
|
||||
}
|
||||
@@ -222,12 +300,11 @@ namespace v2rayN.Handler
|
||||
myHttpWebRequest.Timeout = downloadTimeout * 1000;
|
||||
myHttpWebRequest.Proxy = webProxy;
|
||||
|
||||
Stopwatch timer = new Stopwatch();
|
||||
Stopwatch timer = new();
|
||||
timer.Start();
|
||||
|
||||
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
|
||||
if (myHttpWebResponse.StatusCode != HttpStatusCode.OK
|
||||
&& myHttpWebResponse.StatusCode != HttpStatusCode.NoContent)
|
||||
if (myHttpWebResponse.StatusCode is not HttpStatusCode.OK and not HttpStatusCode.NoContent)
|
||||
{
|
||||
msg = myHttpWebResponse.StatusDescription;
|
||||
}
|
||||
@@ -244,7 +321,7 @@ namespace v2rayN.Handler
|
||||
return msg;
|
||||
}
|
||||
|
||||
private WebProxy GetWebProxy(bool blProxy)
|
||||
private WebProxy? GetWebProxy(bool blProxy)
|
||||
{
|
||||
if (!blProxy)
|
||||
{
|
||||
@@ -261,11 +338,11 @@ namespace v2rayN.Handler
|
||||
|
||||
private bool SocketCheck(string ip, int port)
|
||||
{
|
||||
Socket sock = null;
|
||||
Socket? sock = null;
|
||||
try
|
||||
{
|
||||
IPAddress ipa = IPAddress.Parse(ip);
|
||||
IPEndPoint point = new IPEndPoint(ipa, port);
|
||||
IPEndPoint point = new(ipa, port);
|
||||
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
sock.Connect(point);
|
||||
return true;
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
public sealed class LazyConfig
|
||||
{
|
||||
private static readonly Lazy<LazyConfig> _instance = new Lazy<LazyConfig>(() => new());
|
||||
private static readonly Lazy<LazyConfig> _instance = new(() => new());
|
||||
private Config _config;
|
||||
private List<CoreInfo> coreInfos;
|
||||
|
||||
@@ -17,11 +17,12 @@ namespace v2rayN.Handler
|
||||
SqliteHelper.Instance.CreateTable<ProfileItem>();
|
||||
SqliteHelper.Instance.CreateTable<ServerStatItem>();
|
||||
SqliteHelper.Instance.CreateTable<RoutingItem>();
|
||||
SqliteHelper.Instance.CreateTable<ProfileExItem>();
|
||||
}
|
||||
|
||||
#region Config
|
||||
|
||||
public void SetConfig(ref Config config)
|
||||
public void SetConfig(Config config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
@@ -81,29 +82,43 @@ namespace v2rayN.Handler
|
||||
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
|
||||
}
|
||||
}
|
||||
public List<string> ProfileItemIndexs(string subid)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(subid))
|
||||
{
|
||||
return SqliteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public List<ProfileItemModel> ProfileItems(string subid, string filter)
|
||||
{
|
||||
var sql = @$"select a.*
|
||||
,b.remarks subRemarks
|
||||
,case when a.indexId = '{_config.indexId}' then true else false end isActive
|
||||
,b.remarks subRemarks
|
||||
from ProfileItem a
|
||||
left join SubItem b on a.subid = b.id
|
||||
where 1=1 ";
|
||||
if (!Utils.IsNullOrEmpty(subid))
|
||||
{
|
||||
sql += $" and a.subid = {subid}";
|
||||
sql += $" and a.subid = '{subid}'";
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(filter))
|
||||
{
|
||||
if (filter.Contains("'"))
|
||||
{
|
||||
filter = filter.Replace("'", "");
|
||||
}
|
||||
sql += $" and a.remarks like '%{filter}%'";
|
||||
}
|
||||
sql += " order by a.sort";
|
||||
|
||||
return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
|
||||
}
|
||||
|
||||
public ProfileItem GetProfileItem(string indexId)
|
||||
public ProfileItem? GetProfileItem(string indexId)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(indexId))
|
||||
{
|
||||
@@ -112,36 +127,9 @@ namespace v2rayN.Handler
|
||||
return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
|
||||
}
|
||||
|
||||
public Task SetTestResult(string indexId, string delayVal, string speedVal)
|
||||
{
|
||||
string sql = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(delayVal) && !Utils.IsNullOrEmpty(speedVal))
|
||||
{
|
||||
int.TryParse(delayVal, out int delay);
|
||||
decimal.TryParse(speedVal, out decimal speed);
|
||||
sql = $"update ProfileItem set delay={delay},speed={speed} where indexId = '{indexId}'";
|
||||
}
|
||||
else if (!Utils.IsNullOrEmpty(delayVal))
|
||||
{
|
||||
int.TryParse(delayVal, out int delay);
|
||||
sql = $"update ProfileItem set delay={delay} where indexId = '{indexId}'";
|
||||
}
|
||||
else if (!Utils.IsNullOrEmpty(speedVal))
|
||||
{
|
||||
decimal.TryParse(speedVal, out decimal speed);
|
||||
sql = $"update ProfileItem set speed={speed} where indexId = '{indexId}'";
|
||||
}
|
||||
return SqliteHelper.Instance.ExecuteAsync(sql);
|
||||
}
|
||||
|
||||
public List<ServerStatItem> ServerStatItems()
|
||||
{
|
||||
return SqliteHelper.Instance.Table<ServerStatItem>().ToList();
|
||||
}
|
||||
|
||||
public List<RoutingItem> RoutingItems()
|
||||
{
|
||||
return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).ToList();
|
||||
return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
|
||||
}
|
||||
public RoutingItem GetRoutingItem(string id)
|
||||
{
|
||||
@@ -185,7 +173,7 @@ namespace v2rayN.Handler
|
||||
return item.coreType;
|
||||
}
|
||||
|
||||
public CoreInfo GetCoreInfo(ECoreType coreType)
|
||||
public CoreInfo? GetCoreInfo(ECoreType coreType)
|
||||
{
|
||||
if (coreInfos == null)
|
||||
{
|
||||
@@ -194,7 +182,7 @@ namespace v2rayN.Handler
|
||||
return coreInfos.Where(t => t.coreType == coreType).FirstOrDefault();
|
||||
}
|
||||
|
||||
public List<CoreInfo> GetCoreInfos()
|
||||
public List<CoreInfo>? GetCoreInfos()
|
||||
{
|
||||
if (coreInfos == null)
|
||||
{
|
||||
@@ -205,13 +193,13 @@ namespace v2rayN.Handler
|
||||
|
||||
private void InitCoreInfo()
|
||||
{
|
||||
coreInfos = new List<CoreInfo>();
|
||||
coreInfos = new(16);
|
||||
|
||||
coreInfos.Add(new CoreInfo
|
||||
{
|
||||
coreType = ECoreType.v2rayN,
|
||||
coreUrl = Global.NUrl,
|
||||
coreReleaseApiUrl = Global.NUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.NUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN.zip",
|
||||
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
|
||||
});
|
||||
@@ -222,7 +210,7 @@ namespace v2rayN.Handler
|
||||
coreExes = new List<string> { "wv2ray", "v2ray" },
|
||||
arguments = "",
|
||||
coreUrl = Global.v2flyCoreUrl,
|
||||
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||
match = "V2Ray",
|
||||
@@ -236,7 +224,7 @@ namespace v2rayN.Handler
|
||||
coreExes = new List<string> { "SagerNet", "v2ray" },
|
||||
arguments = "run",
|
||||
coreUrl = Global.SagerNetCoreUrl,
|
||||
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||
coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||
match = "V2Ray",
|
||||
@@ -250,7 +238,7 @@ namespace v2rayN.Handler
|
||||
coreExes = new List<string> { "v2ray" },
|
||||
arguments = "run",
|
||||
coreUrl = Global.v2flyCoreUrl,
|
||||
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||
match = "V2Ray",
|
||||
@@ -264,7 +252,7 @@ namespace v2rayN.Handler
|
||||
coreExes = new List<string> { "xray", "wxray" },
|
||||
arguments = "",
|
||||
coreUrl = Global.xrayCoreUrl,
|
||||
coreReleaseApiUrl = Global.xrayCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.xrayCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
||||
coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
||||
match = "Xray",
|
||||
@@ -278,7 +266,7 @@ namespace v2rayN.Handler
|
||||
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
|
||||
arguments = "-f config.json",
|
||||
coreUrl = Global.clashCoreUrl,
|
||||
coreReleaseApiUrl = Global.clashCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.clashCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip",
|
||||
coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip",
|
||||
match = "v",
|
||||
@@ -292,7 +280,7 @@ namespace v2rayN.Handler
|
||||
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
|
||||
arguments = "-f config.json",
|
||||
coreUrl = Global.clashMetaCoreUrl,
|
||||
coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip",
|
||||
coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip",
|
||||
match = "v",
|
||||
@@ -306,7 +294,7 @@ namespace v2rayN.Handler
|
||||
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||
arguments = "",
|
||||
coreUrl = Global.hysteriaCoreUrl,
|
||||
coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"),
|
||||
coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
||||
coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
|
||||
coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
|
||||
redirectInfo = true,
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
public sealed class MainFormHandler
|
||||
{
|
||||
private static readonly Lazy<MainFormHandler> instance = new Lazy<MainFormHandler>(() => new MainFormHandler());
|
||||
private static readonly Lazy<MainFormHandler> instance = new(() => new());
|
||||
//Action<bool, string> _updateUI;
|
||||
|
||||
//private DownloadHandle downloadHandle2;
|
||||
@@ -42,19 +42,14 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return new Icon(fileName);
|
||||
}
|
||||
switch (index)
|
||||
return index switch
|
||||
{
|
||||
case 0:
|
||||
return Properties.Resources.NotifyIcon1;
|
||||
case 1:
|
||||
return Properties.Resources.NotifyIcon2;
|
||||
case 2:
|
||||
return Properties.Resources.NotifyIcon3;
|
||||
case 3:
|
||||
return Properties.Resources.NotifyIcon2;
|
||||
}
|
||||
|
||||
return Properties.Resources.NotifyIcon1;
|
||||
0 => Properties.Resources.NotifyIcon1,
|
||||
1 => Properties.Resources.NotifyIcon2,
|
||||
2 => Properties.Resources.NotifyIcon3,
|
||||
3 => Properties.Resources.NotifyIcon2,
|
||||
_ => Properties.Resources.NotifyIcon1, // default
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -82,11 +77,11 @@ namespace v2rayN.Handler
|
||||
return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute));
|
||||
}
|
||||
|
||||
private Icon GetNotifyIcon4Routing(Config config)
|
||||
private Icon? GetNotifyIcon4Routing(Config config)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!config.enableRoutingAdvanced)
|
||||
if (!config.routingBasicItem.enableRoutingAdvanced)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -107,9 +102,9 @@ namespace v2rayN.Handler
|
||||
int width = 128;
|
||||
int height = 128;
|
||||
|
||||
Bitmap bitmap = new Bitmap(width, height);
|
||||
Bitmap bitmap = new(width, height);
|
||||
Graphics graphics = Graphics.FromImage(bitmap);
|
||||
SolidBrush drawBrush = new SolidBrush(color);
|
||||
SolidBrush drawBrush = new(color);
|
||||
|
||||
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
||||
//graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height));
|
||||
@@ -143,7 +138,7 @@ namespace v2rayN.Handler
|
||||
return;
|
||||
}
|
||||
|
||||
SaveFileDialog fileDialog = new SaveFileDialog
|
||||
SaveFileDialog fileDialog = new()
|
||||
{
|
||||
Filter = "Config|*.json",
|
||||
FilterIndex = 2,
|
||||
@@ -176,14 +171,13 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (item.configType != EConfigType.VMess
|
||||
&& item.configType != EConfigType.VLESS)
|
||||
if (item.configType is not EConfigType.VMess and not EConfigType.VLESS)
|
||||
{
|
||||
UI.Show(ResUI.NonVmessService);
|
||||
return;
|
||||
}
|
||||
|
||||
SaveFileDialog fileDialog = new SaveFileDialog
|
||||
SaveFileDialog fileDialog = new()
|
||||
{
|
||||
Filter = "Config|*.json",
|
||||
FilterIndex = 2,
|
||||
@@ -212,14 +206,14 @@ namespace v2rayN.Handler
|
||||
|
||||
public void BackupGuiNConfig(Config config, bool auto = false)
|
||||
{
|
||||
string fileName = $"guiNConfig_{DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff")}.json";
|
||||
string fileName = $"guiNConfig_{DateTime.Now:yyyy_MM_dd_HH_mm_ss_fff}.json";
|
||||
if (auto)
|
||||
{
|
||||
fileName = Utils.GetBackupPath(fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveFileDialog fileDialog = new SaveFileDialog
|
||||
SaveFileDialog fileDialog = new()
|
||||
{
|
||||
FileName = fileName,
|
||||
Filter = "guiNConfig|*.json",
|
||||
@@ -254,7 +248,7 @@ namespace v2rayN.Handler
|
||||
public bool RestoreGuiNConfig(ref Config config)
|
||||
{
|
||||
var fileContent = string.Empty;
|
||||
using (OpenFileDialog fileDialog = new OpenFileDialog())
|
||||
using (OpenFileDialog fileDialog = new())
|
||||
{
|
||||
fileDialog.InitialDirectory = Utils.GetBackupPath("");
|
||||
fileDialog.Filter = "guiNConfig|*.json|All|*.*";
|
||||
@@ -286,7 +280,7 @@ namespace v2rayN.Handler
|
||||
BackupGuiNConfig(config, true);
|
||||
|
||||
config = resConfig;
|
||||
LazyConfig.Instance.SetConfig(ref config);
|
||||
LazyConfig.Instance.SetConfig(config);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -309,9 +303,9 @@ namespace v2rayN.Handler
|
||||
{
|
||||
var dtNow = DateTime.Now;
|
||||
|
||||
if (config.autoUpdateSubInterval > 0)
|
||||
if (config.guiItem.autoUpdateSubInterval > 0)
|
||||
{
|
||||
if ((dtNow - autoUpdateSubTime).Hours % config.autoUpdateSubInterval == 0)
|
||||
if ((dtNow - autoUpdateSubTime).Hours % config.guiItem.autoUpdateSubInterval == 0)
|
||||
{
|
||||
updateHandle.UpdateSubscriptionProcess(config, "", true, (bool success, string msg) =>
|
||||
{
|
||||
@@ -324,9 +318,9 @@ namespace v2rayN.Handler
|
||||
Thread.Sleep(60000);
|
||||
}
|
||||
|
||||
if (config.autoUpdateInterval > 0)
|
||||
if (config.guiItem.autoUpdateInterval > 0)
|
||||
{
|
||||
if ((dtNow - autoUpdateGeoTime).Hours % config.autoUpdateInterval == 0)
|
||||
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
|
||||
{
|
||||
updateHandle.UpdateGeoFile("geosite", config, (bool success, string msg) =>
|
||||
{
|
||||
@@ -381,12 +375,12 @@ namespace v2rayN.Handler
|
||||
try
|
||||
{
|
||||
HotkeyManager.Current.AddOrReplace(((int)item.eGlobalHotkey).ToString(), gesture, handler);
|
||||
var msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{item.eGlobalHotkey.ToString()}");
|
||||
var msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{item.eGlobalHotkey}");
|
||||
update(false, msg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{item.eGlobalHotkey.ToString()}", ex.Message);
|
||||
var msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{item.eGlobalHotkey}", ex.Message);
|
||||
update(false, msg);
|
||||
Utils.SaveLog(msg);
|
||||
}
|
||||
|
||||
114
v2rayN/v2rayN/Handler/ProfileExHandler.cs
Normal file
114
v2rayN/v2rayN/Handler/ProfileExHandler.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using v2rayN.Base;
|
||||
using v2rayN.Mode;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
{
|
||||
class ProfileExHandler
|
||||
{
|
||||
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
||||
private List<ProfileExItem> _lstProfileEx;
|
||||
public List<ProfileExItem> ProfileExs => _lstProfileEx;
|
||||
public static ProfileExHandler Instance => _instance.Value;
|
||||
|
||||
public ProfileExHandler()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
SqliteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
||||
|
||||
_lstProfileEx = SqliteHelper.Instance.Table<ProfileExItem>().ToList();
|
||||
}
|
||||
|
||||
private void AddProfileEx(string indexId, ref ProfileExItem profileEx)
|
||||
{
|
||||
profileEx = new()
|
||||
{
|
||||
indexId = indexId,
|
||||
delay = 0,
|
||||
speed = 0,
|
||||
sort = 0
|
||||
};
|
||||
_lstProfileEx.Add(profileEx);
|
||||
//SqliteHelper.Instance.Replace(profileEx);
|
||||
}
|
||||
|
||||
public void ClearAll()
|
||||
{
|
||||
SqliteHelper.Instance.Execute($"delete from ProfileExItem ");
|
||||
_lstProfileEx = new();
|
||||
}
|
||||
|
||||
public void SaveTo()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var item in _lstProfileEx)
|
||||
{
|
||||
SqliteHelper.Instance.Replace(item);
|
||||
}
|
||||
//SqliteHelper.Instance.UpdateAll(_lstProfileEx);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Task SetTestDelay(string indexId, string delayVal)
|
||||
{
|
||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
||||
if (profileEx == null)
|
||||
{
|
||||
AddProfileEx(indexId, ref profileEx);
|
||||
}
|
||||
|
||||
int.TryParse(delayVal, out int delay);
|
||||
profileEx.delay = delay;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task SetTestSpeed(string indexId, string speedVal)
|
||||
{
|
||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
||||
if (profileEx == null)
|
||||
{
|
||||
AddProfileEx(indexId, ref profileEx);
|
||||
}
|
||||
|
||||
decimal.TryParse(speedVal, out decimal speed);
|
||||
profileEx.speed = speed;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void SetSort(string indexId, int sort)
|
||||
{
|
||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
||||
if (profileEx == null)
|
||||
{
|
||||
AddProfileEx(indexId, ref profileEx);
|
||||
}
|
||||
profileEx.sort = sort;
|
||||
}
|
||||
|
||||
public int GetSort(string indexId)
|
||||
{
|
||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
|
||||
if (profileEx == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return profileEx.sort;
|
||||
}
|
||||
public int GetMaxSort()
|
||||
{
|
||||
if (_lstProfileEx.Count <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _lstProfileEx.Max(t => t == null ? 0 : t.sort);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,16 +10,16 @@ namespace v2rayN.Handler
|
||||
return SetProxy(null, null, 1);
|
||||
}
|
||||
|
||||
public static bool SetProxy(string strProxy, string exceptions, int type)
|
||||
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
||||
{
|
||||
InternetPerConnOptionList list = new InternetPerConnOptionList();
|
||||
InternetPerConnOptionList list = new();
|
||||
|
||||
int optionCount = 1;
|
||||
if (type == 1)
|
||||
{
|
||||
optionCount = 1;
|
||||
}
|
||||
else if (type == 2 || type == 4)
|
||||
else if (type is 2 or 4)
|
||||
{
|
||||
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
|
||||
}
|
||||
@@ -71,12 +71,12 @@ namespace v2rayN.Handler
|
||||
{
|
||||
if (Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
IntPtr opt = new IntPtr(optionsPtr.ToInt64() + (i * optSize));
|
||||
IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
|
||||
Marshal.StructureToPtr(options[i], opt, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPtr opt = new IntPtr(optionsPtr.ToInt32() + (i * optSize));
|
||||
IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
|
||||
Marshal.StructureToPtr(options[i], opt, false);
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace v2rayN.Handler
|
||||
list.options = optionsPtr;
|
||||
|
||||
// and then make a pointer out of the whole list
|
||||
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem((int)list.dwSize);
|
||||
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize);
|
||||
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
||||
|
||||
// and finally, call the API method!
|
||||
@@ -189,24 +189,21 @@ namespace v2rayN.Handler
|
||||
//判断是否使用代理
|
||||
public static bool UsedProxy()
|
||||
{
|
||||
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
||||
if (rk.GetValue("ProxyEnable").ToString() == "1")
|
||||
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
||||
if (rk?.GetValue("ProxyEnable")?.ToString() == "1")
|
||||
{
|
||||
rk.Close();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rk.Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//获得代理的IP和端口
|
||||
public static string GetProxyProxyServer()
|
||||
public static string? GetProxyProxyServer()
|
||||
{
|
||||
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
||||
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
||||
string ProxyServer = rk.GetValue("ProxyServer").ToString();
|
||||
rk.Close();
|
||||
return ProxyServer;
|
||||
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ namespace v2rayN.Handler
|
||||
/// </summary>
|
||||
public class QRCodeHelper
|
||||
{
|
||||
public static DrawingImage GetQRCode(string strContent)
|
||||
public static DrawingImage? GetQRCode(string strContent)
|
||||
{
|
||||
try
|
||||
{
|
||||
QRCodeGenerator qrGenerator = new QRCodeGenerator();
|
||||
QRCodeGenerator qrGenerator = new();
|
||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H);
|
||||
XamlQRCode qrCode = new XamlQRCode(qrCodeData);
|
||||
XamlQRCode qrCode = new(qrCodeData);
|
||||
DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40);
|
||||
return qrCodeAsXaml;
|
||||
}
|
||||
|
||||
@@ -17,32 +17,22 @@ namespace v2rayN.Handler
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetShareUrl(ProfileItem item)
|
||||
public static string? GetShareUrl(ProfileItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
string url = string.Empty;
|
||||
string? url = string.Empty;
|
||||
|
||||
switch (item.configType)
|
||||
url = item.configType switch
|
||||
{
|
||||
case EConfigType.VMess:
|
||||
url = ShareVmess(item);
|
||||
break;
|
||||
case EConfigType.Shadowsocks:
|
||||
url = ShareShadowsocks(item);
|
||||
break;
|
||||
case EConfigType.Socks:
|
||||
url = ShareSocks(item);
|
||||
break;
|
||||
case EConfigType.Trojan:
|
||||
url = ShareTrojan(item);
|
||||
break;
|
||||
case EConfigType.VLESS:
|
||||
url = ShareVLESS(item);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
EConfigType.VMess => ShareVmess(item),
|
||||
EConfigType.Shadowsocks => ShareShadowsocks(item),
|
||||
EConfigType.Socks => ShareSocks(item),
|
||||
EConfigType.Trojan => ShareTrojan(item),
|
||||
EConfigType.VLESS => ShareVLESS(item),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
return url;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -56,7 +46,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
string url = string.Empty;
|
||||
|
||||
VmessQRCode vmessQRCode = new VmessQRCode
|
||||
VmessQRCode vmessQRCode = new()
|
||||
{
|
||||
v = item.configVersion.ToString(),
|
||||
ps = item.remarks.TrimEx(), //备注也许很长 ;
|
||||
@@ -71,7 +61,8 @@ namespace v2rayN.Handler
|
||||
path = item.path,
|
||||
tls = item.streamSecurity,
|
||||
sni = item.sni,
|
||||
alpn = item.alpn
|
||||
alpn = item.alpn,
|
||||
fp = item.fingerprint
|
||||
};
|
||||
|
||||
url = Utils.ToJson(vmessQRCode);
|
||||
@@ -176,7 +167,7 @@ namespace v2rayN.Handler
|
||||
return Utils.IsIpv6(address) ? $"[{address}]" : address;
|
||||
}
|
||||
|
||||
private static int GetStdTransport(ProfileItem item, string securityDef, ref Dictionary<string, string> dicQuery)
|
||||
private static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(item.flow))
|
||||
{
|
||||
@@ -202,6 +193,10 @@ namespace v2rayN.Handler
|
||||
{
|
||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.fingerprint))
|
||||
{
|
||||
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
|
||||
}
|
||||
|
||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : "tcp");
|
||||
|
||||
@@ -255,7 +250,7 @@ namespace v2rayN.Handler
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
||||
if (item.headerType == Global.GrpcgunMode || item.headerType == Global.GrpcmultiMode)
|
||||
if (item.headerType is Global.GrpcgunMode or Global.GrpcmultiMode)
|
||||
{
|
||||
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
||||
}
|
||||
@@ -273,13 +268,13 @@ namespace v2rayN.Handler
|
||||
/// <summary>
|
||||
/// 从剪贴板导入URL
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
public static ProfileItem ImportFromClipboardConfig(string clipboardData, out string msg)
|
||||
public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
|
||||
{
|
||||
msg = string.Empty;
|
||||
ProfileItem profileItem = new ProfileItem();
|
||||
|
||||
ProfileItem profileItem = new();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -363,7 +358,7 @@ namespace v2rayN.Handler
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
private static ProfileItem ResolveVmess(string result, out string msg)
|
||||
private static ProfileItem? ResolveVmess(string result, out string msg)
|
||||
{
|
||||
msg = string.Empty;
|
||||
var profileItem = new ProfileItem
|
||||
@@ -371,11 +366,11 @@ namespace v2rayN.Handler
|
||||
configType = EConfigType.VMess
|
||||
};
|
||||
|
||||
result = result.Substring(Global.vmessProtocol.Length);
|
||||
result = result[Global.vmessProtocol.Length..];
|
||||
result = Utils.Base64Decode(result);
|
||||
|
||||
//转成Json
|
||||
VmessQRCode vmessQRCode = Utils.FromJson<VmessQRCode>(result);
|
||||
VmessQRCode? vmessQRCode = Utils.FromJson<VmessQRCode>(result);
|
||||
if (vmessQRCode == null)
|
||||
{
|
||||
msg = ResUI.FailedConversionConfiguration;
|
||||
@@ -408,21 +403,22 @@ namespace v2rayN.Handler
|
||||
profileItem.streamSecurity = Utils.ToString(vmessQRCode.tls);
|
||||
profileItem.sni = Utils.ToString(vmessQRCode.sni);
|
||||
profileItem.alpn = Utils.ToString(vmessQRCode.alpn);
|
||||
profileItem.fingerprint = Utils.ToString(vmessQRCode.fp);
|
||||
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
private static ProfileItem ResolveVmess4Kitsunebi(string result)
|
||||
private static ProfileItem? ResolveVmess4Kitsunebi(string result)
|
||||
{
|
||||
ProfileItem profileItem = new ProfileItem
|
||||
ProfileItem profileItem = new()
|
||||
{
|
||||
configType = EConfigType.VMess
|
||||
};
|
||||
result = result.Substring(Global.vmessProtocol.Length);
|
||||
result = result[Global.vmessProtocol.Length..];
|
||||
int indexSplit = result.IndexOf("?");
|
||||
if (indexSplit > 0)
|
||||
{
|
||||
result = result.Substring(0, indexSplit);
|
||||
result = result[..indexSplit];
|
||||
}
|
||||
result = Utils.Base64Decode(result);
|
||||
|
||||
@@ -433,7 +429,7 @@ namespace v2rayN.Handler
|
||||
}
|
||||
string[] arr21 = arr1[0].Split(':');
|
||||
string[] arr22 = arr1[1].Split(':');
|
||||
if (arr21.Length != 2 || arr21.Length != 2)
|
||||
if (arr21.Length != 2 || arr22.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -450,15 +446,15 @@ namespace v2rayN.Handler
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
private static ProfileItem ResolveStdVmess(string result)
|
||||
private static ProfileItem? ResolveStdVmess(string result)
|
||||
{
|
||||
ProfileItem i = new ProfileItem
|
||||
ProfileItem i = new()
|
||||
{
|
||||
configType = EConfigType.VMess,
|
||||
security = "auto"
|
||||
};
|
||||
|
||||
Uri u = new Uri(result);
|
||||
Uri u = new(result);
|
||||
|
||||
i.address = u.IdnHost;
|
||||
i.port = u.Port;
|
||||
@@ -531,7 +527,7 @@ namespace v2rayN.Handler
|
||||
return i;
|
||||
}
|
||||
|
||||
private static ProfileItem ResolveSip002(string result)
|
||||
private static ProfileItem? ResolveSip002(string result)
|
||||
{
|
||||
Uri parsedUrl;
|
||||
try
|
||||
@@ -542,7 +538,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ProfileItem server = new ProfileItem
|
||||
ProfileItem server = new()
|
||||
{
|
||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||
address = parsedUrl.IdnHost,
|
||||
@@ -550,7 +546,7 @@ namespace v2rayN.Handler
|
||||
};
|
||||
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
|
||||
//2022-blake3
|
||||
if (rawUserInfo.Contains(":"))
|
||||
if (rawUserInfo.Contains(':'))
|
||||
{
|
||||
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||
if (userInfoParts.Length != 2)
|
||||
@@ -594,16 +590,16 @@ namespace v2rayN.Handler
|
||||
return server;
|
||||
}
|
||||
|
||||
private static readonly Regex UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase);
|
||||
private static readonly Regex DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase);
|
||||
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
private static ProfileItem ResolveSSLegacy(string result)
|
||||
private static ProfileItem? ResolveSSLegacy(string result)
|
||||
{
|
||||
var match = UrlFinder.Match(result);
|
||||
if (!match.Success)
|
||||
return null;
|
||||
|
||||
ProfileItem server = new ProfileItem();
|
||||
ProfileItem server = new();
|
||||
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||
var tag = match.Groups["tag"].Value;
|
||||
if (!Utils.IsNullOrEmpty(tag))
|
||||
@@ -629,16 +625,16 @@ namespace v2rayN.Handler
|
||||
}
|
||||
|
||||
|
||||
private static readonly Regex StdVmessUserInfo = new Regex(
|
||||
@"^(?<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})$");
|
||||
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);
|
||||
|
||||
private static ProfileItem ResolveSocks(string result)
|
||||
private static ProfileItem? ResolveSocks(string result)
|
||||
{
|
||||
ProfileItem profileItem = new ProfileItem
|
||||
ProfileItem profileItem = new()
|
||||
{
|
||||
configType = EConfigType.Socks
|
||||
};
|
||||
result = result.Substring(Global.socksProtocol.Length);
|
||||
result = result[Global.socksProtocol.Length..];
|
||||
//remark
|
||||
int indexRemark = result.IndexOf("#");
|
||||
if (indexRemark > 0)
|
||||
@@ -648,7 +644,7 @@ namespace v2rayN.Handler
|
||||
profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
||||
}
|
||||
catch { }
|
||||
result = result.Substring(0, indexRemark);
|
||||
result = result[..indexRemark];
|
||||
}
|
||||
//part decode
|
||||
int indexS = result.IndexOf("@");
|
||||
@@ -672,15 +668,15 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return null;
|
||||
}
|
||||
profileItem.address = arr1[1].Substring(0, indexPort);
|
||||
profileItem.port = Utils.ToInt(arr1[1].Substring(indexPort + 1, arr1[1].Length - (indexPort + 1)));
|
||||
profileItem.address = arr1[1][..indexPort];
|
||||
profileItem.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
||||
profileItem.security = arr21[0];
|
||||
profileItem.id = arr21[1];
|
||||
|
||||
return profileItem;
|
||||
}
|
||||
|
||||
private static ProfileItem ResolveSocksNew(string result)
|
||||
private static ProfileItem? ResolveSocksNew(string result)
|
||||
{
|
||||
Uri parsedUrl;
|
||||
try
|
||||
@@ -691,7 +687,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ProfileItem server = new ProfileItem
|
||||
ProfileItem server = new()
|
||||
{
|
||||
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||
address = parsedUrl.IdnHost,
|
||||
@@ -713,12 +709,12 @@ namespace v2rayN.Handler
|
||||
|
||||
private static ProfileItem ResolveTrojan(string result)
|
||||
{
|
||||
ProfileItem item = new ProfileItem
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.Trojan
|
||||
};
|
||||
|
||||
Uri url = new Uri(result);
|
||||
Uri url = new(result);
|
||||
|
||||
item.address = url.IdnHost;
|
||||
item.port = url.Port;
|
||||
@@ -732,13 +728,13 @@ namespace v2rayN.Handler
|
||||
}
|
||||
private static ProfileItem ResolveStdVLESS(string result)
|
||||
{
|
||||
ProfileItem item = new ProfileItem
|
||||
ProfileItem item = new()
|
||||
{
|
||||
configType = EConfigType.VLESS,
|
||||
security = "none"
|
||||
};
|
||||
|
||||
Uri url = new Uri(result);
|
||||
Uri url = new(result);
|
||||
|
||||
item.address = url.IdnHost;
|
||||
item.port = url.Port;
|
||||
@@ -759,6 +755,7 @@ namespace v2rayN.Handler
|
||||
item.streamSecurity = query["security"] ?? "";
|
||||
item.sni = query["sni"] ?? "";
|
||||
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
|
||||
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
|
||||
item.network = query["type"] ?? "tcp";
|
||||
switch (item.network)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace v2rayN.Handler
|
||||
private Config _config;
|
||||
private CoreHandler _coreHandler;
|
||||
private List<ServerTestItem> _selecteds;
|
||||
private ESpeedActionType _actionType;
|
||||
Action<string, string, string> _updateFunc;
|
||||
|
||||
public SpeedtestHandler(Config config)
|
||||
@@ -23,12 +24,20 @@ namespace v2rayN.Handler
|
||||
{
|
||||
_config = config;
|
||||
_coreHandler = coreHandler;
|
||||
//_selecteds = Utils.DeepCopy(selecteds);
|
||||
_actionType = actionType;
|
||||
_updateFunc = update;
|
||||
|
||||
_selecteds = new List<ServerTestItem>();
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (it.configType == EConfigType.Custom)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (it.port <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_selecteds.Add(new ServerTestItem()
|
||||
{
|
||||
indexId = it.indexId,
|
||||
@@ -37,6 +46,25 @@ namespace v2rayN.Handler
|
||||
configType = it.configType
|
||||
});
|
||||
}
|
||||
//clear test result
|
||||
foreach (var it in _selecteds)
|
||||
{
|
||||
switch (actionType)
|
||||
{
|
||||
case ESpeedActionType.Ping:
|
||||
case ESpeedActionType.Tcping:
|
||||
case ESpeedActionType.Realping:
|
||||
UpdateFunc(it.indexId, ResUI.Speedtesting, "");
|
||||
break;
|
||||
case ESpeedActionType.Speedtest:
|
||||
UpdateFunc(it.indexId, "", ResUI.Speedtesting);
|
||||
break;
|
||||
case ESpeedActionType.Mixedtest:
|
||||
UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.Speedtesting);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (actionType)
|
||||
{
|
||||
case ESpeedActionType.Ping:
|
||||
@@ -84,29 +112,29 @@ namespace v2rayN.Handler
|
||||
|
||||
private void RunPing()
|
||||
{
|
||||
RunPingSub((ServerTestItem it) =>
|
||||
RunPingSub(async (ServerTestItem it) =>
|
||||
{
|
||||
long time = Ping(it.address);
|
||||
var output = FormatOut(time, Global.DelayUnit);
|
||||
|
||||
LazyConfig.Instance.SetTestResult(it.indexId, output, "");
|
||||
await ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
||||
UpdateFunc(it.indexId, output);
|
||||
});
|
||||
}
|
||||
|
||||
private void RunTcping()
|
||||
{
|
||||
RunPingSub((ServerTestItem it) =>
|
||||
RunPingSub(async (ServerTestItem it) =>
|
||||
{
|
||||
int time = GetTcpingTime(it.address, it.port);
|
||||
var output = FormatOut(time, Global.DelayUnit);
|
||||
|
||||
LazyConfig.Instance.SetTestResult(it.indexId, output, "");
|
||||
await ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
||||
UpdateFunc(it.indexId, output);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task RunRealPing()
|
||||
private Task RunRealPing()
|
||||
{
|
||||
int pid = -1;
|
||||
try
|
||||
@@ -117,12 +145,12 @@ namespace v2rayN.Handler
|
||||
if (pid < 0)
|
||||
{
|
||||
UpdateFunc("", ResUI.FailedToRunCore);
|
||||
return;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
DownloadHandle downloadHandle = new DownloadHandle();
|
||||
//Thread.Sleep(5000);
|
||||
List<Task> tasks = new List<Task>();
|
||||
List<Task> tasks = new();
|
||||
foreach (var it in _selecteds)
|
||||
{
|
||||
if (!it.allowTest)
|
||||
@@ -133,17 +161,18 @@ namespace v2rayN.Handler
|
||||
{
|
||||
continue;
|
||||
}
|
||||
tasks.Add(Task.Run(() =>
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
LazyConfig.Instance.SetTestResult(it.indexId, "-1", "");
|
||||
|
||||
WebProxy webProxy = new WebProxy(Global.Loopback, it.port);
|
||||
WebProxy webProxy = new(Global.Loopback, it.port);
|
||||
string output = GetRealPingTime(downloadHandle, webProxy);
|
||||
|
||||
LazyConfig.Instance.SetTestResult(it.indexId, output, "");
|
||||
await ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
||||
UpdateFunc(it.indexId, output);
|
||||
int.TryParse(output, out int delay);
|
||||
it.delay = delay;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -161,12 +190,19 @@ namespace v2rayN.Handler
|
||||
finally
|
||||
{
|
||||
if (pid > 0) _coreHandler.CoreStopPid(pid);
|
||||
ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task RunSpeedTestAsync()
|
||||
{
|
||||
string testIndexId = string.Empty;
|
||||
int pid = -1;
|
||||
//if (_actionType == ESpeedActionType.Mixedtest)
|
||||
//{
|
||||
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
|
||||
//}
|
||||
|
||||
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
|
||||
if (pid < 0)
|
||||
@@ -175,14 +211,13 @@ namespace v2rayN.Handler
|
||||
return;
|
||||
}
|
||||
|
||||
string url = _config.constItem.speedTestUrl;
|
||||
DownloadHandle downloadHandle = new DownloadHandle();
|
||||
string url = _config.speedTestItem.speedTestUrl;
|
||||
var timeout = _config.speedTestItem.speedTestTimeout;
|
||||
|
||||
DownloadHandle downloadHandle = new();
|
||||
|
||||
var timeout = 10;
|
||||
foreach (var it in _selecteds)
|
||||
{
|
||||
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1");
|
||||
UpdateFunc(it.indexId, "", ResUI.Speedtesting);
|
||||
if (!it.allowTest)
|
||||
{
|
||||
continue;
|
||||
@@ -191,19 +226,24 @@ namespace v2rayN.Handler
|
||||
{
|
||||
continue;
|
||||
}
|
||||
testIndexId = it.indexId;
|
||||
//if (it.delay < 0)
|
||||
//{
|
||||
// UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
|
||||
// continue;
|
||||
//}
|
||||
await ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
|
||||
|
||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||
if (item is null) continue;
|
||||
|
||||
WebProxy webProxy = new WebProxy(Global.Loopback, it.port);
|
||||
WebProxy webProxy = new(Global.Loopback, it.port);
|
||||
|
||||
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) =>
|
||||
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, async (bool success, string msg) =>
|
||||
{
|
||||
decimal.TryParse(msg, out decimal dec);
|
||||
if (dec > 0)
|
||||
{
|
||||
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", msg);
|
||||
await ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
|
||||
}
|
||||
UpdateFunc(it.indexId, "", msg);
|
||||
});
|
||||
@@ -213,17 +253,75 @@ namespace v2rayN.Handler
|
||||
{
|
||||
_coreHandler.CoreStopPid(pid);
|
||||
}
|
||||
UpdateFunc("", ResUI.SpeedtestingCompleted);
|
||||
ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
|
||||
private async Task RunSpeedTestMulti()
|
||||
{
|
||||
int pid = -1;
|
||||
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
|
||||
if (pid < 0)
|
||||
{
|
||||
UpdateFunc("", ResUI.FailedToRunCore);
|
||||
return;
|
||||
}
|
||||
|
||||
string url = _config.speedTestItem.speedTestUrl;
|
||||
var timeout = _config.speedTestItem.speedTestTimeout;
|
||||
|
||||
DownloadHandle downloadHandle = new();
|
||||
|
||||
foreach (var it in _selecteds)
|
||||
{
|
||||
if (!it.allowTest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (it.configType == EConfigType.Custom)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
await ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
|
||||
|
||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||
if (item is null) continue;
|
||||
|
||||
WebProxy webProxy = new(Global.Loopback, it.port);
|
||||
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, async (bool success, string msg) =>
|
||||
{
|
||||
decimal.TryParse(msg, out decimal dec);
|
||||
if (dec > 0)
|
||||
{
|
||||
await ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
|
||||
}
|
||||
UpdateFunc(it.indexId, "", msg);
|
||||
});
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
|
||||
Thread.Sleep((timeout + 2) * 1000);
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
_coreHandler.CoreStopPid(pid);
|
||||
}
|
||||
UpdateFunc("", ResUI.SpeedtestingCompleted);
|
||||
ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
|
||||
private async Task RunMixedtestAsync()
|
||||
{
|
||||
await RunRealPing();
|
||||
|
||||
await RunSpeedTestAsync();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
await RunSpeedTestMulti();
|
||||
}
|
||||
|
||||
public string GetRealPingTime(DownloadHandle downloadHandle, WebProxy webProxy)
|
||||
{
|
||||
string status = downloadHandle.GetRealPingTime(_config.constItem.speedPingTestUrl, webProxy, 10, out int responseTime);
|
||||
string status = downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
|
||||
//string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
|
||||
return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit);
|
||||
}
|
||||
@@ -240,11 +338,11 @@ namespace v2rayN.Handler
|
||||
ipAddress = ipHostInfo.AddressList[0];
|
||||
}
|
||||
|
||||
Stopwatch timer = new Stopwatch();
|
||||
Stopwatch timer = new();
|
||||
timer.Start();
|
||||
|
||||
IPEndPoint endPoint = new IPEndPoint(ipAddress, port);
|
||||
Socket clientSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
IPEndPoint endPoint = new(ipAddress, port);
|
||||
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
|
||||
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
|
||||
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
||||
@@ -253,7 +351,6 @@ namespace v2rayN.Handler
|
||||
|
||||
timer.Stop();
|
||||
responseTime = timer.Elapsed.Milliseconds;
|
||||
clientSocket.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -275,7 +372,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
int timeout = 30;
|
||||
int echoNum = 2;
|
||||
Ping pingSender = new Ping();
|
||||
using Ping pingSender = new();
|
||||
for (int i = 0; i < echoNum; i++)
|
||||
{
|
||||
PingReply reply = pingSender.Send(host, timeout);
|
||||
|
||||
@@ -13,7 +13,9 @@ namespace v2rayN.Handler
|
||||
private Channel channel_;
|
||||
private StatsService.StatsServiceClient client_;
|
||||
private bool exitFlag_;
|
||||
private ServerStatItem _serverStatItem;
|
||||
private ServerStatItem? _serverStatItem;
|
||||
private List<ServerStatItem> _lstServerStat;
|
||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||
|
||||
Action<ServerSpeedItem> updateFunc_;
|
||||
|
||||
@@ -25,7 +27,7 @@ namespace v2rayN.Handler
|
||||
public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update)
|
||||
{
|
||||
config_ = config;
|
||||
Enable = config.enableStatistics;
|
||||
Enable = config.guiItem.enableStatistics;
|
||||
updateFunc_ = update;
|
||||
exitFlag_ = false;
|
||||
|
||||
@@ -68,7 +70,7 @@ namespace v2rayN.Handler
|
||||
{
|
||||
if (Enable && channel_.State == ChannelState.Ready)
|
||||
{
|
||||
QueryStatsResponse res = null;
|
||||
QueryStatsResponse? res = null;
|
||||
try
|
||||
{
|
||||
res = client_.QueryStats(new QueryStatsRequest() { Pattern = "", Reset = true });
|
||||
@@ -83,24 +85,25 @@ namespace v2rayN.Handler
|
||||
GetServerStatItem(config_.indexId);
|
||||
ParseOutput(res.Stat, out ServerSpeedItem server);
|
||||
|
||||
_serverStatItem.todayUp += server.proxyUp;
|
||||
_serverStatItem.todayDown += server.proxyDown;
|
||||
_serverStatItem.totalUp += server.proxyUp;
|
||||
_serverStatItem.totalDown += server.proxyDown;
|
||||
|
||||
if (server.proxyUp != 0 || server.proxyDown != 0)
|
||||
{
|
||||
_serverStatItem.todayUp += server.proxyUp;
|
||||
_serverStatItem.todayDown += server.proxyDown;
|
||||
_serverStatItem.totalUp += server.proxyUp;
|
||||
_serverStatItem.totalDown += server.proxyDown;
|
||||
}
|
||||
if (Global.ShowInTaskbar)
|
||||
{
|
||||
server.indexId = config_.indexId;
|
||||
server.todayUp = _serverStatItem.todayUp;
|
||||
server.todayDown = _serverStatItem.todayDown;
|
||||
server.totalUp = _serverStatItem.totalUp;
|
||||
server.totalDown = _serverStatItem.totalDown;
|
||||
updateFunc_(server);
|
||||
}
|
||||
if (server.proxyUp != 0 || server.proxyDown != 0)
|
||||
{
|
||||
_ = SqliteHelper.Instance.UpdateAsync(_serverStatItem);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
var sleep = config_.statisticsFreshRate < 1 ? 1 : config_.statisticsFreshRate;
|
||||
var sleep = config_.guiItem.statisticsFreshRate < 1 ? 1 : config_.guiItem.statisticsFreshRate;
|
||||
Thread.Sleep(1000 * sleep);
|
||||
channel_.ConnectAsync();
|
||||
}
|
||||
@@ -114,12 +117,27 @@ namespace v2rayN.Handler
|
||||
{
|
||||
SqliteHelper.Instance.Execute($"delete from ServerStatItem ");
|
||||
_serverStatItem = null;
|
||||
_lstServerStat = new();
|
||||
}
|
||||
|
||||
public void SaveTo()
|
||||
{
|
||||
try
|
||||
{
|
||||
SqliteHelper.Instance.UpdateAll(_lstServerStat);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
long ticks = DateTime.Now.Date.Ticks;
|
||||
SqliteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
|
||||
|
||||
_lstServerStat = SqliteHelper.Instance.Table<ServerStatItem>().ToList();
|
||||
}
|
||||
|
||||
private void GetServerStatItem(string indexId)
|
||||
@@ -132,7 +150,7 @@ namespace v2rayN.Handler
|
||||
|
||||
if (_serverStatItem == null)
|
||||
{
|
||||
_serverStatItem = SqliteHelper.Instance.Table<ServerStatItem>().FirstOrDefault(t => t.indexId == indexId);
|
||||
_serverStatItem = _lstServerStat.FirstOrDefault(t => t.indexId == indexId);
|
||||
if (_serverStatItem == null)
|
||||
{
|
||||
_serverStatItem = new ServerStatItem
|
||||
@@ -145,6 +163,7 @@ namespace v2rayN.Handler
|
||||
dateNow = ticks
|
||||
};
|
||||
_ = SqliteHelper.Instance.Replacesync(_serverStatItem);
|
||||
_lstServerStat.Add(_serverStatItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +229,7 @@ namespace v2rayN.Handler
|
||||
try
|
||||
{
|
||||
// TCP stack please do me a favor
|
||||
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
|
||||
TcpListener l = new(IPAddress.Loopback, 0);
|
||||
l.Start();
|
||||
int port = ((IPEndPoint)l.LocalEndpoint).Port;
|
||||
l.Stop();
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace v2rayN.Handler
|
||||
// <proxy-server><CR-LF>
|
||||
// <bypass-list><CR-LF>
|
||||
// <pac-url>
|
||||
private static SysproxyConfig _userSettings = null;
|
||||
private static SysproxyConfig? _userSettings = null;
|
||||
|
||||
enum RET_ERRORS : int
|
||||
{
|
||||
@@ -154,85 +154,82 @@ namespace v2rayN.Handler
|
||||
// using event to avoid hanging when redirect standard output/error
|
||||
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
|
||||
// and http://blog.csdn.net/zhangweixing0/article/details/7356841
|
||||
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
|
||||
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
|
||||
using AutoResetEvent outputWaitHandle = new(false);
|
||||
using AutoResetEvent errorWaitHandle = new(false);
|
||||
using Process process = new();
|
||||
|
||||
// Configure the process using the StartInfo properties.
|
||||
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
|
||||
process.StartInfo.Arguments = arguments;
|
||||
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
|
||||
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
|
||||
// Need to provide encoding info, or output/error strings we got will be wrong.
|
||||
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
|
||||
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
|
||||
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
|
||||
StringBuilder output = new(1024);
|
||||
StringBuilder error = new(1024);
|
||||
|
||||
process.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
using (Process process = new Process())
|
||||
if (e.Data == null)
|
||||
{
|
||||
// Configure the process using the StartInfo properties.
|
||||
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
|
||||
process.StartInfo.Arguments = arguments;
|
||||
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
|
||||
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
|
||||
// Need to provide encoding info, or output/error strings we got will be wrong.
|
||||
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
|
||||
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
|
||||
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
StringBuilder error = new StringBuilder();
|
||||
|
||||
process.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data == null)
|
||||
{
|
||||
outputWaitHandle.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
output.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
process.ErrorDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data == null)
|
||||
{
|
||||
errorWaitHandle.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
error.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
process.WaitForExit();
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception e)
|
||||
{
|
||||
|
||||
// log the arguments
|
||||
throw new Exception(process.StartInfo.Arguments);
|
||||
}
|
||||
string stderr = error.ToString();
|
||||
string stdout = output.ToString();
|
||||
|
||||
int exitCode = process.ExitCode;
|
||||
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
|
||||
{
|
||||
throw new Exception(stderr);
|
||||
}
|
||||
|
||||
//if (arguments == "query")
|
||||
//{
|
||||
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
|
||||
// {
|
||||
// throw new Exception("failed to query wininet settings");
|
||||
// }
|
||||
// _queryStr = stdout;
|
||||
//}
|
||||
outputWaitHandle.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
output.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
process.ErrorDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data == null)
|
||||
{
|
||||
errorWaitHandle.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
error.AppendLine(e.Data);
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
process.WaitForExit();
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception e)
|
||||
{
|
||||
|
||||
// log the arguments
|
||||
throw new Exception(process.StartInfo.Arguments);
|
||||
}
|
||||
string stderr = error.ToString();
|
||||
string stdout = output.ToString();
|
||||
|
||||
int exitCode = process.ExitCode;
|
||||
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
|
||||
{
|
||||
throw new Exception(stderr);
|
||||
}
|
||||
|
||||
//if (arguments == "query")
|
||||
//{
|
||||
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
|
||||
// {
|
||||
// throw new Exception("failed to query wininet settings");
|
||||
// }
|
||||
// _queryStr = stdout;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,17 +3,18 @@ using System.IO;
|
||||
using System.Reactive.Linq;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Mode;
|
||||
using v2rayN.Resx;
|
||||
|
||||
namespace v2rayN.Base
|
||||
{
|
||||
public sealed class TunHandler
|
||||
{
|
||||
private static readonly Lazy<TunHandler> _instance = new Lazy<TunHandler>(() => new());
|
||||
private static readonly Lazy<TunHandler> _instance = new(() => new());
|
||||
public static TunHandler Instance => _instance.Value;
|
||||
private string _tunConfigName = "tunConfig.json";
|
||||
private static Config _config;
|
||||
private CoreInfo coreInfo;
|
||||
private Process _process;
|
||||
private Process? _process;
|
||||
private static int _socksPort;
|
||||
private static bool _needRestart = true;
|
||||
private static bool _isRunning = false;
|
||||
@@ -60,6 +61,7 @@ namespace v2rayN.Base
|
||||
{
|
||||
return;
|
||||
}
|
||||
CoreStartTest();
|
||||
CoreStart();
|
||||
}
|
||||
}
|
||||
@@ -72,7 +74,16 @@ namespace v2rayN.Base
|
||||
private bool Init()
|
||||
{
|
||||
coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box);
|
||||
//Template
|
||||
string configStr = Utils.GetEmbedText(Global.TunSingboxFileName);
|
||||
if (!Utils.IsNullOrEmpty(_config.tunModeItem.customTemplate) && File.Exists(_config.tunModeItem.customTemplate))
|
||||
{
|
||||
var customTemplate = File.ReadAllText(_config.tunModeItem.customTemplate);
|
||||
if (!Utils.IsNullOrEmpty(customTemplate))
|
||||
{
|
||||
configStr = customTemplate;
|
||||
}
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(configStr))
|
||||
{
|
||||
return false;
|
||||
@@ -91,13 +102,25 @@ namespace v2rayN.Base
|
||||
configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}");
|
||||
configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}");
|
||||
|
||||
//logs
|
||||
configStr = configStr.Replace("$log_disabled$", $"aaa{(!_config.tunModeItem.enabledLog).ToString().ToLower()}");
|
||||
if (_config.tunModeItem.showWindow)
|
||||
{
|
||||
configStr = configStr.Replace("$log_output$", $"");
|
||||
}
|
||||
else
|
||||
{
|
||||
var dtNow = DateTime.Now;
|
||||
var log_output = $"\"output\": \"{Utils.GetLogPath($"singbox_{dtNow:yyyy-MM-dd}.txt")}\", ";
|
||||
configStr = configStr.Replace("$log_output$", $"{log_output.Replace(@"\", @"\\")}");
|
||||
}
|
||||
|
||||
//port
|
||||
configStr = configStr.Replace("$socksPort$", $"{_socksPort}");
|
||||
|
||||
//exe
|
||||
List<string> lstDnsExe = new List<string>();
|
||||
List<string> lstDirectExe = new List<string>();
|
||||
List<string> lstDnsExe = new();
|
||||
List<string> lstDirectExe = new();
|
||||
var coreInfos = LazyConfig.Instance.GetCoreInfos();
|
||||
foreach (var it in coreInfos)
|
||||
{
|
||||
@@ -109,13 +132,13 @@ namespace v2rayN.Base
|
||||
{
|
||||
if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
|
||||
{
|
||||
lstDnsExe.Add(it2);
|
||||
//lstDnsExe.Add(it2);
|
||||
lstDnsExe.Add($"{it2}.exe");
|
||||
}
|
||||
|
||||
if (!lstDirectExe.Contains(it2))
|
||||
{
|
||||
lstDirectExe.Add(it2);
|
||||
//lstDirectExe.Add(it2);
|
||||
lstDirectExe.Add($"{it2}.exe");
|
||||
}
|
||||
}
|
||||
@@ -126,27 +149,45 @@ namespace v2rayN.Base
|
||||
string strDirect = string.Join("\",\"", lstDirectExe.ToArray());
|
||||
configStr = configStr.Replace("$directProcessName$", $"\"{strDirect}\"");
|
||||
|
||||
if (_config.tunModeItem.bypassMode)
|
||||
{
|
||||
//direct ips
|
||||
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0)
|
||||
{
|
||||
var ips = new { outbound = "direct", ip_cidr = _config.tunModeItem.directIP };
|
||||
configStr = configStr.Replace("$ruleDirectIPs$", "," + Utils.ToJson(ips));
|
||||
}
|
||||
//direct process
|
||||
if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0)
|
||||
{
|
||||
var process = new { outbound = "direct", process_name = _config.tunModeItem.directProcess };
|
||||
configStr = configStr.Replace("$ruleDirectProcess$", "," + Utils.ToJson(process));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//proxy ips
|
||||
if (_config.tunModeItem.proxyIP != null && _config.tunModeItem.proxyIP.Count > 0)
|
||||
{
|
||||
var ips = new { outbound = "proxy", ip_cidr = _config.tunModeItem.proxyIP };
|
||||
configStr = configStr.Replace("$ruleProxyIPs$", "," + Utils.ToJson(ips));
|
||||
}
|
||||
//proxy process
|
||||
if (_config.tunModeItem.proxyProcess != null && _config.tunModeItem.proxyProcess.Count > 0)
|
||||
{
|
||||
var process = new { outbound = "proxy", process_name = _config.tunModeItem.proxyProcess };
|
||||
configStr = configStr.Replace("$ruleProxyProcess$", "," + Utils.ToJson(process));
|
||||
}
|
||||
|
||||
//ips
|
||||
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0)
|
||||
{
|
||||
var ips = new { outbound = "direct", ip_cidr = _config.tunModeItem.directIP };
|
||||
configStr = configStr.Replace("$ruleDirectIPs$", "," + Utils.ToJson(ips));
|
||||
}
|
||||
else
|
||||
{
|
||||
configStr = configStr.Replace("$ruleDirectIPs$", "");
|
||||
}
|
||||
//process
|
||||
if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0)
|
||||
{
|
||||
var process = new { outbound = "direct", process_name = _config.tunModeItem.directProcess };
|
||||
configStr = configStr.Replace("$ruleDirectProcess$", "," + Utils.ToJson(process));
|
||||
}
|
||||
else
|
||||
{
|
||||
configStr = configStr.Replace("$ruleDirectProcess$", "");
|
||||
var final = new { outbound = "direct", inbound = "tun-in" };
|
||||
configStr = configStr.Replace("$ruleFinally$", "," + Utils.ToJson(final));
|
||||
}
|
||||
configStr = configStr.Replace("$ruleDirectIPs$", "");
|
||||
configStr = configStr.Replace("$ruleDirectProcess$", "");
|
||||
configStr = configStr.Replace("$ruleProxyIPs$", "");
|
||||
configStr = configStr.Replace("$ruleProxyProcess$", "");
|
||||
configStr = configStr.Replace("$ruleFinally$", "");
|
||||
|
||||
|
||||
File.WriteAllText(Utils.GetConfigPath(_tunConfigName), configStr);
|
||||
|
||||
@@ -163,6 +204,7 @@ namespace v2rayN.Base
|
||||
KillProcess(_process);
|
||||
_process.Dispose();
|
||||
_process = null;
|
||||
_needRestart = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -186,7 +228,8 @@ namespace v2rayN.Base
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(fileName))
|
||||
{
|
||||
|
||||
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
|
||||
Utils.SaveLog(msg);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
@@ -196,19 +239,21 @@ namespace v2rayN.Base
|
||||
try
|
||||
{
|
||||
string fileName = CoreFindexe();
|
||||
if (fileName == "")
|
||||
if (Utils.IsNullOrEmpty(fileName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Process p = new Process
|
||||
var showWindow = _config.tunModeItem.showWindow;
|
||||
Process p = new()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = $"run -c {Utils.GetConfigPath(_tunConfigName)}",
|
||||
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
|
||||
WorkingDirectory = Utils.GetConfigPath(),
|
||||
UseShellExecute = _config.tunModeItem.showWindow,
|
||||
CreateNoWindow = !_config.tunModeItem.showWindow,
|
||||
UseShellExecute = showWindow,
|
||||
CreateNoWindow = !showWindow,
|
||||
//RedirectStandardError = !showWindow,
|
||||
Verb = "runas",
|
||||
}
|
||||
};
|
||||
@@ -217,7 +262,14 @@ namespace v2rayN.Base
|
||||
_isRunning = true;
|
||||
if (p.WaitForExit(1000))
|
||||
{
|
||||
//if (showWindow)
|
||||
//{
|
||||
throw new Exception("start tun mode fail");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// throw new Exception(p.StandardError.ReadToEnd());
|
||||
//}
|
||||
}
|
||||
|
||||
Global.processJob.AddProcess(p.Handle);
|
||||
@@ -245,5 +297,47 @@ namespace v2rayN.Base
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private int CoreStartTest()
|
||||
{
|
||||
Utils.SaveLog("Tun mode configuration file test start");
|
||||
try
|
||||
{
|
||||
string fileName = CoreFindexe();
|
||||
if (fileName == "")
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
Process p = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
|
||||
WorkingDirectory = Utils.GetConfigPath(),
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardError = true,
|
||||
Verb = "runas",
|
||||
}
|
||||
};
|
||||
p.Start();
|
||||
if (p.WaitForExit(2000))
|
||||
{
|
||||
throw new Exception(p.StandardError.ReadToEnd());
|
||||
}
|
||||
KillProcess(p);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
return -1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Utils.SaveLog("Tun mode configuration file test end");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,51 +35,46 @@ namespace v2rayN.Handler
|
||||
_updateFunc = update;
|
||||
var url = string.Empty;
|
||||
|
||||
DownloadHandle downloadHandle = null;
|
||||
if (downloadHandle == null)
|
||||
DownloadHandle downloadHandle = new();
|
||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||
{
|
||||
downloadHandle = new DownloadHandle();
|
||||
|
||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||
if (args.Success)
|
||||
{
|
||||
if (args.Success)
|
||||
{
|
||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
||||
fileName = Utils.UrlEncode(fileName);
|
||||
Process process = new()
|
||||
{
|
||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
||||
fileName = Utils.UrlEncode(fileName);
|
||||
Process process = new Process
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "v2rayUpgrade.exe",
|
||||
Arguments = "\"" + fileName + "\"",
|
||||
WorkingDirectory = Utils.StartupPath()
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
if (process.Id > 0)
|
||||
{
|
||||
_updateFunc(true, "");
|
||||
FileName = "v2rayUpgrade.exe",
|
||||
Arguments = $"\"{fileName}\"",
|
||||
WorkingDirectory = Utils.StartupPath()
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
};
|
||||
process.Start();
|
||||
if (process.Id > 0)
|
||||
{
|
||||
_updateFunc(false, ex.Message);
|
||||
_updateFunc(true, "");
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
_updateFunc(false, args.Msg);
|
||||
_updateFunc(false, ex.Message);
|
||||
}
|
||||
};
|
||||
downloadHandle.Error += (sender2, args) =>
|
||||
}
|
||||
else
|
||||
{
|
||||
_updateFunc(false, args.GetException().Message);
|
||||
};
|
||||
}
|
||||
_updateFunc(false, args.Msg);
|
||||
}
|
||||
};
|
||||
downloadHandle.Error += (sender2, args) =>
|
||||
{
|
||||
_updateFunc(false, args.GetException().Message);
|
||||
};
|
||||
AbsoluteCompleted += (sender2, args) =>
|
||||
{
|
||||
if (args.Success)
|
||||
@@ -106,36 +101,32 @@ namespace v2rayN.Handler
|
||||
_updateFunc = update;
|
||||
var url = string.Empty;
|
||||
|
||||
DownloadHandle downloadHandle = null;
|
||||
if (downloadHandle == null)
|
||||
DownloadHandle downloadHandle = new();
|
||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||
{
|
||||
downloadHandle = new DownloadHandle();
|
||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||
if (args.Success)
|
||||
{
|
||||
if (args.Success)
|
||||
{
|
||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
||||
_updateFunc(false, ResUI.MsgUnpacking);
|
||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
||||
_updateFunc(false, ResUI.MsgUnpacking);
|
||||
|
||||
try
|
||||
{
|
||||
_updateFunc(true, url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_updateFunc(false, ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
try
|
||||
{
|
||||
_updateFunc(false, args.Msg);
|
||||
_updateFunc(true, url);
|
||||
}
|
||||
};
|
||||
downloadHandle.Error += (sender2, args) =>
|
||||
catch (Exception ex)
|
||||
{
|
||||
_updateFunc(false, ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_updateFunc(true, args.GetException().Message);
|
||||
};
|
||||
}
|
||||
_updateFunc(false, args.Msg);
|
||||
}
|
||||
};
|
||||
downloadHandle.Error += (sender2, args) =>
|
||||
{
|
||||
_updateFunc(true, args.GetException().Message);
|
||||
};
|
||||
|
||||
AbsoluteCompleted += (sender2, args) =>
|
||||
{
|
||||
@@ -213,10 +204,10 @@ namespace v2rayN.Handler
|
||||
url = Utils.GetPunycode(url);
|
||||
|
||||
_updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}");
|
||||
var result = await downloadHandle.DownloadStringAsync(url, blProxy, userAgent);
|
||||
var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent);
|
||||
if (blProxy && Utils.IsNullOrEmpty(result))
|
||||
{
|
||||
result = await downloadHandle.DownloadStringAsync(url, false, userAgent);
|
||||
result = await downloadHandle.TryDownloadString(url, false, userAgent);
|
||||
}
|
||||
|
||||
if (Utils.IsNullOrEmpty(result))
|
||||
@@ -226,12 +217,17 @@ namespace v2rayN.Handler
|
||||
else
|
||||
{
|
||||
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
|
||||
if (result.Length < 99)
|
||||
if (result!.Length < 99)
|
||||
{
|
||||
_updateFunc(false, $"{hashCode}{result}");
|
||||
}
|
||||
|
||||
int ret = ConfigHandler.AddBatchServers(ref config, result, id, true);
|
||||
if (ret <= 0)
|
||||
{
|
||||
Utils.SaveLog("FailedImportSubscription");
|
||||
Utils.SaveLog(result);
|
||||
}
|
||||
_updateFunc(false,
|
||||
ret > 0
|
||||
? $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}"
|
||||
@@ -257,45 +253,44 @@ namespace v2rayN.Handler
|
||||
_updateFunc = update;
|
||||
var url = string.Format(Global.geoUrl, geoName);
|
||||
|
||||
DownloadHandle downloadHandle = null;
|
||||
if (downloadHandle == null)
|
||||
DownloadHandle downloadHandle = new();
|
||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||
{
|
||||
downloadHandle = new DownloadHandle();
|
||||
|
||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||
if (args.Success)
|
||||
{
|
||||
if (args.Success)
|
||||
{
|
||||
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
|
||||
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
Global.coreTypes.ForEach(it =>
|
||||
{
|
||||
string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
|
||||
File.Copy(fileName, targetPath, true);
|
||||
});
|
||||
//_updateFunc(true, "");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_updateFunc(false, ex.Message);
|
||||
//Global.coreTypes.ForEach(it =>
|
||||
//{
|
||||
// string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
|
||||
// File.Copy(fileName, targetPath, true);
|
||||
//});
|
||||
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
||||
File.Copy(fileName, targetPath, true);
|
||||
|
||||
File.Delete(fileName);
|
||||
//_updateFunc(true, "");
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
_updateFunc(false, args.Msg);
|
||||
_updateFunc(false, ex.Message);
|
||||
}
|
||||
};
|
||||
downloadHandle.Error += (sender2, args) =>
|
||||
}
|
||||
else
|
||||
{
|
||||
_updateFunc(false, args.GetException().Message);
|
||||
};
|
||||
}
|
||||
_updateFunc(false, args.Msg);
|
||||
}
|
||||
};
|
||||
downloadHandle.Error += (sender2, args) =>
|
||||
{
|
||||
_updateFunc(false, args.GetException().Message);
|
||||
};
|
||||
askToDownload(downloadHandle, url, false);
|
||||
|
||||
}
|
||||
@@ -365,7 +360,7 @@ namespace v2rayN.Handler
|
||||
return "";
|
||||
}
|
||||
|
||||
Process p = new Process();
|
||||
using Process p = new();
|
||||
p.StartInfo.FileName = filePath;
|
||||
p.StartInfo.Arguments = coreInfo.versionArg;
|
||||
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
||||
@@ -457,6 +452,17 @@ namespace v2rayN.Handler
|
||||
throw new ArgumentException("Type");
|
||||
}
|
||||
|
||||
if (type == ECoreType.v2rayN)
|
||||
{
|
||||
decimal.TryParse(curVersion, out decimal decCur);
|
||||
decimal.TryParse(version, out decimal dec);
|
||||
if (decCur >= dec)
|
||||
{
|
||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (curVersion == version)
|
||||
{
|
||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
|
||||
|
||||
@@ -8,148 +8,31 @@
|
||||
{
|
||||
#region property
|
||||
|
||||
/// <summary>
|
||||
/// 允许日志
|
||||
/// </summary>
|
||||
public bool logEnabled
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志等级
|
||||
/// </summary>
|
||||
public string loglevel
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string indexId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 允许Mux多路复用
|
||||
/// </summary>
|
||||
public bool muxEnabled
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ESysProxyType sysProxyType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public bool autoRun { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启用实时网速和流量统计
|
||||
/// </summary>
|
||||
public bool enableStatistics
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 去重时优先保留较旧(顶部)节点
|
||||
/// </summary>
|
||||
public bool keepOlderDedupl
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 视图刷新率
|
||||
/// </summary>
|
||||
public int statisticsFreshRate
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义远程DNS
|
||||
/// </summary>
|
||||
public string remoteDNS
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string indexId { get; set; }
|
||||
|
||||
public string remoteDNS { get; set; }
|
||||
/// <summary>
|
||||
/// Outbound Freedom domainStrategy
|
||||
/// </summary>
|
||||
public string domainStrategy4Freedom
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string domainStrategy4Freedom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许不安全连接
|
||||
/// </summary>
|
||||
public bool defAllowInsecure
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 域名解析策略
|
||||
/// </summary>
|
||||
public string domainStrategy
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string domainMatcher
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string routingIndexId { get; set; }
|
||||
public bool enableRoutingAdvanced
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public bool ignoreGeoUpdateCore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// systemProxyExceptions
|
||||
/// </summary>
|
||||
public string systemProxyExceptions
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public ESysProxyType sysProxyType { get; set; }
|
||||
public string systemProxyExceptions { get; set; }
|
||||
public string systemProxyAdvancedProtocol { get; set; }
|
||||
|
||||
public int autoUpdateInterval { get; set; } = 10;
|
||||
|
||||
public int autoUpdateSubInterval { get; set; } = 10;
|
||||
|
||||
public bool checkPreReleaseUpdate { get; set; } = false;
|
||||
|
||||
public bool enableSecurityProtocolTls13
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int trayMenuServersLimit { get; set; } = 20;
|
||||
|
||||
public bool autoHideStartup { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region other entities
|
||||
|
||||
public CoreBasicItem coreBasicItem { get; set; }
|
||||
public TunModeItem tunModeItem { get; set; }
|
||||
public KcpItem kcpItem { get; set; }
|
||||
public GrpcItem grpcItem { get; set; }
|
||||
public RoutingBasicItem routingBasicItem { get; set; }
|
||||
public GUIItem guiItem { get; set; }
|
||||
public UIItem uiItem { get; set; }
|
||||
public ConstItem constItem { get; set; }
|
||||
public SpeedTestItem speedTestItem { get; set; }
|
||||
public List<InItem> inbound { get; set; }
|
||||
public List<KeyEventItem> globalHotkeys { get; set; }
|
||||
public List<CoreTypeItem> coreTypeItem { get; set; }
|
||||
|
||||
@@ -2,6 +2,37 @@
|
||||
|
||||
namespace v2rayN.Mode
|
||||
{
|
||||
[Serializable]
|
||||
public class CoreBasicItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 允许日志
|
||||
/// </summary>
|
||||
public bool logEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志等级
|
||||
/// </summary>
|
||||
public string loglevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 允许Mux多路复用
|
||||
/// </summary>
|
||||
public bool muxEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许不安全连接
|
||||
/// </summary>
|
||||
public bool defAllowInsecure { get; set; }
|
||||
|
||||
public string defFingerprint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 默认用户代理
|
||||
/// </summary>
|
||||
public string defUserAgent { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class InItem
|
||||
{
|
||||
@@ -51,23 +82,53 @@ namespace v2rayN.Mode
|
||||
public int initial_windows_size { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class GUIItem
|
||||
{
|
||||
public bool autoRun { get; set; }
|
||||
|
||||
public bool enableStatistics { get; set; }
|
||||
|
||||
public int statisticsFreshRate { get; set; }
|
||||
|
||||
public bool keepOlderDedupl { get; set; }
|
||||
|
||||
public bool ignoreGeoUpdateCore { get; set; } = true;
|
||||
|
||||
public int autoUpdateInterval { get; set; } = 10;
|
||||
|
||||
public int autoUpdateSubInterval { get; set; } = 10;
|
||||
|
||||
public bool checkPreReleaseUpdate { get; set; } = false;
|
||||
|
||||
public bool enableSecurityProtocolTls13 { get; set; }
|
||||
|
||||
public int trayMenuServersLimit { get; set; } = 20;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UIItem
|
||||
{
|
||||
public bool enableAutoAdjustMainLvColWidth { get; set; }
|
||||
public double mainWidth { get; set; }
|
||||
public double mainHeight { get; set; }
|
||||
public double mainGirdHeight1 { get; set; }
|
||||
public double mainGirdHeight2 { get; set; }
|
||||
public bool colorModeDark { get; set; }
|
||||
public string? colorPrimaryName { get; set; }
|
||||
public string currentLanguage { get; set; }
|
||||
public string currentFontFamily { get; set; }
|
||||
public int currentFontSize { get; set; }
|
||||
public bool enableDragDropSort { get; set; }
|
||||
public bool doubleClick2Activate { get; set; }
|
||||
public bool autoHideStartup { get; set; } = true;
|
||||
public string mainMsgFilter { get; set; }
|
||||
public Dictionary<string, int> mainLvColWidth { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ConstItem
|
||||
{
|
||||
public string speedTestUrl { get; set; }
|
||||
public string speedPingTestUrl { get; set; }
|
||||
public string defIEProxyExceptions { get; set; }
|
||||
}
|
||||
|
||||
@@ -99,11 +160,37 @@ namespace v2rayN.Mode
|
||||
{
|
||||
public bool enableTun { get; set; }
|
||||
public bool showWindow { get; set; }
|
||||
public bool enabledLog { get; set; }
|
||||
public bool strictRoute { get; set; }
|
||||
public string stack { get; set; }
|
||||
public int mtu { get; set; }
|
||||
public string customTemplate { get; set; }
|
||||
public bool bypassMode { get; set; } = true;
|
||||
public List<string> directIP { get; set; }
|
||||
public List<string> directProcess { get; set; }
|
||||
public List<string> proxyIP { get; set; }
|
||||
public List<string> proxyProcess { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SpeedTestItem
|
||||
{
|
||||
public int speedTestTimeout { get; set; }
|
||||
public string speedTestUrl { get; set; }
|
||||
public string speedPingTestUrl { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RoutingBasicItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 域名解析策略
|
||||
/// </summary>
|
||||
public string domainStrategy { get; set; }
|
||||
public string domainMatcher { get; set; }
|
||||
public string routingIndexId { get; set; }
|
||||
public bool enableRoutingAdvanced { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
14
v2rayN/v2rayN/Mode/ProfileExItem.cs
Normal file
14
v2rayN/v2rayN/Mode/ProfileExItem.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using SQLite;
|
||||
|
||||
namespace v2rayN.Mode
|
||||
{
|
||||
[Serializable]
|
||||
public class ProfileExItem
|
||||
{
|
||||
[PrimaryKey]
|
||||
public string indexId { get; set; }
|
||||
public int delay { get; set; }
|
||||
public decimal speed { get; set; }
|
||||
public int sort { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ namespace v2rayN.Mode
|
||||
indexId = string.Empty;
|
||||
configType = EConfigType.VMess;
|
||||
configVersion = 2;
|
||||
sort = 0;
|
||||
address = string.Empty;
|
||||
port = 0;
|
||||
id = string.Empty;
|
||||
@@ -107,11 +106,6 @@ namespace v2rayN.Mode
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int sort
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远程服务器地址
|
||||
/// </summary>
|
||||
@@ -202,9 +196,6 @@ namespace v2rayN.Mode
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int delay { get; set; }
|
||||
public decimal speed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// SubItem id
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
{
|
||||
public bool isActive { get; set; }
|
||||
public string subRemarks { get; set; }
|
||||
public int delay { get; set; }
|
||||
public decimal speed { get; set; }
|
||||
public int sort { get; set; }
|
||||
public string delayVal { get; set; }
|
||||
public string speedVal { get; set; }
|
||||
public string todayUp { get; set; }
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace v2rayN.Mode
|
||||
public bool locked { get; set; }
|
||||
public string customIcon { get; set; }
|
||||
public string domainStrategy { get; set; }
|
||||
public int sort { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
namespace v2rayN.Mode
|
||||
{
|
||||
[Serializable]
|
||||
class ServerSpeedItem
|
||||
class ServerSpeedItem : ServerStatItem
|
||||
{
|
||||
public string indexId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public long proxyUp
|
||||
{
|
||||
get; set;
|
||||
|
||||
@@ -3,25 +3,11 @@
|
||||
[Serializable]
|
||||
class ServerTestItem
|
||||
{
|
||||
public string indexId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string address
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public int port
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public EConfigType configType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public bool allowTest
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string indexId { get; set; }
|
||||
public string address { get; set; }
|
||||
public int port { get; set; }
|
||||
public EConfigType configType { get; set; }
|
||||
public bool allowTest { get; set; }
|
||||
public int delay { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace v2rayN.Mode
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace v2rayN.Mode
|
||||
{
|
||||
/// <summary>
|
||||
/// v2ray配置文件实体类
|
||||
@@ -505,6 +507,12 @@
|
||||
///
|
||||
/// </summary>
|
||||
public string Host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户代理
|
||||
/// </summary>
|
||||
[JsonProperty("User-Agent")]
|
||||
public string UserAgent { get; set; }
|
||||
}
|
||||
|
||||
public class HttpSettings
|
||||
|
||||
@@ -63,5 +63,10 @@
|
||||
/// TLS alpn
|
||||
/// </summary>
|
||||
public string alpn { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// TLS fingerprint
|
||||
/// </summary>
|
||||
public string fp { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
210
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
210
v2rayN/v2rayN/Resx/ResUI.Designer.cs
generated
@@ -70,7 +70,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 All servers 的本地化字符串。
|
||||
/// 查找类似 All 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string AllGroupServers {
|
||||
get {
|
||||
@@ -681,6 +681,15 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Edit Server (Ctrl+D) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuEditServer {
|
||||
get {
|
||||
return ResourceManager.GetString("menuEditServer", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Exit 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -781,7 +790,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 One-click test Latency and speed (Ctrl+E) 的本地化字符串。
|
||||
/// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuMixedTestServer {
|
||||
get {
|
||||
@@ -807,6 +816,15 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Move to group 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuMoveToGroup {
|
||||
get {
|
||||
return ResourceManager.GetString("menuMoveToGroup", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Move to top (T) 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1105,7 +1123,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Share Server (Ctrl+D) 的本地化字符串。
|
||||
/// 查找类似 Share Server (Ctrl+F) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuShareServer {
|
||||
get {
|
||||
@@ -1743,6 +1761,24 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Test completed 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string SpeedtestingCompleted {
|
||||
get {
|
||||
return ResourceManager.GetString("SpeedtestingCompleted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Skip test 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string SpeedtestingSkip {
|
||||
get {
|
||||
return ResourceManager.GetString("SpeedtestingSkip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 PAC failed to start. Please run this program as Administrator. 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1852,6 +1888,15 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 AutoRefresh 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbAutoRefresh {
|
||||
get {
|
||||
return ResourceManager.GetString("TbAutoRefresh", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Domain and ip are auto sorted when saving 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2347,6 +2392,24 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 FontFamily(Require restart) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsCurrentFontFamily {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsCurrentFontFamily", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Copy the font TTF file to the directory guiFonts, restart the settings 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsCurrentFontFamilyTip {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsCurrentFontFamilyTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 AllowInsecure 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2356,6 +2419,33 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Default TLS fingerprint 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsDefFingerprint {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsDefFingerprint", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 User-Agent 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsDefUserAgent {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsDefUserAgent", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 This parameter is valid only for tcp/http and ws 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsDefUserAgentTips {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsDefUserAgentTips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2365,6 +2455,15 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Double-click server make active 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsDoubleClick2Activate {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsDoubleClick2Activate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Automatically adjust column width after updating subscription 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2383,6 +2482,15 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Server Drag Drop Sort(Require restart) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsEnableDragDropSort {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsEnableDragDropSort", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Exception 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2401,6 +2509,15 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 FontSize 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsFontSize {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsFontSize", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Http Port 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2438,7 +2555,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Language 的本地化字符串。
|
||||
/// 查找类似 Language(Restart) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsLanguage {
|
||||
get {
|
||||
@@ -2447,7 +2564,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Record local logs 的本地化字符串。
|
||||
/// 查找类似 Enable Log 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsLogEnabled {
|
||||
get {
|
||||
@@ -2563,6 +2680,33 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 http port=socks port+1 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsSocksPortTip {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsSocksPortTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsSpeedTestTimeout {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsSpeedTestTimeout", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 SpeedTest Url 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsSpeedTestUrl {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsSpeedTestUrl", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Start on boot 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2572,6 +2716,15 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Set this with admin privileges, get admin privileges after startup 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsStartBootTip {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsStartBootTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Statistics (Require restart) 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2635,6 +2788,33 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Bypass Mode 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunModeBypassMode {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunModeBypassMode", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable: If no route matches, the final proxy 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunModeBypassModeTip {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunModeBypassModeTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Custom Template 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunModeCustomTemplate {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunModeCustomTemplate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Direct IP CIDR, separated by commas (,) 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2653,6 +2833,24 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Proxy IP CIDR, separated by commas (,) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunModeProxyIP {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunModeProxyIP", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Proxy Process name, separated by commas (,) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunModeProxyProcess {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunModeProxyProcess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Show console 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2870,7 +3068,7 @@ namespace v2rayN.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 *QUIC securty 的本地化字符串。
|
||||
/// 查找类似 *QUIC security 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TransportRequestHostTip4 {
|
||||
get {
|
||||
|
||||
@@ -118,22 +118,22 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
||||
<value>Batch export subscription to clipboard successfully</value>
|
||||
<value>صادرات دسته ای محتوای اشتراک به کلیپ بورد با موفقیت انجام شد</value>
|
||||
</data>
|
||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||
<value>Batch export share URL to clipboard successfully</value>
|
||||
</data>
|
||||
<data name="CheckServerSettings" xml:space="preserve">
|
||||
<value>Please check the server settings first</value>
|
||||
<value>لطفا ابتدا تنظیمات سرور را بررسی کنید</value>
|
||||
</data>
|
||||
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
||||
<value>Invalid configuration format</value>
|
||||
<value>فرمت پیکربندی نادرست است</value>
|
||||
</data>
|
||||
<data name="CustomServerTips" xml:space="preserve">
|
||||
<value>Note that custom configuration relies entirely on your own configuration and does not work with all settings. If you want to use the system proxy, please modify the listening port manually.</value>
|
||||
<value>توجه داشته باشید که پیکربندی سفارشی کاملاً به پیکربندی خود شما بستگی دارد و با همه تنظیمات کار نمی کند. اگر می خواهید از پروکسی سیستم استفاده کنید، لطفاً پورت درحال شنود را به صورت دستی تغییر دهید.</value>
|
||||
</data>
|
||||
<data name="Downloading" xml:space="preserve">
|
||||
<value>Downloading...</value>
|
||||
<value>درحال دانلود...</value>
|
||||
</data>
|
||||
<data name="downloadSpeed" xml:space="preserve">
|
||||
<value>دانلود</value>
|
||||
@@ -142,55 +142,55 @@
|
||||
<value>Whether to download? {0}</value>
|
||||
</data>
|
||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||
<value>Failed to convert configuration file</value>
|
||||
<value>تبدیل فایل پیکربندی انجام نشد</value>
|
||||
</data>
|
||||
<data name="FailedGenDefaultConfiguration" xml:space="preserve">
|
||||
<value>Failed to generate default configuration file</value>
|
||||
<value>فایل پیکربندی پیش فرض ایجاد نشد</value>
|
||||
</data>
|
||||
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
||||
<value> Failed to get the default configuration</value>
|
||||
<value>پیکربندی پیش فرض دریافت نشد</value>
|
||||
</data>
|
||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||
<value>Failed to import custom configuration server</value>
|
||||
<value>سرور پیکربندی سفارشی وارد نشد</value>
|
||||
</data>
|
||||
<data name="FailedReadConfiguration" xml:space="preserve">
|
||||
<value>Failed to read configuration file</value>
|
||||
<value>فایل پیکربندی خوانده نشد</value>
|
||||
</data>
|
||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||
<value>Please fill in the correct format server port</value>
|
||||
<value>لطفا فرمت صحیح پورت سرور را پر کنید</value>
|
||||
</data>
|
||||
<data name="FillKcpParameters" xml:space="preserve">
|
||||
<value>Please fill in the KCP parameters correctly</value>
|
||||
<value>لطفاً پارامترهای KCP را به درستی پر کنید</value>
|
||||
</data>
|
||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||
<value>Please fill in the local listening port</value>
|
||||
<value>لطفاً پورت گوش دادن محلی را پر کنید</value>
|
||||
</data>
|
||||
<data name="FillPassword" xml:space="preserve">
|
||||
<value>Please fill in the password</value>
|
||||
<value>لطفا رمز عبور را وارد کنید</value>
|
||||
</data>
|
||||
<data name="FillServerAddress" xml:space="preserve">
|
||||
<value>Please fill in the server address</value>
|
||||
<value>لطفا آدرس سرور را وارد کنید</value>
|
||||
</data>
|
||||
<data name="FillUUID" xml:space="preserve">
|
||||
<value>Please fill in the user ID</value>
|
||||
<value>لطفا شناسه کاربری را وارد کنید</value>
|
||||
</data>
|
||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
||||
<value> is not the correct client configuration file, please check</value>
|
||||
<value>فایل پیکربندی مشتری صحیح نیست، لطفا بررسی کنید</value>
|
||||
</data>
|
||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||
<value> is not the correct configuration, please check</value>
|
||||
<value>پیکربندی درستی نیست، لطفا بررسی کنید</value>
|
||||
</data>
|
||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
||||
<value> is not the correct server configuration file, please check</value>
|
||||
<value>فایل پیکربندی سرور صحیح نیست، لطفا بررسی کنید</value>
|
||||
</data>
|
||||
<data name="InitialConfiguration" xml:space="preserve">
|
||||
<value>Initial Configuration</value>
|
||||
<value>پیکربندی اولیه</value>
|
||||
</data>
|
||||
<data name="IsLatestCore" xml:space="preserve">
|
||||
<value>{0} already up to date.</value>
|
||||
<value>{0} در حال حاضر به روز است.</value>
|
||||
</data>
|
||||
<data name="IsLatestN" xml:space="preserve">
|
||||
<value>{0} already up to date.</value>
|
||||
<value>{0} در حال حاضر به روز است.</value>
|
||||
</data>
|
||||
<data name="LvAddress" xml:space="preserve">
|
||||
<value>آدرس</value>
|
||||
@@ -205,52 +205,52 @@
|
||||
<value>پورت</value>
|
||||
</data>
|
||||
<data name="LvServiceType" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
<value>نوع</value>
|
||||
</data>
|
||||
<data name="LvSubscription" xml:space="preserve">
|
||||
<value>Subs group</value>
|
||||
<value>گروه فرعی</value>
|
||||
</data>
|
||||
<data name="LvTestResults" xml:space="preserve">
|
||||
<value>Test Results</value>
|
||||
<value>نتایج تست</value>
|
||||
</data>
|
||||
<data name="LvTodayDownloadDataAmount" xml:space="preserve">
|
||||
<value>Download traffic today</value>
|
||||
<value> ترافیک دانلود امروز</value>
|
||||
</data>
|
||||
<data name="LvTodayUploadDataAmount" xml:space="preserve">
|
||||
<value>Upload traffic today</value>
|
||||
<value> ترافیک اپلود امروز</value>
|
||||
</data>
|
||||
<data name="LvTotalDownloadDataAmount" xml:space="preserve">
|
||||
<value>Total download traffic</value>
|
||||
<value>کل ترافیک دانلود</value>
|
||||
</data>
|
||||
<data name="LvTotalUploadDataAmount" xml:space="preserve">
|
||||
<value>Total upload traffic</value>
|
||||
<value>کل ترافیک آپلود</value>
|
||||
</data>
|
||||
<data name="LvTransportProtocol" xml:space="preserve">
|
||||
<value>Transport</value>
|
||||
<value>جابجایی</value>
|
||||
</data>
|
||||
<data name="MediumFresh" xml:space="preserve">
|
||||
<value>Medium</value>
|
||||
<value>متوسط</value>
|
||||
</data>
|
||||
<data name="MsgClearSubscription" xml:space="preserve">
|
||||
<value>Clear original subscription content</value>
|
||||
<value>محتوای اشتراک اصلی را پاک کنید</value>
|
||||
</data>
|
||||
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
||||
<value>Download Core successfully</value>
|
||||
<value>دانلود Core با موفقیت</value>
|
||||
</data>
|
||||
<data name="MsgFailedImportSubscription" xml:space="preserve">
|
||||
<value>Failed to import subscription content</value>
|
||||
<value>محتوای اشتراک وارد نشد</value>
|
||||
</data>
|
||||
<data name="MsgGetSubscriptionSuccessfully" xml:space="preserve">
|
||||
<value>Get subscription content successfully</value>
|
||||
<value>محتوای اشتراک با موفقیت دریافت شد</value>
|
||||
</data>
|
||||
<data name="MsgNoValidSubscription" xml:space="preserve">
|
||||
<value>No valid subscriptions set</value>
|
||||
<value>هیچ اشتراک معتبری تنظیم نشده است</value>
|
||||
</data>
|
||||
<data name="MsgPACUpdateFailed" xml:space="preserve">
|
||||
<value>PAC update failed</value>
|
||||
<value>به روز رسانی PAC ناموفق بود</value>
|
||||
</data>
|
||||
<data name="MsgPACUpdateSuccessfully" xml:space="preserve">
|
||||
<value>PAC update succeeded</value>
|
||||
<value>به روز رسانی PAC با موفقیت انجام شد</value>
|
||||
</data>
|
||||
<data name="MsgParsingSuccessfully" xml:space="preserve">
|
||||
<value>Resolve {0} successfully</value>
|
||||
@@ -259,31 +259,31 @@
|
||||
<value>Simplify PAC Success</value>
|
||||
</data>
|
||||
<data name="MsgStartGettingSubscriptions" xml:space="preserve">
|
||||
<value>Start getting subscriptions</value>
|
||||
<value>شروع به دریافت اشتراک شد</value>
|
||||
</data>
|
||||
<data name="MsgStartUpdating" xml:space="preserve">
|
||||
<value>Start updating {0}...</value>
|
||||
<value>شروع بروزرسانی {0}...</value>
|
||||
</data>
|
||||
<data name="MsgStartUpdatingPAC" xml:space="preserve">
|
||||
<value>Start updating PAC...</value>
|
||||
<value>شروع بروزرسانی PAC...</value>
|
||||
</data>
|
||||
<data name="MsgSubscriptionDecodingFailed" xml:space="preserve">
|
||||
<value>Invalid subscription content</value>
|
||||
<value>محتوای اشتراک نامعتبر است</value>
|
||||
</data>
|
||||
<data name="MsgUnpacking" xml:space="preserve">
|
||||
<value>is unpacking...</value>
|
||||
<value>در حال باز کردن بسته می باشد ...</value>
|
||||
</data>
|
||||
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
|
||||
<value>Update subscription end</value>
|
||||
<value>بروزرسانی اشتراک به پایان رسید</value>
|
||||
</data>
|
||||
<data name="MsgUpdateSubscriptionStart" xml:space="preserve">
|
||||
<value>Update subscription starts</value>
|
||||
<value>بروزرسانی اشتراک شروع شد</value>
|
||||
</data>
|
||||
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
|
||||
<value>Update Core successfully</value>
|
||||
<value>هسته با موفقیت بروزرسانی شد</value>
|
||||
</data>
|
||||
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
|
||||
<value>Update Core successfully! Restarting service...</value>
|
||||
<value>هسته با موفقیت بروزرسانی شد! راه اندازی مجدد سرویس...</value>
|
||||
</data>
|
||||
<data name="NeedHttpGlobalProxy" xml:space="preserve">
|
||||
<value> This feature relies on the Http global proxy, please set it correctly first.</value>
|
||||
@@ -301,28 +301,28 @@
|
||||
<value>Scan completed, no valid QR code found</value>
|
||||
</data>
|
||||
<data name="OperationFailed" xml:space="preserve">
|
||||
<value> operation failed, please check and retry</value>
|
||||
<value> عملیات انجام نشد، لطفا بررسی کنید و دوباره امتحان کنید</value>
|
||||
</data>
|
||||
<data name="PleaseFillRemarks" xml:space="preserve">
|
||||
<value>Please Fill Remarks</value>
|
||||
</data>
|
||||
<data name="PleaseSelectEncryption" xml:space="preserve">
|
||||
<value>Please select the encryption method</value>
|
||||
<value>لطفاً روش رمزگذاری را انتخاب کنید</value>
|
||||
</data>
|
||||
<data name="PleaseSelectProtocol" xml:space="preserve">
|
||||
<value>Please select a protocol</value>
|
||||
<value>لطفا یک پروتکل انتخاب کنید</value>
|
||||
</data>
|
||||
<data name="PleaseSelectServer" xml:space="preserve">
|
||||
<value>Please select the server first</value>
|
||||
<value>لطفا ابتدا سرور را انتخاب کنید</value>
|
||||
</data>
|
||||
<data name="QuickFresh" xml:space="preserve">
|
||||
<value>Fast</value>
|
||||
<value>سریع</value>
|
||||
</data>
|
||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||
<value>Servers deduplication completed. Old: {0}, New: {1}.</value>
|
||||
</data>
|
||||
<data name="RemoveServer" xml:space="preserve">
|
||||
<value>Are you sure to remove the server?</value>
|
||||
<value>آیا مطمئن هستید که سرور را حذف می کنید؟</value>
|
||||
</data>
|
||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||
<value>The client configuration file is saved at: {0}</value>
|
||||
@@ -331,44 +331,44 @@
|
||||
<value>The server configuration file is saved at: {0}</value>
|
||||
</data>
|
||||
<data name="SlowFresh" xml:space="preserve">
|
||||
<value>Slow</value>
|
||||
<value>آهسته. تدریجی</value>
|
||||
</data>
|
||||
<data name="SpeedServerTips" xml:space="preserve">
|
||||
<value>Note: This feature relies on the Http global proxy. Please manually adjust the Http global proxy and active node after testing.</value>
|
||||
<value>توجه: این ویژگی به پروکسی جهانی Http متکی است. لطفاً پس از آزمایش، پراکسی جهانی Http و گره فعال را به صورت دستی تنظیم کنید.</value>
|
||||
</data>
|
||||
<data name="StartPacFailed" xml:space="preserve">
|
||||
<value>PAC failed to start. Please run this program as Administrator.</value>
|
||||
<value>PAC شروع نشد. لطفا این برنامه را به عنوان Administrator اجرا کنید.</value>
|
||||
</data>
|
||||
<data name="StartService" xml:space="preserve">
|
||||
<value>Start service ({0})...</value>
|
||||
</data>
|
||||
<data name="SuccessfulConfiguration" xml:space="preserve">
|
||||
<value>Configuration successful
|
||||
<value>پیکربندی با موفقیت انجام شد
|
||||
{0}</value>
|
||||
</data>
|
||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||
<value>Custom configuration server imported successfully.</value>
|
||||
<value>سرور پیکربندی سفارشی با موفقیت وارد شد.</value>
|
||||
</data>
|
||||
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
||||
<value>{0} servers have been imported from clipboard.</value>
|
||||
<value>{0} سرورها از کلیپ بورد وارد شده اند.</value>
|
||||
</data>
|
||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||
<value>Scan import URL successfully</value>
|
||||
<value>اسکن URL وارد کردن با موفقیت</value>
|
||||
</data>
|
||||
<data name="TestMeOutput" xml:space="preserve">
|
||||
<value>The ping of current service: {0} ms</value>
|
||||
<value>پینگ سرویس فعلی: {0} ms</value>
|
||||
</data>
|
||||
<data name="OperationSuccess" xml:space="preserve">
|
||||
<value>Operation success</value>
|
||||
<value>موفقیت عملیات</value>
|
||||
</data>
|
||||
<data name="PleaseSelectRules" xml:space="preserve">
|
||||
<value>Please select rules</value>
|
||||
<value>لطفا قوانین را انتخاب کنید</value>
|
||||
</data>
|
||||
<data name="RemoveRules" xml:space="preserve">
|
||||
<value>Are you sure to remove the rules?</value>
|
||||
<value>آیا مطمئن هستید که قوانین را حذف می کنید؟</value>
|
||||
</data>
|
||||
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
|
||||
<value>{0},One of the required.</value>
|
||||
<value>{0},یکی از مورد نیاز.</value>
|
||||
</data>
|
||||
<data name="LvRemarks" xml:space="preserve">
|
||||
<value>Remarks</value>
|
||||
@@ -386,16 +386,16 @@
|
||||
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value>
|
||||
</data>
|
||||
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
||||
<value>Download GeoFile: {0} successfully</value>
|
||||
<value>دانلود GeoFile: {0} با موفقیت</value>
|
||||
</data>
|
||||
<data name="MsgInformationTitle" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
<value>اطلاعات</value>
|
||||
</data>
|
||||
<data name="LvCustomIcon" xml:space="preserve">
|
||||
<value>Custom Icon</value>
|
||||
<value>نماد سفارشی</value>
|
||||
</data>
|
||||
<data name="FillCorrectDNSText" xml:space="preserve">
|
||||
<value>Please fill in the correct custom DNS</value>
|
||||
<value>لطفاً DNS سفارشی صحیح را پر کنید</value>
|
||||
</data>
|
||||
<data name="TransportPathTip1" xml:space="preserve">
|
||||
<value>*ws path</value>
|
||||
@@ -446,34 +446,34 @@
|
||||
<value>Global hotkey {0} registered successfully</value>
|
||||
</data>
|
||||
<data name="UngroupedServers" xml:space="preserve">
|
||||
<value>Ungrouped</value>
|
||||
<value>گروه بندی نشده</value>
|
||||
</data>
|
||||
<data name="AllGroupServers" xml:space="preserve">
|
||||
<value>All servers</value>
|
||||
<value>همه سرورها</value>
|
||||
</data>
|
||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||
<value>Please browse to import server configuration</value>
|
||||
</data>
|
||||
<data name="SystemProxy" xml:space="preserve">
|
||||
<value>System proxy</value>
|
||||
<value>پروکسی سیستم</value>
|
||||
</data>
|
||||
<data name="Speedtesting" xml:space="preserve">
|
||||
<value>Testing...</value>
|
||||
<value>درحال تست کردن...</value>
|
||||
</data>
|
||||
<data name="TooManyServersTip" xml:space="preserve">
|
||||
<value>Too many servers, please open the main interface</value>
|
||||
<value>تعداد سرورها خیلی زیاد است، لطفا رابط اصلی را باز کنید</value>
|
||||
</data>
|
||||
<data name="LabLAN" xml:space="preserve">
|
||||
<value>LAN</value>
|
||||
</data>
|
||||
<data name="LabLocal" xml:space="preserve">
|
||||
<value>Local</value>
|
||||
<value>محلی</value>
|
||||
</data>
|
||||
<data name="MsgServerTitle" xml:space="preserve">
|
||||
<value>Servers Filter</value>
|
||||
<value>فیلتر سرورها</value>
|
||||
</data>
|
||||
<data name="NetFrameworkRequirementsTip" xml:space="preserve">
|
||||
<value>Normal use of this version requires .NET Framework 4.8</value>
|
||||
<value>استفاده معمولی از این نسخه به .NET Framework 4.8 نیاز دارد</value>
|
||||
</data>
|
||||
<data name="menuCheckUpdate" xml:space="preserve">
|
||||
<value>بررسی بروزرسانی</value>
|
||||
@@ -491,10 +491,10 @@
|
||||
<value>کمک</value>
|
||||
</data>
|
||||
<data name="menuOptionSetting" xml:space="preserve">
|
||||
<value>تنظیمات گزینه</value>
|
||||
<value>تنظیمات پارامتر</value>
|
||||
</data>
|
||||
<data name="menuPromotion" xml:space="preserve">
|
||||
<value>Promotion</value>
|
||||
<value>ترفیع</value>
|
||||
</data>
|
||||
<data name="menuReload" xml:space="preserve">
|
||||
<value>بارگذاری مجدد</value>
|
||||
@@ -524,7 +524,7 @@
|
||||
<value>اشتراک را بدون پروکسی به روز شود</value>
|
||||
</data>
|
||||
<data name="menuSubUpdateViaProxy" xml:space="preserve">
|
||||
<value>Update subscription with proxy</value>
|
||||
<value>اشتراک را با پروکسی به روز شود</value>
|
||||
</data>
|
||||
<data name="menuSystemproxy" xml:space="preserve">
|
||||
<value>پروکسی سیستم</value>
|
||||
@@ -536,7 +536,7 @@
|
||||
<value>پروکسی سیستم تغییر نکند</value>
|
||||
</data>
|
||||
<data name="menuSystemProxyPac" xml:space="preserve">
|
||||
<value>Pac Mode</value>
|
||||
<value>حالت Pac</value>
|
||||
</data>
|
||||
<data name="menuSystemProxySet" xml:space="preserve">
|
||||
<value>تنظیم پراکسی سیستم</value>
|
||||
@@ -551,91 +551,91 @@
|
||||
<value>زبان</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||
<value>Import bulk URL from clipboard (Ctrl+V)</value>
|
||||
<value>وارد کردن URL انبوه از کلیپ بورد (Ctrl+V)</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaScan" xml:space="preserve">
|
||||
<value>Scan QR code on the screen (Ctrl+S)</value>
|
||||
<value>اسکن کد QR روی صفحه (Ctrl+S)</value>
|
||||
</data>
|
||||
<data name="menuCopyServer" xml:space="preserve">
|
||||
<value>Clone selected server</value>
|
||||
<value>سرور انتخاب شده را شبیه سازی کنید</value>
|
||||
</data>
|
||||
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
||||
<value>Remove duplicate servers</value>
|
||||
<value>سرورهای تکراری را حذف کنید</value>
|
||||
</data>
|
||||
<data name="menuRemoveServer" xml:space="preserve">
|
||||
<value>Remove selected servers (Delete)</value>
|
||||
<value>حذف سرورهای انتخابی (Delete)</value>
|
||||
</data>
|
||||
<data name="menuSetDefaultServer" xml:space="preserve">
|
||||
<value>Set as active server (Enter)</value>
|
||||
<value>به عنوان سرور فعال تنظیم کنید (Enter)</value>
|
||||
</data>
|
||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||
<value>Clear all service statistics</value>
|
||||
<value>تمام آمار خدمات را پاک کنید</value>
|
||||
</data>
|
||||
<data name="menuPingServer" xml:space="preserve">
|
||||
<value>Test servers ping (Ctrl+P)</value>
|
||||
<value>تست پینگ سرورها (Ctrl+P)</value>
|
||||
</data>
|
||||
<data name="menuRealPingServer" xml:space="preserve">
|
||||
<value>Test servers real delay (Ctrl+R)</value>
|
||||
<value>آزمایش سرورها با تاخیر واقعی (Ctrl+R)</value>
|
||||
</data>
|
||||
<data name="menuSortServerResult" xml:space="preserve">
|
||||
<value>Sort by test result</value>
|
||||
<value>مرتب سازی بر اساس نتیجه تست</value>
|
||||
</data>
|
||||
<data name="menuSpeedServer" xml:space="preserve">
|
||||
<value>Test servers download speed (Ctrl+T)</value>
|
||||
<value>تست سرعت دانلود سرورها (Ctrl+T)</value>
|
||||
</data>
|
||||
<data name="menuTcpingServer" xml:space="preserve">
|
||||
<value>Test servers with tcping (Ctrl+O)</value>
|
||||
<value>تست سرورها با tcping (Ctrl+O)</value>
|
||||
</data>
|
||||
<data name="menuTestMe" xml:space="preserve">
|
||||
<value>Test current service status</value>
|
||||
<value>وضعیت سرویس فعلی را تست کنید</value>
|
||||
</data>
|
||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
|
||||
</data>
|
||||
<data name="menuExport2ServerConfig" xml:space="preserve">
|
||||
<value>Export selected server for server configuration</value>
|
||||
<value>سرور انتخاب شده را برای پیکربندی سرور صادر کنید</value>
|
||||
</data>
|
||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||
<value>Export share URLs to clipboard (Ctrl+C)</value>
|
||||
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value>
|
||||
</data>
|
||||
<data name="menuExport2SubContent" xml:space="preserve">
|
||||
<value>Export subscription (base64) share to clipboard</value>
|
||||
<value>اشتراک (base64) را به کلیپ بورد صادر کنید</value>
|
||||
</data>
|
||||
<data name="menuAddCustomServer" xml:space="preserve">
|
||||
<value>یک سرور پیکربندی سفارشی اضافه شود</value>
|
||||
</data>
|
||||
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
||||
<value>Add [Shadowsocks] server</value>
|
||||
<value>سرور [شادوساکس] را اضافه کنید</value>
|
||||
</data>
|
||||
<data name="menuAddSocksServer" xml:space="preserve">
|
||||
<value>Add [Socks] server</value>
|
||||
<value>سرور [ساکس] را اضافه کنید</value>
|
||||
</data>
|
||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||
<value>Add [Trojan] server</value>
|
||||
<value>سرور [تروجان] را اضافه کنید</value>
|
||||
</data>
|
||||
<data name="menuAddVlessServer" xml:space="preserve">
|
||||
<value>Add [VLESS] server</value>
|
||||
<value>سرور [VLESS] را اضافه کنید</value>
|
||||
</data>
|
||||
<data name="menuAddVmessServer" xml:space="preserve">
|
||||
<value>Add [VMess] server</value>
|
||||
<value>سرور [VMess] را اضافه کنید</value>
|
||||
</data>
|
||||
<data name="menuSelectAll" xml:space="preserve">
|
||||
<value>Select All (Ctrl+A)</value>
|
||||
<value>انتخاب همه (Ctrl+A)</value>
|
||||
</data>
|
||||
<data name="menuMsgViewClear" xml:space="preserve">
|
||||
<value>Clear All</value>
|
||||
<value>همه را پاک کن</value>
|
||||
</data>
|
||||
<data name="menuMsgViewCopy" xml:space="preserve">
|
||||
<value>Copy (Ctrl+C)</value>
|
||||
<value>کپی (Ctrl+C)</value>
|
||||
</data>
|
||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||
<value>Copy All</value>
|
||||
<value>کپی همه</value>
|
||||
</data>
|
||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
||||
<value>Set message filters</value>
|
||||
<value>فیلترهای پیام را تنظیم کنید</value>
|
||||
</data>
|
||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||
<value>Select All (Ctrl+A)</value>
|
||||
<value>انتخاب همه (Ctrl+A)</value>
|
||||
</data>
|
||||
<data name="menuSubAdd" xml:space="preserve">
|
||||
<value>اضافه کردن</value>
|
||||
@@ -665,7 +665,7 @@
|
||||
<value>تایید</value>
|
||||
</data>
|
||||
<data name="GbTransport" xml:space="preserve">
|
||||
<value>Transport</value>
|
||||
<value>انتقال</value>
|
||||
</data>
|
||||
<data name="TbAddress" xml:space="preserve">
|
||||
<value>آدرس</value>
|
||||
@@ -689,7 +689,7 @@
|
||||
<value>UUID(id)</value>
|
||||
</data>
|
||||
<data name="TbNetwork" xml:space="preserve">
|
||||
<value>Transport protocol(network)</value>
|
||||
<value>پروتکل جابجایی (شبکه)</value>
|
||||
</data>
|
||||
<data name="TbPath" xml:space="preserve">
|
||||
<value>مسیر</value>
|
||||
@@ -716,10 +716,10 @@
|
||||
<value>*Default value tcp</value>
|
||||
</data>
|
||||
<data name="TbCoreType" xml:space="preserve">
|
||||
<value>Core Type</value>
|
||||
<value>نوع هسته</value>
|
||||
</data>
|
||||
<data name="TbFlow5" xml:space="preserve">
|
||||
<value>Flow</value>
|
||||
<value>جریان</value>
|
||||
</data>
|
||||
<data name="TbGUID" xml:space="preserve">
|
||||
<value>Generate</value>
|
||||
@@ -728,19 +728,19 @@
|
||||
<value>رمزعبور</value>
|
||||
</data>
|
||||
<data name="TbId4" xml:space="preserve">
|
||||
<value>Password(Optional)</value>
|
||||
<value>رمز عبور (اختیاری)</value>
|
||||
</data>
|
||||
<data name="TbId5" xml:space="preserve">
|
||||
<value>UUID(id)</value>
|
||||
</data>
|
||||
<data name="TbSecurity3" xml:space="preserve">
|
||||
<value>Encryption</value>
|
||||
<value>رمزگذاری</value>
|
||||
</data>
|
||||
<data name="TbSecurity4" xml:space="preserve">
|
||||
<value>User(Optional)</value>
|
||||
<value>کاربر (اختیاری)</value>
|
||||
</data>
|
||||
<data name="TbSecurity5" xml:space="preserve">
|
||||
<value>Encryption</value>
|
||||
<value>رمزگذاری</value>
|
||||
</data>
|
||||
<data name="TbPreSocksPort" xml:space="preserve">
|
||||
<value>txtPreSocksPort</value>
|
||||
@@ -755,46 +755,46 @@
|
||||
<value>ویرایش</value>
|
||||
</data>
|
||||
<data name="TbSettingsAdvancedProtocol" xml:space="preserve">
|
||||
<value>Advanced proxy settings, protocol selection (optional)</value>
|
||||
<value>تنظیمات پیشرفته پروکسی، انتخاب پروتکل (اختیاری)</value>
|
||||
</data>
|
||||
<data name="TbSettingsAllowLAN" xml:space="preserve">
|
||||
<value>Allow connections from the LAN</value>
|
||||
<value>اتصالات از LAN را مجاز کنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
|
||||
<value>Auto hide startup</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoTest" xml:space="preserve">
|
||||
<value>Automatic latency test interval (minutes)</value>
|
||||
<value>فاصله تست تأخیر خودکار (دقیقه)</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoUpdate" xml:space="preserve">
|
||||
<value>Automatic update interval of subscriptions (hours)</value>
|
||||
<value>فاصله به روز رسانی خودکار اشتراک ها (ساعت)</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
||||
<value>Automatic update interval of and Geo (hours)</value>
|
||||
<value>فاصله به روز رسانی خودکار و Geo (ساعت)</value>
|
||||
</data>
|
||||
<data name="TbSettingsCore" xml:space="preserve">
|
||||
<value>Core: basic settings</value>
|
||||
<value>هسته: تنظیمات اولیه</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreDns" xml:space="preserve">
|
||||
<value>Core: DNS settings</value>
|
||||
<value>هسته: تنظیمات DNS</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||
<value>Core: KCP settings</value>
|
||||
<value>هسته: تنظیمات KCP</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreType" xml:space="preserve">
|
||||
<value>CoreType settings</value>
|
||||
<value>تنظیمات CoreType</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefAllowInsecure" xml:space="preserve">
|
||||
<value>AllowInsecure</value>
|
||||
<value>اجازه ناامن</value>
|
||||
</data>
|
||||
<data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve">
|
||||
<value>Outbound Freedom domainStrategy</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
||||
<value>Automatically adjust column width after updating subscription</value>
|
||||
<value>پس از بهروزرسانی اشتراک، عرض ستون را به صورت خودکار تنظیم شود</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
|
||||
<value>Check for pre-release updates</value>
|
||||
<value>به روز رسانی های پیش از انتشار را بررسی شود</value>
|
||||
</data>
|
||||
<data name="TbSettingsException" xml:space="preserve">
|
||||
<value>استثنا</value>
|
||||
@@ -803,37 +803,37 @@
|
||||
<value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value>
|
||||
</data>
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>Http Port</value>
|
||||
<value>پورت Http</value>
|
||||
</data>
|
||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||
<value>Ignore Geo files when updating core</value>
|
||||
<value>هنگام بهروزرسانی هسته، فایلهای Geo را نادیده بگیرید</value>
|
||||
</data>
|
||||
<data name="TbSettingsIpv6" xml:space="preserve">
|
||||
<value>Enable IPv6</value>
|
||||
<value>IPv6 را فعال کنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>Keep older when deduplication</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogEnabled" xml:space="preserve">
|
||||
<value>Record local logs</value>
|
||||
<value>ثبت گزارش های محلی</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogLevel" xml:space="preserve">
|
||||
<value>Log Level</value>
|
||||
<value>سطح ثبت رویداد</value>
|
||||
</data>
|
||||
<data name="TbSettingsMuxEnabled" xml:space="preserve">
|
||||
<value>Turn on Mux Multiplexing</value>
|
||||
</data>
|
||||
<data name="TbSettingsN" xml:space="preserve">
|
||||
<value>v2rayN settings</value>
|
||||
<value>تنظیمات v2rayN</value>
|
||||
</data>
|
||||
<data name="TbSettingsPacListenPort" xml:space="preserve">
|
||||
<value>Pac listen port</value>
|
||||
<value>Pac پورت درحال شنود</value>
|
||||
</data>
|
||||
<data name="TbSettingsPass" xml:space="preserve">
|
||||
<value>Auth pass</value>
|
||||
</data>
|
||||
<data name="TbSettingsRemoteDNS" xml:space="preserve">
|
||||
<value>Custom DNS (multiple, separated by commas (,))</value>
|
||||
<value>سفارشی DNS (multiple, separated by commas (,))</value>
|
||||
</data>
|
||||
<data name="TbSettingsSaveTip" xml:space="preserve">
|
||||
<value>After modifying the following parameters, click Save to take effect</value>
|
||||
@@ -845,22 +845,22 @@
|
||||
<value>Turn on Sniffing</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||
<value>Socks Port</value>
|
||||
<value>ساکس Port</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||
<value>Start on boot</value>
|
||||
<value>درهنگام راه ائدازی شروع شود</value>
|
||||
</data>
|
||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||
<value>Enable Statistics (Require restart)</value>
|
||||
<value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value>
|
||||
</data>
|
||||
<data name="TbSettingsStatisticsFreshRate" xml:space="preserve">
|
||||
<value>Statistics freshrate (second)</value>
|
||||
<value>نرخ تازه سازی آمار (ثانیه)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||
<value>Subscription conversion Url</value>
|
||||
</data>
|
||||
<data name="TbSettingsSystemproxy" xml:space="preserve">
|
||||
<value>System proxy settings</value>
|
||||
<value>تنظیمات پراکسی سیستم</value>
|
||||
</data>
|
||||
<data name="TbSettingsTLS13" xml:space="preserve">
|
||||
<value>Enable Security Protocol TLS v1.3 (subscription/update)</value>
|
||||
@@ -875,19 +875,19 @@
|
||||
<value>Auth user</value>
|
||||
</data>
|
||||
<data name="TbClearSystemProxy" xml:space="preserve">
|
||||
<value>Clear system proxy</value>
|
||||
<value>پاک کردن پروکسی سیستم</value>
|
||||
</data>
|
||||
<data name="TbDisplayGUI" xml:space="preserve">
|
||||
<value>Display GUI</value>
|
||||
<value>نمایش رابط کاربری گرافیکی</value>
|
||||
</data>
|
||||
<data name="TbGlobalHotkeySetting" xml:space="preserve">
|
||||
<value>GlobalHotkey Setting</value>
|
||||
<value>تنظیم کلید میانبر جهانی</value>
|
||||
</data>
|
||||
<data name="TbGlobalHotkeySettingTip" xml:space="preserve">
|
||||
<value>Set directly by pressing the keyboard, Take effect after restart</value>
|
||||
<value>مستقیماً با فشار دادن صفحه کلید تنظیم کنید، بعد از راه اندازی مجدد اعمال شود</value>
|
||||
</data>
|
||||
<data name="TbNotChangeSystemProxy" xml:space="preserve">
|
||||
<value>Do not change system proxy</value>
|
||||
<value>پروکسی سیستم را تغییر ندهید</value>
|
||||
</data>
|
||||
<data name="TbReset" xml:space="preserve">
|
||||
<value>بازنشانی</value>
|
||||
@@ -896,10 +896,10 @@
|
||||
<value>تنظیم پراکسی سیستم</value>
|
||||
</data>
|
||||
<data name="TbSystemProxyPac" xml:space="preserve">
|
||||
<value>Pac Mode</value>
|
||||
<value>حالت Pac</value>
|
||||
</data>
|
||||
<data name="menuShareServer" xml:space="preserve">
|
||||
<value>Share Server (Ctrl+D)</value>
|
||||
<value>اشتراک گذاری سرور(Ctrl+F)</value>
|
||||
</data>
|
||||
<data name="menuRouting" xml:space="preserve">
|
||||
<value>مسیریابی</value>
|
||||
@@ -911,10 +911,10 @@
|
||||
<value>اجرا به عنوان ادمین</value>
|
||||
</data>
|
||||
<data name="menuMoveBottom" xml:space="preserve">
|
||||
<value>Move to bottom (B)</value>
|
||||
<value>به پایین حرکت شود(B)</value>
|
||||
</data>
|
||||
<data name="menuMoveDown" xml:space="preserve">
|
||||
<value>Down (D)</value>
|
||||
<value>پایین (D)</value>
|
||||
</data>
|
||||
<data name="menuMoveTop" xml:space="preserve">
|
||||
<value>Move to top (T)</value>
|
||||
@@ -929,31 +929,31 @@
|
||||
<value>{0} Website</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
||||
<value>Advanced Function</value>
|
||||
<value>عملکرد پیشرفته</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
|
||||
<value>اضافه کردن</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedImportRules" xml:space="preserve">
|
||||
<value>Import Advanced Rules</value>
|
||||
<value>وارد کردن قوانین پیشرفته</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
||||
<value>Remove selected</value>
|
||||
<value>حذف انتخاب شده</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
|
||||
<value>Set as active rule</value>
|
||||
</data>
|
||||
<data name="menuRoutingBasic" xml:space="preserve">
|
||||
<value>Basic Function</value>
|
||||
<value>عملکرد پایه</value>
|
||||
</data>
|
||||
<data name="menuRoutingBasicImportRules" xml:space="preserve">
|
||||
<value>Import Basic Rules</value>
|
||||
<value>واردات قوانین اساسی</value>
|
||||
</data>
|
||||
<data name="TbdomainMatcher" xml:space="preserve">
|
||||
<value>Domain Matcher</value>
|
||||
<value>تطبیق دامنه</value>
|
||||
</data>
|
||||
<data name="TbdomainStrategy" xml:space="preserve">
|
||||
<value>Domain strategy</value>
|
||||
<value>استراتژی دامنه</value>
|
||||
</data>
|
||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||
<value>فعال کردن عملکرد پیشرفته</value>
|
||||
@@ -968,58 +968,58 @@
|
||||
<value>1.Proxy Domain or IP</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||
<value>Pre-defined Rule Set List</value>
|
||||
<value>لیست مجموعه قوانین از پیش تعریف شده</value>
|
||||
</data>
|
||||
<data name="TbRoutingTips" xml:space="preserve">
|
||||
<value>*Set the rules, separated by commas (,); The comma in the regular is replaced by <COMMA></value>
|
||||
</data>
|
||||
<data name="menuImportRulesFromClipboard" xml:space="preserve">
|
||||
<value>Import Rules From Clipboard</value>
|
||||
<value>وارد کردن قوانین از کلیپ بورد</value>
|
||||
</data>
|
||||
<data name="menuImportRulesFromFile" xml:space="preserve">
|
||||
<value>Import Rules From File</value>
|
||||
<value>وارد کردن قوانین از فایل</value>
|
||||
</data>
|
||||
<data name="menuImportRulesFromUrl" xml:space="preserve">
|
||||
<value>Import Rules From Sub Url</value>
|
||||
<value>وارد کردن قوانین از Sub Url</value>
|
||||
</data>
|
||||
<data name="menuRoutingRuleSetting" xml:space="preserve">
|
||||
<value>تنظیم قانون</value>
|
||||
</data>
|
||||
<data name="menuRuleAdd" xml:space="preserve">
|
||||
<value>Rule Add</value>
|
||||
<value>اضافه کردن قانون</value>
|
||||
</data>
|
||||
<data name="menuRuleExportSelected" xml:space="preserve">
|
||||
<value>Export Selected Rules</value>
|
||||
<value>صادر کردن قوانین انتخاب شده</value>
|
||||
</data>
|
||||
<data name="menuRuleList" xml:space="preserve">
|
||||
<value>Rule List</value>
|
||||
<value>فهرست قوانین</value>
|
||||
</data>
|
||||
<data name="menuRuleRemove" xml:space="preserve">
|
||||
<value>Remove Rules</value>
|
||||
<value>حذف قوانین</value>
|
||||
</data>
|
||||
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
||||
<value>RoutingRuleDetailsSetting</value>
|
||||
<value>تنظیم جزئیات قانون مسیریابی</value>
|
||||
</data>
|
||||
<data name="TbAutoSort" xml:space="preserve">
|
||||
<value>Domain and ip are auto sorted when saving</value>
|
||||
<value>دامنه و آی پی در هنگام ذخیره به طور خودکار مرتب می شوند</value>
|
||||
</data>
|
||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||
<value>Ruleobject Doc</value>
|
||||
</data>
|
||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||
<value>Support DnsObject</value>
|
||||
<value>پشتیبانی از DnsObject</value>
|
||||
</data>
|
||||
<data name="SubUrlTips" xml:space="preserve">
|
||||
<value>Group please leave blank here</value>
|
||||
<value>گروه لطفا اینجا را خالی بگذارید</value>
|
||||
</data>
|
||||
<data name="TipChangeRouting" xml:space="preserve">
|
||||
<value>Routing setting is changed</value>
|
||||
<value>تنظیمات مسیریابی تغییر کرده است</value>
|
||||
</data>
|
||||
<data name="TipChangeSystemProxy" xml:space="preserve">
|
||||
<value>System proxy setting is changed</value>
|
||||
<value>تنظیمات پراکسی سیستم تغییر کرده است</value>
|
||||
</data>
|
||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||
<value>RouteOnly</value>
|
||||
<value>فقط مسیر</value>
|
||||
</data>
|
||||
<data name="menuMixedTestServer" xml:space="preserve">
|
||||
<value>One-click test Latency and speed (Ctrl+E)</value>
|
||||
@@ -1031,25 +1031,25 @@
|
||||
<value>Speed(M/s)</value>
|
||||
</data>
|
||||
<data name="FailedToRunCore" xml:space="preserve">
|
||||
<value>Failed to run Core, please see the log</value>
|
||||
<value>Core اجرا نشد، لطفاً گزارش را ببینید</value>
|
||||
</data>
|
||||
<data name="LvFilter" xml:space="preserve">
|
||||
<value>Remarks regular filter</value>
|
||||
</data>
|
||||
<data name="TbDisplayLog" xml:space="preserve">
|
||||
<value>Display Log</value>
|
||||
<value>نمایش گزارش</value>
|
||||
</data>
|
||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||
<value>Import old config guiNConfig</value>
|
||||
<value>پیکربندی قدیمی guiNConfig را وارد شود</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>Enable Tun</value>
|
||||
<value>Tun را فعال شود</value>
|
||||
</data>
|
||||
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
||||
<value>New Port for LAN</value>
|
||||
<value>پورت جدید برای LAN</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||
<value>TunMode settings</value>
|
||||
<value>تنظیمات TunMode</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
||||
<value>Direct IP CIDR, separated by commas (,)</value>
|
||||
@@ -1060,4 +1060,10 @@
|
||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
||||
<value>نمایش کنسول</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
||||
<value>User-Agent</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefUserAgentTips" xml:space="preserve">
|
||||
<value>This parameter is valid only for tcp/http and ws</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -419,7 +419,7 @@
|
||||
<value>*h2 host Separated by commas (,)</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip4" xml:space="preserve">
|
||||
<value>*QUIC securty</value>
|
||||
<value>*QUIC security</value>
|
||||
</data>
|
||||
<data name="TransportHeaderTypeTip1" xml:space="preserve">
|
||||
<value>*tcp camouflage type</value>
|
||||
@@ -449,7 +449,7 @@
|
||||
<value>Ungrouped</value>
|
||||
</data>
|
||||
<data name="AllGroupServers" xml:space="preserve">
|
||||
<value>All servers</value>
|
||||
<value>All</value>
|
||||
</data>
|
||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||
<value>Please browse to import server configuration</value>
|
||||
@@ -548,7 +548,7 @@
|
||||
<value>Dark Mode</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>Language</value>
|
||||
<value>Language(Restart)</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||
<value>Import bulk URL from clipboard (Ctrl+V)</value>
|
||||
@@ -815,7 +815,7 @@
|
||||
<value>Keep older when deduplication</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogEnabled" xml:space="preserve">
|
||||
<value>Record local logs</value>
|
||||
<value>Enable Log</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogLevel" xml:space="preserve">
|
||||
<value>Log Level</value>
|
||||
@@ -899,7 +899,7 @@
|
||||
<value>Pac Mode</value>
|
||||
</data>
|
||||
<data name="menuShareServer" xml:space="preserve">
|
||||
<value>Share Server (Ctrl+D)</value>
|
||||
<value>Share Server (Ctrl+F)</value>
|
||||
</data>
|
||||
<data name="menuRouting" xml:space="preserve">
|
||||
<value>Routing</value>
|
||||
@@ -1022,7 +1022,7 @@
|
||||
<value>RouteOnly</value>
|
||||
</data>
|
||||
<data name="menuMixedTestServer" xml:space="preserve">
|
||||
<value>One-click test Latency and speed (Ctrl+E)</value>
|
||||
<value>One-click multi test Latency and speed (Ctrl+E)</value>
|
||||
</data>
|
||||
<data name="LvTestDelay" xml:space="preserve">
|
||||
<value>Delay(ms)</value>
|
||||
@@ -1060,4 +1060,70 @@
|
||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
||||
<value>Show console</value>
|
||||
</data>
|
||||
<data name="menuMoveToGroup" xml:space="preserve">
|
||||
<value>Move to group</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
||||
<value>Custom Template</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||
<value>Enable Server Drag Drop Sort(Require restart)</value>
|
||||
</data>
|
||||
<data name="TbAutoRefresh" xml:space="preserve">
|
||||
<value>AutoRefresh</value>
|
||||
</data>
|
||||
<data name="SpeedtestingSkip" xml:space="preserve">
|
||||
<value>Skip test</value>
|
||||
</data>
|
||||
<data name="menuEditServer" xml:space="preserve">
|
||||
<value>Edit Server (Ctrl+D)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
||||
<value>Double-click server make active</value>
|
||||
</data>
|
||||
<data name="SpeedtestingCompleted" xml:space="preserve">
|
||||
<value>Test completed</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefFingerprint" xml:space="preserve">
|
||||
<value>Default TLS fingerprint</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
||||
<value>User-Agent</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefUserAgentTips" xml:space="preserve">
|
||||
<value>This parameter is valid only for tcp/http and ws</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
||||
<value>FontFamily(Require restart)</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||
<value>Copy the font TTF file to the directory guiFonts, restart the settings</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||
<value>http port=socks port+1</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||
<value>Set this with admin privileges, get admin privileges after startup</value>
|
||||
</data>
|
||||
<data name="TbSettingsFontSize" xml:space="preserve">
|
||||
<value>FontSize</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
||||
<value>Proxy IP CIDR, separated by commas (,)</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
|
||||
<value>Proxy Process name, separated by commas (,)</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
||||
<value>Bypass Mode</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
|
||||
<value>Enable: If no route matches, the final proxy</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||
<value>SpeedTest Single Timeout Value</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||
<value>SpeedTest Url</value>
|
||||
</data>
|
||||
</root>
|
||||
1111
v2rayN/v2rayN/Resx/ResUI.ru.resx
Normal file
1111
v2rayN/v2rayN/Resx/ResUI.ru.resx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -130,7 +130,7 @@
|
||||
<value>配置格式不正确</value>
|
||||
</data>
|
||||
<data name="CustomServerTips" xml:space="preserve">
|
||||
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手工修改监听端口。</value>
|
||||
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手动修改监听端口。</value>
|
||||
</data>
|
||||
<data name="Downloading" xml:space="preserve">
|
||||
<value>下载开始...</value>
|
||||
@@ -148,7 +148,7 @@
|
||||
<value>生成默认配置文件失败</value>
|
||||
</data>
|
||||
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
||||
<value>取得默认配置失败</value>
|
||||
<value>获取默认配置失败</value>
|
||||
</data>
|
||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||
<value>导入自定义配置服务器失败</value>
|
||||
@@ -449,7 +449,7 @@
|
||||
<value>未分组服务器</value>
|
||||
</data>
|
||||
<data name="AllGroupServers" xml:space="preserve">
|
||||
<value>所有服务器</value>
|
||||
<value>所有</value>
|
||||
</data>
|
||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||
<value>请浏览导入服务器配置</value>
|
||||
@@ -548,7 +548,7 @@
|
||||
<value>暗黑模式</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>语言</value>
|
||||
<value>语言(重启)</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||
<value>从剪贴板导入批量URL (Ctrl+V)</value>
|
||||
@@ -815,7 +815,7 @@
|
||||
<value>去重时保留序号较小的项</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogEnabled" xml:space="preserve">
|
||||
<value>记录本地日志(默认关闭)</value>
|
||||
<value>启用日志(默认关闭)</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogLevel" xml:space="preserve">
|
||||
<value>日志等级</value>
|
||||
@@ -851,7 +851,7 @@
|
||||
<value>开机启动(可能会不成功)</value>
|
||||
</data>
|
||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||
<value>启用统计(实时网速显示,需要重启)</value>
|
||||
<value>启用统计(实时网速显示,需重启)</value>
|
||||
</data>
|
||||
<data name="TbSettingsStatisticsFreshRate" xml:space="preserve">
|
||||
<value>统计刷新频率(单位秒)</value>
|
||||
@@ -899,13 +899,13 @@
|
||||
<value>Pac模式</value>
|
||||
</data>
|
||||
<data name="menuShareServer" xml:space="preserve">
|
||||
<value>分享服务器 (Ctrl+D)</value>
|
||||
<value>分享服务器 (Ctrl+F)</value>
|
||||
</data>
|
||||
<data name="menuRouting" xml:space="preserve">
|
||||
<value>路由</value>
|
||||
</data>
|
||||
<data name="NotRunAsAdmin" xml:space="preserve">
|
||||
<value>非以管理员身份运行</value>
|
||||
<value>以非管理员身份运行</value>
|
||||
</data>
|
||||
<data name="RunAsAdmin" xml:space="preserve">
|
||||
<value>以管理员身份运行</value>
|
||||
@@ -1022,7 +1022,7 @@
|
||||
<value>RouteOnly</value>
|
||||
</data>
|
||||
<data name="menuMixedTestServer" xml:space="preserve">
|
||||
<value>一键测试延迟和速度 (Ctrl+E)</value>
|
||||
<value>一键多线程测试延迟和速度 (Ctrl+E)</value>
|
||||
</data>
|
||||
<data name="LvTestDelay" xml:space="preserve">
|
||||
<value>延迟(ms)</value>
|
||||
@@ -1060,4 +1060,70 @@
|
||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
||||
<value>显示控制台</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="menuMoveToGroup" xml:space="preserve">
|
||||
<value>移至订阅分组</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
||||
<value>自定义配置模板</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||
<value>启用服务器拖放排序(需重启)</value>
|
||||
</data>
|
||||
<data name="TbAutoRefresh" xml:space="preserve">
|
||||
<value>自动刷新</value>
|
||||
</data>
|
||||
<data name="SpeedtestingSkip" xml:space="preserve">
|
||||
<value>跳过测试</value>
|
||||
</data>
|
||||
<data name="menuEditServer" xml:space="preserve">
|
||||
<value>编辑服务器 (Ctrl+D)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
||||
<value>主界面双击设为活动服务器</value>
|
||||
</data>
|
||||
<data name="SpeedtestingCompleted" xml:space="preserve">
|
||||
<value>测试完成</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefFingerprint" xml:space="preserve">
|
||||
<value>默认TLS指纹(fingerprint)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
||||
<value>用户代理(User-Agent)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefUserAgentTips" xml:space="preserve">
|
||||
<value>仅对tcp/http、ws协议生效</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
||||
<value>当前字体(需重启)</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||
<value>拷贝字体TTF文件到目录guiFonts,重启设置</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||
<value>http端口=socks端口+1</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
||||
</data>
|
||||
<data name="TbSettingsFontSize" xml:space="preserve">
|
||||
<value>字体大小</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
||||
<value>代理的IP CIDR,用逗号(,)分隔</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
|
||||
<value>代理的进程名,用逗号(,)分隔</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
||||
<value>绕行模式</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
|
||||
<value>启用:路由无匹配则最终代理</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||
<value>测速单个超时值</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||
<value>测速文件地址</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":"1.1","method":"GET","path":[$requestPath$],"headers":{"Host":[$requestHost$],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}
|
||||
{"version":"1.1","method":"GET","path":[$requestPath$],"headers":{"Host":[$requestHost$],"User-Agent":[$requestUserAgent$],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}
|
||||
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": $log_disabled$,
|
||||
"level": "debug",
|
||||
$log_output$
|
||||
"timestamp": true
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "223.5.5.5",
|
||||
@@ -27,6 +29,7 @@
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"tag": "tun-in",
|
||||
"interface_name": "singbox_tun",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
|
||||
@@ -106,6 +109,9 @@
|
||||
}
|
||||
$ruleDirectIPs$
|
||||
$ruleDirectProcess$
|
||||
$ruleProxyIPs$
|
||||
$ruleProxyProcess$
|
||||
$ruleFinally$
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,7 @@ namespace v2rayN.Tool
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
|
||||
fs.Write(content, 0, content.Length);
|
||||
File.WriteAllBytes(fileName, content);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -25,20 +24,9 @@ namespace v2rayN.Tool
|
||||
{
|
||||
try
|
||||
{
|
||||
// Because the uncompressed size of the file is unknown,
|
||||
// we are using an arbitrary buffer size.
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
|
||||
using (FileStream fs = File.Create(fileName))
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(content),
|
||||
CompressionMode.Decompress, false))
|
||||
{
|
||||
while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
fs.Write(buffer, 0, n);
|
||||
}
|
||||
}
|
||||
using FileStream fs = File.Create(fileName);
|
||||
using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
|
||||
input.CopyTo(fs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -55,42 +43,38 @@ namespace v2rayN.Tool
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
using (StreamReader sr = new StreamReader(fs, encoding))
|
||||
{
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
using StreamReader sr = new(fs, encoding);
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
throw ex;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (ZipArchive archive = ZipFile.OpenRead(fileName))
|
||||
using ZipArchive archive = ZipFile.OpenRead(fileName);
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
if (entry.Length == 0)
|
||||
{
|
||||
if (entry.Length == 0)
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
}
|
||||
entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Utils.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ namespace v2rayN
|
||||
{
|
||||
handle = CreateJobObject(IntPtr.Zero, null);
|
||||
IntPtr extendedInfoPtr = IntPtr.Zero;
|
||||
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
|
||||
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
|
||||
{
|
||||
LimitFlags = 0x2000
|
||||
};
|
||||
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
|
||||
{
|
||||
BasicLimitInformation = info
|
||||
};
|
||||
@@ -100,7 +100,7 @@ namespace v2rayN
|
||||
#region Interop
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr CreateJobObject(IntPtr a, string lpName);
|
||||
private static extern IntPtr CreateJobObject(IntPtr a, string? lpName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace v2rayN.Tool
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
LoggingConfiguration config = new LoggingConfiguration();
|
||||
FileTarget fileTarget = new FileTarget();
|
||||
LoggingConfiguration config = new();
|
||||
FileTarget fileTarget = new();
|
||||
config.AddTarget("file", fileTarget);
|
||||
fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
|
||||
fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Win32.TaskScheduler;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
@@ -47,11 +48,10 @@ namespace v2rayN
|
||||
try
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
using (Stream stream = assembly.GetManifestResourceStream(res))
|
||||
using (StreamReader reader = new StreamReader(stream))
|
||||
{
|
||||
result = reader.ReadToEnd();
|
||||
}
|
||||
using Stream? stream = assembly.GetManifestResourceStream(res);
|
||||
ArgumentNullException.ThrowIfNull(stream);
|
||||
using StreamReader reader = new(stream);
|
||||
result = reader.ReadToEnd();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -71,10 +71,12 @@ namespace v2rayN
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(res))
|
||||
if (!File.Exists(res))
|
||||
{
|
||||
result = reader.ReadToEnd();
|
||||
return result;
|
||||
}
|
||||
using StreamReader reader = new(res);
|
||||
result = reader.ReadToEnd();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -89,7 +91,7 @@ namespace v2rayN
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="strJson"></param>
|
||||
/// <returns></returns>
|
||||
public static T FromJson<T>(string strJson)
|
||||
public static T? FromJson<T>(string strJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -97,8 +99,7 @@ namespace v2rayN
|
||||
{
|
||||
return default;
|
||||
}
|
||||
T obj = JsonConvert.DeserializeObject<T>(strJson);
|
||||
return obj;
|
||||
return JsonConvert.DeserializeObject<T>(strJson);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -111,7 +112,7 @@ namespace v2rayN
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToJson(Object obj, bool indented = true)
|
||||
public static string ToJson(object? obj, bool indented = true)
|
||||
{
|
||||
string result = string.Empty;
|
||||
try
|
||||
@@ -140,25 +141,23 @@ namespace v2rayN
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public static int ToJsonFile(Object obj, string filePath, bool nullValue = true)
|
||||
public static int ToJsonFile(object? obj, string filePath, bool nullValue = true)
|
||||
{
|
||||
int result;
|
||||
try
|
||||
{
|
||||
using (StreamWriter file = File.CreateText(filePath))
|
||||
using StreamWriter file = File.CreateText(filePath);
|
||||
JsonSerializer serializer;
|
||||
if (nullValue)
|
||||
{
|
||||
JsonSerializer serializer;
|
||||
if (nullValue)
|
||||
{
|
||||
serializer = new JsonSerializer() { Formatting = Formatting.Indented };
|
||||
}
|
||||
else
|
||||
{
|
||||
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
|
||||
}
|
||||
|
||||
serializer.Serialize(file, obj);
|
||||
serializer = new JsonSerializer() { Formatting = Formatting.Indented };
|
||||
}
|
||||
else
|
||||
{
|
||||
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
|
||||
}
|
||||
|
||||
serializer.Serialize(file, obj);
|
||||
result = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -169,7 +168,7 @@ namespace v2rayN
|
||||
return result;
|
||||
}
|
||||
|
||||
public static JObject ParseJson(string strJson)
|
||||
public static JObject? ParseJson(string strJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -201,7 +200,7 @@ namespace v2rayN
|
||||
}
|
||||
if (wrap)
|
||||
{
|
||||
return string.Join("," + Environment.NewLine, lst.ToArray());
|
||||
return string.Join("," + Environment.NewLine, lst);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -224,7 +223,7 @@ namespace v2rayN
|
||||
try
|
||||
{
|
||||
str = str.Replace(Environment.NewLine, "");
|
||||
return new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries));
|
||||
return new List<string>(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -243,8 +242,9 @@ namespace v2rayN
|
||||
try
|
||||
{
|
||||
str = str.Replace(Environment.NewLine, "");
|
||||
List<string> list = new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries));
|
||||
return list.OrderBy(x => x).ToList();
|
||||
List<string> list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
|
||||
list.Sort();
|
||||
return list;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -336,7 +336,7 @@ namespace v2rayN
|
||||
{
|
||||
try
|
||||
{
|
||||
return (obj == null ? string.Empty : obj.ToString());
|
||||
return obj?.ToString() ?? string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -413,10 +413,9 @@ namespace v2rayN
|
||||
|
||||
public static string GetMD5(string str)
|
||||
{
|
||||
var md5 = MD5.Create();
|
||||
byte[] byteOld = Encoding.UTF8.GetBytes(str);
|
||||
byte[] byteNew = md5.ComputeHash(byteOld);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte[] byteNew = MD5.HashData(byteOld);
|
||||
StringBuilder sb = new(32);
|
||||
foreach (byte b in byteNew)
|
||||
{
|
||||
sb.Append(b.ToString("x2"));
|
||||
@@ -439,7 +438,7 @@ namespace v2rayN
|
||||
}
|
||||
try
|
||||
{
|
||||
Uri uri = new Uri(url);
|
||||
Uri uri = new(url);
|
||||
if (uri.Host == uri.IdnHost)
|
||||
{
|
||||
return url;
|
||||
@@ -567,18 +566,14 @@ namespace v2rayN
|
||||
|
||||
public static bool IsIpv6(string ip)
|
||||
{
|
||||
IPAddress address;
|
||||
if (IPAddress.TryParse(ip, out address))
|
||||
if (IPAddress.TryParse(ip, out IPAddress? address))
|
||||
{
|
||||
switch (address.AddressFamily)
|
||||
return address.AddressFamily switch
|
||||
{
|
||||
case AddressFamily.InterNetwork:
|
||||
return false;
|
||||
case AddressFamily.InterNetworkV6:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
AddressFamily.InterNetwork => false,
|
||||
AddressFamily.InterNetworkV6 => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -601,17 +596,28 @@ namespace v2rayN
|
||||
|
||||
//delete first
|
||||
RegWriteValue(Global.AutoRunRegPath, autoRunName, "");
|
||||
if (IsAdministrator())
|
||||
{
|
||||
AutoStart(autoRunName, "", "");
|
||||
}
|
||||
|
||||
if (run)
|
||||
{
|
||||
string exePath = $"\"{GetExePath()}\"";
|
||||
RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath);
|
||||
if (IsAdministrator())
|
||||
{
|
||||
AutoStart(autoRunName, exePath, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -670,13 +676,13 @@ namespace v2rayN
|
||||
return Application.StartupPath;
|
||||
}
|
||||
|
||||
public static string RegReadValue(string path, string name, string def)
|
||||
public static string? RegReadValue(string path, string name, string def)
|
||||
{
|
||||
RegistryKey regKey = null;
|
||||
RegistryKey? regKey = null;
|
||||
try
|
||||
{
|
||||
regKey = Registry.CurrentUser.OpenSubKey(path, false);
|
||||
string value = regKey?.GetValue(name) as string;
|
||||
string? value = regKey?.GetValue(name) as string;
|
||||
if (IsNullOrEmpty(value))
|
||||
{
|
||||
return def;
|
||||
@@ -699,7 +705,7 @@ namespace v2rayN
|
||||
|
||||
public static void RegWriteValue(string path, string name, object value)
|
||||
{
|
||||
RegistryKey regKey = null;
|
||||
RegistryKey? regKey = null;
|
||||
try
|
||||
{
|
||||
regKey = Registry.CurrentUser.CreateSubKey(path);
|
||||
@@ -731,14 +737,55 @@ namespace v2rayN
|
||||
public static bool CheckForDotNetVersion(int release = 528040)
|
||||
{
|
||||
const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
|
||||
using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
|
||||
using RegistryKey? ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey);
|
||||
if (ndpKey != null && ndpKey.GetValue("Release") != null)
|
||||
{
|
||||
if (ndpKey != null && ndpKey.GetValue("Release") != null)
|
||||
{
|
||||
return (int)ndpKey.GetValue("Release") >= release ? true : false;
|
||||
}
|
||||
return false;
|
||||
return (int)ndpKey.GetValue("Release") >= release ? true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto Start via TaskService
|
||||
/// </summary>
|
||||
/// <param name="taskName"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="description"></param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public static void AutoStart(string taskName, string fileName, string description)
|
||||
{
|
||||
if (string.IsNullOrEmpty(taskName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
string TaskName = taskName;
|
||||
var logonUser = WindowsIdentity.GetCurrent().Name;
|
||||
string taskDescription = description;
|
||||
string deamonFileName = fileName;
|
||||
|
||||
using var taskService = new TaskService();
|
||||
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
|
||||
foreach (var t in tasks)
|
||||
{
|
||||
taskService.RootFolder.DeleteTask(t.Name);
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var task = taskService.NewTask();
|
||||
task.RegistrationInfo.Description = taskDescription;
|
||||
task.Settings.DisallowStartIfOnBatteries = false;
|
||||
task.Settings.StopIfGoingOnBatteries = false;
|
||||
task.Settings.RunOnlyIfIdle = false;
|
||||
task.Settings.IdleSettings.StopOnIdleEnd = false;
|
||||
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
||||
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromMinutes(1) });
|
||||
task.Principal.RunLevel = TaskRunLevel.Highest;
|
||||
task.Actions.Add(new ExecAction(deamonFileName));
|
||||
|
||||
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -847,16 +894,13 @@ namespace v2rayN
|
||||
public static T DeepCopy<T>(T obj)
|
||||
{
|
||||
object retval;
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
//序列化成流
|
||||
bf.Serialize(ms, obj);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
//反序列化成对象
|
||||
retval = bf.Deserialize(ms);
|
||||
ms.Close();
|
||||
}
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
//序列化成流
|
||||
bf.Serialize(ms, obj);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
//反序列化成对象
|
||||
retval = bf.Deserialize(ms);
|
||||
return (T)retval;
|
||||
}
|
||||
|
||||
@@ -864,7 +908,7 @@ namespace v2rayN
|
||||
/// 获取剪贴板数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetClipboardData()
|
||||
public static string? GetClipboardData()
|
||||
{
|
||||
string strData = string.Empty;
|
||||
try
|
||||
@@ -951,7 +995,7 @@ namespace v2rayN
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public static IPAddress GetDefaultGateway()
|
||||
public static IPAddress? GetDefaultGateway()
|
||||
{
|
||||
return NetworkInterface
|
||||
.GetAllNetworkInterfaces()
|
||||
@@ -1014,14 +1058,11 @@ namespace v2rayN
|
||||
|
||||
public static string UnGzip(byte[] buf)
|
||||
{
|
||||
MemoryStream sb = new MemoryStream();
|
||||
using (GZipStream input = new GZipStream(new MemoryStream(buf),
|
||||
CompressionMode.Decompress,
|
||||
false))
|
||||
{
|
||||
input.CopyTo(sb);
|
||||
}
|
||||
return Encoding.UTF8.GetString(sb.ToArray());
|
||||
using MemoryStream sb = new();
|
||||
using GZipStream input = new(new MemoryStream(buf), CompressionMode.Decompress, false);
|
||||
input.CopyTo(sb);
|
||||
sb.Position = 0;
|
||||
return new StreamReader(sb, Encoding.UTF8).ReadToEnd();
|
||||
}
|
||||
|
||||
public static string GetBackupPath(string filename)
|
||||
@@ -1064,7 +1105,14 @@ namespace v2rayN
|
||||
Directory.CreateDirectory(_tempPath);
|
||||
}
|
||||
}
|
||||
return Path.Combine(_tempPath, filename);
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
return _tempPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.Combine(_tempPath, filename);
|
||||
}
|
||||
}
|
||||
public static string GetLogPath(string filename = "")
|
||||
{
|
||||
@@ -1082,6 +1130,22 @@ namespace v2rayN
|
||||
return Path.Combine(_tempPath, filename);
|
||||
}
|
||||
}
|
||||
public static string GetFontsPath(string filename = "")
|
||||
{
|
||||
string _tempPath = Path.Combine(StartupPath(), "guiFonts");
|
||||
if (!Directory.Exists(_tempPath))
|
||||
{
|
||||
Directory.CreateDirectory(_tempPath);
|
||||
}
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
return _tempPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Path.Combine(_tempPath, filename);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1114,42 +1178,40 @@ namespace v2rayN
|
||||
{
|
||||
foreach (Screen screen in Screen.AllScreens)
|
||||
{
|
||||
using (Bitmap fullImage = new Bitmap(screen.Bounds.Width,
|
||||
screen.Bounds.Height))
|
||||
using Bitmap fullImage = new Bitmap(screen.Bounds.Width,
|
||||
screen.Bounds.Height);
|
||||
using (Graphics g = Graphics.FromImage(fullImage))
|
||||
{
|
||||
using (Graphics g = Graphics.FromImage(fullImage))
|
||||
g.CopyFromScreen(screen.Bounds.X,
|
||||
screen.Bounds.Y,
|
||||
0, 0,
|
||||
fullImage.Size,
|
||||
CopyPixelOperation.SourceCopy);
|
||||
}
|
||||
int maxTry = 10;
|
||||
for (int i = 0; i < maxTry; i++)
|
||||
{
|
||||
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
|
||||
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
|
||||
Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
|
||||
Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
|
||||
|
||||
double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width;
|
||||
using (Graphics g = Graphics.FromImage(target))
|
||||
{
|
||||
g.CopyFromScreen(screen.Bounds.X,
|
||||
screen.Bounds.Y,
|
||||
0, 0,
|
||||
fullImage.Size,
|
||||
CopyPixelOperation.SourceCopy);
|
||||
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
|
||||
cropRect,
|
||||
GraphicsUnit.Pixel);
|
||||
}
|
||||
int maxTry = 10;
|
||||
for (int i = 0; i < maxTry; i++)
|
||||
|
||||
BitmapLuminanceSource source = new BitmapLuminanceSource(target);
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
QRCodeReader reader = new QRCodeReader();
|
||||
Result result = reader.decode(bitmap);
|
||||
if (result != null)
|
||||
{
|
||||
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
|
||||
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
|
||||
Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
|
||||
Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
|
||||
|
||||
double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width;
|
||||
using (Graphics g = Graphics.FromImage(target))
|
||||
{
|
||||
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
|
||||
cropRect,
|
||||
GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
BitmapLuminanceSource source = new BitmapLuminanceSource(target);
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
QRCodeReader reader = new QRCodeReader();
|
||||
Result result = reader.decode(bitmap);
|
||||
if (result != null)
|
||||
{
|
||||
string ret = result.Text;
|
||||
return ret;
|
||||
}
|
||||
string ret = result.Text;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace v2rayN.ViewModels
|
||||
public ReactiveCommand<Unit, Unit> BrowseServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> EditServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SaveServerCmd { get; }
|
||||
public bool IsModified { get; set; }
|
||||
|
||||
public AddServer2ViewModel(ProfileItem profileItem, Window view)
|
||||
{
|
||||
@@ -86,6 +87,7 @@ namespace v2rayN.ViewModels
|
||||
item.remarks = SelectedSource.remarks;
|
||||
item.address = SelectedSource.address;
|
||||
item.coreType = SelectedSource.coreType;
|
||||
item.displayLog = SelectedSource.displayLog;
|
||||
item.preSocksPort = SelectedSource.preSocksPort;
|
||||
}
|
||||
|
||||
@@ -104,7 +106,7 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
UI.Show(ResUI.CustomServerTips);
|
||||
|
||||
OpenFileDialog fileDialog = new OpenFileDialog
|
||||
OpenFileDialog fileDialog = new()
|
||||
{
|
||||
Multiselect = false,
|
||||
Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*"
|
||||
@@ -119,15 +121,16 @@ namespace v2rayN.ViewModels
|
||||
return;
|
||||
}
|
||||
var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId);
|
||||
if (item is null)
|
||||
{
|
||||
item = SelectedSource;
|
||||
}
|
||||
item ??= SelectedSource;
|
||||
item.address = fileName;
|
||||
if (ConfigHandler.AddCustomServer(ref _config, item, false) == 0)
|
||||
{
|
||||
_noticeHandler?.Enqueue(ResUI.SuccessfullyImportedCustomServer);
|
||||
_view.DialogResult = true;
|
||||
if (!Utils.IsNullOrEmpty(item.indexId))
|
||||
{
|
||||
SelectedSource = Utils.DeepCopy(item);
|
||||
}
|
||||
IsModified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Splat;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
@@ -36,7 +37,7 @@ namespace v2rayN.ViewModels
|
||||
private string _serverFilter = string.Empty;
|
||||
private static Config _config;
|
||||
private NoticeHandler? _noticeHandler;
|
||||
private readonly PaletteHelper _paletteHelper = new PaletteHelper();
|
||||
private readonly PaletteHelper _paletteHelper = new();
|
||||
private Dictionary<int, bool> _dicHeaderSort = new();
|
||||
private Action<string> _updateView;
|
||||
|
||||
@@ -62,6 +63,8 @@ namespace v2rayN.ViewModels
|
||||
[Reactive]
|
||||
public SubItem SelectedSub { get; set; }
|
||||
[Reactive]
|
||||
public SubItem SelectedMoveToGroup { get; set; }
|
||||
[Reactive]
|
||||
public RoutingItem SelectedRouting { get; set; }
|
||||
[Reactive]
|
||||
public ComboItem SelectedServer { get; set; }
|
||||
@@ -81,12 +84,13 @@ namespace v2rayN.ViewModels
|
||||
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
|
||||
//servers delete
|
||||
public ReactiveCommand<Unit, Unit> EditServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> RemoveServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> RemoveDuplicateServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> CopyServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SetDefaultServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> ShareServerCmd { get; }
|
||||
//servers move
|
||||
//servers move
|
||||
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
|
||||
@@ -109,8 +113,8 @@ namespace v2rayN.ViewModels
|
||||
public ReactiveCommand<Unit, Unit> SubSettingCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddSubCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SubUpdateCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SubGroupUpdateCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SubUpdateViaProxyCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SubGroupUpdateCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SubGroupUpdateViaProxyCmd { get; }
|
||||
|
||||
//Setting
|
||||
@@ -185,6 +189,8 @@ namespace v2rayN.ViewModels
|
||||
public IObservableCollection<Swatch> Swatches => _swatches;
|
||||
[Reactive]
|
||||
public Swatch SelectedSwatch { get; set; }
|
||||
[Reactive]
|
||||
public int CurrentFontSize { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string CurrentLanguage { get; set; }
|
||||
@@ -205,8 +211,13 @@ namespace v2rayN.ViewModels
|
||||
|
||||
SelectedProfile = new();
|
||||
SelectedSub = new();
|
||||
SelectedMoveToGroup = new();
|
||||
SelectedRouting = new();
|
||||
SelectedServer = new();
|
||||
if (_config.tunModeItem.enableTun && Utils.IsAdministrator())
|
||||
{
|
||||
EnableTun = true;
|
||||
}
|
||||
|
||||
//RefreshServers();
|
||||
InitSubscriptionView();
|
||||
@@ -220,6 +231,10 @@ namespace v2rayN.ViewModels
|
||||
x => x.SelectedSub,
|
||||
y => y != null && !y.remarks.IsNullOrEmpty() && _subId != y.id)
|
||||
.Subscribe(c => SubSelectedChanged(c));
|
||||
this.WhenAnyValue(
|
||||
x => x.SelectedMoveToGroup,
|
||||
y => y != null && !y.remarks.IsNullOrEmpty())
|
||||
.Subscribe(c => MoveToGroup(c));
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.SelectedRouting,
|
||||
@@ -239,7 +254,7 @@ namespace v2rayN.ViewModels
|
||||
SystemProxySelected = (int)_config.sysProxyType;
|
||||
this.WhenAnyValue(
|
||||
x => x.SystemProxySelected,
|
||||
y => y != null && y >= 0)
|
||||
y => y >= 0)
|
||||
.Subscribe(c => DoSystemProxySelected(c));
|
||||
|
||||
this.WhenAnyValue(
|
||||
@@ -285,6 +300,10 @@ namespace v2rayN.ViewModels
|
||||
return ScanScreenTaskAsync();
|
||||
});
|
||||
//servers delete
|
||||
EditServerCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
EditServer(false, EConfigType.Custom);
|
||||
}, canEditRemove);
|
||||
RemoveServerCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
RemoveServer();
|
||||
@@ -305,7 +324,7 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
ShareServer();
|
||||
}, canEditRemove);
|
||||
//servers move
|
||||
//servers move
|
||||
MoveTopCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
MoveServer(EMove.Top);
|
||||
@@ -380,13 +399,13 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
UpdateSubscriptionProcess("", false);
|
||||
});
|
||||
SubGroupUpdateCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
UpdateSubscriptionProcess(_subId, true);
|
||||
});
|
||||
SubUpdateViaProxyCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
UpdateSubscriptionProcess("", false);
|
||||
UpdateSubscriptionProcess("", true);
|
||||
});
|
||||
SubGroupUpdateCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
UpdateSubscriptionProcess(_subId, false);
|
||||
});
|
||||
SubGroupUpdateViaProxyCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
@@ -487,7 +506,7 @@ namespace v2rayN.ViewModels
|
||||
//MainFormHandler.Instance.BackupGuiNConfig(_config, true);
|
||||
_coreHandler = new CoreHandler(UpdateHandler);
|
||||
|
||||
if (_config.enableStatistics)
|
||||
if (_config.guiItem.enableStatistics)
|
||||
{
|
||||
_statistics = new StatisticsHandler(_config, UpdateStatisticsHandler);
|
||||
}
|
||||
@@ -513,12 +532,17 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
_noticeHandler?.SendMessage(msg);
|
||||
}
|
||||
private async void UpdateTaskHandler(bool success, string msg)
|
||||
private void UpdateTaskHandler(bool success, string msg)
|
||||
{
|
||||
_noticeHandler?.SendMessage(msg);
|
||||
if (success)
|
||||
{
|
||||
RefreshServers();
|
||||
Reload();
|
||||
if (_config.uiItem.enableAutoAdjustMainLvColWidth)
|
||||
{
|
||||
_updateView("AdjustMainLvColWidth");
|
||||
}
|
||||
}
|
||||
}
|
||||
private void UpdateStatisticsHandler(ServerSpeedItem update)
|
||||
@@ -533,6 +557,33 @@ namespace v2rayN.ViewModels
|
||||
}
|
||||
SpeedProxyDisplay = string.Format("{0}:{1}/s<><73> | {2}/s<><73>", Global.agentTag, Utils.HumanFy(update.proxyUp), Utils.HumanFy(update.proxyDown));
|
||||
SpeedDirectDisplay = string.Format("{0}:{1}/s<><73> | {2}/s<><73>", Global.directTag, Utils.HumanFy(update.directUp), Utils.HumanFy(update.directDown));
|
||||
|
||||
if (update.proxyUp + update.proxyDown > 0)
|
||||
{
|
||||
var second = DateTime.Now.Second;
|
||||
if (second % 3 == 0)
|
||||
{
|
||||
var item = _profileItems.Where(it => it.indexId == update.indexId).FirstOrDefault();
|
||||
if (item != null)
|
||||
{
|
||||
item.todayDown = Utils.HumanFy(update.todayDown);
|
||||
item.todayUp = Utils.HumanFy(update.todayUp);
|
||||
item.totalDown = Utils.HumanFy(update.totalDown);
|
||||
item.totalUp = Utils.HumanFy(update.totalUp);
|
||||
|
||||
if (SelectedProfile?.indexId == item.indexId)
|
||||
{
|
||||
var temp = Utils.DeepCopy(item);
|
||||
_profileItems.Replace(item, temp);
|
||||
SelectedProfile = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
_profileItems.Replace(item, Utils.DeepCopy(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -551,7 +602,8 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(indexId))
|
||||
{
|
||||
_noticeHandler?.SendMessage(delay);
|
||||
_noticeHandler?.SendMessage(delay, true);
|
||||
_noticeHandler?.Enqueue(delay);
|
||||
return;
|
||||
}
|
||||
var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault();
|
||||
@@ -612,6 +664,9 @@ namespace v2rayN.ViewModels
|
||||
SysProxyHandle.UpdateSysProxy(_config, true);
|
||||
}
|
||||
|
||||
ProfileExHandler.Instance.SaveTo();
|
||||
|
||||
_statistics?.SaveTo();
|
||||
_statistics?.Close();
|
||||
|
||||
_coreHandler.CoreStop();
|
||||
@@ -638,6 +693,8 @@ namespace v2rayN.ViewModels
|
||||
_subId = SelectedSub?.id;
|
||||
|
||||
RefreshServers();
|
||||
|
||||
_updateView("ProfilesFocus");
|
||||
}
|
||||
|
||||
private void ServerFilterChanged(bool c)
|
||||
@@ -653,17 +710,19 @@ namespace v2rayN.ViewModels
|
||||
private void RefreshServers()
|
||||
{
|
||||
List<ProfileItemModel> lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter);
|
||||
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
|
||||
ConfigHandler.SetDefaultServer(_config, lstModel);
|
||||
|
||||
List<ServerStatItem> lstServerStat = new();
|
||||
if (_statistics != null && _statistics.Enable)
|
||||
{
|
||||
lstServerStat = LazyConfig.Instance.ServerStatItems();
|
||||
lstServerStat = _statistics.ServerStat;
|
||||
}
|
||||
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
|
||||
lstModel = (from t in lstModel
|
||||
join t2 in lstServerStat
|
||||
on t.indexId equals t2.indexId into t2b
|
||||
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
|
||||
from t22 in t2b.DefaultIfEmpty()
|
||||
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
|
||||
from t33 in t3b.DefaultIfEmpty()
|
||||
select new ProfileItemModel
|
||||
{
|
||||
indexId = t.indexId,
|
||||
@@ -675,17 +734,16 @@ namespace v2rayN.ViewModels
|
||||
network = t.network,
|
||||
streamSecurity = t.streamSecurity,
|
||||
subRemarks = t.subRemarks,
|
||||
isActive = t.isActive,
|
||||
delay = t.delay,
|
||||
delayVal = t.delay > 0 ? $"{t.delay} {Global.DelayUnit}" : string.Empty,
|
||||
speedVal = t.speed > 0 ? $"{t.speed} {Global.SpeedUnit}" : string.Empty,
|
||||
isActive = t.indexId == _config.indexId,
|
||||
sort = t33 == null ? 0 : t33.sort,
|
||||
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
|
||||
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
|
||||
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
|
||||
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
|
||||
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
|
||||
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
|
||||
}).ToList();
|
||||
|
||||
ConfigHandler.SetDefaultServer(_config, _lstProfile);
|
||||
}).OrderBy(t => t.sort).ToList();
|
||||
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
|
||||
|
||||
Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||
{
|
||||
@@ -693,7 +751,15 @@ namespace v2rayN.ViewModels
|
||||
_profileItems.AddRange(lstModel);
|
||||
if (lstModel.Count > 0)
|
||||
{
|
||||
SelectedProfile = lstModel[0];
|
||||
var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId);
|
||||
if (selected != null)
|
||||
{
|
||||
SelectedProfile = selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedProfile = lstModel[0];
|
||||
}
|
||||
}
|
||||
|
||||
RefreshServersMenu();
|
||||
@@ -710,7 +776,7 @@ namespace v2rayN.ViewModels
|
||||
private void RefreshServersMenu()
|
||||
{
|
||||
_servers.Clear();
|
||||
if (_lstProfile.Count > _config.trayMenuServersLimit)
|
||||
if (_lstProfile.Count > _config.guiItem.trayMenuServersLimit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -738,7 +804,14 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
_subItems.Add(item);
|
||||
}
|
||||
SelectedSub = _subItems[0];
|
||||
if (_subId != null && _subItems.FirstOrDefault(t => t.id == _subId) != null)
|
||||
{
|
||||
SelectedSub = _subItems.FirstOrDefault(t => t.id == _subId);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedSub = _subItems[0];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -747,7 +820,7 @@ namespace v2rayN.ViewModels
|
||||
private int GetProfileItems(out List<ProfileItem> lstSelecteds)
|
||||
{
|
||||
lstSelecteds = new List<ProfileItem>();
|
||||
if (SelectedProfiles == null && SelectedProfiles.Count() <= 0)
|
||||
if (SelectedProfiles == null || SelectedProfiles.Count <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -812,6 +885,7 @@ namespace v2rayN.ViewModels
|
||||
int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData, _subId, false);
|
||||
if (ret > 0)
|
||||
{
|
||||
InitSubscriptionView();
|
||||
RefreshServers();
|
||||
_noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret));
|
||||
}
|
||||
@@ -836,6 +910,7 @@ namespace v2rayN.ViewModels
|
||||
int ret = ConfigHandler.AddBatchServers(ref _config, result, _subId, false);
|
||||
if (ret > 0)
|
||||
{
|
||||
InitSubscriptionView();
|
||||
RefreshServers();
|
||||
_noticeHandler?.Enqueue(ResUI.SuccessfullyImportedServerViaScan);
|
||||
}
|
||||
@@ -852,12 +927,16 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
return;
|
||||
}
|
||||
var exists = lstSelecteds.Exists(t => t.indexId == _config.indexId);
|
||||
|
||||
ConfigHandler.RemoveServer(_config, lstSelecteds);
|
||||
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||
|
||||
RefreshServers();
|
||||
Reload();
|
||||
if (exists)
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveDuplicateServer()
|
||||
@@ -883,7 +962,7 @@ namespace v2rayN.ViewModels
|
||||
|
||||
public void SetDefaultServer()
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(SelectedProfile.indexId))
|
||||
if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -906,7 +985,7 @@ namespace v2rayN.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConfigHandler.SetDefaultServer(ref _config, item) == 0)
|
||||
if (ConfigHandler.SetDefaultServerIndex(ref _config, indexId) == 0)
|
||||
{
|
||||
RefreshServers();
|
||||
Reload();
|
||||
@@ -982,7 +1061,7 @@ namespace v2rayN.ViewModels
|
||||
}
|
||||
(new UpdateHandle()).RunAvailabilityCheck((bool success, string msg) =>
|
||||
{
|
||||
_noticeHandler?.SendMessage(msg);
|
||||
_noticeHandler?.SendMessage(msg, true);
|
||||
Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||
{
|
||||
if (!Global.ShowInTaskbar)
|
||||
@@ -995,6 +1074,26 @@ namespace v2rayN.ViewModels
|
||||
}
|
||||
|
||||
//move server
|
||||
private void MoveToGroup(bool c)
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetProfileItems(out List<ProfileItem> lstSelecteds) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigHandler.MoveToGroup(_config, lstSelecteds, SelectedMoveToGroup.id);
|
||||
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
|
||||
|
||||
RefreshServers();
|
||||
SelectedMoveToGroup = new();
|
||||
//Reload();
|
||||
}
|
||||
|
||||
public void MoveServer(EMove eMove)
|
||||
{
|
||||
var item = _lstProfile.FirstOrDefault(t => t.indexId == SelectedProfile.indexId);
|
||||
@@ -1015,6 +1114,17 @@ namespace v2rayN.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveServerTo(int startIndex, ProfileItemModel targetItem)
|
||||
{
|
||||
var targetIndex = _profileItems.IndexOf(targetItem);
|
||||
if (startIndex >= 0 && targetIndex >= 0 && startIndex != targetIndex)
|
||||
{
|
||||
if (ConfigHandler.MoveServer(ref _config, ref _lstProfile, startIndex, EMove.Position, targetIndex) == 0)
|
||||
{
|
||||
RefreshServers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerSpeedtest(ESpeedActionType actionType)
|
||||
{
|
||||
@@ -1027,7 +1137,7 @@ namespace v2rayN.ViewModels
|
||||
return;
|
||||
}
|
||||
//ClearTestResult();
|
||||
SpeedtestHandler statistics = new SpeedtestHandler(_config, _coreHandler, lstSelecteds, actionType, UpdateSpeedtestHandler);
|
||||
new SpeedtestHandler(_config, _coreHandler, lstSelecteds, actionType, UpdateSpeedtestHandler);
|
||||
}
|
||||
|
||||
private void Export2ClientConfig()
|
||||
@@ -1059,7 +1169,7 @@ namespace v2rayN.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new();
|
||||
foreach (var it in lstSelecteds)
|
||||
{
|
||||
string url = ShareHandler.GetShareUrl(it);
|
||||
@@ -1073,7 +1183,7 @@ namespace v2rayN.ViewModels
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
Utils.SetClipboardData(sb.ToString());
|
||||
_noticeHandler?.Enqueue(ResUI.BatchExportURLSuccessfully);
|
||||
_noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1084,10 +1194,10 @@ namespace v2rayN.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new();
|
||||
foreach (var it in lstSelecteds)
|
||||
{
|
||||
string url = ShareHandler.GetShareUrl(it);
|
||||
string? url = ShareHandler.GetShareUrl(it);
|
||||
if (Utils.IsNullOrEmpty(url))
|
||||
{
|
||||
continue;
|
||||
@@ -1098,7 +1208,7 @@ namespace v2rayN.ViewModels
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
Utils.SetClipboardData(Utils.Base64Encode(sb.ToString()));
|
||||
_noticeHandler?.Enqueue(ResUI.BatchExportSubscriptionSuccessfully);
|
||||
_noticeHandler?.SendMessage(ResUI.BatchExportSubscriptionSuccessfully);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1127,20 +1237,7 @@ namespace v2rayN.ViewModels
|
||||
|
||||
private void UpdateSubscriptionProcess(string subId, bool blProxy)
|
||||
{
|
||||
void _updateUI(bool success, string msg)
|
||||
{
|
||||
_noticeHandler?.SendMessage(msg);
|
||||
if (success)
|
||||
{
|
||||
RefreshServers();
|
||||
if (_config.uiItem.enableAutoAdjustMainLvColWidth)
|
||||
{
|
||||
_updateView("AdjustMainLvColWidth");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(new UpdateHandle()).UpdateSubscriptionProcess(_config, subId, blProxy, _updateUI);
|
||||
(new UpdateHandle()).UpdateSubscriptionProcess(_config, subId, blProxy, UpdateTaskHandler);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1171,7 +1268,7 @@ namespace v2rayN.ViewModels
|
||||
|
||||
private void ImportOldGuiConfig()
|
||||
{
|
||||
OpenFileDialog fileDialog = new OpenFileDialog
|
||||
OpenFileDialog fileDialog = new()
|
||||
{
|
||||
Multiselect = false,
|
||||
Filter = "guiNConfig|*.json|All|*.*"
|
||||
@@ -1215,7 +1312,7 @@ namespace v2rayN.ViewModels
|
||||
MyAppExit(false);
|
||||
}
|
||||
};
|
||||
(new UpdateHandle()).CheckUpdateGuiN(_config, _updateUI, _config.checkPreReleaseUpdate);
|
||||
(new UpdateHandle()).CheckUpdateGuiN(_config, _updateUI, _config.guiItem.checkPreReleaseUpdate);
|
||||
}
|
||||
|
||||
private void CheckUpdateCore(ECoreType type)
|
||||
@@ -1230,16 +1327,21 @@ namespace v2rayN.ViewModels
|
||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(msg));
|
||||
string toPath = Utils.GetBinPath("", type);
|
||||
|
||||
FileManager.ZipExtractToFile(fileName, toPath, _config.ignoreGeoUpdateCore ? "geo" : "");
|
||||
FileManager.ZipExtractToFile(fileName, toPath, _config.guiItem.ignoreGeoUpdateCore ? "geo" : "");
|
||||
|
||||
_noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
|
||||
|
||||
Reload();
|
||||
|
||||
_noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfully);
|
||||
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
File.Delete(fileName);
|
||||
}
|
||||
}
|
||||
};
|
||||
(new UpdateHandle()).CheckUpdateCore(type, _config, _updateUI, _config.checkPreReleaseUpdate);
|
||||
(new UpdateHandle()).CheckUpdateCore(type, _config, _updateUI, _config.guiItem.checkPreReleaseUpdate);
|
||||
}
|
||||
|
||||
private void CheckUpdateGeo()
|
||||
@@ -1343,7 +1445,7 @@ namespace v2rayN.ViewModels
|
||||
private void RefreshRoutingsMenu()
|
||||
{
|
||||
_routingItems.Clear();
|
||||
if (!_config.enableRoutingAdvanced)
|
||||
if (!_config.routingBasicItem.enableRoutingAdvanced)
|
||||
{
|
||||
BlRouting = false;
|
||||
return;
|
||||
@@ -1354,7 +1456,7 @@ namespace v2rayN.ViewModels
|
||||
foreach (var item in routings)
|
||||
{
|
||||
_routingItems.Add(item);
|
||||
if (item.id.Equals(_config.routingIndexId))
|
||||
if (item.id.Equals(_config.routingBasicItem.routingIndexId))
|
||||
{
|
||||
SelectedRouting = item;
|
||||
}
|
||||
@@ -1378,7 +1480,7 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_config.routingIndexId == item.id)
|
||||
if (_config.routingBasicItem.routingIndexId == item.id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1430,7 +1532,7 @@ namespace v2rayN.ViewModels
|
||||
|
||||
public void ShowHideWindow(bool? blShow)
|
||||
{
|
||||
var bl = blShow.HasValue ? blShow.Value : !Global.ShowInTaskbar;
|
||||
var bl = blShow ?? !Global.ShowInTaskbar;
|
||||
if (bl)
|
||||
{
|
||||
//Application.Current.MainWindow.ShowInTaskbar = true;
|
||||
@@ -1479,6 +1581,7 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
SelectedSwatch = _swatches.FirstOrDefault(t => t.Name == _config.uiItem.colorPrimaryName);
|
||||
}
|
||||
CurrentFontSize = _config.uiItem.currentFontSize;
|
||||
CurrentLanguage = _config.uiItem.currentLanguage;
|
||||
|
||||
this.WhenAnyValue(
|
||||
@@ -1514,6 +1617,24 @@ namespace v2rayN.ViewModels
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentFontSize,
|
||||
y => y > 0)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (CurrentFontSize >= Global.MinFontSize)
|
||||
{
|
||||
_config.uiItem.currentFontSize = CurrentFontSize;
|
||||
double size = (long)CurrentFontSize;
|
||||
Application.Current.Resources["StdFontSize"] = size;
|
||||
Application.Current.Resources["StdFontSize1"] = size + 1;
|
||||
Application.Current.Resources["StdFontSize2"] = size + 2;
|
||||
Application.Current.Resources["StdFontSizeMsg"] = size - 1;
|
||||
|
||||
ConfigHandler.SaveConfig(ref _config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentLanguage,
|
||||
y => y != null && !y.IsNullOrEmpty())
|
||||
@@ -1530,7 +1651,7 @@ namespace v2rayN.ViewModels
|
||||
|
||||
public void InboundDisplayStaus()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new();
|
||||
sb.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}]");
|
||||
sb.Append(" | ");
|
||||
//if (_config.sysProxyType == ESysProxyType.ForcedChange)
|
||||
@@ -1541,21 +1662,21 @@ namespace v2rayN.ViewModels
|
||||
//{
|
||||
sb.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]");
|
||||
//}
|
||||
InboundDisplay = $"{ResUI.LabLocal}:{sb.ToString()}";
|
||||
InboundDisplay = $"{ResUI.LabLocal}:{sb}";
|
||||
|
||||
if (_config.inbound[0].allowLANConn)
|
||||
{
|
||||
if (_config.inbound[0].newPort4LAN)
|
||||
{
|
||||
StringBuilder sb2 = new StringBuilder();
|
||||
StringBuilder sb2 = new();
|
||||
sb2.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks2)}]");
|
||||
sb2.Append(" | ");
|
||||
sb2.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp2)}]");
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2.ToString()}";
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}";
|
||||
}
|
||||
else
|
||||
{
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{sb.ToString()}";
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{sb}";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1586,16 +1707,16 @@ namespace v2rayN.ViewModels
|
||||
|
||||
private void AutoHideStartup()
|
||||
{
|
||||
if (_config.autoHideStartup)
|
||||
if (_config.uiItem.autoHideStartup)
|
||||
{
|
||||
Observable.Range(1, 1)
|
||||
.Delay(TimeSpan.FromSeconds(1))
|
||||
.Subscribe(x =>
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
ShowHideWindow(false);
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace v2rayN.ViewModels
|
||||
[Reactive] public bool logEnabled { get; set; }
|
||||
[Reactive] public string loglevel { get; set; }
|
||||
[Reactive] public bool defAllowInsecure { get; set; }
|
||||
[Reactive] public string defFingerprint { get; set; }
|
||||
[Reactive] public string defUserAgent { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Core DNS
|
||||
@@ -55,9 +57,15 @@ namespace v2rayN.ViewModels
|
||||
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
|
||||
[Reactive] public bool AutoHideStartup { get; set; }
|
||||
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; }
|
||||
[Reactive] public bool EnableDragDropSort { get; set; }
|
||||
[Reactive] public bool DoubleClick2Activate { get; set; }
|
||||
[Reactive] public int autoUpdateInterval { get; set; }
|
||||
[Reactive] public int autoUpdateSubInterval { get; set; }
|
||||
[Reactive] public int trayMenuServersLimit { get; set; }
|
||||
[Reactive] public string currentFontFamily { get; set; }
|
||||
[Reactive] public int SpeedTestTimeout { get; set; }
|
||||
[Reactive] public string SpeedTestUrl { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region System proxy
|
||||
@@ -67,11 +75,17 @@ namespace v2rayN.ViewModels
|
||||
|
||||
#region Tun mode
|
||||
[Reactive] public bool TunShowWindow { get; set; }
|
||||
[Reactive] public bool TunEnabledLog { get; set; }
|
||||
[Reactive] public bool TunStrictRoute { get; set; }
|
||||
[Reactive] public string TunStack { get; set; }
|
||||
[Reactive] public int TunMtu { get; set; }
|
||||
[Reactive] public string TunCustomTemplate { get; set; }
|
||||
[Reactive] public bool TunBypassMode { get; set; }
|
||||
[Reactive] public bool TunBypassMode2 { get; set; }
|
||||
[Reactive] public string TunDirectIP { get; set; }
|
||||
[Reactive] public string TunDirectProcess { get; set; }
|
||||
[Reactive] public string TunProxyIP { get; set; }
|
||||
[Reactive] public string TunProxyProcess { get; set; }
|
||||
#endregion
|
||||
|
||||
#region CoreType
|
||||
@@ -103,10 +117,12 @@ namespace v2rayN.ViewModels
|
||||
newPort4LAN = inbound.newPort4LAN;
|
||||
user = inbound.user;
|
||||
pass = inbound.pass;
|
||||
muxEnabled = _config.muxEnabled;
|
||||
logEnabled = _config.logEnabled;
|
||||
loglevel = _config.loglevel;
|
||||
defAllowInsecure = _config.defAllowInsecure;
|
||||
muxEnabled = _config.coreBasicItem.muxEnabled;
|
||||
logEnabled = _config.coreBasicItem.logEnabled;
|
||||
loglevel = _config.coreBasicItem.loglevel;
|
||||
defAllowInsecure = _config.coreBasicItem.defAllowInsecure;
|
||||
defFingerprint = _config.coreBasicItem.defFingerprint;
|
||||
defUserAgent = _config.coreBasicItem.defUserAgent;
|
||||
#endregion
|
||||
|
||||
#region Core DNS
|
||||
@@ -125,18 +141,24 @@ namespace v2rayN.ViewModels
|
||||
#endregion
|
||||
|
||||
#region UI
|
||||
AutoRun = _config.autoRun;
|
||||
EnableStatistics = _config.enableStatistics;
|
||||
StatisticsFreshRate = _config.statisticsFreshRate;
|
||||
KeepOlderDedupl = _config.keepOlderDedupl;
|
||||
IgnoreGeoUpdateCore = _config.ignoreGeoUpdateCore;
|
||||
AutoRun = _config.guiItem.autoRun;
|
||||
EnableStatistics = _config.guiItem.enableStatistics;
|
||||
StatisticsFreshRate = _config.guiItem.statisticsFreshRate;
|
||||
KeepOlderDedupl = _config.guiItem.keepOlderDedupl;
|
||||
IgnoreGeoUpdateCore = _config.guiItem.ignoreGeoUpdateCore;
|
||||
EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth;
|
||||
EnableSecurityProtocolTls13 = _config.enableSecurityProtocolTls13;
|
||||
AutoHideStartup = _config.autoHideStartup;
|
||||
EnableCheckPreReleaseUpdate = _config.checkPreReleaseUpdate;
|
||||
autoUpdateInterval = _config.autoUpdateInterval;
|
||||
autoUpdateSubInterval = _config.autoUpdateSubInterval;
|
||||
trayMenuServersLimit = _config.trayMenuServersLimit;
|
||||
EnableSecurityProtocolTls13 = _config.guiItem.enableSecurityProtocolTls13;
|
||||
AutoHideStartup = _config.uiItem.autoHideStartup;
|
||||
EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate;
|
||||
EnableDragDropSort = _config.uiItem.enableDragDropSort;
|
||||
DoubleClick2Activate = _config.uiItem.doubleClick2Activate;
|
||||
autoUpdateInterval = _config.guiItem.autoUpdateInterval;
|
||||
autoUpdateSubInterval = _config.guiItem.autoUpdateSubInterval;
|
||||
trayMenuServersLimit = _config.guiItem.trayMenuServersLimit;
|
||||
currentFontFamily = _config.uiItem.currentFontFamily;
|
||||
SpeedTestTimeout = _config.speedTestItem.speedTestTimeout;
|
||||
SpeedTestUrl = _config.speedTestItem.speedTestUrl;
|
||||
|
||||
#endregion
|
||||
|
||||
#region System proxy
|
||||
@@ -147,11 +169,19 @@ namespace v2rayN.ViewModels
|
||||
#region Tun mode
|
||||
|
||||
TunShowWindow = _config.tunModeItem.showWindow;
|
||||
TunEnabledLog = _config.tunModeItem.enabledLog;
|
||||
TunStrictRoute = _config.tunModeItem.strictRoute;
|
||||
TunStack = _config.tunModeItem.stack;
|
||||
TunMtu = _config.tunModeItem.mtu;
|
||||
TunCustomTemplate = _config.tunModeItem.customTemplate;
|
||||
TunBypassMode = _config.tunModeItem.bypassMode;
|
||||
TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true);
|
||||
TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true);
|
||||
TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true);
|
||||
TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true);
|
||||
this.WhenAnyValue(
|
||||
x => x.TunBypassMode)
|
||||
.Subscribe(c => TunBypassMode2 = !TunBypassMode);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -259,10 +289,12 @@ namespace v2rayN.ViewModels
|
||||
{
|
||||
_config.inbound.RemoveAt(1);
|
||||
}
|
||||
_config.logEnabled = logEnabled;
|
||||
_config.loglevel = loglevel;
|
||||
_config.muxEnabled = muxEnabled;
|
||||
_config.defAllowInsecure = defAllowInsecure;
|
||||
_config.coreBasicItem.logEnabled = logEnabled;
|
||||
_config.coreBasicItem.loglevel = loglevel;
|
||||
_config.coreBasicItem.muxEnabled = muxEnabled;
|
||||
_config.coreBasicItem.defAllowInsecure = defAllowInsecure;
|
||||
_config.coreBasicItem.defFingerprint = defFingerprint;
|
||||
_config.coreBasicItem.defUserAgent = defUserAgent;
|
||||
|
||||
|
||||
//DNS
|
||||
@@ -282,22 +314,27 @@ namespace v2rayN.ViewModels
|
||||
|
||||
//UI
|
||||
Utils.SetAutoRun(AutoRun);
|
||||
_config.autoRun = AutoRun;
|
||||
_config.enableStatistics = EnableStatistics;
|
||||
_config.statisticsFreshRate = StatisticsFreshRate;
|
||||
if (_config.statisticsFreshRate > 100 || _config.statisticsFreshRate < 1)
|
||||
_config.guiItem.autoRun = AutoRun;
|
||||
_config.guiItem.enableStatistics = EnableStatistics;
|
||||
_config.guiItem.statisticsFreshRate = StatisticsFreshRate;
|
||||
if (_config.guiItem.statisticsFreshRate > 100 || _config.guiItem.statisticsFreshRate < 1)
|
||||
{
|
||||
_config.statisticsFreshRate = 1;
|
||||
_config.guiItem.statisticsFreshRate = 1;
|
||||
}
|
||||
_config.keepOlderDedupl = KeepOlderDedupl;
|
||||
_config.ignoreGeoUpdateCore = IgnoreGeoUpdateCore;
|
||||
_config.guiItem.keepOlderDedupl = KeepOlderDedupl;
|
||||
_config.guiItem.ignoreGeoUpdateCore = IgnoreGeoUpdateCore;
|
||||
_config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth;
|
||||
_config.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
|
||||
_config.autoHideStartup = AutoHideStartup;
|
||||
_config.autoUpdateInterval = autoUpdateInterval;
|
||||
_config.autoUpdateSubInterval = autoUpdateSubInterval;
|
||||
_config.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
|
||||
_config.trayMenuServersLimit = trayMenuServersLimit;
|
||||
_config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
|
||||
_config.uiItem.autoHideStartup = AutoHideStartup;
|
||||
_config.guiItem.autoUpdateInterval = autoUpdateInterval;
|
||||
_config.guiItem.autoUpdateSubInterval = autoUpdateSubInterval;
|
||||
_config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
|
||||
_config.uiItem.enableDragDropSort = EnableDragDropSort;
|
||||
_config.uiItem.doubleClick2Activate = DoubleClick2Activate;
|
||||
_config.guiItem.trayMenuServersLimit = trayMenuServersLimit;
|
||||
_config.uiItem.currentFontFamily = currentFontFamily;
|
||||
_config.speedTestItem.speedTestTimeout = SpeedTestTimeout;
|
||||
_config.speedTestItem.speedTestUrl = SpeedTestUrl;
|
||||
|
||||
//systemProxy
|
||||
_config.systemProxyExceptions = systemProxyExceptions;
|
||||
@@ -305,11 +342,16 @@ namespace v2rayN.ViewModels
|
||||
|
||||
//tun mode
|
||||
_config.tunModeItem.showWindow = TunShowWindow;
|
||||
_config.tunModeItem.enabledLog = TunEnabledLog;
|
||||
_config.tunModeItem.strictRoute = TunStrictRoute;
|
||||
_config.tunModeItem.stack = TunStack;
|
||||
_config.tunModeItem.mtu = TunMtu;
|
||||
_config.tunModeItem.customTemplate = TunCustomTemplate;
|
||||
_config.tunModeItem.bypassMode = TunBypassMode;
|
||||
_config.tunModeItem.directIP = Utils.String2List(TunDirectIP);
|
||||
_config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess);
|
||||
_config.tunModeItem.proxyIP = Utils.String2List(TunProxyIP);
|
||||
_config.tunModeItem.proxyProcess = Utils.String2List(TunProxyProcess);
|
||||
|
||||
//coreType
|
||||
SaveCoreType();
|
||||
|
||||
@@ -71,9 +71,9 @@ namespace v2rayN.ViewModels
|
||||
|
||||
ConfigHandler.InitBuiltinRouting(ref _config);
|
||||
|
||||
enableRoutingAdvanced = _config.enableRoutingAdvanced;
|
||||
domainStrategy = _config.domainStrategy;
|
||||
domainMatcher = _config.domainMatcher;
|
||||
enableRoutingAdvanced = _config.routingBasicItem.enableRoutingAdvanced;
|
||||
domainStrategy = _config.routingBasicItem.domainStrategy;
|
||||
domainMatcher = _config.routingBasicItem.domainMatcher;
|
||||
|
||||
RefreshRoutingItems();
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace v2rayN.ViewModels
|
||||
foreach (var item in routings)
|
||||
{
|
||||
bool def = false;
|
||||
if (item.id.Equals(_config.routingIndexId))
|
||||
if (item.id.Equals(_config.routingBasicItem.routingIndexId))
|
||||
{
|
||||
def = true;
|
||||
}
|
||||
@@ -176,15 +176,16 @@ namespace v2rayN.ViewModels
|
||||
remarks = item.remarks,
|
||||
url = item.url,
|
||||
customIcon = item.customIcon,
|
||||
sort = item.sort,
|
||||
};
|
||||
_routingItems.Add(it);
|
||||
}
|
||||
}
|
||||
private void SaveRouting()
|
||||
{
|
||||
_config.domainStrategy = domainStrategy;
|
||||
_config.enableRoutingAdvanced = enableRoutingAdvanced;
|
||||
_config.domainMatcher = domainMatcher;
|
||||
_config.routingBasicItem.domainStrategy = domainStrategy;
|
||||
_config.routingBasicItem.enableRoutingAdvanced = enableRoutingAdvanced;
|
||||
_config.routingBasicItem.domainMatcher = domainMatcher;
|
||||
|
||||
EndBindingLockedData();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Views="clr-namespace:v2rayN.Views"
|
||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:v2rayN"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
@@ -15,7 +16,10 @@
|
||||
Height="500"
|
||||
x:TypeArguments="vms:AddServer2ViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -70,7 +74,7 @@
|
||||
Margin="4"
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -88,7 +92,7 @@
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
@@ -122,6 +126,7 @@
|
||||
Width="200"
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
MaxDropDownHeight="1000"
|
||||
Style="{StaticResource MaterialDesignOutlinedComboBox}" />
|
||||
|
||||
@@ -154,7 +159,7 @@
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
<StackPanel
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace v2rayN.Views
|
||||
public AddServer2Window(ProfileItem profileItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
this.Loaded += Window_Loaded;
|
||||
ViewModel = new AddServer2ViewModel(profileItem, this);
|
||||
|
||||
@@ -44,7 +45,14 @@ namespace v2rayN.Views
|
||||
}
|
||||
private void btnCancel_Click(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
if (ViewModel?.IsModified == true)
|
||||
{
|
||||
this.DialogResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.Views.AddServerWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -13,7 +14,10 @@
|
||||
Height="800"
|
||||
x:TypeArguments="vms:AddServerViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -80,7 +84,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -94,7 +99,8 @@
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
@@ -109,7 +115,8 @@
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
</Grid>
|
||||
|
||||
<Separator
|
||||
@@ -145,7 +152,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<Button
|
||||
x:Name="btnGUID"
|
||||
Grid.Row="1"
|
||||
@@ -168,7 +176,8 @@
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
@@ -213,7 +222,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -258,7 +268,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -272,7 +283,8 @@
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
</Grid>
|
||||
<Grid
|
||||
@@ -303,7 +315,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<Button
|
||||
x:Name="btnGUID5"
|
||||
Grid.Row="1"
|
||||
@@ -341,7 +354,8 @@
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTrojan"
|
||||
@@ -370,7 +384,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -475,7 +490,8 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<TextBlock
|
||||
x:Name="tipRequestHost"
|
||||
Grid.Row="3"
|
||||
@@ -497,7 +513,8 @@
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}" />
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<TextBlock
|
||||
x:Name="tipPath"
|
||||
Grid.Row="4"
|
||||
@@ -569,7 +586,8 @@
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -599,6 +617,7 @@
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
IsEditable="True"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace v2rayN.Views
|
||||
public AddServerWindow(ProfileItem profileItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
this.Loaded += Window_Loaded;
|
||||
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
||||
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Views="clr-namespace:v2rayN.Views"
|
||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -14,8 +15,11 @@
|
||||
Height="500"
|
||||
x:TypeArguments="vms:SubEditViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
KeyDown="GlobalHotkeySettingWindow_KeyDown"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -68,7 +72,7 @@
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -85,7 +89,7 @@
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
@@ -102,7 +106,7 @@
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
@@ -118,7 +122,7 @@
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
@@ -134,7 +138,7 @@
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace v2rayN.Views
|
||||
public GlobalHotkeySettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
_config = LazyConfig.Instance.GetConfig();
|
||||
|
||||
if (_config.globalHotkeys == null)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:base="clr-namespace:v2rayN.Base"
|
||||
xmlns:converters="clr-namespace:v2rayN.Converters"
|
||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:v2rayN.Views"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
@@ -19,7 +19,9 @@
|
||||
MinHeight="600"
|
||||
x:TypeArguments="vms:MainWindowViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ShowInTaskbar="True"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -31,7 +33,7 @@
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
||||
<converters:DelayColorConverter x:Key="DelayColorConverter" />
|
||||
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
@@ -47,7 +49,7 @@
|
||||
VerticalAlignment="Center"
|
||||
ClipToBounds="True"
|
||||
Style="{StaticResource MaterialDesignToolBar}">
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -93,7 +95,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -125,7 +127,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -163,7 +165,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem x:Name="menuReload" Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -174,7 +176,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -215,7 +217,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem x:Name="menuHelp" Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -226,7 +228,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem
|
||||
x:Name="menuPromotion"
|
||||
Padding="8,0"
|
||||
@@ -240,7 +242,7 @@
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}">
|
||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||
<MenuItem
|
||||
x:Name="menuClose"
|
||||
Padding="8,0"
|
||||
@@ -259,71 +261,106 @@
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
|
||||
<StackPanel Margin="8">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsColorMode}" />
|
||||
<ToggleButton x:Name="togDarkMode" Margin="8" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ToggleButton
|
||||
x:Name="togDarkMode"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsColor}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSwatches"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Margin="8"
|
||||
DisplayMemberPath="Name"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsFontSize}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCurrentFontSize"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Margin="8"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLanguage}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCurrentLanguage"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Margin="8"
|
||||
materialDesign:HintAssist.Hint="Language"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</ToolBar>
|
||||
</ToolBarTray>
|
||||
<ToolBarTray DockPanel.Dock="Top">
|
||||
<ToolBar
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
ClipToBounds="True"
|
||||
Style="{StaticResource MaterialDesignToolBar}">
|
||||
<ListBox x:Name="lstGroup" Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding remarks}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button
|
||||
x:Name="btnAddSub"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||
<materialDesign:PackIcon Kind="Plus" />
|
||||
</Button>
|
||||
<Separator />
|
||||
<TextBox
|
||||
x:Name="txtServerFilter"
|
||||
Width="200"
|
||||
Margin="8,0"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
||||
materialDesign:TextFieldAssist.HasClearButton="True" />
|
||||
</ToolBar>
|
||||
</ToolBarTray>
|
||||
<WrapPanel Margin="2" DockPanel.Dock="Top">
|
||||
<ListBox
|
||||
x:Name="lstGroup"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
|
||||
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding remarks}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button
|
||||
x:Name="btnAddSub"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="4,0"
|
||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
|
||||
<materialDesign:PackIcon Kind="Plus" />
|
||||
</Button>
|
||||
<TextBox
|
||||
x:Name="txtServerFilter"
|
||||
Width="200"
|
||||
Margin="4,0"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
</WrapPanel>
|
||||
|
||||
<materialDesign:ColorZone
|
||||
Height="50"
|
||||
@@ -350,11 +387,12 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
x:Name="spEnableTun"
|
||||
Width="auto"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left">
|
||||
<TextBlock x:Name="txtEnableTun" Text="{x:Static resx:ResUI.TbEnableTunAs}" />
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbEnableTunAs}" />
|
||||
<ToggleButton
|
||||
x:Name="togEnableTun"
|
||||
Margin="4"
|
||||
@@ -371,6 +409,7 @@
|
||||
Width="120"
|
||||
Margin="8,0"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSystemproxy}"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
Style="{StaticResource MaterialDesignFloatingHintComboBox}">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
|
||||
@@ -384,6 +423,7 @@
|
||||
Margin="8,0"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
|
||||
DisplayMemberPath="remarks"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
Style="{StaticResource MaterialDesignFloatingHintComboBox}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -401,7 +441,7 @@
|
||||
</DockPanel>
|
||||
</materialDesign:ColorZone>
|
||||
|
||||
<Grid>
|
||||
<Grid x:Name="gridMain">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="10" />
|
||||
@@ -410,7 +450,7 @@
|
||||
<DataGrid
|
||||
x:Name="lstProfiles"
|
||||
Grid.Row="0"
|
||||
materialDesign:DataGridAssist.CellPadding="1,0"
|
||||
materialDesign:DataGridAssist.CellPadding="2,2"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
CanUserAddRows="False"
|
||||
@@ -430,6 +470,10 @@
|
||||
</DataGrid.InputBindings>
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||
<MenuItem
|
||||
x:Name="menuEditServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuEditServer}" />
|
||||
<MenuItem
|
||||
x:Name="menuSetDefaultServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
@@ -451,28 +495,6 @@
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuShareServer}" />
|
||||
<Separator />
|
||||
<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
|
||||
x:Name="menuSelectAll"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Click="menuSelectAll_Click"
|
||||
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuMixedTestServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
@@ -498,6 +520,46 @@
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuMoveToGroup"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
||||
<MenuItem Height="Auto">
|
||||
<MenuItem.Header>
|
||||
<DockPanel>
|
||||
<ComboBox
|
||||
x:Name="cmbMoveToGroup"
|
||||
Width="200"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
|
||||
DisplayMemberPath="remarks"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}" />
|
||||
</DockPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
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
|
||||
x:Name="menuSelectAll"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Click="menuSelectAll_Click"
|
||||
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuExport2ClientConfig"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
@@ -679,6 +741,7 @@
|
||||
MaxWidth="300"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
|
||||
DisplayMemberPath="remarks"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}" />
|
||||
</DockPanel>
|
||||
</MenuItem.Header>
|
||||
@@ -691,6 +754,7 @@
|
||||
MaxWidth="300"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}"
|
||||
DisplayMemberPath="Text"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}" />
|
||||
</DockPanel>
|
||||
</MenuItem.Header>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Mode;
|
||||
using v2rayN.Resx;
|
||||
using v2rayN.ViewModels;
|
||||
using Point = System.Windows.Point;
|
||||
using SystemInformation = System.Windows.Forms.SystemInformation;
|
||||
|
||||
namespace v2rayN.Views
|
||||
@@ -29,10 +33,23 @@ namespace v2rayN.Views
|
||||
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
|
||||
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
|
||||
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
|
||||
if (_config.uiItem.enableDragDropSort)
|
||||
{
|
||||
lstProfiles.AllowDrop = true;
|
||||
lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown;
|
||||
lstProfiles.MouseMove += LstProfiles_MouseMove;
|
||||
lstProfiles.DragEnter += LstProfiles_DragEnter;
|
||||
lstProfiles.Drop += LstProfiles_Drop;
|
||||
}
|
||||
|
||||
ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
|
||||
|
||||
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++)
|
||||
{
|
||||
cmbCurrentFontSize.Items.Add(i.ToString());
|
||||
}
|
||||
|
||||
Global.Languages.ForEach(it =>
|
||||
{
|
||||
cmbCurrentLanguage.Items.Add(it);
|
||||
@@ -59,6 +76,7 @@ namespace v2rayN.Views
|
||||
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
||||
|
||||
//servers delete
|
||||
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.menuEditServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoveServerCmd, v => v.menuRemoveServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoveDuplicateServerCmd, v => v.menuRemoveDuplicateServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables);
|
||||
@@ -66,6 +84,9 @@ namespace v2rayN.Views
|
||||
this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables);
|
||||
|
||||
//servers move
|
||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables);
|
||||
@@ -88,8 +109,8 @@ namespace v2rayN.Views
|
||||
//sub
|
||||
this.BindCommand(ViewModel, vm => vm.SubSettingCmd, v => v.menuSubSetting).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubGroupUpdateCmd, v => v.menuSubGroupUpdate).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubGroupUpdateCmd, v => v.menuSubGroupUpdate).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubGroupUpdateViaProxyCmd, v => v.menuSubGroupUpdateViaProxy).DisposeWith(disposables);
|
||||
|
||||
//setting
|
||||
@@ -157,6 +178,7 @@ namespace v2rayN.Views
|
||||
this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).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.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
@@ -166,8 +188,7 @@ namespace v2rayN.Views
|
||||
var IsAdministrator = Utils.IsAdministrator();
|
||||
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||
|
||||
togEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Hidden;
|
||||
txtEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Hidden;
|
||||
spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
#region Event
|
||||
@@ -184,6 +205,10 @@ namespace v2rayN.Views
|
||||
}
|
||||
}));
|
||||
}
|
||||
else if (action == "ProfilesFocus")
|
||||
{
|
||||
lstProfiles.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void MainWindow_Closing(object? sender, CancelEventArgs e)
|
||||
@@ -212,27 +237,42 @@ namespace v2rayN.Views
|
||||
}
|
||||
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
||||
{
|
||||
if (e.Row.GetIndex() == 0)
|
||||
{
|
||||
lstProfiles.Focus();
|
||||
}
|
||||
//if (e.Row.GetIndex() == 0)
|
||||
//{
|
||||
// lstProfiles.Focus();
|
||||
//}
|
||||
|
||||
e.Row.Header = e.Row.GetIndex() + 1;
|
||||
}
|
||||
|
||||
private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
ViewModel?.EditServer(false, EConfigType.Custom);
|
||||
if (_config.uiItem.doubleClick2Activate)
|
||||
{
|
||||
ViewModel?.SetDefaultServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel?.EditServer(false, EConfigType.Custom);
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_ColumnHeader_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var colHeader = sender as DataGridColumnHeader;
|
||||
if (colHeader == null || colHeader.TabIndex < 0)
|
||||
if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (colHeader.TabIndex == 0)
|
||||
|
||||
//find index
|
||||
var index = lstProfiles.Columns.IndexOf(colHeader.Column);
|
||||
if (index < 0)
|
||||
{
|
||||
index = colHeader.TabIndex;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
foreach (var it in lstProfiles.Columns)
|
||||
{
|
||||
@@ -242,7 +282,7 @@ namespace v2rayN.Views
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel?.SortServer(colHeader.TabIndex);
|
||||
ViewModel?.SortServer(index);
|
||||
}
|
||||
|
||||
private void menuSelectAll_Click(object sender, RoutedEventArgs e)
|
||||
@@ -305,6 +345,10 @@ namespace v2rayN.Views
|
||||
ViewModel?.Export2ShareUrl();
|
||||
}
|
||||
else if (e.Key == Key.D)
|
||||
{
|
||||
ViewModel?.EditServer(false, EConfigType.Custom);
|
||||
}
|
||||
else if (e.Key == Key.F)
|
||||
{
|
||||
ViewModel?.ShareServer();
|
||||
}
|
||||
@@ -323,15 +367,15 @@ namespace v2rayN.Views
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Top);
|
||||
}
|
||||
else if (e.Key == Key.B)
|
||||
else if (e.Key == Key.U)
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Up);
|
||||
}
|
||||
else if (e.Key == Key.U)
|
||||
else if (e.Key == Key.D)
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Down);
|
||||
}
|
||||
else if (e.Key == Key.D)
|
||||
else if (e.Key == Key.B)
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Bottom);
|
||||
}
|
||||
@@ -365,24 +409,32 @@ namespace v2rayN.Views
|
||||
{
|
||||
if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0)
|
||||
{
|
||||
if (_config.uiItem.mainWidth > SystemInformation.WorkingArea.Width)
|
||||
{
|
||||
_config.uiItem.mainWidth = SystemInformation.WorkingArea.Width * 2 / 3;
|
||||
}
|
||||
if (_config.uiItem.mainHeight > SystemInformation.WorkingArea.Height)
|
||||
{
|
||||
_config.uiItem.mainHeight = SystemInformation.WorkingArea.Height * 2 / 3;
|
||||
}
|
||||
|
||||
this.Width = _config.uiItem.mainWidth;
|
||||
this.Height = _config.uiItem.mainHeight;
|
||||
Width = _config.uiItem.mainWidth;
|
||||
Height = _config.uiItem.mainHeight;
|
||||
}
|
||||
|
||||
IntPtr hWnd = new WindowInteropHelper(this).EnsureHandle();
|
||||
Graphics g = Graphics.FromHwnd(hWnd);
|
||||
if (Width > SystemInformation.WorkingArea.Width * 96 / g.DpiX)
|
||||
{
|
||||
Width = SystemInformation.WorkingArea.Width * 96 / g.DpiX;
|
||||
}
|
||||
if (Height > SystemInformation.WorkingArea.Height * 96 / g.DpiY)
|
||||
{
|
||||
Height = SystemInformation.WorkingArea.Height * 96 / g.DpiY;
|
||||
}
|
||||
if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0)
|
||||
{
|
||||
gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
|
||||
gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
|
||||
}
|
||||
|
||||
for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
||||
{
|
||||
var width = ConfigHandler.GetformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].Width.Value));
|
||||
lstProfiles.Columns[k].Width = width;
|
||||
}
|
||||
if (!_config.enableStatistics)
|
||||
if (!_config.guiItem.enableStatistics)
|
||||
{
|
||||
colTodayUp.Visibility = Visibility.Hidden;
|
||||
colTodayDown.Visibility = Visibility.Hidden;
|
||||
@@ -399,6 +451,8 @@ namespace v2rayN.Views
|
||||
{
|
||||
ConfigHandler.AddformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].ActualWidth));
|
||||
}
|
||||
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1);
|
||||
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1);
|
||||
}
|
||||
|
||||
private void AddHelpMenuItem()
|
||||
@@ -426,6 +480,100 @@ namespace v2rayN.Views
|
||||
|
||||
|
||||
#endregion
|
||||
#region Drag and Drop
|
||||
|
||||
private Point startPoint = new Point();
|
||||
private int startIndex = -1;
|
||||
private string formatData = "ProfileItemModel";
|
||||
|
||||
/// <summary>
|
||||
/// Helper to search up the VisualTree
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="current"></param>
|
||||
/// <returns></returns>
|
||||
private static T? FindAnchestor<T>(DependencyObject current) where T : DependencyObject
|
||||
{
|
||||
do
|
||||
{
|
||||
if (current is T)
|
||||
{
|
||||
return (T)current;
|
||||
}
|
||||
current = VisualTreeHelper.GetParent(current);
|
||||
}
|
||||
while (current != null);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void LstProfiles_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Get current mouse position
|
||||
startPoint = e.GetPosition(null);
|
||||
}
|
||||
private void LstProfiles_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Get the current mouse position
|
||||
Point mousePos = e.GetPosition(null);
|
||||
Vector diff = startPoint - mousePos;
|
||||
|
||||
if (e.LeftButton == MouseButtonState.Pressed &&
|
||||
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
||||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
|
||||
{
|
||||
// Get the dragged Item
|
||||
var listView = sender as DataGrid;
|
||||
if (listView == null) return;
|
||||
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
||||
if (listViewItem == null) return; // Abort
|
||||
// Find the data behind the ListViewItem
|
||||
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||
if (item == null) return; // Abort
|
||||
// Initialize the drag & drop operation
|
||||
startIndex = lstProfiles.SelectedIndex;
|
||||
DataObject dragData = new DataObject(formatData, item);
|
||||
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_DragEnter(object sender, DragEventArgs e)
|
||||
{
|
||||
if (!e.Data.GetDataPresent(formatData) || sender != e.Source)
|
||||
{
|
||||
e.Effects = DragDropEffects.None;
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_Drop(object sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data.GetDataPresent(formatData) && sender == e.Source)
|
||||
{
|
||||
// Get the drop Item destination
|
||||
var listView = sender as DataGrid;
|
||||
if (listView == null) return;
|
||||
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
||||
if (listViewItem == null)
|
||||
{
|
||||
// Abort
|
||||
e.Effects = DragDropEffects.None;
|
||||
return;
|
||||
}
|
||||
// Find the data behind the Item
|
||||
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||
if (item == null) return;
|
||||
// Move item into observable collection
|
||||
// (this will be automatically reflected to lstView.ItemsSource)
|
||||
e.Effects = DragDropEffects.Move;
|
||||
|
||||
ViewModel?.MoveServerTo(startIndex, item);
|
||||
|
||||
startIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,20 +20,35 @@
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource PrimaryHueLightBrush}"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
<TextBox
|
||||
x:Name="txtMsgFilter"
|
||||
<ComboBox
|
||||
x:Name="cmbMsgFilter"
|
||||
Width="200"
|
||||
Margin="8,0"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}"
|
||||
materialDesign:TextFieldAssist.HasClearButton="True" />
|
||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||
IsEditable="True"
|
||||
Style="{StaticResource DefComboBox}"
|
||||
TextBoxBase.TextChanged="cmbMsgFilter_TextChanged" />
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||
<ToggleButton
|
||||
x:Name="togAutoRefresh"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="True" />
|
||||
</StackPanel>
|
||||
<TextBox
|
||||
Name="txtMsg"
|
||||
BorderThickness="0"
|
||||
FontSize="11"
|
||||
FontSize="{DynamicResource StdFontSizeMsg}"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
IsReadOnly="True"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
<TextBox.ContextMenu>
|
||||
|
||||
@@ -3,15 +3,27 @@ using System.Reactive.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Threading;
|
||||
using v2rayN.Base;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Mode;
|
||||
|
||||
namespace v2rayN.Views
|
||||
{
|
||||
public partial class MsgView
|
||||
{
|
||||
private static Config _config;
|
||||
public MsgView()
|
||||
{
|
||||
InitializeComponent();
|
||||
_config = LazyConfig.Instance.GetConfig();
|
||||
MessageBus.Current.Listen<string>("MsgView").Subscribe(x => DelegateAppendText(x));
|
||||
Global.PresetMsgFilters.ForEach(it =>
|
||||
{
|
||||
cmbMsgFilter.Items.Add(it);
|
||||
});
|
||||
if (!_config.uiItem.mainMsgFilter.IsNullOrEmpty())
|
||||
{
|
||||
cmbMsgFilter.Text = _config.uiItem.mainMsgFilter;
|
||||
}
|
||||
}
|
||||
|
||||
void DelegateAppendText(string msg)
|
||||
@@ -26,7 +38,11 @@ namespace v2rayN.Views
|
||||
ClearMsg();
|
||||
return;
|
||||
}
|
||||
var MsgFilter = txtMsgFilter.Text.TrimEx();
|
||||
if (!togAutoRefresh.IsChecked.Value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var MsgFilter = cmbMsgFilter.Text.TrimEx();
|
||||
if (!Utils.IsNullOrEmpty(MsgFilter))
|
||||
{
|
||||
if (!Regex.IsMatch(msg, MsgFilter))
|
||||
@@ -79,6 +95,10 @@ namespace v2rayN.Views
|
||||
{
|
||||
ClearMsg();
|
||||
}
|
||||
private void cmbMsgFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
|
||||
{
|
||||
_config.uiItem.mainMsgFilter = cmbMsgFilter.Text.TrimEx();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.Views.OptionSettingWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -13,7 +14,10 @@
|
||||
Height="700"
|
||||
x:TypeArguments="vms:OptionSettingViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -45,194 +49,250 @@
|
||||
|
||||
<TabControl>
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCore}">
|
||||
<Grid Margin="{StaticResource SettingItemMargin}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||
<Grid Margin="{StaticResource SettingItemMargin}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSocksPort}" />
|
||||
<TextBox
|
||||
x:Name="txtlocalPort"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSocksPort}" />
|
||||
<TextBox
|
||||
x:Name="txtlocalPort"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSocksPortTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUdpEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="togudpEnabled"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUdpEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="togudpEnabled"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSniffingEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="togsniffingEnabled"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSniffingEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="togsniffingEnabled"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsRouteOnly}" />
|
||||
<ToggleButton
|
||||
x:Name="togrouteOnly"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsRouteOnly}" />
|
||||
<ToggleButton
|
||||
x:Name="togrouteOnly"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAllowLAN}" />
|
||||
<ToggleButton
|
||||
x:Name="togAllowLANConn"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAllowLAN}" />
|
||||
<ToggleButton
|
||||
x:Name="togAllowLANConn"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsNewPort4LAN}" />
|
||||
<ToggleButton
|
||||
x:Name="togNewPort4LAN"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsNewPort4LAN}" />
|
||||
<ToggleButton
|
||||
x:Name="togNewPort4LAN"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUser}" />
|
||||
<TextBox
|
||||
x:Name="txtuser"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUser}" />
|
||||
<TextBox
|
||||
x:Name="txtuser"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsPass}" />
|
||||
<TextBox
|
||||
x:Name="txtpass"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsPass}" />
|
||||
<TextBox
|
||||
x:Name="txtpass"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="togmuxEnabled"
|
||||
Grid.Row="8"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="togmuxEnabled"
|
||||
Grid.Row="8"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="toglogEnabled"
|
||||
Grid.Row="9"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="toglogEnabled"
|
||||
Grid.Row="9"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLogLevel}" />
|
||||
<ComboBox
|
||||
x:Name="cmbloglevel"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
materialDesign:HintAssist.Hint="Level" />
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLogLevel}" />
|
||||
<ComboBox
|
||||
x:Name="cmbloglevel"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
materialDesign:HintAssist.Hint="Level"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefAllowInsecure}" />
|
||||
<ToggleButton
|
||||
x:Name="togdefAllowInsecure"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefAllowInsecure}" />
|
||||
<ToggleButton
|
||||
x:Name="togdefAllowInsecure"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="12"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefFingerprint}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdefFingerprint"
|
||||
Grid.Row="12"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
IsEditable="True"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="13"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefUserAgent}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdefUserAgent"
|
||||
Grid.Row="13"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
IsEditable="True"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="13"
|
||||
Grid.Column="3"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefUserAgentTips}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||
@@ -246,7 +306,8 @@
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Freedom"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
@@ -270,6 +331,7 @@
|
||||
VerticalAlignment="Stretch"
|
||||
AcceptsReturn="True"
|
||||
BorderThickness="1"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</DockPanel>
|
||||
@@ -303,7 +365,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="mtu" />
|
||||
<TextBox
|
||||
<TextBox Style="{StaticResource DefTextBox}"
|
||||
x:Name="txtKcpmtu"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
@@ -317,7 +379,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="tti" />
|
||||
<TextBox
|
||||
<TextBox Style="{StaticResource DefTextBox}"
|
||||
x:Name="txtKcptti"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
@@ -331,7 +393,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="uplinkCapacity" />
|
||||
<TextBox
|
||||
<TextBox Style="{StaticResource DefTextBox}"
|
||||
x:Name="txtKcpuplinkCapacity"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
@@ -345,7 +407,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="downlinkCapacity" />
|
||||
<TextBox
|
||||
<TextBox Style="{StaticResource DefTextBox}"
|
||||
x:Name="txtKcpdownlinkCapacity"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
@@ -359,7 +421,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="readBufferSize" />
|
||||
<TextBox
|
||||
<TextBox Style="{StaticResource DefTextBox}"
|
||||
x:Name="txtKcpreadBufferSize"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
@@ -373,7 +435,7 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="writeBufferSize" />
|
||||
<TextBox
|
||||
<TextBox Style="{StaticResource DefTextBox}"
|
||||
x:Name="txtKcpwriteBufferSize"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
@@ -415,10 +477,15 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
@@ -434,6 +501,13 @@
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -461,7 +535,8 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
@@ -553,13 +628,13 @@
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAutoUpdateInterval}" />
|
||||
<TextBox
|
||||
x:Name="txtautoUpdateInterval"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableDragDropSort}" />
|
||||
<ToggleButton
|
||||
x:Name="togEnableDragDropSort"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
@@ -567,16 +642,48 @@
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDoubleClick2Activate}" />
|
||||
<ToggleButton
|
||||
x:Name="togDoubleClick2Activate"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="12"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAutoUpdateInterval}" />
|
||||
<TextBox
|
||||
x:Name="txtautoUpdateInterval"
|
||||
Grid.Row="12"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="13"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAutoUpdate}" />
|
||||
<TextBox
|
||||
x:Name="txtautoUpdateSubInterval"
|
||||
Grid.Row="11"
|
||||
Grid.Row="13"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="12"
|
||||
Grid.Row="14"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -584,10 +691,65 @@
|
||||
Text="{x:Static resx:ResUI.TbSettingsTrayMenuServersLimit}" />
|
||||
<TextBox
|
||||
x:Name="txttrayMenuServersLimit"
|
||||
Grid.Row="12"
|
||||
Grid.Row="14"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="15"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamily}" />
|
||||
<ComboBox
|
||||
x:Name="cmbcurrentFontFamily"
|
||||
Grid.Row="15"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
MaxDropDownHeight="1000"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="15"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="16"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSpeedTestTimeout}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSpeedTestTimeout"
|
||||
Grid.Row="16"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="17"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSpeedTestUrl}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSpeedTestUrl"
|
||||
Grid.Row="17"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
@@ -604,8 +766,10 @@
|
||||
<ComboBox
|
||||
x:Name="cmbsystemProxyAdvancedProtocol"
|
||||
Grid.Row="4"
|
||||
MinWidth="200"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
materialDesign:HintAssist.Hint="Protocol" />
|
||||
materialDesign:HintAssist.Hint="Protocol"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
@@ -622,6 +786,7 @@
|
||||
VerticalAlignment="Stretch"
|
||||
AcceptsReturn="True"
|
||||
BorderThickness="1"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</DockPanel>
|
||||
@@ -642,14 +807,16 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
@@ -657,6 +824,20 @@
|
||||
Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" />
|
||||
<ToggleButton
|
||||
x:Name="togShowWindow"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" />
|
||||
<ToggleButton
|
||||
x:Name="togEnabledLog"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
@@ -688,7 +869,9 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
@@ -702,10 +885,65 @@
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsTunModeCustomTemplate}" />
|
||||
<TextBox
|
||||
x:Name="txtCustomTemplate"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="btnBrowse"
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Width="100"
|
||||
Margin="2,0,8,0"
|
||||
Click="btnBrowse_Click"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}"
|
||||
Style="{StaticResource DefButton}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsTunModeBypassMode}" />
|
||||
<ToggleButton
|
||||
x:Name="togBypassMode"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource ServerItemMargin}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsTunModeBypassModeTip}" />
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="{StaticResource SettingItemMargin}">
|
||||
|
||||
<Grid
|
||||
x:Name="gridTunModeDirect"
|
||||
Width="600"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
@@ -714,10 +952,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="0"
|
||||
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectIP}"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtDirectIP"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
@@ -725,14 +964,51 @@
|
||||
<GroupBox
|
||||
Grid.Column="2"
|
||||
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectProcess}"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtDirectProcess"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
x:Name="gridTunModeProxy"
|
||||
Width="600"
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
HorizontalAlignment="Left">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<GroupBox
|
||||
Grid.Column="0"
|
||||
Header="{x:Static resx:ResUI.TbSettingsTunModeProxyIP}"
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtProxyIP"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||
<GroupBox
|
||||
Grid.Column="2"
|
||||
Header="{x:Static resx:ResUI.TbSettingsTunModeProxyProcess}"
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtProxyProcess"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
@@ -763,7 +1039,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -777,7 +1054,8 @@
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
@@ -791,7 +1069,8 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
@@ -805,7 +1084,8 @@
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
@@ -819,7 +1099,8 @@
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
@@ -833,7 +1114,8 @@
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource SettingItemMargin}" />
|
||||
Margin="{StaticResource SettingItemMargin}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
using ReactiveUI;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using v2rayN.Handler;
|
||||
using v2rayN.Mode;
|
||||
using v2rayN.ViewModels;
|
||||
|
||||
namespace v2rayN.Views
|
||||
{
|
||||
public partial class OptionSettingWindow
|
||||
{
|
||||
private static Config _config;
|
||||
|
||||
public OptionSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
_config = LazyConfig.Instance.GetConfig();
|
||||
|
||||
ViewModel = new OptionSettingViewModel(this);
|
||||
|
||||
@@ -21,6 +30,14 @@ namespace v2rayN.Views
|
||||
{
|
||||
cmbloglevel.Items.Add(it);
|
||||
});
|
||||
Global.fingerprints.ForEach(it =>
|
||||
{
|
||||
cmbdefFingerprint.Items.Add(it);
|
||||
});
|
||||
Global.userAgent.ForEach(it =>
|
||||
{
|
||||
cmbdefUserAgent.Items.Add(it);
|
||||
});
|
||||
Global.domainStrategy4Freedoms.ForEach(it =>
|
||||
{
|
||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
||||
@@ -47,6 +64,57 @@ namespace v2rayN.Views
|
||||
cmbCoreType6.Items.Add(it);
|
||||
});
|
||||
|
||||
for (int i = 2; i <= 6; i++)
|
||||
{
|
||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
||||
}
|
||||
Global.SpeedTestUrls.ForEach(it =>
|
||||
{
|
||||
cmbSpeedTestUrl.Items.Add(it);
|
||||
});
|
||||
|
||||
//fill fonts
|
||||
try
|
||||
{
|
||||
var dir = new DirectoryInfo(Utils.GetFontsPath());
|
||||
var files = dir.GetFiles("*.ttf");
|
||||
var culture = _config.uiItem.currentLanguage.Equals(Global.Languages[0]) ? "zh-cn" : "en-us";
|
||||
var culture2 = "en-us";
|
||||
foreach (var it in files)
|
||||
{
|
||||
var families = Fonts.GetFontFamilies(Utils.GetFontsPath(it.Name));
|
||||
foreach (FontFamily family in families)
|
||||
{
|
||||
var typefaces = family.GetTypefaces();
|
||||
foreach (Typeface typeface in typefaces)
|
||||
{
|
||||
typeface.TryGetGlyphTypeface(out GlyphTypeface glyph);
|
||||
//var fontFace = glyph.Win32FaceNames[new CultureInfo("en-us")];
|
||||
//if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal"))
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
var fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture)];
|
||||
if (Utils.IsNullOrEmpty(fontFamily))
|
||||
{
|
||||
fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture2)];
|
||||
if (Utils.IsNullOrEmpty(fontFamily))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cmbcurrentFontFamily.Items.Add(fontFamily);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.SaveLog("fill fonts error", ex);
|
||||
}
|
||||
cmbcurrentFontFamily.Items.Add(string.Empty);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.localPort, v => v.txtlocalPort.Text).DisposeWith(disposables);
|
||||
@@ -63,6 +131,8 @@ namespace v2rayN.Views
|
||||
this.Bind(ViewModel, vm => vm.logEnabled, v => v.toglogEnabled.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.loglevel, v => v.cmbloglevel.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.defAllowInsecure, v => v.togdefAllowInsecure.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.defFingerprint, v => v.cmbdefFingerprint.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.defUserAgent, v => v.cmbdefUserAgent.Text).DisposeWith(disposables);
|
||||
|
||||
|
||||
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);
|
||||
@@ -87,9 +157,14 @@ namespace v2rayN.Views
|
||||
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableDragDropSort, v => v.togEnableDragDropSort.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.autoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.autoUpdateSubInterval, v => v.txtautoUpdateSubInterval.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.trayMenuServersLimit, v => v.txttrayMenuServersLimit.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.currentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
|
||||
|
||||
|
||||
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
|
||||
@@ -97,11 +172,18 @@ namespace v2rayN.Views
|
||||
|
||||
|
||||
this.Bind(ViewModel, vm => vm.TunShowWindow, v => v.togShowWindow.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnabledLog, v => v.togEnabledLog.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunCustomTemplate, v => v.txtCustomTemplate.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunBypassMode, v => v.togBypassMode.IsChecked).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.TunBypassMode, v => v.gridTunModeDirect.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.TunBypassMode2, v => v.gridTunModeProxy.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunDirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunProxyIP, v => v.txtProxyIP.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunProxyProcess, v => v.txtProxyProcess.Text).DisposeWith(disposables);
|
||||
|
||||
|
||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
|
||||
@@ -124,6 +206,13 @@ namespace v2rayN.Views
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
private void btnBrowse_Click(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
var openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
|
||||
openFileDialog1.Filter = "tunConfig|*.json|All|*.*";
|
||||
openFileDialog1.ShowDialog();
|
||||
|
||||
txtCustomTemplate.Text = openFileDialog1.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300"
|
||||
mc:Ignorable="d">
|
||||
<Grid Margin="16">
|
||||
<Grid Margin="30">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -13,7 +14,10 @@
|
||||
Height="700"
|
||||
x:TypeArguments="vms:RoutingRuleDetailsViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -62,7 +66,8 @@
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left" />
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -77,6 +82,7 @@
|
||||
Grid.Column="1"
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
|
||||
|
||||
<TextBlock
|
||||
@@ -91,6 +97,7 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="4"
|
||||
FontSize="{DynamicResource StdFontSize}"
|
||||
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
|
||||
|
||||
<TextBlock
|
||||
@@ -140,7 +147,7 @@
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center">
|
||||
<CheckBox x:Name="chkAutoSort">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbAutoSort}" />
|
||||
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.TbAutoSort}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Button
|
||||
@@ -169,10 +176,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="0"
|
||||
Header="Domain"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtDomain"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
@@ -180,10 +188,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="2"
|
||||
Header="IP"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtIP"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace v2rayN.Views
|
||||
public RoutingRuleDetailsWindow(RulesItem rulesItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
this.Loaded += Window_Loaded;
|
||||
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
||||
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.Views.RoutingRuleSettingWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -13,7 +14,10 @@
|
||||
Height="700"
|
||||
x:TypeArguments="vms:RoutingRuleSettingViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -89,6 +93,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
@@ -111,6 +116,7 @@
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
@@ -143,6 +149,7 @@
|
||||
Margin="4"
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
@@ -160,6 +167,7 @@
|
||||
Margin="4"
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="btnBrowse"
|
||||
@@ -171,6 +179,23 @@
|
||||
Content="{x:Static resx:ResUI.TbBrowse}"
|
||||
Style="{StaticResource DefButton}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="4"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.LvSort}" />
|
||||
<TextBox
|
||||
x:Name="txtSort"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<TabControl x:Name="tabAdvanced">
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace v2rayN.Views
|
||||
public RoutingRuleSettingWindow(RoutingItem routingItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
this.Loaded += Window_Loaded;
|
||||
this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
|
||||
lstRules.SelectionChanged += lstRules_SelectionChanged;
|
||||
@@ -33,6 +34,7 @@ namespace v2rayN.Views
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.domainStrategy, v => v.cmbdomainStrategy.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.url, v => v.txtUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.customIcon, v => v.txtCustomIcon.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.sort, v => v.txtSort.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.RuleAddCmd, v => v.menuRuleAdd).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ImportRulesFromFileCmd, v => v.menuImportRulesFromFile).DisposeWith(disposables);
|
||||
@@ -75,15 +77,15 @@ namespace v2rayN.Views
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Top);
|
||||
}
|
||||
else if (e.Key == Key.B)
|
||||
else if (e.Key == Key.U)
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Up);
|
||||
}
|
||||
else if (e.Key == Key.U)
|
||||
else if (e.Key == Key.D)
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Down);
|
||||
}
|
||||
else if (e.Key == Key.D)
|
||||
else if (e.Key == Key.B)
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Bottom);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.Views.RoutingSettingWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -13,7 +14,10 @@
|
||||
Height="700"
|
||||
x:TypeArguments="vms:RoutingSettingViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -194,15 +198,19 @@
|
||||
Binding="{Binding remarks}"
|
||||
Header="{x:Static resx:ResUI.LvAlias}" />
|
||||
<DataGridTextColumn
|
||||
Width="70"
|
||||
Width="60"
|
||||
Binding="{Binding ruleNum}"
|
||||
Header="{x:Static resx:ResUI.LvCount}" />
|
||||
<DataGridTextColumn
|
||||
Width="280"
|
||||
Width="60"
|
||||
Binding="{Binding sort}"
|
||||
Header="{x:Static resx:ResUI.LvSort}" />
|
||||
<DataGridTextColumn
|
||||
Width="260"
|
||||
Binding="{Binding url}"
|
||||
Header="{x:Static resx:ResUI.LvUrl}" />
|
||||
<DataGridTextColumn
|
||||
Width="280"
|
||||
Width="260"
|
||||
Binding="{Binding customIcon}"
|
||||
Header="{x:Static resx:ResUI.LvCustomIcon}" />
|
||||
</DataGrid.Columns>
|
||||
@@ -221,10 +229,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="0"
|
||||
Header="Domain"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtProxyDomain"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
@@ -232,10 +241,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="2"
|
||||
Header="IP"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtProxyIP"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
@@ -252,10 +262,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="0"
|
||||
Header="Domain"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtDirectDomain"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
@@ -263,10 +274,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="2"
|
||||
Header="IP"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtDirectIP"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
@@ -283,10 +295,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="0"
|
||||
Header="Domain"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtBlockDomain"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
@@ -294,10 +307,11 @@
|
||||
<GroupBox
|
||||
Grid.Column="2"
|
||||
Header="IP"
|
||||
Style="{StaticResource MaterialDesignGroupBox}">
|
||||
Style="{StaticResource MyGroupBox}">
|
||||
<TextBox
|
||||
Name="txtBlockIP"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalScrollBarVisibility="Auto" />
|
||||
</GroupBox>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using v2rayN.Mode;
|
||||
using v2rayN.ViewModels;
|
||||
@@ -11,6 +12,8 @@ namespace v2rayN.Views
|
||||
public RoutingSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
this.Closing += RoutingSettingWindow_Closing;
|
||||
this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown;
|
||||
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;
|
||||
lstRoutings.MouseDoubleClick += LstRoutings_MouseDoubleClick;
|
||||
@@ -61,6 +64,14 @@ namespace v2rayN.Views
|
||||
});
|
||||
}
|
||||
|
||||
private void RoutingSettingWindow_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (ViewModel?.IsModified == true)
|
||||
{
|
||||
this.DialogResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void RoutingSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.Views.SubEditWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -13,7 +14,10 @@
|
||||
Height="550"
|
||||
x:TypeArguments="vms:SubEditViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
@@ -66,7 +70,7 @@
|
||||
Margin="4"
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||
Style="{StaticResource MyOutlinedTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
@@ -85,7 +89,7 @@
|
||||
VerticalAlignment="Top"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||
Style="{StaticResource MyOutlinedTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
@@ -117,7 +121,7 @@
|
||||
VerticalAlignment="Top"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||
Style="{StaticResource MyOutlinedTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
@@ -136,7 +140,7 @@
|
||||
VerticalAlignment="Top"
|
||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
@@ -153,7 +157,7 @@
|
||||
Margin="4"
|
||||
VerticalAlignment="Top"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource MaterialDesignOutlinedTextBox}" />
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
|
||||
</Grid>
|
||||
<Grid
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace v2rayN.Views
|
||||
public SubEditWindow(SubItem subItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
this.Loaded += Window_Loaded;
|
||||
|
||||
ViewModel = new SubEditViewModel(subItem, this);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="v2rayN.Views.SubSettingWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -13,7 +14,10 @@
|
||||
Height="600"
|
||||
x:TypeArguments="vms:SubSettingViewModel"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextOptions.TextFormattingMode="Display"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using ReactiveUI;
|
||||
using System.ComponentModel;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using v2rayN.ViewModels;
|
||||
|
||||
@@ -10,8 +12,10 @@ namespace v2rayN.Views
|
||||
public SubSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
|
||||
ViewModel = new SubSettingViewModel(this);
|
||||
this.Closing += SubSettingWindow_Closing;
|
||||
lstSubscription.MouseDoubleClick += LstSubscription_MouseDoubleClick;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
@@ -27,6 +31,14 @@ namespace v2rayN.Views
|
||||
});
|
||||
}
|
||||
|
||||
private void SubSettingWindow_Closing(object? sender, CancelEventArgs e)
|
||||
{
|
||||
if (ViewModel?.IsModified == true)
|
||||
{
|
||||
this.DialogResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void LstSubscription_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
ViewModel?.EditSub(false);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -9,11 +10,12 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ApplicationIcon>v2rayN.ico</ApplicationIcon>
|
||||
<Copyright>Copyright © 2017-2023 (GPLv3)</Copyright>
|
||||
<FileVersion>6.1</FileVersion>
|
||||
<FileVersion>6.13</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaterialDesignThemes" Version="4.6.1" />
|
||||
<PackageReference Include="Downloader" Version="3.0.3" />
|
||||
<PackageReference Include="MaterialDesignThemes" Version="4.7.1" />
|
||||
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="NHotkey" Version="2.1.0" />
|
||||
@@ -25,7 +27,7 @@
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="18.4.1" />
|
||||
<PackageReference Include="ReactiveUI.Validation" Version="3.0.22" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="18.4.1" />
|
||||
<PackageReference Include="Splat.NLog" Version="14.6.1" />
|
||||
<PackageReference Include="Splat.NLog" Version="14.6.8" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -99,6 +101,9 @@
|
||||
<EmbeddedResource Update="Resx\ResUI.fa-Ir.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resx\ResUI.ru.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user