Compare commits

...

131 Commits
6.6 ... 6.15

Author SHA1 Message Date
2dust
69050bfe41 up 6.15 2023-03-04 08:52:03 +08:00
2dust
eebc16bcdd Minimize windows when auto-hide is enabled 2023-03-04 08:51:29 +08:00
2dust
d4921535f2 Add lock for db 2023-03-04 08:43:44 +08:00
2dust
b1eeb648a7 Adjust style for icon 2023-03-04 08:36:57 +08:00
2dust
285f91e9e8 bug fixes 2023-03-03 10:45:09 +08:00
2dust
947a7aa7df Modify blacklist rules 2023-03-03 10:15:39 +08:00
2dust
0b37e36036 Merge pull request #3382 from hvvvvvvv/master
解决全局热键不能录制Alt组合键的问题
2023-03-01 09:18:04 +08:00
2dust
92320f5086 Merge pull request #3380 from qiopgh/master
为tun做dns分流
2023-03-01 09:17:52 +08:00
chao wan
ae17e0c264 解决全局热键不能录制Alt组合键的问题 2023-02-28 23:32:58 +08:00
qiopgh
ec756ee943 Update tun_singbox_dns
为tun做dns分流
2023-02-28 22:08:15 +08:00
2dust
b0ff814753 Adjust Running Server ToolTipText 2023-02-28 20:37:45 +08:00
2dust
1f7eb2d48a Optimizing reload core 2023-02-28 20:23:15 +08:00
2dust
eeab8e4a90 Setting tab 2023-02-27 13:26:08 +08:00
2dust
77fbddf488 Improve subscription update without proxy 2023-02-27 13:25:45 +08:00
2dust
bf396f8802 Merge pull request #3370 from hxdhttk/hxdhttk/trayToolTip
Add tray tool tip for the current running server.
2023-02-27 13:04:05 +08:00
Minghao Hu
13cb8b84bf Add tray tool tip for running server. 2023-02-27 11:30:54 +08:00
2dust
3ab992f5fb Merge pull request #3340 from ShiinaRinne/patch-2
Update OptionSettingWindow.xaml
2023-02-24 21:06:27 +08:00
2dust
a386ecfc9c Merge pull request #3336 from ShiinaRinne/patch-1
Update MainWindow.xaml
2023-02-24 21:05:42 +08:00
ShiinaRinne
a71399c42c Update OptionSettingWindow.xaml
调整option页宽度,设置说明自动换行
2023-02-24 15:00:19 +08:00
ShiinaRinne
5a5d7e0981 Update MainWindow.xaml
确保popupbox在点击功能后不会自动关闭,方便测试或多次调整看效果
2023-02-24 12:32:32 +08:00
2dust
b663a7f52a up 6.14 2023-02-24 11:55:32 +08:00
2dust
7390039086 adjust move up and down menu 2023-02-24 11:27:06 +08:00
2dust
12af02435f header sort memory 2023-02-24 11:13:13 +08:00
2dust
6f357828b7 Update SysProxyHandle.cs 2023-02-24 11:11:33 +08:00
2dust
09e1a4386d fix pac bug 2023-02-24 11:11:01 +08:00
2dust
dcc8e6dc34 Add subscription id memory 2023-02-21 20:43:32 +08:00
2dust
1b19ef54e4 Add Tun mode DNS settings 2023-02-21 20:42:55 +08:00
2dust
8ce476caf1 Optimizing sorting storage 2023-02-20 20:15:08 +08:00
2dust
dd2d9133eb Merge pull request #3323 from ilyfairy/master
commit
2023-02-20 19:56:33 +08:00
小仙女
2147d12ac8 update 2023-02-20 18:16:30 +08:00
2dust
22641a1da0 Merge pull request #3315 from ilyfairy/master
修复了一些问题
2023-02-19 20:23:38 +08:00
小仙女
2bd4088d40 使用==替代string.Equals 2023-02-19 19:15:02 +08:00
小仙女
ee61363c31 update 2023-02-19 19:06:35 +08:00
小仙女
8285688ec9 fix: 当过滤器是无效的正则时, 会输出大量异常日志 2023-02-19 18:51:08 +08:00
2dust
4eb076540e Merge pull request #3311 from ilyfairy/master
Update v2rayUpgrade
2023-02-19 16:22:53 +08:00
小仙女
527bfec24c Update v2rayUpgrade 2023-02-19 16:16:10 +08:00
2dust
2fff7d7160 Update TunHandler.cs 2023-02-19 16:09:31 +08:00
2dust
aac2b4aaf0 up 6.13 2023-02-19 15:44:52 +08:00
2dust
fe070b306f Merge pull request #3309 from ilyfairy/master
改为可空类型, 简化代码
2023-02-19 15:33:25 +08:00
2dust
ecfadf8a23 Merge branch 'master' into master 2023-02-19 15:23:04 +08:00
2dust
653af71596 Add log switch in tun mode 2023-02-19 14:55:44 +08:00
小仙女
6a89be2e89 简化代码 2023-02-19 13:34:22 +08:00
小仙女
b84bad4e1a 改为可空类型 2023-02-19 12:18:08 +08:00
2dust
0f8d86f081 Refactoring sorting and delayed storage 2023-02-19 11:23:45 +08:00
2dust
d44f311ba1 Refactoring sorting and delayed storage 2023-02-19 10:43:42 +08:00
2dust
6f5428ca61 Merge pull request #3306 from Weltolk/master
语句更通顺
2023-02-19 09:59:47 +08:00
2dust
b0bee3ca1a Merge pull request #3305 from ilyfairy/master
优化, 改成使用语法糖
2023-02-19 09:59:30 +08:00
2dust
7908194d27 Merge pull request #3301 from meaqese/add-russian-language
full-russian-support
2023-02-18 20:07:57 +08:00
小仙女
b27c7fb2dd string.Join的第二个参数(List<string>)改成ToArray 2023-02-17 22:06:17 +08:00
小仙女
a23cb95a10 性能优化 2023-02-17 15:17:01 +08:00
小仙女
fc137f9b1c 语句更通顺 2023-02-17 15:09:26 +08:00
Weltolk
84780bf9ef Update ResUI.zh-Hans.resx 2023-02-17 14:39:59 +08:00
小仙女
1321037c52 优化, 改成使用语法糖 2023-02-17 14:36:28 +08:00
meaqese
de1da12d45 full-russian-support 2023-02-17 03:18:41 +03:00
2dust
6d4cbacd50 GenerateSatelliteAssembliesForCore 2023-02-15 20:48:56 +08:00
2dust
bf9f7ca990 Adjust the group style 2023-02-15 20:47:17 +08:00
2dust
ca334104d7 bug fixes 2023-02-15 20:37:51 +08:00
2dust
c3e00ba31b bug fixes 2023-02-15 20:37:27 +08:00
2dust
ea3a9cc70e ShowInTaskbar = false 2023-02-15 20:36:50 +08:00
2dust
7ad22e0a73 up 6.12 2023-02-12 20:54:41 +08:00
2dust
ca1abb58eb Add subscription update multiple update function 2023-02-12 20:42:10 +08:00
2dust
3e353944b2 Update App.xaml 2023-02-12 20:41:06 +08:00
2dust
007a250f55 up 6.11 2023-02-12 08:54:23 +08:00
2dust
e9bb6a9951 bug fixes 2023-02-12 08:53:28 +08:00
2dust
82f236e07b up 6.10 2023-02-11 20:03:54 +08:00
2dust
17bfe74ecf Add routing sort 2023-02-11 19:34:15 +08:00
2dust
b77827df90 Update v2rayN.csproj 2023-02-10 21:02:41 +08:00
2dust
a359a508ae fix Import old config 2023-02-10 21:02:29 +08:00
2dust
3a740118f0 Adjust task service settings 2023-02-10 18:58:20 +08:00
2dust
58d9bcbd14 tidy code github 2023-02-10 16:25:16 +08:00
2dust
24be7b2180 store msg filter 2023-02-10 16:01:47 +08:00
2dust
f4c9ca8dff Refactor routing basic settings 2023-02-10 14:51:00 +08:00
2dust
9b8181b72b Refactor gui settings 2023-02-10 14:36:37 +08:00
2dust
1ff1962425 Refactor basic settings 2023-02-10 14:16:59 +08:00
2dust
9b05736746 Add environment variables to geo files 2023-02-10 11:22:03 +08:00
2dust
dec722e693 Update UpdateHandle.cs 2023-02-10 11:05:11 +08:00
2dust
49fa0a4c67 DownloadStringAsyncOri 2023-02-10 11:04:57 +08:00
2dust
0cdc69e1e8 Update MsgView.xaml 2023-02-10 09:39:18 +08:00
2dust
0494cc4ce7 adjust group style 2023-02-09 16:43:50 +08:00
2dust
30d82947d6 fix 2023-02-09 15:17:52 +08:00
2dust
ec59249d79 Optimize file download 2023-02-09 14:54:54 +08:00
2dust
7eb869ab1d Optimize file download 2023-02-09 10:54:31 +08:00
2dust
d014724a2d Optimize speed test 2023-02-08 19:20:44 +08:00
2dust
dfb6cef364 Update OptionSettingWindow.xaml.cs 2023-02-08 15:07:23 +08:00
2dust
0ebf8c9349 Optimize Font size 2023-02-07 19:05:49 +08:00
2dust
9dfd89c90d up 6.9 2023-02-06 19:28:43 +08:00
2dust
f6972125cd Update tun_singbox 2023-02-06 19:19:36 +08:00
2dust
6e366bf55a Improved enhanced tun mode 2023-02-06 15:29:10 +08:00
2dust
5e2e45c673 Merge branch 'master' of https://github.com/2dust/v2rayN 2023-02-05 20:17:07 +08:00
2dust
f879235564 fix get Win32FamilyNames 2023-02-05 20:17:03 +08:00
2dust
b00aee2ae7 Merge pull request #3187 from saphirique/patch-1
Add russian language
2023-02-05 19:57:08 +08:00
saphirique
28c2159ec3 add russian language 2023-02-05 17:55:24 +08:00
2dust
33dcef2285 Optimize Update Subscription 2023-02-04 18:52:17 +08:00
2dust
b9acd0ec28 Font size custom 2023-02-04 15:43:49 +08:00
2dust
7989d5180b adjust style 2023-02-04 14:25:21 +08:00
2dust
238086942e change fonts folder 2023-02-04 12:50:38 +08:00
2dust
a704a30242 up 6.8 2023-02-03 20:03:21 +08:00
2dust
26dd0d0ea5 add more PresetFingerprints 2023-02-03 09:45:21 +08:00
2dust
e31a4bcaa9 share link to add fingerprint 2023-02-03 09:39:39 +08:00
2dust
1722dc570b Modified the tun mode configuration template 2023-02-03 08:59:28 +08:00
2dust
3575e69b43 Tun mode can be auto turned on at startup 2023-02-02 16:27:35 +08:00
2dust
373d89874c Add custom font settings 2023-02-02 13:51:58 +08:00
2dust
976087ce97 Merge pull request #3165 from DanielBlackBeard/master
add more Farsi Translation
2023-02-02 10:51:21 +08:00
2dust
69a45788ee Merge pull request #3154 from mojpangr26/dev
增加自定义UA
2023-02-02 10:51:03 +08:00
mojpangr26
92e4de12fb 修改可编辑cmb
增加提示
2023-02-02 09:41:23 +08:00
Persian Prince
ea7fdb9b3d add more Farsi Translation 2023-02-01 21:40:26 +03:30
mojpangr26
fe1c043b8e 自定义UA 2023-02-01 17:07:36 +08:00
2dust
146f597a0b Fix the problem after clicking to sort and drag 2023-02-01 15:23:17 +08:00
2dust
d2bef312ce Add default fingerprint settings 2023-02-01 11:24:45 +08:00
2dust
61f297215d Optimize remove server 2023-02-01 11:08:05 +08:00
2dust
639a9fd540 Add test completion prompt 2023-02-01 10:06:19 +08:00
2dust
3d0428c518 add info filter the preset value 2023-02-01 09:53:37 +08:00
2dust
f40f926ce1 up 6.7 2023-01-31 19:24:55 +08:00
2dust
d6db4f0e4c Add double-click server as active parameter 2023-01-31 16:08:26 +08:00
2dust
fcbc9471aa add edit server menu 2023-01-31 14:33:17 +08:00
2dust
b147e05794 bug fix 2023-01-31 14:13:25 +08:00
2dust
47e6eb546d Optimize speed test info 2023-01-31 14:05:31 +08:00
2dust
8ba05cb4ed Replace the font with Source Han Sans CN 2023-01-31 13:34:32 +08:00
2dust
84b91e9649 Fix activity node display 2023-01-31 13:25:52 +08:00
2dust
703e17478d fix speed test url 2023-01-31 12:55:19 +08:00
2dust
8584e15c32 Optimize Sort as delay 2023-01-30 15:30:48 +08:00
2dust
46be7aadab Add refresh switch to information window 2023-01-30 14:44:49 +08:00
2dust
a5871f6cba memory log window size 2023-01-30 14:06:18 +08:00
2dust
917dc1803c Optimize custom configuration 2023-01-30 13:16:48 +08:00
2dust
c0c0961b2b Increase list line spacing 2023-01-30 12:30:04 +08:00
2dust
0995ac6f9a fix rules setting key 2023-01-30 12:27:41 +08:00
2dust
b7f40e4cbf Increase the Margin of qrcode 2023-01-30 11:18:01 +08:00
2dust
754cbb9eaa fix allowInsecure bug 2023-01-30 09:53:04 +08:00
2dust
7052b56069 Optimize font 2023-01-30 09:36:27 +08:00
2dust
decdee825b Merge pull request #3107 from buiawpkgew1/patch-1
修改hysteria 官网
2023-01-28 16:08:44 +08:00
菾凴
5f66afc399 修改hysteria 官网
https://github.com/2dust/v2rayN/issues/3094
2023-01-20 21:44:54 +08:00
78 changed files with 4893 additions and 2065 deletions

View File

@@ -20,14 +20,8 @@ public class PacHandler
public static void Start(string configPath, int httpPort, int pacPort) public static void Start(string configPath, int httpPort, int pacPort)
{ {
if (configPath.Equals(_configPath) _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
&& httpPort.Equals(_httpPort)
&& pacPort.Equals(_pacPort)
&& _isRunning)
{
_needRestart = false;
}
_configPath = configPath; _configPath = configPath;
_httpPort = httpPort; _httpPort = httpPort;
_pacPort = pacPort; _pacPort = pacPort;

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.App" x:Class="v2rayN.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:local="clr-namespace:v2rayN" xmlns:local="clr-namespace:v2rayN"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
ShutdownMode="OnExplicitShutdown" ShutdownMode="OnExplicitShutdown"
@@ -16,6 +17,10 @@
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<system:Double x:Key="MenuItemHeight">26</system:Double> <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 <Thickness
x:Key="ServerItemMargin" x:Key="ServerItemMargin"
Bottom="4" Bottom="4"
@@ -32,19 +37,19 @@
x:Key="ModuleTitle" x:Key="ModuleTitle"
BasedOn="{StaticResource MaterialDesignTextBlock}" BasedOn="{StaticResource MaterialDesignTextBlock}"
TargetType="{x:Type TextBlock}"> TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="16" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize2}" />
</Style> </Style>
<Style <Style
x:Key="ToolbarTextBlock" x:Key="ToolbarTextBlock"
BasedOn="{StaticResource MaterialDesignTextBlock}" BasedOn="{StaticResource MaterialDesignTextBlock}"
TargetType="{x:Type TextBlock}"> TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style> </Style>
<Style <Style
x:Key="StatusbarItem" x:Key="StatusbarItem"
BasedOn="{StaticResource MaterialDesignTextBlock}" BasedOn="{StaticResource MaterialDesignTextBlock}"
TargetType="{x:Type TextBlock}"> TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Setter Property="Padding" Value="0" /> <Setter Property="Padding" Value="0" />
</Style> </Style>
<Style TargetType="{x:Type TextElement}"> <Style TargetType="{x:Type TextElement}">
@@ -57,7 +62,7 @@
</Style> </Style>
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}"> <Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
<Setter Property="Height" Value="20" /> <Setter Property="Height" Value="20" />
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Style.Triggers> <Style.Triggers>
<Trigger Property="IsSelected" Value="true"> <Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" /> <Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
@@ -75,44 +80,69 @@
x:Key="ListItemCheckBox" x:Key="ListItemCheckBox"
BasedOn="{StaticResource MaterialDesignUserForegroundCheckBox}" BasedOn="{StaticResource MaterialDesignUserForegroundCheckBox}"
TargetType="{x:Type CheckBox}"> TargetType="{x:Type CheckBox}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style>
<Style x:Key="ListItemChip" TargetType="{x:Type materialDesign:Chip}">
<Setter Property="FontSize" Value="11" />
</Style> </Style>
<Style <Style
x:Key="DefButton" x:Key="DefButton"
BasedOn="{StaticResource MaterialDesignRaisedButton}" BasedOn="{StaticResource MaterialDesignRaisedButton}"
TargetType="{x:Type ButtonBase}"> TargetType="{x:Type ButtonBase}">
<Setter Property="FontSize" Value="14" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
</Style> </Style>
<Style <Style
x:Key="DefContextMenu" x:Key="DefContextMenu"
BasedOn="{StaticResource MaterialDesignContextMenu}" BasedOn="{StaticResource MaterialDesignContextMenu}"
TargetType="{x:Type ContextMenu}"> 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>
<Style <Style
x:Key="ToolbarMenu" x:Key="ToolbarMenu"
BasedOn="{StaticResource MaterialDesignMenu}" BasedOn="{StaticResource MaterialDesignMenu}"
TargetType="{x:Type Menu}"> 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>
<Style <Style
x:Key="DefComboBox" x:Key="DefComboBox"
BasedOn="{StaticResource MaterialDesignComboBox}" BasedOn="{StaticResource MaterialDesignComboBox}"
TargetType="{x:Type ComboBox}"> TargetType="{x:Type ComboBox}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="HorizontalAlignment" Value="Left" />
</Style> </Style>
<Style <Style
x:Key="DefDataGrid" x:Key="DefDataGrid"
BasedOn="{StaticResource MaterialDesignDataGrid}" BasedOn="{StaticResource MaterialDesignDataGrid}"
TargetType="{x:Type DataGrid}"> TargetType="{x:Type DataGrid}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style> </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> </ResourceDictionary>
</Application.Resources> </Application.Resources>

View 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 value.Error;
}
};
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("......");
using var stream = 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;
}
}
}

View File

@@ -1,6 +1,7 @@
using System.IO; using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Mime;
using System.Text;
namespace v2rayN.Base namespace v2rayN.Base
{ {
@@ -8,208 +9,149 @@ namespace v2rayN.Base
/// </summary> /// </summary>
public class HttpClientHelper public class HttpClientHelper
{ {
private static HttpClientHelper httpClientHelper = null; private readonly static Lazy<HttpClientHelper> _instance = new(() =>
private HttpClient httpClient;
/// <summary>
/// </summary>
private HttpClientHelper() { }
/// <summary>
/// </summary>
/// <returns></returns>
public static HttpClientHelper GetInstance()
{ {
if (httpClientHelper != null) HttpClientHandler handler = new() { UseCookies = false };
{ HttpClientHelper helper = new(new HttpClient(handler));
return httpClientHelper; return helper;
} });
else public static HttpClientHelper Instance => _instance.Value;
{ private readonly HttpClient httpClient;
HttpClientHelper httpClientHelper = new HttpClientHelper();
HttpClientHandler handler = new HttpClientHandler() { UseCookies = false }; private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
httpClientHelper.httpClient = new HttpClient(handler);
return httpClientHelper; public async Task<string?> GetAsync(string url)
} {
if (string.IsNullOrEmpty(url)) return null;
return await httpClient.GetStringAsync(url);
} }
public async Task<string> GetAsync(string url)
{
if (string.IsNullOrEmpty(url))
{
return null;
}
HttpResponseMessage response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync(); public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
}
public async Task<string> GetAsync(HttpClient client, string url, CancellationToken token)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrWhiteSpace(url)) return null;
{ return await client.GetStringAsync(url, token);
return null;
}
HttpResponseMessage response = await client.GetAsync(url, token);
if (!response.IsSuccessStatusCode)
{
throw new Exception(string.Format("{0}", response.StatusCode));
}
return await response.Content.ReadAsStringAsync();
} }
public async Task PutAsync(string url, Dictionary<string, string> headers) public async Task PutAsync(string url, Dictionary<string, string> headers)
{ {
var myContent = Utils.ToJson(headers); var jsonContent = Utils.ToJson(headers);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent); var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = await httpClient.PutAsync(url, byteContent); var result = await httpClient.PutAsync(url, content);
} }
public async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double> progress, CancellationToken token) public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
{ {
if (string.IsNullOrEmpty(url)) ArgumentNullException.ThrowIfNull(url);
{ ArgumentNullException.ThrowIfNull(fileName);
throw new ArgumentNullException("url"); if (File.Exists(fileName)) File.Delete(fileName);
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("fileName");
}
if (File.Exists(fileName))
{
File.Delete(fileName);
}
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString());
{
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; 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 progressPercentage = 0;
while (true)
{ {
using (var file = File.Create(fileName)) token.ThrowIfCancellationRequested();
var read = await stream.ReadAsync(buffer, token);
totalRead += read;
if (read == 0) break;
file.Write(buffer, 0, read);
if (canReportProgress)
{ {
var totalRead = 0L; var percent = (int)(100.0 * totalRead / total);
var buffer = new byte[1024 * 1024]; //if (progressPercentage != percent && percent % 10 == 0)
var isMoreToRead = true;
var progressPercentage = 0;
do
{ {
token.ThrowIfCancellationRequested(); progressPercentage = percent;
progress!.Report(percent);
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
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);
} }
} }
} }
if (canReportProgress)
{
progress!.Report(101);
}
} }
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token) public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
{ {
throw new ArgumentNullException("url"); throw new ArgumentNullException(nameof(url));
} }
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
throw new Exception(string.Format("{0}", response.StatusCode)); throw new Exception(response.StatusCode.ToString());
} }
//var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L; //var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
//var canReportProgress = total != -1 && progress != null; //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; if (token.IsCancellationRequested)
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 (totalRead > 0)
{ {
if (totalRead > 0) return;
{
return;
}
else
{
token.ThrowIfCancellationRequested();
}
}
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
if (read == 0)
{
isMoreToRead = false;
} }
else else
{ {
var data = new byte[read]; token.ThrowIfCancellationRequested();
buffer.ToList().CopyTo(0, data, 0, read); }
}
// TODO: var read = await stream.ReadAsync(buffer, token);
totalRead += read;
TimeSpan ts = (DateTime.Now - totalDatetime); if (read == 0)
if (progress != null && ts.Seconds > totalSecond) {
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; progressSpeed = speed;
var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0"); progress.Report(speed);
if (progressSpeed != speed)
{
progressSpeed = speed;
progress.Report(speed);
}
} }
} }
} while (isMoreToRead); }
} } while (isMoreToRead);
} }
} }

View File

@@ -0,0 +1,10 @@
using System.Windows.Controls;
namespace v2rayN.Base
{
internal class MyDGTextColumn : DataGridTextColumn
{
public string ExName { get; set; }
}
}

View File

@@ -6,11 +6,12 @@ namespace v2rayN.Base
{ {
public sealed class SqliteHelper 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; public static SqliteHelper Instance => _instance.Value;
private string _connstr; private string _connstr;
public SQLiteConnection _db; private SQLiteConnection _db;
public SQLiteAsyncConnection _dbAsync; private SQLiteAsyncConnection _dbAsync;
private static readonly object objLock = new();
public SqliteHelper() public SqliteHelper()
{ {
@@ -34,7 +35,10 @@ namespace v2rayN.Base
} }
public int Replace(object model) public int Replace(object model)
{ {
return _db.InsertOrReplace(model); lock (objLock)
{
return _db.InsertOrReplace(model);
}
} }
public async Task<int> Replacesync(object model) public async Task<int> Replacesync(object model)
{ {
@@ -43,7 +47,10 @@ namespace v2rayN.Base
public int Update(object model) public int Update(object model)
{ {
return _db.Update(model); lock (objLock)
{
return _db.Update(model);
}
} }
public async Task<int> UpdateAsync(object model) public async Task<int> UpdateAsync(object model)
{ {
@@ -51,12 +58,18 @@ namespace v2rayN.Base
} }
public int UpdateAll(IEnumerable models) public int UpdateAll(IEnumerable models)
{ {
return _db.UpdateAll(models); lock (objLock)
{
return _db.UpdateAll(models);
}
} }
public int Delete(object model) public int Delete(object model)
{ {
return _db.Delete(model); lock (objLock)
{
return _db.Delete(model);
}
} }
public async Task<int> DeleteAsync(object model) public async Task<int> DeleteAsync(object model)
{ {

View File

@@ -1,15 +1,16 @@
using System.IO; using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace v2rayN.Base namespace v2rayN.Base
{ {
static class StringEx static class StringEx
{ {
public static bool IsNullOrEmpty(this string value) public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{ {
return string.IsNullOrEmpty(value); return string.IsNullOrEmpty(value);
} }
public static bool IsNullOrWhiteSpace(this string value) public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
{ {
return string.IsNullOrWhiteSpace(value); return string.IsNullOrWhiteSpace(value);
} }
@@ -34,7 +35,7 @@ namespace v2rayN.Base
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader) public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
{ {
string line; string? line;
while ((line = reader.ReadLine()) != null) while ((line = reader.ReadLine()) != null)
{ {
if (line.IsWhiteSpace()) continue; if (line.IsWhiteSpace()) continue;
@@ -42,7 +43,7 @@ namespace v2rayN.Base
} }
} }
public static string TrimEx(this string value) public static string TrimEx(this string? value)
{ {
return value == null ? string.Empty : value.Trim(); return value == null ? string.Empty : value.Trim();
} }

View File

@@ -17,7 +17,7 @@ namespace v2rayN.Converters
return new SolidColorBrush(Colors.IndianRed); 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; return null;
} }

View 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");
}
}
}

View File

@@ -3,6 +3,8 @@
class Global class Global
{ {
#region const #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 v2rayWebsiteUrl = @"https://www.v2fly.org/";
public const string AboutUrl = @"https://github.com/2dust/v2rayN"; public const string AboutUrl = @"https://github.com/2dust/v2rayN";
public const string UpdateUrl = AboutUrl + @"/releases"; public const string UpdateUrl = AboutUrl + @"/releases";
@@ -12,12 +14,11 @@
public const string NUrl = @"https://github.com/2dust/v2rayN/releases"; public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
public const string clashCoreUrl = "https://github.com/Dreamacro/clash/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 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 naiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/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 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 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 SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"; public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
@@ -32,6 +33,7 @@
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_"; public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound"; public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound";
public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox"; public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox";
public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
public const string DefaultSecurity = "auto"; public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp"; public const string DefaultNetwork = "tcp";
@@ -77,40 +79,51 @@
public const string CommandClearMsg = "CommandClearMsg"; public const string CommandClearMsg = "CommandClearMsg";
public const string DelayUnit = ""; public const string DelayUnit = "";
public const string SpeedUnit = ""; 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}", "{ip}:{http_port}",
"socks={ip}:{socks_port}", "socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={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}", "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> vmessSecuritys = new() { "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> ssSecuritys = new() { "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> 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 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> 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 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> 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 List<string> { "tcp", "kcp", "ws", "h2", "quic", "grpc" }; public static readonly List<string> networks = new() { "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> kcpHeaderTypes = new() { "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> coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
public static readonly List<string> domainStrategys = new List<string> { "AsIs", "IPIfNonMatch", "IPOnDemand" }; public static readonly List<string> domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
public static readonly List<string> domainMatchers = new List<string> { "linear", "mph", "" }; public static readonly List<string> domainMatchers = new() { "linear", "mph", "" };
public static readonly List<string> fingerprints = new List<string> { "chrome", "firefox", "safari", "randomized", "" }; public static readonly List<string> fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
public static readonly List<string> allowInsecures = new List<string> { "true", "false", "" }; public static readonly List<string> userAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
public static readonly List<string> domainStrategy4Freedoms = new List<string> { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" }; public static readonly Dictionary<string, string> userAgentTxt = new()
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", "" }; {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
public static readonly List<string> LogLevel = new List<string> { "debug", "info", "warning", "error", "none" }; {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
public static readonly List<string> InboundTags = new List<string> { "socks", "http", "socks2", "http2" }; {"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" },
public static readonly List<string> Protocols = new List<string> { "http", "tls", "bittorrent" }; {"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" },
public static readonly List<string> TunMtus = new List<string> { "9000", "1500" }; {"none",""}
public static readonly List<string> TunStacks = new List<string> { "gvisor", "system" }; };
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 #endregion
#region global variable #region global variable
public static bool reloadCore { get; set; }
public static int statePort { get; set; } public static int statePort { get; set; }
public static Job processJob { get; set; } public static Job processJob { get; set; }
public static bool ShowInTaskbar { get; set; } public static bool ShowInTaskbar { get; set; }

View File

@@ -13,7 +13,7 @@ namespace v2rayN.Handler
class ConfigHandler class ConfigHandler
{ {
private static string configRes = Global.ConfigFileName; private static string configRes = Global.ConfigFileName;
private static readonly object objLock = new object(); private static readonly object objLock = new();
#region ConfigHandler #region ConfigHandler
@@ -43,18 +43,17 @@ namespace v2rayN.Handler
if (config == null) if (config == null)
{ {
config = new Config config = new Config
{
};
}
if (config.coreBasicItem == null)
{
config.coreBasicItem = new()
{ {
logEnabled = false, logEnabled = false,
loglevel = "warning", loglevel = "warning",
//Mux
muxEnabled = false, muxEnabled = false,
enableStatistics = false,
statisticsFreshRate = 1,
enableRoutingAdvanced = true
}; };
} }
@@ -62,7 +61,7 @@ namespace v2rayN.Handler
if (config.inbound == null) if (config.inbound == null)
{ {
config.inbound = new List<InItem>(); config.inbound = new List<InItem>();
InItem inItem = new InItem InItem inItem = new()
{ {
protocol = Global.InboundSocks, protocol = Global.InboundSocks,
localPort = 10808, localPort = 10808,
@@ -87,10 +86,17 @@ namespace v2rayN.Handler
config.inbound[0].protocol = Global.InboundSocks; config.inbound[0].protocol = Global.InboundSocks;
} }
} }
//路由规则 if (config.routingBasicItem == null)
if (Utils.IsNullOrEmpty(config.domainStrategy))
{ {
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)) //if (Utils.IsNullOrEmpty(config.domainMatcher))
//{ //{
@@ -130,6 +136,14 @@ namespace v2rayN.Handler
mtu = 9000, mtu = 9000,
}; };
} }
if (config.guiItem == null)
{
config.guiItem = new()
{
enableStatistics = false,
statisticsFreshRate = 1,
};
}
if (config.uiItem == null) if (config.uiItem == null)
{ {
config.uiItem = new UIItem() config.uiItem = new UIItem()
@@ -137,9 +151,9 @@ namespace v2rayN.Handler
enableAutoAdjustMainLvColWidth = true enableAutoAdjustMainLvColWidth = true
}; };
} }
if (config.uiItem.mainLvColWidth == null) if (config.uiItem.mainColumnItem == null)
{ {
config.uiItem.mainLvColWidth = new Dictionary<string, int>(); config.uiItem.mainColumnItem = new();
} }
if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage)) if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage))
{ {
@@ -150,14 +164,6 @@ namespace v2rayN.Handler
{ {
config.constItem = new ConstItem(); 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)) if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions))
{ {
config.constItem.defIEProxyExceptions = Global.IEProxyExceptions; config.constItem.defIEProxyExceptions = Global.IEProxyExceptions;
@@ -167,22 +173,29 @@ namespace v2rayN.Handler
// config.remoteDNS = "1.1.1.1"; // 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 == null) if (config.guiItem.statisticsFreshRate is > 100 or < 1)
{ {
Global.reloadCore = false; config.guiItem.statisticsFreshRate = 1;
}
else
{
Global.reloadCore = true;
} }
LazyConfig.Instance.SetConfig(ref config); LazyConfig.Instance.SetConfig(config);
return 0; return 0;
} }
/// <summary> /// <summary>
@@ -192,7 +205,6 @@ namespace v2rayN.Handler
/// <returns></returns> /// <returns></returns>
public static int SaveConfig(ref Config config, bool reload = true) public static int SaveConfig(ref Config config, bool reload = true)
{ {
Global.reloadCore = reload;
ToJsonFile(config); ToJsonFile(config);
@@ -288,20 +300,45 @@ namespace v2rayN.Handler
} }
config = Utils.FromJson<Config>(Utils.ToJson(configOld)); config = Utils.FromJson<Config>(Utils.ToJson(configOld));
if (config.tunModeItem == null)
if (config.coreBasicItem == null)
{ {
config.tunModeItem = new TunModeItem config.coreBasicItem = new()
{ {
enableTun = false, logEnabled = configOld.logEnabled,
showWindow = true, loglevel = configOld.loglevel,
mtu = 9000, 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); GetDefaultServer(ref config);
GetDefaultRouting(ref config); GetDefaultRouting(ref config);
SaveConfig(ref config); SaveConfig(ref config);
LazyConfig.Instance.SetConfig(ref config); LoadConfig(ref config);
return 0; return 0;
} }
@@ -390,49 +427,48 @@ namespace v2rayN.Handler
/// <param name="config"></param> /// <param name="config"></param>
/// <param name="item"></param> /// <param name="item"></param>
/// <returns></returns> /// <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; return -1;
} }
config.indexId = item.indexId; config.indexId = indexId;
Global.reloadCore = true;
ToJsonFile(config); ToJsonFile(config);
return 0; 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)) if (lstProfile.Exists(t => t.indexId == config.indexId))
{ {
return 0; return 0;
} }
var allItems = LazyConfig.Instance.ProfileItemIndexs("");
if (SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.indexId == config.indexId).Count() > 0) if (allItems.Where(t => t == config.indexId).Any())
{ {
return 0; return 0;
} }
if (lstProfile.Count > 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; return -1;
} }
public static ProfileItem GetDefaultServer(ref Config config) public static ProfileItem? GetDefaultServer(ref Config config)
{ {
var item = LazyConfig.Instance.GetProfileItem(config.indexId); var item = LazyConfig.Instance.GetProfileItem(config.indexId);
if (item is null) if (item is null)
{ {
var item2 = SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(); var item2 = SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault();
SetDefaultServer(ref config, item2); SetDefaultServerIndex(ref config, item2?.indexId);
return item2; return item2;
} }
@@ -457,9 +493,10 @@ namespace v2rayN.Handler
for (int i = 0; i < lstProfile.Count; i++) 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) switch (eMove)
{ {
case EMove.Top: case EMove.Top:
@@ -468,7 +505,7 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[0].sort - 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
break; break;
} }
@@ -478,7 +515,7 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[index - 1].sort - 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
break; break;
} }
@@ -489,7 +526,7 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[index + 1].sort + 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
break; break;
} }
@@ -499,18 +536,16 @@ namespace v2rayN.Handler
{ {
return 0; return 0;
} }
lstProfile[index].sort = lstProfile[lstProfile.Count - 1].sort + 1; sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1;
break; break;
} }
case EMove.Position: case EMove.Position:
lstProfile[index].sort = pos * 10 + 1; sort = pos * 10 + 1;
break; break;
} }
SqliteHelper.Instance.UpdateAll(lstProfile); ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
return 0; return 0;
} }
@@ -638,7 +673,7 @@ namespace v2rayN.Handler
} }
if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
{ {
profileItem.allowInsecure = config.defAllowInsecure.ToString(); profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
} }
AddServerCommon(ref config, profileItem); AddServerCommon(ref config, profileItem);
@@ -647,14 +682,34 @@ namespace v2rayN.Handler
} }
public static int SortServers(ref Config config, string subId, EServerColName name, bool asc) public static int SortServers(ref Config config, string subId, string colName, bool asc)
{ {
var lstModel = LazyConfig.Instance.ProfileItems(subId, ""); var lstModel = LazyConfig.Instance.ProfileItems(subId, "");
var lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel)); if (lstModel.Count <= 0)
if (lstProfile.Count <= 0)
{ {
return -1; 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();
Enum.TryParse(colName, true, out EServerColName name);
var propertyName = string.Empty; var propertyName = string.Empty;
switch (name) switch (name)
{ {
@@ -665,10 +720,14 @@ namespace v2rayN.Handler
case EServerColName.security: case EServerColName.security:
case EServerColName.network: case EServerColName.network:
case EServerColName.streamSecurity: case EServerColName.streamSecurity:
case EServerColName.delay:
case EServerColName.speed:
propertyName = name.ToString(); propertyName = name.ToString();
break; break;
case EServerColName.delayVal:
propertyName = "delay";
break;
case EServerColName.speedVal:
propertyName = "speed";
break;
case EServerColName.subRemarks: case EServerColName.subRemarks:
propertyName = "subid"; propertyName = "subid";
break; break;
@@ -688,10 +747,30 @@ namespace v2rayN.Handler
} }
for (int i = 0; i < lstProfile.Count; i++) 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.delayVal)
{
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.speedVal)
{
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; return 0;
} }
@@ -723,9 +802,9 @@ namespace v2rayN.Handler
public static int DedupServerList(ref Config config, ref List<ProfileItem> lstProfile) public static int DedupServerList(ref Config config, ref List<ProfileItem> lstProfile)
{ {
List<ProfileItem> source = 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 if (!keepOlder) source.Reverse(); // Remove the early items first
foreach (ProfileItem item in source) foreach (ProfileItem item in source)
@@ -750,7 +829,7 @@ namespace v2rayN.Handler
profileItem.configVersion = 2; profileItem.configVersion = 2;
if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) 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)) if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network))
{ {
@@ -760,19 +839,11 @@ namespace v2rayN.Handler
if (Utils.IsNullOrEmpty(profileItem.indexId)) if (Utils.IsNullOrEmpty(profileItem.indexId))
{ {
profileItem.indexId = Utils.GetGUID(false); profileItem.indexId = Utils.GetGUID(false);
if (profileItem.sort <= 0) var maxSort = ProfileExHandler.Instance.GetMaxSort();
{ ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
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;
}
} }
else if (profileItem.indexId == config.indexId) else if (profileItem.indexId == config.indexId)
{ {
Global.reloadCore = true;
} }
if (SqliteHelper.Instance.Replace(profileItem) > 0) if (SqliteHelper.Instance.Replace(profileItem) > 0)
@@ -859,11 +930,11 @@ namespace v2rayN.Handler
} }
int countServers = 0; int countServers = 0;
var maxSort = 0; //var maxSort = 0;
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0) //if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
{ //{
maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort); // maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort);
} //}
string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray()); string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray());
foreach (string str in arrData) foreach (string str in arrData)
{ {
@@ -888,7 +959,7 @@ namespace v2rayN.Handler
var existItem = lstOriSub?.FirstOrDefault(t => CompareProfileItem(t, profileItem, true)); var existItem = lstOriSub?.FirstOrDefault(t => CompareProfileItem(t, profileItem, true));
if (existItem != null) if (existItem != null)
{ {
profileItem = existItem; profileItem.indexId = existItem.indexId;
} }
//filter //filter
if (!Utils.IsNullOrEmpty(subFilter)) if (!Utils.IsNullOrEmpty(subFilter))
@@ -901,7 +972,7 @@ namespace v2rayN.Handler
} }
profileItem.subid = subid; profileItem.subid = subid;
profileItem.isSub = isSub; profileItem.isSub = isSub;
profileItem.sort = maxSort + countServers + 1; //profileItem.sort = maxSort + countServers + 1;
if (profileItem.configType == EConfigType.VMess) if (profileItem.configType == EConfigType.VMess)
{ {
@@ -951,14 +1022,21 @@ namespace v2rayN.Handler
return -1; 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 //Is v2ray configuration
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData);
if (v2rayConfig != null if (v2rayConfig?.inbounds?.Count > 0
&& v2rayConfig.inbounds != null && v2rayConfig.outbounds?.Count > 0)
&& v2rayConfig.inbounds.Count > 0
&& v2rayConfig.outbounds != null
&& v2rayConfig.outbounds.Count > 0)
{ {
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData); File.WriteAllText(fileName, clipboardData);
@@ -968,9 +1046,7 @@ namespace v2rayN.Handler
profileItem.remarks = "v2ray_custom"; profileItem.remarks = "v2ray_custom";
} }
//Is Clash configuration //Is Clash configuration
else if (clipboardData.IndexOf("port") >= 0 else if (Containss(clipboardData, "port", "socks-port", "proxies"))
&& clipboardData.IndexOf("socks-port") >= 0
&& clipboardData.IndexOf("proxies") >= 0)
{ {
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml"); var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
File.WriteAllText(fileName, clipboardData); File.WriteAllText(fileName, clipboardData);
@@ -980,12 +1056,7 @@ namespace v2rayN.Handler
profileItem.remarks = "clash_custom"; profileItem.remarks = "clash_custom";
} }
//Is hysteria configuration //Is hysteria configuration
else if (clipboardData.IndexOf("server") >= 0 else if (Containss(clipboardData, "server", "up", "down", "listen", "<html>", "<body>"))
&& clipboardData.IndexOf("up") >= 0
&& clipboardData.IndexOf("down") >= 0
&& clipboardData.IndexOf("listen") >= 0
&& clipboardData.IndexOf("<html>") < 0
&& clipboardData.IndexOf("<body>") < 0)
{ {
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData); File.WriteAllText(fileName, clipboardData);
@@ -995,10 +1066,7 @@ namespace v2rayN.Handler
profileItem.remarks = "hysteria_custom"; profileItem.remarks = "hysteria_custom";
} }
//Is naiveproxy configuration //Is naiveproxy configuration
else if (clipboardData.IndexOf("listen") >= 0 else if (Containss(clipboardData, "listen", "proxy", "<html>", "<body>"))
&& clipboardData.IndexOf("proxy") >= 0
&& clipboardData.IndexOf("<html>") < 0
&& clipboardData.IndexOf("<body>") < 0)
{ {
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData); File.WriteAllText(fileName, clipboardData);
@@ -1022,7 +1090,7 @@ namespace v2rayN.Handler
{ {
RemoveServerViaSubid(ref config, subid, isSub); RemoveServerViaSubid(ref config, subid, isSub);
} }
if (isSub && lstOriSub != null && lstOriSub.Count == 1) if (isSub && lstOriSub?.Count == 1)
{ {
profileItem.indexId = lstOriSub[0].indexId; profileItem.indexId = lstOriSub[0].indexId;
} }
@@ -1059,16 +1127,16 @@ namespace v2rayN.Handler
//SsSIP008 //SsSIP008
var lstSsServer = Utils.FromJson<List<SsServer>>(clipboardData); var lstSsServer = Utils.FromJson<List<SsServer>>(clipboardData);
if (lstSsServer == null || lstSsServer.Count <= 0) if (lstSsServer?.Count <= 0)
{ {
var ssSIP008 = Utils.FromJson<SsSIP008>(clipboardData); var ssSIP008 = Utils.FromJson<SsSIP008>(clipboardData);
if (ssSIP008?.servers != null && ssSIP008.servers.Count > 0) if (ssSIP008?.servers?.Count > 0)
{ {
lstSsServer = ssSIP008.servers; lstSsServer = ssSIP008.servers;
} }
} }
if (lstSsServer != null && lstSsServer.Count > 0) if (lstSsServer?.Count > 0)
{ {
int counter = 0; int counter = 0;
foreach (var it in lstSsServer) foreach (var it in lstSsServer)
@@ -1098,7 +1166,7 @@ namespace v2rayN.Handler
public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub) 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)) if (isSub && !Utils.IsNullOrEmpty(subid))
{ {
lstOriSub = LazyConfig.Instance.ProfileItems(subid); lstOriSub = LazyConfig.Instance.ProfileItems(subid);
@@ -1143,7 +1211,7 @@ namespace v2rayN.Handler
return 0; return 0;
} }
SubItem subItem = new SubItem SubItem subItem = new()
{ {
id = string.Empty, id = string.Empty,
remarks = "import_sub", remarks = "import_sub",
@@ -1235,44 +1303,6 @@ namespace v2rayN.Handler
} }
#endregion #endregion
#region UI
public static int AddformMainLvColWidth(ref Config config, string name, int width)
{
if (config.uiItem.mainLvColWidth == null)
{
config.uiItem.mainLvColWidth = new Dictionary<string, int>();
}
if (config.uiItem.mainLvColWidth.ContainsKey(name))
{
config.uiItem.mainLvColWidth[name] = width;
}
else
{
config.uiItem.mainLvColWidth.Add(name, width);
}
ToJsonFile(config);
return 0;
}
public static int GetformMainLvColWidth(ref Config config, string name, int width)
{
if (config.uiItem.mainLvColWidth == null)
{
config.uiItem.mainLvColWidth = new Dictionary<string, int>();
}
if (config.uiItem.mainLvColWidth.ContainsKey(name))
{
return config.uiItem.mainLvColWidth[name];
}
else
{
return width;
}
}
#endregion
#region Routing #region Routing
public static int SaveRoutingItem(ref Config config, RoutingItem item) public static int SaveRoutingItem(ref Config config, RoutingItem item)
@@ -1415,18 +1445,16 @@ namespace v2rayN.Handler
{ {
if (SqliteHelper.Instance.Table<RoutingItem>().Where(t => t.id == routingItem.id).Count() > 0) 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;
ToJsonFile(config); ToJsonFile(config);
return 0; return 0;
} }
public static RoutingItem GetDefaultRouting(ref Config config) 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) if (item is null)
{ {
var item2 = SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(t => t.locked == false); var item2 = SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(t => t.locked == false);
@@ -1439,13 +1467,16 @@ namespace v2rayN.Handler
public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false) 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 //Bypass the mainland
var item2 = new RoutingItem() var item2 = new RoutingItem()
{ {
remarks = "绕过大陆(Whitelist)", remarks = "绕过大陆(Whitelist)",
url = string.Empty, url = string.Empty,
sort = maxSort + 1,
}; };
AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white")); AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
@@ -1454,6 +1485,7 @@ namespace v2rayN.Handler
{ {
remarks = "黑名单(Blacklist)", remarks = "黑名单(Blacklist)",
url = string.Empty, url = string.Empty,
sort = maxSort + 2,
}; };
AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black")); AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
@@ -1462,6 +1494,7 @@ namespace v2rayN.Handler
{ {
remarks = "全局(Global)", remarks = "全局(Global)",
url = string.Empty, url = string.Empty,
sort = maxSort + 3,
}; };
AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global")); AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));

View File

@@ -25,7 +25,7 @@ namespace v2rayN.Handler
/// <param name="msg"></param> /// <param name="msg"></param>
/// <param name="content"></param> /// <param name="content"></param>
/// <returns></returns> /// <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; content = string.Empty;
try try
@@ -43,7 +43,7 @@ namespace v2rayN.Handler
} }
else else
{ {
V2rayConfig v2rayConfig = null; V2rayConfig? v2rayConfig = null;
if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0) if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0)
{ {
return -1; return -1;
@@ -73,28 +73,29 @@ namespace v2rayN.Handler
{ {
if (blExport) if (blExport)
{ {
if (config.logEnabled) if (config.coreBasicItem.logEnabled)
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
} }
else else
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = "";
v2rayConfig.log.error = ""; v2rayConfig.log.error = "";
} }
} }
else else
{ {
if (config.logEnabled) if (config.coreBasicItem.logEnabled)
{ {
v2rayConfig.log.loglevel = config.loglevel; var dtNow = DateTime.Now;
v2rayConfig.log.access = Utils.GetLogPath(v2rayConfig.log.access); v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.error = Utils.GetLogPath(v2rayConfig.log.error); v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
} }
else else
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = "";
v2rayConfig.log.error = ""; v2rayConfig.log.error = "";
} }
@@ -113,11 +114,11 @@ namespace v2rayN.Handler
{ {
v2rayConfig.inbounds = new List<Inbounds>(); 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); v2rayConfig.inbounds.Add(inbound);
//http //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); v2rayConfig.inbounds.Add(inbound2);
if (config.inbound[0].allowLANConn) if (config.inbound[0].allowLANConn)
@@ -156,7 +157,7 @@ namespace v2rayN.Handler
return 0; 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); string result = Utils.GetEmbedText(Global.v2raySampleInbound);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
@@ -183,13 +184,12 @@ namespace v2rayN.Handler
{ {
try try
{ {
if (v2rayConfig.routing != null if (v2rayConfig.routing?.rules != null)
&& v2rayConfig.routing.rules != null)
{ {
v2rayConfig.routing.domainStrategy = config.domainStrategy; v2rayConfig.routing.domainStrategy = config.routingBasicItem.domainStrategy;
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.domainMatcher) ? null : config.domainMatcher; 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); var routing = ConfigHandler.GetDefaultRouting(ref config);
if (routing != null) if (routing != null)
@@ -240,25 +240,25 @@ namespace v2rayN.Handler
{ {
rules.port = null; rules.port = null;
} }
if (rules.domain != null && rules.domain.Count == 0) if (rules.domain?.Count == 0)
{ {
rules.domain = null; rules.domain = null;
} }
if (rules.ip != null && rules.ip.Count == 0) if (rules.ip?.Count == 0)
{ {
rules.ip = null; rules.ip = null;
} }
if (rules.protocol != null && rules.protocol.Count == 0) if (rules.protocol?.Count == 0)
{ {
rules.protocol = null; rules.protocol = null;
} }
if (rules.inboundTag != null && rules.inboundTag.Count == 0) if (rules.inboundTag?.Count == 0)
{ {
rules.inboundTag = null; rules.inboundTag = null;
} }
var hasDomainIp = false; var hasDomainIp = false;
if (rules.domain != null && rules.domain.Count > 0) if (rules.domain?.Count > 0)
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
it.ip = null; it.ip = null;
@@ -274,7 +274,7 @@ namespace v2rayN.Handler
v2rayConfig.routing.rules.Add(it); v2rayConfig.routing.rules.Add(it);
hasDomainIp = true; hasDomainIp = true;
} }
if (rules.ip != null && rules.ip.Count > 0) if (rules.ip?.Count > 0)
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
it.domain = null; it.domain = null;
@@ -285,8 +285,8 @@ namespace v2rayN.Handler
if (!hasDomainIp) if (!hasDomainIp)
{ {
if (!Utils.IsNullOrEmpty(rules.port) if (!Utils.IsNullOrEmpty(rules.port)
|| (rules.protocol != null && rules.protocol.Count > 0) || (rules.protocol?.Count > 0)
|| (rules.inboundTag != null && rules.inboundTag.Count > 0) || (rules.inboundTag?.Count > 0)
) )
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
@@ -347,8 +347,8 @@ namespace v2rayN.Handler
} }
//Mux //Mux
outbound.mux.enabled = config.muxEnabled; outbound.mux.enabled = config.coreBasicItem.muxEnabled;
outbound.mux.concurrency = config.muxEnabled ? 8 : -1; outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
boundStreamSettings(node, "out", outbound.streamSettings); boundStreamSettings(node, "out", outbound.streamSettings);
@@ -404,7 +404,7 @@ namespace v2rayN.Handler
if (!Utils.IsNullOrEmpty(node.security) if (!Utils.IsNullOrEmpty(node.security)
&& !Utils.IsNullOrEmpty(node.id)) && !Utils.IsNullOrEmpty(node.id))
{ {
SocksUsersItem socksUsersItem = new SocksUsersItem SocksUsersItem socksUsersItem = new()
{ {
user = node.security, user = node.security,
pass = node.id, pass = node.id,
@@ -451,8 +451,8 @@ namespace v2rayN.Handler
usersItem.encryption = node.security; usersItem.encryption = node.security;
//Mux //Mux
outbound.mux.enabled = config.muxEnabled; outbound.mux.enabled = config.coreBasicItem.muxEnabled;
outbound.mux.concurrency = config.muxEnabled ? 8 : -1; outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
boundStreamSettings(node, "out", outbound.streamSettings); boundStreamSettings(node, "out", outbound.streamSettings);
@@ -546,17 +546,29 @@ namespace v2rayN.Handler
streamSettings.network = node.GetNetwork(); streamSettings.network = node.GetNetwork();
string host = node.requestHost.TrimEx(); string host = node.requestHost.TrimEx();
string sni = node.sni; 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 tls
if (node.streamSecurity == Global.StreamSecurity) if (node.streamSecurity == Global.StreamSecurity)
{ {
streamSettings.security = node.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(), alpn = node.GetAlpn(),
fingerprint = node.fingerprint fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
}; };
if (!string.IsNullOrWhiteSpace(sni)) if (!string.IsNullOrWhiteSpace(sni))
{ {
@@ -574,11 +586,11 @@ namespace v2rayN.Handler
{ {
streamSettings.security = node.streamSecurity; 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(), alpn = node.GetAlpn(),
fingerprint = node.fingerprint fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
}; };
if (!string.IsNullOrWhiteSpace(sni)) if (!string.IsNullOrWhiteSpace(sni))
{ {
@@ -595,17 +607,17 @@ namespace v2rayN.Handler
switch (node.GetNetwork()) switch (node.GetNetwork())
{ {
case "kcp": case "kcp":
KcpSettings kcpSettings = new KcpSettings KcpSettings kcpSettings = new()
{ {
mtu = config.kcpItem.mtu, mtu = config.kcpItem.mtu,
tti = config.kcpItem.tti tti = config.kcpItem.tti
}; };
if (iobound.Equals("out")) if (iobound == "out")
{ {
kcpSettings.uplinkCapacity = config.kcpItem.uplinkCapacity; kcpSettings.uplinkCapacity = config.kcpItem.uplinkCapacity;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity; kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
} }
else if (iobound.Equals("in")) else if (iobound == "in")
{ {
kcpSettings.uplinkCapacity = config.kcpItem.downlinkCapacity; ; kcpSettings.uplinkCapacity = config.kcpItem.downlinkCapacity; ;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity; kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
@@ -631,22 +643,21 @@ namespace v2rayN.Handler
break; break;
//ws //ws
case "ws": case "ws":
WsSettings wsSettings = new WsSettings WsSettings wsSettings = new();
{ wsSettings.headers = new Headers();
};
string path = node.path; string path = node.path;
if (!string.IsNullOrWhiteSpace(host)) if (!string.IsNullOrWhiteSpace(host))
{ {
wsSettings.headers = new Headers wsSettings.headers.Host = host;
{
Host = host
};
} }
if (!string.IsNullOrWhiteSpace(path)) if (!string.IsNullOrWhiteSpace(path))
{ {
wsSettings.path = path; wsSettings.path = path;
} }
if (!string.IsNullOrWhiteSpace(useragent))
{
wsSettings.headers.UserAgent = useragent;
}
streamSettings.wsSettings = wsSettings; streamSettings.wsSettings = wsSettings;
//TlsSettings tlsSettings = new TlsSettings(); //TlsSettings tlsSettings = new TlsSettings();
@@ -659,7 +670,7 @@ namespace v2rayN.Handler
break; break;
//h2 //h2
case "h2": case "h2":
HttpSettings httpSettings = new HttpSettings(); HttpSettings httpSettings = new();
if (!string.IsNullOrWhiteSpace(host)) if (!string.IsNullOrWhiteSpace(host))
{ {
@@ -675,7 +686,7 @@ namespace v2rayN.Handler
break; break;
//quic //quic
case "quic": case "quic":
QuicSettings quicsettings = new QuicSettings QuicSettings quicsettings = new()
{ {
security = host, security = host,
key = node.path, key = node.path,
@@ -698,7 +709,7 @@ namespace v2rayN.Handler
} }
break; break;
case "grpc": case "grpc":
var grpcSettings = new GrpcSettings GrpcSettings grpcSettings = new()
{ {
serviceName = node.path, serviceName = node.path,
multiMode = (node.headerType == Global.GrpcmultiMode), multiMode = (node.headerType == Global.GrpcmultiMode),
@@ -712,9 +723,9 @@ namespace v2rayN.Handler
break; break;
default: default:
//tcp //tcp
if (node.headerType.Equals(Global.TcpHeaderHttp)) if (node.headerType == Global.TcpHeaderHttp)
{ {
TcpSettings tcpSettings = new TcpSettings TcpSettings tcpSettings = new()
{ {
header = new Header header = new Header
{ {
@@ -722,7 +733,7 @@ namespace v2rayN.Handler
} }
}; };
if (iobound.Equals("out")) if (iobound == "out")
{ {
//request Host //request Host
string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName); string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName);
@@ -730,7 +741,7 @@ namespace v2rayN.Handler
string host2 = string.Join("\",\"", arrHost); string host2 = string.Join("\",\"", arrHost);
request = request.Replace("$requestHost$", $"\"{host2}\""); request = request.Replace("$requestHost$", $"\"{host2}\"");
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost())); //request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost()));
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
//Path //Path
string pathHttp = @"/"; string pathHttp = @"/";
if (!Utils.IsNullOrEmpty(node.path)) if (!Utils.IsNullOrEmpty(node.path))
@@ -741,7 +752,7 @@ namespace v2rayN.Handler
request = request.Replace("$requestPath$", $"\"{pathHttp}\""); request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
tcpSettings.header.request = Utils.FromJson<object>(request); tcpSettings.header.request = Utils.FromJson<object>(request);
} }
else if (iobound.Equals("in")) else if (iobound == "in")
{ {
//string response = Utils.GetEmbedText(Global.v2raySampleHttpresponseFileName); //string response = Utils.GetEmbedText(Global.v2raySampleHttpresponseFileName);
//tcpSettings.header.response = Utils.FromJson<object>(response); //tcpSettings.header.response = Utils.FromJson<object>(response);
@@ -777,13 +788,13 @@ namespace v2rayN.Handler
} }
var obj = Utils.ParseJson(config.remoteDNS); var obj = Utils.ParseJson(config.remoteDNS);
if (obj != null && obj.ContainsKey("servers")) if (obj?.ContainsKey("servers") == true)
{ {
v2rayConfig.dns = obj; v2rayConfig.dns = obj;
} }
else else
{ {
List<string> servers = new List<string>(); List<string> servers = new();
string[] arrDNS = config.remoteDNS.Split(','); string[] arrDNS = config.remoteDNS.Split(',');
foreach (string str in arrDNS) foreach (string str in arrDNS)
@@ -809,12 +820,12 @@ namespace v2rayN.Handler
private static int statistic(Config config, ref V2rayConfig v2rayConfig) private static int statistic(Config config, ref V2rayConfig v2rayConfig)
{ {
if (config.enableStatistics) if (config.guiItem.enableStatistics)
{ {
string tag = Global.InboundAPITagName; string tag = Global.InboundAPITagName;
API apiObj = new API(); API apiObj = new();
Policy policyObj = new Policy(); Policy policyObj = new();
SystemPolicy policySystemSetting = new SystemPolicy(); SystemPolicy policySystemSetting = new();
string[] services = { "StatsService" }; string[] services = { "StatsService" };
@@ -831,8 +842,8 @@ namespace v2rayN.Handler
if (!v2rayConfig.inbounds.Exists(item => item.tag == tag)) if (!v2rayConfig.inbounds.Exists(item => item.tag == tag))
{ {
Inbounds apiInbound = new Inbounds(); Inbounds apiInbound = new();
Inboundsettings apiInboundSettings = new Inboundsettings(); Inboundsettings apiInboundSettings = new();
apiInbound.tag = tag; apiInbound.tag = tag;
apiInbound.listen = Global.Loopback; apiInbound.listen = Global.Loopback;
apiInbound.port = Global.statePort; apiInbound.port = Global.statePort;
@@ -844,7 +855,7 @@ namespace v2rayN.Handler
if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag)) if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag))
{ {
RulesItem apiRoutingRule = new RulesItem RulesItem apiRoutingRule = new()
{ {
inboundTag = new List<string> { tag }, inboundTag = new List<string> { tag },
outboundTag = tag, outboundTag = tag,
@@ -941,7 +952,7 @@ namespace v2rayN.Handler
return 0; 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 try
{ {
@@ -1018,7 +1029,7 @@ namespace v2rayN.Handler
return -1; return -1;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
@@ -1107,10 +1118,10 @@ namespace v2rayN.Handler
#region Import (export) client/server configuration #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; msg = string.Empty;
ProfileItem profileItem = new ProfileItem(); ProfileItem profileItem = new();
try try
{ {
@@ -1121,7 +1132,7 @@ namespace v2rayN.Handler
return null; return null;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -1159,30 +1170,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}"; profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp //tcp or kcp
if (outbound.streamSettings != null if (outbound.streamSettings?.network != null
&& outbound.streamSettings.network != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.network)) && !Utils.IsNullOrEmpty(outbound.streamSettings.network))
{ {
profileItem.network = outbound.streamSettings.network; profileItem.network = outbound.streamSettings.network;
} }
//tcp http //tcp http
if (outbound.streamSettings != null if (outbound.streamSettings?.tcpSettings?.header != null
&& outbound.streamSettings.tcpSettings != null
&& outbound.streamSettings.tcpSettings.header != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.tcpSettings.header.type)) && !Utils.IsNullOrEmpty(outbound.streamSettings.tcpSettings.header.type))
{ {
if (outbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) if (outbound.streamSettings.tcpSettings.header.type == Global.TcpHeaderHttp)
{ {
profileItem.headerType = outbound.streamSettings.tcpSettings.header.type; profileItem.headerType = outbound.streamSettings.tcpSettings.header.type;
string request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request); string? request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request)) if (!Utils.IsNullOrEmpty(request))
{ {
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request); V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null if (v2rayTcpRequest?.headers?.Host?.Count > 0)
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
{ {
profileItem.requestHost = v2rayTcpRequest.headers.Host[0]; profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
} }
@@ -1190,17 +1195,14 @@ namespace v2rayN.Handler
} }
} }
//kcp //kcp
if (outbound.streamSettings != null if (outbound?.streamSettings?.kcpSettings?.header != null
&& outbound.streamSettings.kcpSettings != null
&& outbound.streamSettings.kcpSettings.header != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type)) && !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type))
{ {
profileItem.headerType = outbound.streamSettings.kcpSettings.header.type; profileItem.headerType = outbound.streamSettings.kcpSettings.header.type;
} }
//ws //ws
if (outbound.streamSettings != null if (outbound?.streamSettings?.wsSettings != null)
&& outbound.streamSettings.wsSettings != null)
{ {
if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path)) if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path))
{ {
@@ -1214,24 +1216,20 @@ namespace v2rayN.Handler
} }
//h2 //h2
if (outbound.streamSettings != null if (outbound?.streamSettings?.httpSettings != null)
&& outbound.streamSettings.httpSettings != null)
{ {
if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path)) if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path))
{ {
profileItem.path = outbound.streamSettings.httpSettings.path; profileItem.path = outbound.streamSettings.httpSettings.path;
} }
if (outbound.streamSettings.httpSettings.host != null if (outbound.streamSettings.httpSettings.host?.Count > 0)
&& outbound.streamSettings.httpSettings.host.Count > 0)
{ {
profileItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host); profileItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host);
} }
} }
//tls //tls
if (outbound.streamSettings != null if (outbound?.streamSettings?.security == Global.StreamSecurity)
&& outbound.streamSettings.security != null
&& outbound.streamSettings.security == Global.StreamSecurity)
{ {
profileItem.streamSecurity = Global.StreamSecurity; profileItem.streamSecurity = Global.StreamSecurity;
} }
@@ -1246,21 +1244,21 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
public static ProfileItem ImportFromServerConfig(string fileName, out string msg) public static ProfileItem? ImportFromServerConfig(string fileName, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem(); ProfileItem profileItem = new();
try try
{ {
string result = Utils.LoadResource(fileName); string? result = Utils.LoadResource(fileName);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
msg = ResUI.FailedReadConfiguration; msg = ResUI.FailedReadConfiguration;
return null; return null;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -1297,30 +1295,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}"; profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp //tcp or kcp
if (inbound.streamSettings != null if (inbound.streamSettings?.network != null
&& inbound.streamSettings.network != null
&& !Utils.IsNullOrEmpty(inbound.streamSettings.network)) && !Utils.IsNullOrEmpty(inbound.streamSettings.network))
{ {
profileItem.network = inbound.streamSettings.network; profileItem.network = inbound.streamSettings.network;
} }
//tcp http //tcp http
if (inbound.streamSettings != null if (inbound.streamSettings?.tcpSettings?.header != null
&& inbound.streamSettings.tcpSettings != null
&& inbound.streamSettings.tcpSettings.header != null
&& !Utils.IsNullOrEmpty(inbound.streamSettings.tcpSettings.header.type)) && !Utils.IsNullOrEmpty(inbound.streamSettings.tcpSettings.header.type))
{ {
if (inbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) if (inbound.streamSettings.tcpSettings.header.type == Global.TcpHeaderHttp)
{ {
profileItem.headerType = inbound.streamSettings.tcpSettings.header.type; profileItem.headerType = inbound.streamSettings.tcpSettings.header.type;
string request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request); string? request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request)) if (!Utils.IsNullOrEmpty(request))
{ {
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request); V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null if (v2rayTcpRequest?.headers?.Host?.Count > 0)
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
{ {
profileItem.requestHost = v2rayTcpRequest.headers.Host[0]; profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
} }
@@ -1337,8 +1329,7 @@ namespace v2rayN.Handler
//} //}
//ws //ws
if (inbound.streamSettings != null if (inbound.streamSettings?.wsSettings != null)
&& inbound.streamSettings.wsSettings != null)
{ {
if (!Utils.IsNullOrEmpty(inbound.streamSettings.wsSettings.path)) if (!Utils.IsNullOrEmpty(inbound.streamSettings.wsSettings.path))
{ {
@@ -1352,24 +1343,20 @@ namespace v2rayN.Handler
} }
//h2 //h2
if (inbound.streamSettings != null if (inbound.streamSettings?.httpSettings != null)
&& inbound.streamSettings.httpSettings != null)
{ {
if (!Utils.IsNullOrEmpty(inbound.streamSettings.httpSettings.path)) if (!Utils.IsNullOrEmpty(inbound.streamSettings.httpSettings.path))
{ {
profileItem.path = inbound.streamSettings.httpSettings.path; profileItem.path = inbound.streamSettings.httpSettings.path;
} }
if (inbound.streamSettings.httpSettings.host != null if (inbound.streamSettings.httpSettings.host?.Count > 0)
&& inbound.streamSettings.httpSettings.host.Count > 0)
{ {
profileItem.requestHost = Utils.List2String(inbound.streamSettings.httpSettings.host); profileItem.requestHost = Utils.List2String(inbound.streamSettings.httpSettings.host);
} }
} }
//tls //tls
if (inbound.streamSettings != null if (inbound.streamSettings?.security == Global.StreamSecurity)
&& inbound.streamSettings.security != null
&& inbound.streamSettings.security == Global.StreamSecurity)
{ {
profileItem.streamSecurity = Global.StreamSecurity; profileItem.streamSecurity = Global.StreamSecurity;
} }
@@ -1385,7 +1372,7 @@ namespace v2rayN.Handler
public static int Export2ClientConfig(ProfileItem node, string fileName, out string msg) 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) if (GenerateClientConfigContent(node, true, ref v2rayConfig, out msg) != 0)
{ {
return -1; return -1;
@@ -1424,14 +1411,14 @@ namespace v2rayN.Handler
return ""; return "";
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
return ""; return "";
} }
List<IPEndPoint> lstIpEndPoints = new List<IPEndPoint>(); List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new List<TcpConnectionInformation>(); List<TcpConnectionInformation> lstTcpConns = new();
try try
{ {
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
@@ -1461,7 +1448,7 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (it.configType == EConfigType.VMess || it.configType == EConfigType.VLESS) if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{ {
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId); var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id)) if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
@@ -1474,11 +1461,11 @@ namespace v2rayN.Handler
var port = httpPort; var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++) for (int k = httpPort; k < Global.MaxPort; k++)
{ {
if (lstIpEndPoints != null && lstIpEndPoints.FindIndex(_it => _it.Port == k) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{ {
continue; continue;
} }
if (lstTcpConns != null && lstTcpConns.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0) if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{ {
continue; continue;
} }
@@ -1489,7 +1476,7 @@ namespace v2rayN.Handler
} }
//Port In Used //Port In Used
if (lstIpEndPoints != null && lstIpEndPoints.FindIndex(_it => _it.Port == port) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{ {
continue; continue;
} }
@@ -1497,7 +1484,7 @@ namespace v2rayN.Handler
it.allowTest = true; it.allowTest = true;
//inbound //inbound
Inbounds inbound = new Inbounds Inbounds inbound = new()
{ {
listen = Global.Loopback, listen = Global.Loopback,
port = port, port = port,
@@ -1507,7 +1494,7 @@ namespace v2rayN.Handler
v2rayConfig.inbounds.Add(inbound); v2rayConfig.inbounds.Add(inbound);
//outbound //outbound
V2rayConfig v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
var item = LazyConfig.Instance.GetProfileItem(it.indexId); var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null) if (item is null)
{ {
@@ -1524,7 +1511,7 @@ namespace v2rayN.Handler
v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]); v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]);
//rule //rule
RulesItem rule = new RulesItem RulesItem rule = new()
{ {
inboundTag = new List<string> { inbound.tag }, inboundTag = new List<string> { inbound.tag },
outboundTag = v2rayConfigCopy.outbounds[0].tag, outboundTag = v2rayConfigCopy.outbounds[0].tag,

View File

@@ -12,58 +12,58 @@ namespace v2rayN.Handler
class CoreHandler class CoreHandler
{ {
private static string _coreCConfigRes = Global.coreConfigFileName; private static string _coreCConfigRes = Global.coreConfigFileName;
private CoreInfo _coreInfo; private CoreInfo? _coreInfo;
private int _processId = 0; private int _processId = 0;
private Process _process; private Process? _process;
Action<bool, string> _updateFunc; Action<bool, string> _updateFunc;
public CoreHandler(Action<bool, string> update) public CoreHandler(Action<bool, string> update)
{ {
_updateFunc = 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) public void LoadCore(Config config)
{ {
if (Global.reloadCore) var node = ConfigHandler.GetDefaultServer(ref config);
if (node == null)
{ {
var node = ConfigHandler.GetDefaultServer(ref config); ShowMsg(false, ResUI.CheckServerSettings);
if (node == null) return;
{ }
ShowMsg(false, ResUI.CheckServerSettings);
return;
}
if (SetCore(config, node) != 0) if (SetCore(config, node) != 0)
{ {
ShowMsg(false, ResUI.CheckServerSettings); ShowMsg(false, ResUI.CheckServerSettings);
return; return;
} }
string fileName = Utils.GetConfigPath(_coreCConfigRes); string fileName = Utils.GetConfigPath(_coreCConfigRes);
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0) if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
} }
else else
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
ShowMsg(true, $"{node.GetSummary()}"); ShowMsg(true, $"{node.GetSummary()}");
CoreStop(); CoreStop();
CoreStart(node); CoreStart(node);
} }
//start a socks service //start a socks service
if (_process != null && !_process.HasExited && node.configType == EConfigType.Custom && node.preSocksPort > 0) if (_process != null && !_process.HasExited && node.configType == EConfigType.Custom && node.preSocksPort > 0)
{
var itemSocks = new ProfileItem()
{ {
var itemSocks = new ProfileItem() configType = EConfigType.Socks,
{ address = Global.Loopback,
configType = EConfigType.Socks, port = node.preSocksPort
address = Global.Loopback, };
port = node.preSocksPort if (CoreConfigHandler.GenerateClientConfig(itemSocks, null, out string msg2, out string configStr) == 0)
}; {
if (CoreConfigHandler.GenerateClientConfig(itemSocks, null, out string msg2, out string configStr) == 0) _processId = CoreStartViaString(configStr);
{
_processId = CoreStartViaString(configStr);
}
} }
} }
} }
@@ -105,7 +105,7 @@ namespace v2rayN.Handler
Process[] existing = Process.GetProcessesByName(vName); Process[] existing = Process.GetProcessesByName(vName);
foreach (Process p in existing) foreach (Process p in existing)
{ {
string path = p.MainModule.FileName; string? path = p.MainModule?.FileName;
if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe") if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe")
{ {
KillProcess(p); KillProcess(p);
@@ -170,7 +170,8 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(_coreInfo); string fileName = CoreFindexe(_coreInfo);
if (fileName == "") return; if (fileName == "") return;
Process p = new Process var displayLog = node.configType != EConfigType.Custom || node.displayLog;
Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -178,18 +179,18 @@ namespace v2rayN.Handler
Arguments = _coreInfo.arguments, Arguments = _coreInfo.arguments,
WorkingDirectory = Utils.GetConfigPath(), WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = node.displayLog, RedirectStandardOutput = displayLog,
RedirectStandardError = node.displayLog, RedirectStandardError = displayLog,
CreateNoWindow = true, CreateNoWindow = true,
StandardOutputEncoding = node.displayLog ? Encoding.UTF8 : null, StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = node.displayLog ? Encoding.UTF8 : null, StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
} }
}; };
if (node.displayLog) if (displayLog)
{ {
p.OutputDataReceived += (sender, e) => p.OutputDataReceived += (sender, e) =>
{ {
if (!String.IsNullOrEmpty(e.Data)) if (!string.IsNullOrEmpty(e.Data))
{ {
string msg = e.Data + Environment.NewLine; string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg); ShowMsg(false, msg);
@@ -197,7 +198,7 @@ namespace v2rayN.Handler
}; };
} }
p.Start(); p.Start();
if (node.displayLog) if (displayLog)
{ {
p.BeginOutputReadLine(); p.BeginOutputReadLine();
} }
@@ -205,7 +206,7 @@ namespace v2rayN.Handler
if (p.WaitForExit(1000)) 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); Global.processJob.AddProcess(p.Handle);
@@ -228,7 +229,7 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(coreInfo); string fileName = CoreFindexe(coreInfo);
if (fileName == "") return -1; if (fileName == "") return -1;
Process p = new Process Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {

View File

@@ -14,9 +14,9 @@ namespace v2rayN.Handler
/// </summary> /// </summary>
class DownloadHandle class DownloadHandle
{ {
public event EventHandler<ResultEventArgs> UpdateCompleted; public event EventHandler<ResultEventArgs>? UpdateCompleted;
public event ErrorEventHandler Error; public event ErrorEventHandler? Error;
public class ResultEventArgs : EventArgs 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) public async Task<int> DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action<bool, string> update)
{ {
var hasValue = false;
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = webProxy
});
var progress = new Progress<string>(); var progress = new Progress<string>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
{ {
hasValue = true;
if (update != null) if (update != null)
{ {
string msg = $"{value}"; string msg = $"{value}";
@@ -54,22 +47,17 @@ namespace v2rayN.Handler
} }
}; };
var cancellationToken = new CancellationTokenSource(); await DownloaderHelper.Instance.DownloadDataAsync4Speed(webProxy,
cancellationToken.CancelAfter(downloadTimeout * 1000);
await HttpClientHelper.GetInstance().DownloadDataAsync4Speed(client,
url, url,
progress, progress,
cancellationToken.Token); downloadTimeout);
} }
catch (Exception ex) catch (Exception ex)
{ {
if (!hasValue) update(false, ex.Message);
if (ex.InnerException != null)
{ {
update(false, ex.Message); update(false, ex.InnerException.Message);
if (ex.InnerException != null)
{
update(false, ex.InnerException.Message);
}
} }
} }
return 0; return 0;
@@ -79,30 +67,21 @@ namespace v2rayN.Handler
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading)); UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading));
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = GetWebProxy(blProxy)
});
var progress = new Progress<double>(); var progress = new Progress<double>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
{ {
if (UpdateCompleted != null) UpdateCompleted?.Invoke(this, new ResultEventArgs(value > 100, $"...{value}%"));
{
string msg = $"...{value}%";
UpdateCompleted(this, new ResultEventArgs(value > 100 ? true : false, msg));
}
}; };
var cancellationToken = new CancellationTokenSource(); var webProxy = GetWebProxy(blProxy);
_ = HttpClientHelper.GetInstance().DownloadFileAsync(client, _ = DownloaderHelper.Instance.DownloadFileAsync(webProxy,
url, url,
Utils.GetTempPath(Utils.GetDownloadFileName(url)), Utils.GetTempPath(Utils.GetDownloadFileName(url)),
progress, progress,
cancellationToken.Token); downloadTimeout);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -116,18 +95,18 @@ 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 var webRequestHandler = new SocketsHttpHandler
{ {
AllowAutoRedirect = false, AllowAutoRedirect = false,
Proxy = GetWebProxy(blProxy) Proxy = GetWebProxy(blProxy)
}; };
HttpClient client = new HttpClient(webRequestHandler); HttpClient client = new(webRequestHandler);
HttpResponseMessage response = await client.GetAsync(url); HttpResponseMessage response = await client.GetAsync(url);
if (response.StatusCode.ToString() == "Redirect") if (response.StatusCode == HttpStatusCode.Redirect && response.Headers.Location is not null)
{ {
return response.Headers.Location.ToString(); return response.Headers.Location.ToString();
} }
@@ -138,27 +117,91 @@ 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> /// <summary>
/// DownloadString /// DownloadString
/// </summary> /// </summary>
/// <param name="url"></param> /// <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 try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
var client = new HttpClient(new SocketsHttpHandler() var client = new HttpClient(new SocketsHttpHandler()
{ {
Proxy = GetWebProxy(blProxy) Proxy = webProxy,
UseProxy = webProxy != null
}); });
if (Utils.IsNullOrEmpty(userAgent)) if (Utils.IsNullOrEmpty(userAgent))
{ {
userAgent = $"{Utils.GetVersion(false)}"; userAgent = Utils.GetVersion(false);
} }
client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent); client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent);
Uri uri = new Uri(url); Uri uri = new(url);
//Authorization Header //Authorization Header
if (!Utils.IsNullOrEmpty(uri.UserInfo)) if (!Utils.IsNullOrEmpty(uri.UserInfo))
{ {
@@ -168,7 +211,7 @@ namespace v2rayN.Handler
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
cts.CancelAfter(1000 * 30); cts.CancelAfter(1000 * 30);
var result = await HttpClientHelper.GetInstance().GetAsync(client, url, cts.Token); var result = await HttpClientHelper.Instance.GetAsync(client, url, cts.Token);
return result; return result;
} }
catch (Exception ex) catch (Exception ex)
@@ -183,7 +226,39 @@ namespace v2rayN.Handler
return null; 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(IWebProxy? webProxy)
{ {
try try
{ {
@@ -195,7 +270,8 @@ namespace v2rayN.Handler
try 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); bool noError = Utils.IsNullOrEmpty(status);
return noError ? responseTime : -1; return noError ? responseTime : -1;
} }
@@ -212,7 +288,7 @@ namespace v2rayN.Handler
} }
} }
public string GetRealPingTime(string url, WebProxy webProxy, int downloadTimeout, out int responseTime) public string GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout, out int responseTime)
{ {
string msg = string.Empty; string msg = string.Empty;
responseTime = -1; responseTime = -1;
@@ -222,19 +298,14 @@ namespace v2rayN.Handler
myHttpWebRequest.Timeout = downloadTimeout * 1000; myHttpWebRequest.Timeout = downloadTimeout * 1000;
myHttpWebRequest.Proxy = webProxy; myHttpWebRequest.Proxy = webProxy;
Stopwatch timer = new Stopwatch(); Stopwatch timer = Stopwatch.StartNew();
timer.Start();
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); using HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
if (myHttpWebResponse.StatusCode != HttpStatusCode.OK if (myHttpWebResponse.StatusCode is not HttpStatusCode.OK and not HttpStatusCode.NoContent)
&& myHttpWebResponse.StatusCode != HttpStatusCode.NoContent)
{ {
msg = myHttpWebResponse.StatusDescription; msg = myHttpWebResponse.StatusDescription;
} }
timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = timer.Elapsed.Milliseconds;
myHttpWebResponse.Close();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -244,7 +315,7 @@ namespace v2rayN.Handler
return msg; return msg;
} }
private WebProxy GetWebProxy(bool blProxy) private WebProxy? GetWebProxy(bool blProxy)
{ {
if (!blProxy) if (!blProxy)
{ {
@@ -261,25 +332,17 @@ namespace v2rayN.Handler
private bool SocketCheck(string ip, int port) private bool SocketCheck(string ip, int port)
{ {
Socket sock = null;
try try
{ {
IPAddress ipa = IPAddress.Parse(ip); IPEndPoint point = new(IPAddress.Parse(ip), port);
IPEndPoint point = new IPEndPoint(ipa, port); using Socket? sock = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(point); sock.Connect(point);
return true; return true;
} }
catch { } catch (Exception)
finally
{ {
if (sock != null) return false;
{
sock.Close();
sock.Dispose();
}
} }
return false;
} }
} }
} }

View File

@@ -5,7 +5,7 @@ namespace v2rayN.Handler
{ {
public sealed class LazyConfig 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 Config _config;
private List<CoreInfo> coreInfos; private List<CoreInfo> coreInfos;
@@ -17,11 +17,12 @@ namespace v2rayN.Handler
SqliteHelper.Instance.CreateTable<ProfileItem>(); SqliteHelper.Instance.CreateTable<ProfileItem>();
SqliteHelper.Instance.CreateTable<ServerStatItem>(); SqliteHelper.Instance.CreateTable<ServerStatItem>();
SqliteHelper.Instance.CreateTable<RoutingItem>(); SqliteHelper.Instance.CreateTable<RoutingItem>();
SqliteHelper.Instance.CreateTable<ProfileExItem>();
} }
#region Config #region Config
public void SetConfig(ref Config config) public void SetConfig(Config config)
{ {
_config = config; _config = config;
} }
@@ -81,12 +82,23 @@ namespace v2rayN.Handler
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList(); 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) public List<ProfileItemModel> ProfileItems(string subid, string filter)
{ {
var sql = @$"select a.* var sql = @$"select a.*
,b.remarks subRemarks ,b.remarks subRemarks
,case when a.indexId = '{_config.indexId}' then true else false end isActive
from ProfileItem a from ProfileItem a
left join SubItem b on a.subid = b.id left join SubItem b on a.subid = b.id
where 1=1 "; where 1=1 ";
@@ -96,14 +108,17 @@ namespace v2rayN.Handler
} }
if (!Utils.IsNullOrEmpty(filter)) if (!Utils.IsNullOrEmpty(filter))
{ {
if (filter.Contains('\''))
{
filter = filter.Replace("'", "");
}
sql += $" and a.remarks like '%{filter}%'"; sql += $" and a.remarks like '%{filter}%'";
} }
sql += " order by a.sort";
return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList(); return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
} }
public ProfileItem GetProfileItem(string indexId) public ProfileItem? GetProfileItem(string indexId)
{ {
if (Utils.IsNullOrEmpty(indexId)) if (Utils.IsNullOrEmpty(indexId))
{ {
@@ -112,31 +127,9 @@ namespace v2rayN.Handler
return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId); 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<RoutingItem> RoutingItems() 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) public RoutingItem GetRoutingItem(string id)
{ {
@@ -163,7 +156,7 @@ namespace v2rayN.Handler
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType) public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
{ {
if (profileItem != null && profileItem.coreType != null) if (profileItem?.coreType != null)
{ {
return (ECoreType)profileItem.coreType; return (ECoreType)profileItem.coreType;
} }
@@ -180,16 +173,16 @@ namespace v2rayN.Handler
return item.coreType; return item.coreType;
} }
public CoreInfo GetCoreInfo(ECoreType coreType) public CoreInfo? GetCoreInfo(ECoreType coreType)
{ {
if (coreInfos == null) if (coreInfos == null)
{ {
InitCoreInfo(); InitCoreInfo();
} }
return coreInfos.Where(t => t.coreType == coreType).FirstOrDefault(); return coreInfos!.FirstOrDefault(t => t.coreType == coreType);
} }
public List<CoreInfo> GetCoreInfos() public List<CoreInfo>? GetCoreInfos()
{ {
if (coreInfos == null) if (coreInfos == null)
{ {
@@ -200,13 +193,13 @@ namespace v2rayN.Handler
private void InitCoreInfo() private void InitCoreInfo()
{ {
coreInfos = new List<CoreInfo>(); coreInfos = new(16);
coreInfos.Add(new CoreInfo coreInfos.Add(new CoreInfo
{ {
coreType = ECoreType.v2rayN, coreType = ECoreType.v2rayN,
coreUrl = Global.NUrl, 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", coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN.zip",
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip", coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
}); });
@@ -217,7 +210,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "wv2ray", "v2ray" }, coreExes = new List<string> { "wv2ray", "v2ray" },
arguments = "", arguments = "",
coreUrl = Global.v2flyCoreUrl, 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", coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
@@ -231,7 +224,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "SagerNet", "v2ray" }, coreExes = new List<string> { "SagerNet", "v2ray" },
arguments = "run", arguments = "run",
coreUrl = Global.SagerNetCoreUrl, 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", coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
@@ -245,7 +238,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "v2ray" }, coreExes = new List<string> { "v2ray" },
arguments = "run", arguments = "run",
coreUrl = Global.v2flyCoreUrl, 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", coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
@@ -259,7 +252,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "xray", "wxray" }, coreExes = new List<string> { "xray", "wxray" },
arguments = "", arguments = "",
coreUrl = Global.xrayCoreUrl, 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", coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
match = "Xray", match = "Xray",
@@ -273,7 +266,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" }, coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
arguments = "-f config.json", arguments = "-f config.json",
coreUrl = Global.clashCoreUrl, 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", coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip", coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip",
match = "v", match = "v",
@@ -287,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" }, coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
arguments = "-f config.json", arguments = "-f config.json",
coreUrl = Global.clashMetaCoreUrl, 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", coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip", coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip",
match = "v", match = "v",
@@ -301,7 +294,7 @@ namespace v2rayN.Handler
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
arguments = "", arguments = "",
coreUrl = Global.hysteriaCoreUrl, 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", coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe", coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
redirectInfo = true, redirectInfo = true,

View File

@@ -12,7 +12,7 @@ namespace v2rayN.Handler
{ {
public sealed class MainFormHandler 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; //Action<bool, string> _updateUI;
//private DownloadHandle downloadHandle2; //private DownloadHandle downloadHandle2;
@@ -42,19 +42,14 @@ namespace v2rayN.Handler
{ {
return new Icon(fileName); return new Icon(fileName);
} }
switch (index) return index switch
{ {
case 0: 0 => Properties.Resources.NotifyIcon1,
return Properties.Resources.NotifyIcon1; 1 => Properties.Resources.NotifyIcon2,
case 1: 2 => Properties.Resources.NotifyIcon3,
return Properties.Resources.NotifyIcon2; 3 => Properties.Resources.NotifyIcon2,
case 2: _ => Properties.Resources.NotifyIcon1, // default
return Properties.Resources.NotifyIcon3; };
case 3:
return Properties.Resources.NotifyIcon2;
}
return Properties.Resources.NotifyIcon1;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -82,11 +77,11 @@ namespace v2rayN.Handler
return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute)); return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute));
} }
private Icon GetNotifyIcon4Routing(Config config) private Icon? GetNotifyIcon4Routing(Config config)
{ {
try try
{ {
if (!config.enableRoutingAdvanced) if (!config.routingBasicItem.enableRoutingAdvanced)
{ {
return null; return null;
} }
@@ -107,9 +102,9 @@ namespace v2rayN.Handler
int width = 128; int width = 128;
int height = 128; int height = 128;
Bitmap bitmap = new Bitmap(width, height); Bitmap bitmap = new(width, height);
Graphics graphics = Graphics.FromImage(bitmap); Graphics graphics = Graphics.FromImage(bitmap);
SolidBrush drawBrush = new SolidBrush(color); SolidBrush drawBrush = new(color);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height)); //graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height));
@@ -143,7 +138,7 @@ namespace v2rayN.Handler
return; return;
} }
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
Filter = "Config|*.json", Filter = "Config|*.json",
FilterIndex = 2, FilterIndex = 2,
@@ -176,14 +171,13 @@ namespace v2rayN.Handler
{ {
return; return;
} }
if (item.configType != EConfigType.VMess if (item.configType is not EConfigType.VMess and not EConfigType.VLESS)
&& item.configType != EConfigType.VLESS)
{ {
UI.Show(ResUI.NonVmessService); UI.Show(ResUI.NonVmessService);
return; return;
} }
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
Filter = "Config|*.json", Filter = "Config|*.json",
FilterIndex = 2, FilterIndex = 2,
@@ -212,14 +206,14 @@ namespace v2rayN.Handler
public void BackupGuiNConfig(Config config, bool auto = false) 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) if (auto)
{ {
fileName = Utils.GetBackupPath(fileName); fileName = Utils.GetBackupPath(fileName);
} }
else else
{ {
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
FileName = fileName, FileName = fileName,
Filter = "guiNConfig|*.json", Filter = "guiNConfig|*.json",
@@ -254,7 +248,7 @@ namespace v2rayN.Handler
public bool RestoreGuiNConfig(ref Config config) public bool RestoreGuiNConfig(ref Config config)
{ {
var fileContent = string.Empty; var fileContent = string.Empty;
using (OpenFileDialog fileDialog = new OpenFileDialog()) using (OpenFileDialog fileDialog = new())
{ {
fileDialog.InitialDirectory = Utils.GetBackupPath(""); fileDialog.InitialDirectory = Utils.GetBackupPath("");
fileDialog.Filter = "guiNConfig|*.json|All|*.*"; fileDialog.Filter = "guiNConfig|*.json|All|*.*";
@@ -286,7 +280,7 @@ namespace v2rayN.Handler
BackupGuiNConfig(config, true); BackupGuiNConfig(config, true);
config = resConfig; config = resConfig;
LazyConfig.Instance.SetConfig(ref config); LazyConfig.Instance.SetConfig(config);
return true; return true;
} }
@@ -309,9 +303,9 @@ namespace v2rayN.Handler
{ {
var dtNow = DateTime.Now; 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) => updateHandle.UpdateSubscriptionProcess(config, "", true, (bool success, string msg) =>
{ {
@@ -324,9 +318,9 @@ namespace v2rayN.Handler
Thread.Sleep(60000); 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) => updateHandle.UpdateGeoFile("geosite", config, (bool success, string msg) =>
{ {
@@ -381,12 +375,12 @@ namespace v2rayN.Handler
try try
{ {
HotkeyManager.Current.AddOrReplace(((int)item.eGlobalHotkey).ToString(), gesture, handler); 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); update(false, msg);
} }
catch (Exception ex) 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); update(false, msg);
Utils.SaveLog(msg); Utils.SaveLog(msg);
} }

View File

@@ -0,0 +1,144 @@
using System.Collections.Concurrent;
using System.Reactive.Linq;
using v2rayN.Base;
using v2rayN.Mode;
namespace v2rayN.Handler
{
class ProfileExHandler
{
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx;
private Queue<string> _queIndexIds = new();
public ConcurrentBag<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 = new(SqliteHelper.Instance.Table<ProfileExItem>());
Task.Run(() =>
{
while (true)
{
var cnt = _queIndexIds.Count;
for (int i = 0; i < cnt; i++)
{
var id = _queIndexIds.Dequeue();
var item = _lstProfileEx.FirstOrDefault(t => t.indexId == id);
if (item is not null)
{
SqliteHelper.Instance.Replace(item);
}
}
Thread.Sleep(1000 * 60);
}
});
}
private void IndexIdEnqueue(string indexId)
{
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
{
_queIndexIds.Enqueue(indexId);
}
}
private void AddProfileEx(string indexId, ref ProfileExItem profileEx)
{
profileEx = new()
{
indexId = indexId,
delay = 0,
speed = 0,
sort = 0
};
_lstProfileEx.Add(profileEx);
IndexIdEnqueue(indexId);
}
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 void 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;
IndexIdEnqueue(indexId);
}
public void 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;
IndexIdEnqueue(indexId);
}
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;
IndexIdEnqueue(indexId);
}
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);
}
}
}

View File

@@ -10,16 +10,16 @@ namespace v2rayN.Handler
return SetProxy(null, null, 1); 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; int optionCount = 1;
if (type == 1) if (type == 1)
{ {
optionCount = 1; optionCount = 1;
} }
else if (type == 2 || type == 4) else if (type is 2 or 4)
{ {
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3; optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
} }
@@ -71,12 +71,12 @@ namespace v2rayN.Handler
{ {
if (Environment.Is64BitOperatingSystem) if (Environment.Is64BitOperatingSystem)
{ {
IntPtr opt = new IntPtr(optionsPtr.ToInt64() + (i * optSize)); IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
else else
{ {
IntPtr opt = new IntPtr(optionsPtr.ToInt32() + (i * optSize)); IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
} }
@@ -84,7 +84,7 @@ namespace v2rayN.Handler
list.options = optionsPtr; list.options = optionsPtr;
// and then make a pointer out of the whole list // and then make a pointer out of the whole list
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem((int)list.dwSize); IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize);
Marshal.StructureToPtr(list, ipcoListPtr, false); Marshal.StructureToPtr(list, ipcoListPtr, false);
// and finally, call the API method! // and finally, call the API method!
@@ -189,24 +189,21 @@ namespace v2rayN.Handler
//判断是否使用代理 //判断是否使用代理
public static bool UsedProxy() public static bool UsedProxy()
{ {
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);
if (rk.GetValue("ProxyEnable").ToString() == "1") if (rk?.GetValue("ProxyEnable")?.ToString() == "1")
{ {
rk.Close();
return true; return true;
} }
else else
{ {
rk.Close();
return false; return false;
} }
} }
//获得代理的IP和端口 //获得代理的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(); string ProxyServer = rk.GetValue("ProxyServer").ToString();
rk.Close();
return ProxyServer; return ProxyServer;
} }

View File

@@ -9,13 +9,13 @@ namespace v2rayN.Handler
/// </summary> /// </summary>
public class QRCodeHelper public class QRCodeHelper
{ {
public static DrawingImage GetQRCode(string strContent) public static DrawingImage? GetQRCode(string strContent)
{ {
try try
{ {
QRCodeGenerator qrGenerator = new QRCodeGenerator(); QRCodeGenerator qrGenerator = new();
QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H); QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H);
XamlQRCode qrCode = new XamlQRCode(qrCodeData); XamlQRCode qrCode = new(qrCodeData);
DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40); DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40);
return qrCodeAsXaml; return qrCodeAsXaml;
} }

View File

@@ -17,32 +17,22 @@ namespace v2rayN.Handler
/// </summary> /// </summary>
/// <param name="item"></param> /// <param name="item"></param>
/// <returns></returns> /// <returns></returns>
public static string GetShareUrl(ProfileItem item) public static string? GetShareUrl(ProfileItem item)
{ {
try try
{ {
string url = string.Empty; string? url = string.Empty;
switch (item.configType) url = item.configType switch
{ {
case EConfigType.VMess: EConfigType.VMess => ShareVmess(item),
url = ShareVmess(item); EConfigType.Shadowsocks => ShareShadowsocks(item),
break; EConfigType.Socks => ShareSocks(item),
case EConfigType.Shadowsocks: EConfigType.Trojan => ShareTrojan(item),
url = ShareShadowsocks(item); EConfigType.VLESS => ShareVLESS(item),
break; _ => null,
case EConfigType.Socks: };
url = ShareSocks(item);
break;
case EConfigType.Trojan:
url = ShareTrojan(item);
break;
case EConfigType.VLESS:
url = ShareVLESS(item);
break;
default:
break;
}
return url; return url;
} }
catch (Exception ex) catch (Exception ex)
@@ -56,7 +46,7 @@ namespace v2rayN.Handler
{ {
string url = string.Empty; string url = string.Empty;
VmessQRCode vmessQRCode = new VmessQRCode VmessQRCode vmessQRCode = new()
{ {
v = item.configVersion.ToString(), v = item.configVersion.ToString(),
ps = item.remarks.TrimEx(), //备注也许很长 ; ps = item.remarks.TrimEx(), //备注也许很长 ;
@@ -71,7 +61,8 @@ namespace v2rayN.Handler
path = item.path, path = item.path,
tls = item.streamSecurity, tls = item.streamSecurity,
sni = item.sni, sni = item.sni,
alpn = item.alpn alpn = item.alpn,
fp = item.fingerprint
}; };
url = Utils.ToJson(vmessQRCode); url = Utils.ToJson(vmessQRCode);
@@ -176,7 +167,7 @@ namespace v2rayN.Handler
return Utils.IsIpv6(address) ? $"[{address}]" : address; 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)) if (!Utils.IsNullOrEmpty(item.flow))
{ {
@@ -202,6 +193,10 @@ namespace v2rayN.Handler
{ {
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn)); 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"); dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : "tcp");
@@ -255,7 +250,7 @@ namespace v2rayN.Handler
if (!Utils.IsNullOrEmpty(item.path)) if (!Utils.IsNullOrEmpty(item.path))
{ {
dicQuery.Add("serviceName", Utils.UrlEncode(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)); dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
} }
@@ -273,13 +268,13 @@ namespace v2rayN.Handler
/// <summary> /// <summary>
/// 从剪贴板导入URL /// 从剪贴板导入URL
/// </summary> /// </summary>
/// <param name="fileName"></param>
/// <param name="msg"></param> /// <param name="msg"></param>
/// <returns></returns> /// <returns></returns>
public static ProfileItem ImportFromClipboardConfig(string clipboardData, out string msg) public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem();
ProfileItem profileItem = new();
try try
{ {
@@ -363,7 +358,7 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveVmess(string result, out string msg) private static ProfileItem? ResolveVmess(string result, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
var profileItem = new ProfileItem var profileItem = new ProfileItem
@@ -371,11 +366,11 @@ namespace v2rayN.Handler
configType = EConfigType.VMess configType = EConfigType.VMess
}; };
result = result.Substring(Global.vmessProtocol.Length); result = result[Global.vmessProtocol.Length..];
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
//转成Json //转成Json
VmessQRCode vmessQRCode = Utils.FromJson<VmessQRCode>(result); VmessQRCode? vmessQRCode = Utils.FromJson<VmessQRCode>(result);
if (vmessQRCode == null) if (vmessQRCode == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -408,21 +403,22 @@ namespace v2rayN.Handler
profileItem.streamSecurity = Utils.ToString(vmessQRCode.tls); profileItem.streamSecurity = Utils.ToString(vmessQRCode.tls);
profileItem.sni = Utils.ToString(vmessQRCode.sni); profileItem.sni = Utils.ToString(vmessQRCode.sni);
profileItem.alpn = Utils.ToString(vmessQRCode.alpn); profileItem.alpn = Utils.ToString(vmessQRCode.alpn);
profileItem.fingerprint = Utils.ToString(vmessQRCode.fp);
return profileItem; return profileItem;
} }
private static ProfileItem ResolveVmess4Kitsunebi(string result) private static ProfileItem? ResolveVmess4Kitsunebi(string result)
{ {
ProfileItem profileItem = new ProfileItem ProfileItem profileItem = new()
{ {
configType = EConfigType.VMess configType = EConfigType.VMess
}; };
result = result.Substring(Global.vmessProtocol.Length); result = result[Global.vmessProtocol.Length..];
int indexSplit = result.IndexOf("?"); int indexSplit = result.IndexOf("?");
if (indexSplit > 0) if (indexSplit > 0)
{ {
result = result.Substring(0, indexSplit); result = result[..indexSplit];
} }
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
@@ -433,7 +429,7 @@ namespace v2rayN.Handler
} }
string[] arr21 = arr1[0].Split(':'); string[] arr21 = arr1[0].Split(':');
string[] arr22 = arr1[1].Split(':'); string[] arr22 = arr1[1].Split(':');
if (arr21.Length != 2 || arr21.Length != 2) if (arr21.Length != 2 || arr22.Length != 2)
{ {
return null; return null;
} }
@@ -450,15 +446,15 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveStdVmess(string result) private static ProfileItem? ResolveStdVmess(string result)
{ {
ProfileItem i = new ProfileItem ProfileItem i = new()
{ {
configType = EConfigType.VMess, configType = EConfigType.VMess,
security = "auto" security = "auto"
}; };
Uri u = new Uri(result); Uri u = new(result);
i.address = u.IdnHost; i.address = u.IdnHost;
i.port = u.Port; i.port = u.Port;
@@ -531,7 +527,7 @@ namespace v2rayN.Handler
return i; return i;
} }
private static ProfileItem ResolveSip002(string result) private static ProfileItem? ResolveSip002(string result)
{ {
Uri parsedUrl; Uri parsedUrl;
try try
@@ -542,7 +538,7 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
ProfileItem server = new ProfileItem ProfileItem server = new()
{ {
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost, address = parsedUrl.IdnHost,
@@ -550,7 +546,7 @@ namespace v2rayN.Handler
}; };
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped); string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
//2022-blake3 //2022-blake3
if (rawUserInfo.Contains(":")) if (rawUserInfo.Contains(':'))
{ {
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2) if (userInfoParts.Length != 2)
@@ -594,16 +590,16 @@ namespace v2rayN.Handler
return server; return server;
} }
private static readonly Regex UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", 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 Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase); 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); var match = UrlFinder.Match(result);
if (!match.Success) if (!match.Success)
return null; return null;
ProfileItem server = new ProfileItem(); ProfileItem server = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/'); var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value; var tag = match.Groups["tag"].Value;
if (!Utils.IsNullOrEmpty(tag)) if (!Utils.IsNullOrEmpty(tag))
@@ -629,16 +625,16 @@ namespace v2rayN.Handler
} }
private static readonly Regex StdVmessUserInfo = new Regex( 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})$"); @"^(?<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 configType = EConfigType.Socks
}; };
result = result.Substring(Global.socksProtocol.Length); result = result[Global.socksProtocol.Length..];
//remark //remark
int indexRemark = result.IndexOf("#"); int indexRemark = result.IndexOf("#");
if (indexRemark > 0) if (indexRemark > 0)
@@ -648,7 +644,7 @@ namespace v2rayN.Handler
profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
} }
catch { } catch { }
result = result.Substring(0, indexRemark); result = result[..indexRemark];
} }
//part decode //part decode
int indexS = result.IndexOf("@"); int indexS = result.IndexOf("@");
@@ -672,15 +668,15 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
profileItem.address = arr1[1].Substring(0, indexPort); profileItem.address = arr1[1][..indexPort];
profileItem.port = Utils.ToInt(arr1[1].Substring(indexPort + 1, arr1[1].Length - (indexPort + 1))); profileItem.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
profileItem.security = arr21[0]; profileItem.security = arr21[0];
profileItem.id = arr21[1]; profileItem.id = arr21[1];
return profileItem; return profileItem;
} }
private static ProfileItem ResolveSocksNew(string result) private static ProfileItem? ResolveSocksNew(string result)
{ {
Uri parsedUrl; Uri parsedUrl;
try try
@@ -691,7 +687,7 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
ProfileItem server = new ProfileItem ProfileItem server = new()
{ {
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost, address = parsedUrl.IdnHost,
@@ -713,12 +709,12 @@ namespace v2rayN.Handler
private static ProfileItem ResolveTrojan(string result) private static ProfileItem ResolveTrojan(string result)
{ {
ProfileItem item = new ProfileItem ProfileItem item = new()
{ {
configType = EConfigType.Trojan configType = EConfigType.Trojan
}; };
Uri url = new Uri(result); Uri url = new(result);
item.address = url.IdnHost; item.address = url.IdnHost;
item.port = url.Port; item.port = url.Port;
@@ -732,13 +728,13 @@ namespace v2rayN.Handler
} }
private static ProfileItem ResolveStdVLESS(string result) private static ProfileItem ResolveStdVLESS(string result)
{ {
ProfileItem item = new ProfileItem ProfileItem item = new()
{ {
configType = EConfigType.VLESS, configType = EConfigType.VLESS,
security = "none" security = "none"
}; };
Uri url = new Uri(result); Uri url = new(result);
item.address = url.IdnHost; item.address = url.IdnHost;
item.port = url.Port; item.port = url.Port;
@@ -759,6 +755,7 @@ namespace v2rayN.Handler
item.streamSecurity = query["security"] ?? ""; item.streamSecurity = query["security"] ?? "";
item.sni = query["sni"] ?? ""; item.sni = query["sni"] ?? "";
item.alpn = Utils.UrlDecode(query["alpn"] ?? ""); item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
item.network = query["type"] ?? "tcp"; item.network = query["type"] ?? "tcp";
switch (item.network) switch (item.network)
{ {

View File

@@ -30,6 +30,14 @@ namespace v2rayN.Handler
_selecteds = new List<ServerTestItem>(); _selecteds = new List<ServerTestItem>();
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
if (it.configType == EConfigType.Custom)
{
continue;
}
if (it.port <= 0)
{
continue;
}
_selecteds.Add(new ServerTestItem() _selecteds.Add(new ServerTestItem()
{ {
indexId = it.indexId, indexId = it.indexId,
@@ -38,6 +46,29 @@ namespace v2rayN.Handler
configType = it.configType 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, "");
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
break;
case ESpeedActionType.Speedtest:
UpdateFunc(it.indexId, "", ResUI.Speedtesting);
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break;
case ESpeedActionType.Mixedtest:
UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.Speedtesting);
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break;
}
}
switch (actionType) switch (actionType)
{ {
case ESpeedActionType.Ping: case ESpeedActionType.Ping:
@@ -90,7 +121,7 @@ namespace v2rayN.Handler
long time = Ping(it.address); long time = Ping(it.address);
var output = FormatOut(time, Global.DelayUnit); var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
@@ -102,7 +133,7 @@ namespace v2rayN.Handler
int time = GetTcpingTime(it.address, it.port); int time = GetTcpingTime(it.address, it.port);
var output = FormatOut(time, Global.DelayUnit); var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
@@ -123,7 +154,7 @@ namespace v2rayN.Handler
DownloadHandle downloadHandle = new DownloadHandle(); DownloadHandle downloadHandle = new DownloadHandle();
//Thread.Sleep(5000); //Thread.Sleep(5000);
List<Task> tasks = new List<Task>(); List<Task> tasks = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (!it.allowTest) if (!it.allowTest)
@@ -138,12 +169,11 @@ namespace v2rayN.Handler
{ {
try 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); string output = GetRealPingTime(downloadHandle, webProxy);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
int.TryParse(output, out int delay); int.TryParse(output, out int delay);
it.delay = delay; it.delay = delay;
@@ -164,6 +194,7 @@ namespace v2rayN.Handler
finally finally
{ {
if (pid > 0) _coreHandler.CoreStopPid(pid); if (pid > 0) _coreHandler.CoreStopPid(pid);
ProfileExHandler.Instance.SaveTo();
} }
return Task.CompletedTask; return Task.CompletedTask;
@@ -172,10 +203,10 @@ namespace v2rayN.Handler
private async Task RunSpeedTestAsync() private async Task RunSpeedTestAsync()
{ {
int pid = -1; int pid = -1;
if (_actionType == ESpeedActionType.Mixedtest) //if (_actionType == ESpeedActionType.Mixedtest)
{ //{
_selecteds = _selecteds.OrderBy(t => t.delay).ToList(); // _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
} //}
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds); pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
if (pid < 0) if (pid < 0)
@@ -184,10 +215,11 @@ namespace v2rayN.Handler
return; return;
} }
string url = _config.constItem.speedTestUrl; string url = _config.speedTestItem.speedTestUrl;
DownloadHandle downloadHandle = new DownloadHandle(); var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new();
var timeout = 8;
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (!it.allowTest) if (!it.allowTest)
@@ -198,24 +230,24 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (it.delay < 0) //if (it.delay < 0)
{ //{
continue; // UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
} // continue;
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1"); //}
UpdateFunc(it.indexId, "", ResUI.Speedtesting); ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
var item = LazyConfig.Instance.GetProfileItem(it.indexId); var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null) continue; 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); decimal.TryParse(msg, out decimal dec);
if (dec > 0) if (dec > 0)
{ {
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", msg); ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
} }
UpdateFunc(it.indexId, "", msg); UpdateFunc(it.indexId, "", msg);
}); });
@@ -225,19 +257,75 @@ namespace v2rayN.Handler
{ {
_coreHandler.CoreStopPid(pid); _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;
}
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)
{
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() private async Task RunMixedtestAsync()
{ {
await RunRealPing(); await RunRealPing();
Thread.Sleep(1000); Thread.Sleep(1000);
await RunSpeedTestAsync(); await RunSpeedTestMulti();
} }
public string GetRealPingTime(DownloadHandle downloadHandle, WebProxy webProxy) public string GetRealPingTime(DownloadHandle downloadHandle, IWebProxy 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; //string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit); return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit);
} }
@@ -254,11 +342,11 @@ namespace v2rayN.Handler
ipAddress = ipHostInfo.AddressList[0]; ipAddress = ipHostInfo.AddressList[0];
} }
Stopwatch timer = new Stopwatch(); Stopwatch timer = new();
timer.Start(); timer.Start();
IPEndPoint endPoint = new IPEndPoint(ipAddress, port); IPEndPoint endPoint = new(ipAddress, port);
Socket clientSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null); IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))) if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
@@ -267,7 +355,6 @@ namespace v2rayN.Handler
timer.Stop(); timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = timer.Elapsed.Milliseconds;
clientSocket.Close();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -289,7 +376,7 @@ namespace v2rayN.Handler
{ {
int timeout = 30; int timeout = 30;
int echoNum = 2; int echoNum = 2;
Ping pingSender = new Ping(); using Ping pingSender = new();
for (int i = 0; i < echoNum; i++) for (int i = 0; i < echoNum; i++)
{ {
PingReply reply = pingSender.Send(host, timeout); PingReply reply = pingSender.Send(host, timeout);

View File

@@ -13,7 +13,7 @@ namespace v2rayN.Handler
private Channel channel_; private Channel channel_;
private StatsService.StatsServiceClient client_; private StatsService.StatsServiceClient client_;
private bool exitFlag_; private bool exitFlag_;
private ServerStatItem _serverStatItem; private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat; private List<ServerStatItem> _lstServerStat;
public List<ServerStatItem> ServerStat => _lstServerStat; public List<ServerStatItem> ServerStat => _lstServerStat;
@@ -27,7 +27,7 @@ namespace v2rayN.Handler
public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update) public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update)
{ {
config_ = config; config_ = config;
Enable = config.enableStatistics; Enable = config.guiItem.enableStatistics;
updateFunc_ = update; updateFunc_ = update;
exitFlag_ = false; exitFlag_ = false;
@@ -70,7 +70,7 @@ namespace v2rayN.Handler
{ {
if (Enable && channel_.State == ChannelState.Ready) if (Enable && channel_.State == ChannelState.Ready)
{ {
QueryStatsResponse res = null; QueryStatsResponse? res = null;
try try
{ {
res = client_.QueryStats(new QueryStatsRequest() { Pattern = "", Reset = true }); res = client_.QueryStats(new QueryStatsRequest() { Pattern = "", Reset = true });
@@ -103,7 +103,7 @@ namespace v2rayN.Handler
} }
} }
} }
var sleep = config_.statisticsFreshRate < 1 ? 1 : config_.statisticsFreshRate; var sleep = config_.guiItem.statisticsFreshRate < 1 ? 1 : config_.guiItem.statisticsFreshRate;
Thread.Sleep(1000 * sleep); Thread.Sleep(1000 * sleep);
channel_.ConnectAsync(); channel_.ConnectAsync();
} }
@@ -162,7 +162,7 @@ namespace v2rayN.Handler
todayDown = 0, todayDown = 0,
dateNow = ticks dateNow = ticks
}; };
_ = SqliteHelper.Instance.Replacesync(_serverStatItem); SqliteHelper.Instance.Replace(_serverStatItem);
_lstServerStat.Add(_serverStatItem); _lstServerStat.Add(_serverStatItem);
} }
} }
@@ -229,7 +229,7 @@ namespace v2rayN.Handler
try try
{ {
// TCP stack please do me a favor // TCP stack please do me a favor
TcpListener l = new TcpListener(IPAddress.Loopback, 0); TcpListener l = new(IPAddress.Loopback, 0);
l.Start(); l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port; int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop(); l.Stop();

View File

@@ -20,7 +20,7 @@ namespace v2rayN.Handler
// <proxy-server><CR-LF> // <proxy-server><CR-LF>
// <bypass-list><CR-LF> // <bypass-list><CR-LF>
// <pac-url> // <pac-url>
private static SysproxyConfig _userSettings = null; private static SysproxyConfig? _userSettings = null;
enum RET_ERRORS : int enum RET_ERRORS : int
{ {
@@ -50,7 +50,7 @@ namespace v2rayN.Handler
{ {
var type = config.sysProxyType; var type = config.sysProxyType;
if (forceDisable && type == ESysProxyType.ForcedChange) if (forceDisable && type != ESysProxyType.Unchanged)
{ {
type = ESysProxyType.ForcedClear; type = ESysProxyType.ForcedClear;
} }
@@ -154,85 +154,82 @@ namespace v2rayN.Handler
// using event to avoid hanging when redirect standard output/error // using event to avoid hanging when redirect standard output/error
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why // ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
// and http://blog.csdn.net/zhangweixing0/article/details/7356841 // and http://blog.csdn.net/zhangweixing0/article/details/7356841
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) using AutoResetEvent outputWaitHandle = new(false);
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(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. outputWaitHandle.Set();
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;
//}
} }
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;
//}
} }

View File

@@ -3,17 +3,18 @@ using System.IO;
using System.Reactive.Linq; using System.Reactive.Linq;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Base namespace v2rayN.Base
{ {
public sealed class TunHandler 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; public static TunHandler Instance => _instance.Value;
private string _tunConfigName = "tunConfig.json"; private string _tunConfigName = "tunConfig.json";
private static Config _config; private static Config _config;
private CoreInfo coreInfo; private CoreInfo coreInfo;
private Process _process; private Process? _process;
private static int _socksPort; private static int _socksPort;
private static bool _needRestart = true; private static bool _needRestart = true;
private static bool _isRunning = false; private static bool _isRunning = false;
@@ -44,7 +45,7 @@ namespace v2rayN.Base
{ {
var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks); var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
if (socksPort.Equals(_socksPort) if (socksPort == _socksPort
&& _process != null && _process != null
&& !_process.HasExited) && !_process.HasExited)
{ {
@@ -60,6 +61,7 @@ namespace v2rayN.Base
{ {
return; return;
} }
CoreStartTest();
CoreStart(); CoreStart();
} }
} }
@@ -100,13 +102,41 @@ namespace v2rayN.Base
configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}"); configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}");
configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}"); configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}");
//logs
configStr = configStr.Replace("$log_disabled$", $"{(!_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 //port
configStr = configStr.Replace("$socksPort$", $"{_socksPort}"); configStr = configStr.Replace("$socksPort$", $"{_socksPort}");
//dns
string dnsObject = String.Empty;
if (_config.tunModeItem.bypassMode)
{
dnsObject = _config.tunModeItem.directDNS;
}
else
{
dnsObject = _config.tunModeItem.proxyDNS;
}
if (dnsObject.IsNullOrEmpty() || Utils.ParseJson(dnsObject)?.ContainsKey("servers") == false)
{
dnsObject = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
}
configStr = configStr.Replace("$dns_object$", dnsObject);
//exe //exe
List<string> lstDnsExe = new List<string>(); List<string> lstDnsExe = new();
List<string> lstDirectExe = new List<string>(); List<string> lstDirectExe = new();
var coreInfos = LazyConfig.Instance.GetCoreInfos(); var coreInfos = LazyConfig.Instance.GetCoreInfos();
foreach (var it in coreInfos) foreach (var it in coreInfos)
{ {
@@ -118,13 +148,13 @@ namespace v2rayN.Base
{ {
if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box) if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
{ {
lstDnsExe.Add(it2); //lstDnsExe.Add(it2);
lstDnsExe.Add($"{it2}.exe"); lstDnsExe.Add($"{it2}.exe");
} }
if (!lstDirectExe.Contains(it2)) if (!lstDirectExe.Contains(it2))
{ {
lstDirectExe.Add(it2); //lstDirectExe.Add(it2);
lstDirectExe.Add($"{it2}.exe"); lstDirectExe.Add($"{it2}.exe");
} }
} }
@@ -135,27 +165,45 @@ namespace v2rayN.Base
string strDirect = string.Join("\",\"", lstDirectExe.ToArray()); string strDirect = string.Join("\",\"", lstDirectExe.ToArray());
configStr = configStr.Replace("$directProcessName$", $"\"{strDirect}\""); 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 var final = new { outbound = "direct", inbound = "tun-in" };
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0) configStr = configStr.Replace("$ruleFinally$", "," + Utils.ToJson(final));
{
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$", "");
} }
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); File.WriteAllText(Utils.GetConfigPath(_tunConfigName), configStr);
@@ -172,6 +220,7 @@ namespace v2rayN.Base
KillProcess(_process); KillProcess(_process);
_process.Dispose(); _process.Dispose();
_process = null; _process = null;
_needRestart = true;
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -195,7 +244,8 @@ namespace v2rayN.Base
} }
if (Utils.IsNullOrEmpty(fileName)) 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; return fileName;
} }
@@ -205,12 +255,12 @@ namespace v2rayN.Base
try try
{ {
string fileName = CoreFindexe(); string fileName = CoreFindexe();
if (fileName == "") if (Utils.IsNullOrEmpty(fileName))
{ {
return; return;
} }
var showWindow = _config.tunModeItem.showWindow; var showWindow = _config.tunModeItem.showWindow;
Process p = new Process Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -263,5 +313,47 @@ namespace v2rayN.Base
Utils.SaveLog(ex.Message, ex); 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");
}
}
} }
} }

View File

@@ -35,51 +35,46 @@ namespace v2rayN.Handler
_updateFunc = update; _updateFunc = update;
var url = string.Empty; var url = string.Empty;
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null) downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
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)); StartInfo = new ProcessStartInfo
fileName = Utils.UrlEncode(fileName);
Process process = new Process
{ {
StartInfo = new ProcessStartInfo FileName = "v2rayUpgrade.exe",
{ Arguments = $"\"{fileName}\"",
FileName = "v2rayUpgrade.exe", WorkingDirectory = Utils.StartupPath()
Arguments = $"\"{fileName}\"",
WorkingDirectory = Utils.StartupPath()
}
};
process.Start();
if (process.Id > 0)
{
_updateFunc(true, "");
} }
} };
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) => AbsoluteCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -106,36 +101,32 @@ namespace v2rayN.Handler
_updateFunc = update; _updateFunc = update;
var url = string.Empty; var url = string.Empty;
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null) downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
{ _updateFunc(false, ResUI.MsgUnpacking);
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(false, ResUI.MsgUnpacking);
try try
{
_updateFunc(true, url);
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
}
}
else
{ {
_updateFunc(false, args.Msg); _updateFunc(true, url);
} }
}; catch (Exception ex)
downloadHandle.Error += (sender2, args) => {
_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) => AbsoluteCompleted += (sender2, args) =>
{ {
@@ -173,14 +164,14 @@ namespace v2rayN.Handler
Task.Run(async () => Task.Run(async () =>
{ {
//Turn off system proxy //Turn off system proxy
bool bSysProxyType = false; //bool bSysProxyType = false;
if (!blProxy && config.sysProxyType == ESysProxyType.ForcedChange) //if (!blProxy && config.sysProxyType == ESysProxyType.ForcedChange)
{ //{
bSysProxyType = true; // bSysProxyType = true;
config.sysProxyType = ESysProxyType.ForcedClear; // config.sysProxyType = ESysProxyType.ForcedClear;
SysProxyHandle.UpdateSysProxy(config, false); // SysProxyHandle.UpdateSysProxy(config, false);
Thread.Sleep(3000); // Thread.Sleep(3000);
} //}
foreach (var item in subItem) foreach (var item in subItem)
{ {
@@ -213,10 +204,10 @@ namespace v2rayN.Handler
url = Utils.GetPunycode(url); url = Utils.GetPunycode(url);
_updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}"); _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)) if (blProxy && Utils.IsNullOrEmpty(result))
{ {
result = await downloadHandle.DownloadStringAsync(url, false, userAgent); result = await downloadHandle.TryDownloadString(url, false, userAgent);
} }
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
@@ -226,7 +217,7 @@ namespace v2rayN.Handler
else else
{ {
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}"); _updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
if (result.Length < 99) if (result!.Length < 99)
{ {
_updateFunc(false, $"{hashCode}{result}"); _updateFunc(false, $"{hashCode}{result}");
} }
@@ -244,12 +235,12 @@ namespace v2rayN.Handler
} }
_updateFunc(false, "-------------------------------------------------------"); _updateFunc(false, "-------------------------------------------------------");
} }
//restore system proxy ////restore system proxy
if (bSysProxyType) //if (bSysProxyType)
{ //{
config.sysProxyType = ESysProxyType.ForcedChange; // config.sysProxyType = ESysProxyType.ForcedChange;
SysProxyHandle.UpdateSysProxy(config, false); // SysProxyHandle.UpdateSysProxy(config, false);
} //}
_updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}"); _updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
}); });
@@ -262,47 +253,44 @@ namespace v2rayN.Handler
_updateFunc = update; _updateFunc = update;
var url = string.Format(Global.geoUrl, geoName); var url = string.Format(Global.geoUrl, geoName);
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null) downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
try
{ {
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName)); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
if (File.Exists(fileName))
try
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); //Global.coreTypes.ForEach(it =>
if (File.Exists(fileName)) //{
{ // string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
Global.coreTypes.ForEach(it => // File.Copy(fileName, targetPath, true);
{ //});
string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it)); string targetPath = Utils.GetBinPath($"{geoName}.dat");
File.Copy(fileName, targetPath, true); File.Copy(fileName, targetPath, true);
});
File.Delete(fileName); File.Delete(fileName);
//_updateFunc(true, ""); //_updateFunc(true, "");
}
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
} }
} }
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); askToDownload(downloadHandle, url, false);
} }
@@ -372,7 +360,7 @@ namespace v2rayN.Handler
return ""; return "";
} }
Process p = new Process(); using Process p = new();
p.StartInfo.FileName = filePath; p.StartInfo.FileName = filePath;
p.StartInfo.Arguments = coreInfo.versionArg; p.StartInfo.Arguments = coreInfo.versionArg;
p.StartInfo.WorkingDirectory = Utils.StartupPath(); p.StartInfo.WorkingDirectory = Utils.StartupPath();

View File

@@ -8,148 +8,32 @@
{ {
#region property #region property
/// <summary> public string indexId { get; set; }
/// 允许日志 public string subIndexId { get; set; }
/// </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 remoteDNS { get; set; }
/// <summary> /// <summary>
/// Outbound Freedom domainStrategy /// Outbound Freedom domainStrategy
/// </summary> /// </summary>
public string domainStrategy4Freedom public string domainStrategy4Freedom { get; set; }
{
get; set;
}
/// <summary> public ESysProxyType sysProxyType { get; set; }
/// 是否允许不安全连接 public string systemProxyExceptions { get; set; }
/// </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 string systemProxyAdvancedProtocol { 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 #endregion
#region other entities #region other entities
public CoreBasicItem coreBasicItem { get; set; }
public TunModeItem tunModeItem { get; set; } public TunModeItem tunModeItem { get; set; }
public KcpItem kcpItem { get; set; } public KcpItem kcpItem { get; set; }
public GrpcItem grpcItem { get; set; } public GrpcItem grpcItem { get; set; }
public RoutingBasicItem routingBasicItem { get; set; }
public GUIItem guiItem { get; set; }
public UIItem uiItem { get; set; } public UIItem uiItem { get; set; }
public ConstItem constItem { get; set; } public ConstItem constItem { get; set; }
public SpeedTestItem speedTestItem { get; set; }
public List<InItem> inbound { get; set; } public List<InItem> inbound { get; set; }
public List<KeyEventItem> globalHotkeys { get; set; } public List<KeyEventItem> globalHotkeys { get; set; }
public List<CoreTypeItem> coreTypeItem { get; set; } public List<CoreTypeItem> coreTypeItem { get; set; }

View File

@@ -2,6 +2,37 @@
namespace v2rayN.Mode 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] [Serializable]
public class InItem public class InItem
{ {
@@ -51,24 +82,54 @@ namespace v2rayN.Mode
public int initial_windows_size { get; set; } 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] [Serializable]
public class UIItem public class UIItem
{ {
public bool enableAutoAdjustMainLvColWidth { get; set; } public bool enableAutoAdjustMainLvColWidth { get; set; }
public double mainWidth { get; set; } public double mainWidth { get; set; }
public double mainHeight { get; set; } public double mainHeight { get; set; }
public double mainGirdHeight1 { get; set; }
public double mainGirdHeight2 { get; set; }
public bool colorModeDark { get; set; } public bool colorModeDark { get; set; }
public string? colorPrimaryName { get; set; } public string? colorPrimaryName { get; set; }
public string currentLanguage { get; set; } public string currentLanguage { get; set; }
public string currentFontFamily { get; set; }
public int currentFontSize { get; set; }
public bool enableDragDropSort { get; set; } public bool enableDragDropSort { get; set; }
public Dictionary<string, int> mainLvColWidth { get; set; } public bool doubleClick2Activate { get; set; }
public bool autoHideStartup { get; set; } = true;
public string mainMsgFilter { get; set; }
public List<ColumnItem> mainColumnItem { get; set; }
} }
[Serializable] [Serializable]
public class ConstItem public class ConstItem
{ {
public string speedTestUrl { get; set; }
public string speedPingTestUrl { get; set; }
public string defIEProxyExceptions { get; set; } public string defIEProxyExceptions { get; set; }
} }
@@ -100,12 +161,47 @@ namespace v2rayN.Mode
{ {
public bool enableTun { get; set; } public bool enableTun { get; set; }
public bool showWindow { get; set; } public bool showWindow { get; set; }
public bool enabledLog { get; set; }
public bool strictRoute { get; set; } public bool strictRoute { get; set; }
public string stack { get; set; } public string stack { get; set; }
public int mtu { get; set; } public int mtu { get; set; }
public string customTemplate { get; set; } public string customTemplate { get; set; }
public bool bypassMode { get; set; } = true;
public List<string> directIP { get; set; } public List<string> directIP { get; set; }
public List<string> directProcess { get; set; } public List<string> directProcess { get; set; }
public string directDNS { get; set; }
public List<string> proxyIP { get; set; }
public List<string> proxyProcess { get; set; }
public string proxyDNS { 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; }
}
[Serializable]
public class ColumnItem
{
public string Name { get; set; }
public int Width { get; set; }
public int Index { get; set; }
}
} }

View File

@@ -12,8 +12,8 @@ namespace v2rayN.Mode
network, network,
streamSecurity, streamSecurity,
subRemarks, subRemarks,
delay, delayVal,
speed, speedVal,
todayDown, todayDown,
todayUp, todayUp,

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

View File

@@ -11,7 +11,6 @@ namespace v2rayN.Mode
indexId = string.Empty; indexId = string.Empty;
configType = EConfigType.VMess; configType = EConfigType.VMess;
configVersion = 2; configVersion = 2;
sort = 0;
address = string.Empty; address = string.Empty;
port = 0; port = 0;
id = string.Empty; id = string.Empty;
@@ -107,11 +106,6 @@ namespace v2rayN.Mode
get; set; get; set;
} }
public int sort
{
get; set;
}
/// <summary> /// <summary>
/// 远程服务器地址 /// 远程服务器地址
/// </summary> /// </summary>
@@ -202,9 +196,6 @@ namespace v2rayN.Mode
get; set; get; set;
} }
public int delay { get; set; }
public decimal speed { get; set; }
/// <summary> /// <summary>
/// SubItem id /// SubItem id
/// </summary> /// </summary>

View File

@@ -5,6 +5,9 @@
{ {
public bool isActive { get; set; } public bool isActive { get; set; }
public string subRemarks { 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 delayVal { get; set; }
public string speedVal { get; set; } public string speedVal { get; set; }
public string todayUp { get; set; } public string todayUp { get; set; }

View File

@@ -15,6 +15,7 @@ namespace v2rayN.Mode
public bool locked { get; set; } public bool locked { get; set; }
public string customIcon { get; set; } public string customIcon { get; set; }
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
public int sort { get; set; }
} }
} }

View File

@@ -1,4 +1,6 @@
namespace v2rayN.Mode using Newtonsoft.Json;
namespace v2rayN.Mode
{ {
/// <summary> /// <summary>
/// v2ray配置文件实体类 /// v2ray配置文件实体类
@@ -505,6 +507,12 @@
/// ///
/// </summary> /// </summary>
public string Host { get; set; } public string Host { get; set; }
/// <summary>
/// 用户代理
/// </summary>
[JsonProperty("User-Agent")]
public string UserAgent { get; set; }
} }
public class HttpSettings public class HttpSettings

View File

@@ -63,5 +63,10 @@
/// TLS alpn /// TLS alpn
/// </summary> /// </summary>
public string alpn { get; set; } = string.Empty; public string alpn { get; set; } = string.Empty;
/// <summary>
/// TLS fingerprint
/// </summary>
public string fp { get; set; } = string.Empty;
} }
} }

View File

@@ -70,7 +70,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 All servers 的本地化字符串。 /// 查找类似 All 的本地化字符串。
/// </summary> /// </summary>
public static string AllGroupServers { public static string AllGroupServers {
get { 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> /// <summary>
/// 查找类似 Exit 的本地化字符串。 /// 查找类似 Exit 的本地化字符串。
/// </summary> /// </summary>
@@ -781,7 +790,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 One-click test Latency and speed (Ctrl+E) 的本地化字符串。 /// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
/// </summary> /// </summary>
public static string menuMixedTestServer { public static string menuMixedTestServer {
get { get {
@@ -807,6 +816,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Move up and down 的本地化字符串。
/// </summary>
public static string menuMoveTo {
get {
return ResourceManager.GetString("menuMoveTo", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Move to group 的本地化字符串。 /// 查找类似 Move to group 的本地化字符串。
/// </summary> /// </summary>
@@ -1114,7 +1132,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Share Server (Ctrl+D) 的本地化字符串。 /// 查找类似 Share Server (Ctrl+F) 的本地化字符串。
/// </summary> /// </summary>
public static string menuShareServer { public static string menuShareServer {
get { get {
@@ -1752,6 +1770,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> /// <summary>
/// 查找类似 PAC failed to start. Please run this program as Administrator. 的本地化字符串。 /// 查找类似 PAC failed to start. Please run this program as Administrator. 的本地化字符串。
/// </summary> /// </summary>
@@ -1861,6 +1897,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 AutoRefresh 的本地化字符串。
/// </summary>
public static string TbAutoRefresh {
get {
return ResourceManager.GetString("TbAutoRefresh", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Domain and ip are auto sorted when saving 的本地化字符串。 /// 查找类似 Domain and ip are auto sorted when saving 的本地化字符串。
/// </summary> /// </summary>
@@ -2356,6 +2401,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> /// <summary>
/// 查找类似 AllowInsecure 的本地化字符串。 /// 查找类似 AllowInsecure 的本地化字符串。
/// </summary> /// </summary>
@@ -2365,6 +2428,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> /// <summary>
/// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。 /// 查找类似 Outbound Freedom domainStrategy 的本地化字符串。
/// </summary> /// </summary>
@@ -2374,6 +2464,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Double-click server make active 的本地化字符串。
/// </summary>
public static string TbSettingsDoubleClick2Activate {
get {
return ResourceManager.GetString("TbSettingsDoubleClick2Activate", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Automatically adjust column width after updating subscription 的本地化字符串。 /// 查找类似 Automatically adjust column width after updating subscription 的本地化字符串。
/// </summary> /// </summary>
@@ -2419,6 +2518,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 FontSize 的本地化字符串。
/// </summary>
public static string TbSettingsFontSize {
get {
return ResourceManager.GetString("TbSettingsFontSize", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Http Port 的本地化字符串。 /// 查找类似 Http Port 的本地化字符串。
/// </summary> /// </summary>
@@ -2456,7 +2564,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Language 的本地化字符串。 /// 查找类似 Language(Restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLanguage { public static string TbSettingsLanguage {
get { get {
@@ -2465,7 +2573,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Record local logs 的本地化字符串。 /// 查找类似 Enable Log 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLogEnabled { public static string TbSettingsLogEnabled {
get { get {
@@ -2581,6 +2689,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> /// <summary>
/// 查找类似 Start on boot 的本地化字符串。 /// 查找类似 Start on boot 的本地化字符串。
/// </summary> /// </summary>
@@ -2590,6 +2725,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> /// <summary>
/// 查找类似 Enable Statistics (Require restart) 的本地化字符串。 /// 查找类似 Enable Statistics (Require restart) 的本地化字符串。
/// </summary> /// </summary>
@@ -2653,6 +2797,24 @@ 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> /// <summary>
/// 查找类似 Custom Template 的本地化字符串。 /// 查找类似 Custom Template 的本地化字符串。
/// </summary> /// </summary>
@@ -2680,6 +2842,33 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 DNS object, e.g. {&quot;servers&quot;:[]} 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeDNS {
get {
return ResourceManager.GetString("TbSettingsTunModeDNS", resourceCulture);
}
}
/// <summary>
/// 查找类似 Proxy IP CIDR, separated by commas (,) 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeProxyIP {
get {
return ResourceManager.GetString("TbSettingsTunModeProxyIP", resourceCulture);
}
}
/// <summary>
/// 查找类似 Proxy Process name, separated by commas (,) 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeProxyProcess {
get {
return ResourceManager.GetString("TbSettingsTunModeProxyProcess", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Show console 的本地化字符串。 /// 查找类似 Show console 的本地化字符串。
/// </summary> /// </summary>
@@ -2897,7 +3086,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *QUIC securty 的本地化字符串。 /// 查找类似 *QUIC security 的本地化字符串。
/// </summary> /// </summary>
public static string TransportRequestHostTip4 { public static string TransportRequestHostTip4 {
get { get {

View File

@@ -130,7 +130,7 @@
<value>فرمت پیکربندی نادرست است</value> <value>فرمت پیکربندی نادرست است</value>
</data> </data>
<data name="CustomServerTips" xml:space="preserve"> <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>
<data name="Downloading" xml:space="preserve"> <data name="Downloading" xml:space="preserve">
<value>درحال دانلود...</value> <value>درحال دانلود...</value>
@@ -187,10 +187,10 @@
<value>پیکربندی اولیه</value> <value>پیکربندی اولیه</value>
</data> </data>
<data name="IsLatestCore" xml:space="preserve"> <data name="IsLatestCore" xml:space="preserve">
<value>{0} already up to date.</value> <value>{0} در حال حاضر به روز است.</value>
</data> </data>
<data name="IsLatestN" xml:space="preserve"> <data name="IsLatestN" xml:space="preserve">
<value>{0} already up to date.</value> <value>{0} در حال حاضر به روز است.</value>
</data> </data>
<data name="LvAddress" xml:space="preserve"> <data name="LvAddress" xml:space="preserve">
<value>آدرس</value> <value>آدرس</value>
@@ -262,28 +262,28 @@
<value>شروع به دریافت اشتراک شد</value> <value>شروع به دریافت اشتراک شد</value>
</data> </data>
<data name="MsgStartUpdating" xml:space="preserve"> <data name="MsgStartUpdating" xml:space="preserve">
<value>Start updating {0}...</value> <value>شروع بروزرسانی {0}...</value>
</data> </data>
<data name="MsgStartUpdatingPAC" xml:space="preserve"> <data name="MsgStartUpdatingPAC" xml:space="preserve">
<value>Start updating PAC...</value> <value>شروع بروزرسانی PAC...</value>
</data> </data>
<data name="MsgSubscriptionDecodingFailed" xml:space="preserve"> <data name="MsgSubscriptionDecodingFailed" xml:space="preserve">
<value>محتوای اشتراک نامعتبر است</value> <value>محتوای اشتراک نامعتبر است</value>
</data> </data>
<data name="MsgUnpacking" xml:space="preserve"> <data name="MsgUnpacking" xml:space="preserve">
<value>is unpacking...</value> <value>در حال باز کردن بسته می باشد ...</value>
</data> </data>
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve"> <data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
<value>Update subscription end</value> <value>بروزرسانی اشتراک به پایان رسید</value>
</data> </data>
<data name="MsgUpdateSubscriptionStart" xml:space="preserve"> <data name="MsgUpdateSubscriptionStart" xml:space="preserve">
<value>Update subscription starts</value> <value>بروزرسانی اشتراک شروع شد</value>
</data> </data>
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
<value>Update Core successfully</value> <value>هسته با موفقیت بروزرسانی شد</value>
</data> </data>
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve"> <data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
<value>Update Core successfully! Restarting service...</value> <value>هسته با موفقیت بروزرسانی شد! راه اندازی مجدد سرویس...</value>
</data> </data>
<data name="NeedHttpGlobalProxy" xml:space="preserve"> <data name="NeedHttpGlobalProxy" xml:space="preserve">
<value> This feature relies on the Http global proxy, please set it correctly first.</value> <value> This feature relies on the Http global proxy, please set it correctly first.</value>
@@ -301,7 +301,7 @@
<value>Scan completed, no valid QR code found</value> <value>Scan completed, no valid QR code found</value>
</data> </data>
<data name="OperationFailed" xml:space="preserve"> <data name="OperationFailed" xml:space="preserve">
<value> operation failed, please check and retry</value> <value> عملیات انجام نشد، لطفا بررسی کنید و دوباره امتحان کنید</value>
</data> </data>
<data name="PleaseFillRemarks" xml:space="preserve"> <data name="PleaseFillRemarks" xml:space="preserve">
<value>Please Fill Remarks</value> <value>Please Fill Remarks</value>
@@ -343,20 +343,20 @@
<value>Start service ({0})...</value> <value>Start service ({0})...</value>
</data> </data>
<data name="SuccessfulConfiguration" xml:space="preserve"> <data name="SuccessfulConfiguration" xml:space="preserve">
<value>Configuration successful <value>پیکربندی با موفقیت انجام شد
{0}</value> {0}</value>
</data> </data>
<data name="SuccessfullyImportedCustomServer" xml:space="preserve"> <data name="SuccessfullyImportedCustomServer" xml:space="preserve">
<value>سرور پیکربندی سفارشی با موفقیت وارد شد.</value> <value>سرور پیکربندی سفارشی با موفقیت وارد شد.</value>
</data> </data>
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve"> <data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
<value>{0} servers have been imported from clipboard.</value> <value>{0} سرورها از کلیپ بورد وارد شده اند.</value>
</data> </data>
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve"> <data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
<value>Scan import URL successfully</value> <value>اسکن URL وارد کردن با موفقیت</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>The ping of current service: {0} ms</value> <value>پینگ سرویس فعلی: {0} ms</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>موفقیت عملیات</value> <value>موفقیت عملیات</value>
@@ -368,7 +368,7 @@
<value>آیا مطمئن هستید که قوانین را حذف می کنید؟</value> <value>آیا مطمئن هستید که قوانین را حذف می کنید؟</value>
</data> </data>
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve"> <data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
<value>{0},One of the required.</value> <value>{0},یکی از مورد نیاز.</value>
</data> </data>
<data name="LvRemarks" xml:space="preserve"> <data name="LvRemarks" xml:space="preserve">
<value>Remarks</value> <value>Remarks</value>
@@ -386,7 +386,7 @@
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value> <value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value>
</data> </data>
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve"> <data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
<value>Download GeoFile: {0} successfully</value> <value>دانلود GeoFile: {0} با موفقیت</value>
</data> </data>
<data name="MsgInformationTitle" xml:space="preserve"> <data name="MsgInformationTitle" xml:space="preserve">
<value>اطلاعات</value> <value>اطلاعات</value>
@@ -536,7 +536,7 @@
<value>پروکسی سیستم تغییر نکند</value> <value>پروکسی سیستم تغییر نکند</value>
</data> </data>
<data name="menuSystemProxyPac" xml:space="preserve"> <data name="menuSystemProxyPac" xml:space="preserve">
<value>Pac Mode</value> <value>حالت Pac</value>
</data> </data>
<data name="menuSystemProxySet" xml:space="preserve"> <data name="menuSystemProxySet" xml:space="preserve">
<value>تنظیم پراکسی سیستم</value> <value>تنظیم پراکسی سیستم</value>
@@ -791,10 +791,10 @@
<value>Outbound Freedom domainStrategy</value> <value>Outbound Freedom domainStrategy</value>
</data> </data>
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve"> <data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
<value>Automatically adjust column width after updating subscription</value> <value>پس از به‌روزرسانی اشتراک، عرض ستون را به صورت خودکار تنظیم شود</value>
</data> </data>
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve"> <data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
<value>به روز رسانی های پیش از انتشار را بررسی کنید</value> <value>به روز رسانی های پیش از انتشار را بررسی شود</value>
</data> </data>
<data name="TbSettingsException" xml:space="preserve"> <data name="TbSettingsException" xml:space="preserve">
<value>استثنا</value> <value>استثنا</value>
@@ -827,13 +827,13 @@
<value>تنظیمات v2rayN</value> <value>تنظیمات v2rayN</value>
</data> </data>
<data name="TbSettingsPacListenPort" xml:space="preserve"> <data name="TbSettingsPacListenPort" xml:space="preserve">
<value>Pac listen port</value> <value>Pac پورت درحال شنود</value>
</data> </data>
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>Auth pass</value> <value>Auth pass</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve"> <data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>Custom DNS (multiple, separated by commas (,))</value> <value>سفارشی DNS (multiple, separated by commas (,))</value>
</data> </data>
<data name="TbSettingsSaveTip" xml:space="preserve"> <data name="TbSettingsSaveTip" xml:space="preserve">
<value>After modifying the following parameters, click Save to take effect</value> <value>After modifying the following parameters, click Save to take effect</value>
@@ -845,16 +845,16 @@
<value>Turn on Sniffing</value> <value>Turn on Sniffing</value>
</data> </data>
<data name="TbSettingsSocksPort" xml:space="preserve"> <data name="TbSettingsSocksPort" xml:space="preserve">
<value>Socks Port</value> <value>ساکس Port</value>
</data> </data>
<data name="TbSettingsStartBoot" xml:space="preserve"> <data name="TbSettingsStartBoot" xml:space="preserve">
<value>Start on boot</value> <value>درهنگام راه ائدازی شروع شود</value>
</data> </data>
<data name="TbSettingsStatistics" xml:space="preserve"> <data name="TbSettingsStatistics" xml:space="preserve">
<value>Enable Statistics (Require restart)</value> <value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsStatisticsFreshRate" xml:space="preserve"> <data name="TbSettingsStatisticsFreshRate" xml:space="preserve">
<value>Statistics freshrate (second)</value> <value>نرخ تازه سازی آمار (ثانیه)</value>
</data> </data>
<data name="TbSettingsSubConvert" xml:space="preserve"> <data name="TbSettingsSubConvert" xml:space="preserve">
<value>Subscription conversion Url</value> <value>Subscription conversion Url</value>
@@ -884,7 +884,7 @@
<value>تنظیم کلید میانبر جهانی</value> <value>تنظیم کلید میانبر جهانی</value>
</data> </data>
<data name="TbGlobalHotkeySettingTip" xml:space="preserve"> <data name="TbGlobalHotkeySettingTip" xml:space="preserve">
<value>Set directly by pressing the keyboard, Take effect after restart</value> <value>مستقیماً با فشار دادن صفحه کلید تنظیم کنید، بعد از راه اندازی مجدد اعمال شود</value>
</data> </data>
<data name="TbNotChangeSystemProxy" xml:space="preserve"> <data name="TbNotChangeSystemProxy" xml:space="preserve">
<value>پروکسی سیستم را تغییر ندهید</value> <value>پروکسی سیستم را تغییر ندهید</value>
@@ -899,7 +899,7 @@
<value>حالت Pac</value> <value>حالت Pac</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>اشتراک گذاری سرور(Ctrl+D)</value> <value>اشتراک گذاری سرور(Ctrl+F)</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>مسیریابی</value> <value>مسیریابی</value>
@@ -929,7 +929,7 @@
<value>{0} Website</value> <value>{0} Website</value>
</data> </data>
<data name="menuRoutingAdvanced" xml:space="preserve"> <data name="menuRoutingAdvanced" xml:space="preserve">
<value>Advanced Function</value> <value>عملکرد پیشرفته</value>
</data> </data>
<data name="menuRoutingAdvancedAdd" xml:space="preserve"> <data name="menuRoutingAdvancedAdd" xml:space="preserve">
<value>اضافه کردن</value> <value>اضافه کردن</value>
@@ -1001,7 +1001,7 @@
<value>تنظیم جزئیات قانون مسیریابی</value> <value>تنظیم جزئیات قانون مسیریابی</value>
</data> </data>
<data name="TbAutoSort" xml:space="preserve"> <data name="TbAutoSort" xml:space="preserve">
<value>Domain and ip are auto sorted when saving</value> <value>دامنه و آی پی در هنگام ذخیره به طور خودکار مرتب می شوند</value>
</data> </data>
<data name="TbRuleobjectDoc" xml:space="preserve"> <data name="TbRuleobjectDoc" xml:space="preserve">
<value>Ruleobject Doc</value> <value>Ruleobject Doc</value>
@@ -1060,4 +1060,10 @@
<data name="TbSettingsTunModeShowWindow" xml:space="preserve"> <data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>نمایش کنسول</value> <value>نمایش کنسول</value>
</data> </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> </root>

View File

@@ -419,7 +419,7 @@
<value>*h2 host Separated by commas (,)</value> <value>*h2 host Separated by commas (,)</value>
</data> </data>
<data name="TransportRequestHostTip4" xml:space="preserve"> <data name="TransportRequestHostTip4" xml:space="preserve">
<value>*QUIC securty</value> <value>*QUIC security</value>
</data> </data>
<data name="TransportHeaderTypeTip1" xml:space="preserve"> <data name="TransportHeaderTypeTip1" xml:space="preserve">
<value>*tcp camouflage type</value> <value>*tcp camouflage type</value>
@@ -449,7 +449,7 @@
<value>Ungrouped</value> <value>Ungrouped</value>
</data> </data>
<data name="AllGroupServers" xml:space="preserve"> <data name="AllGroupServers" xml:space="preserve">
<value>All servers</value> <value>All</value>
</data> </data>
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>Please browse to import server configuration</value> <value>Please browse to import server configuration</value>
@@ -548,7 +548,7 @@
<value>Dark Mode</value> <value>Dark Mode</value>
</data> </data>
<data name="TbSettingsLanguage" xml:space="preserve"> <data name="TbSettingsLanguage" xml:space="preserve">
<value>Language</value> <value>Language(Restart)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>Import bulk URL from clipboard (Ctrl+V)</value> <value>Import bulk URL from clipboard (Ctrl+V)</value>
@@ -815,7 +815,7 @@
<value>Keep older when deduplication</value> <value>Keep older when deduplication</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>Record local logs</value> <value>Enable Log</value>
</data> </data>
<data name="TbSettingsLogLevel" xml:space="preserve"> <data name="TbSettingsLogLevel" xml:space="preserve">
<value>Log Level</value> <value>Log Level</value>
@@ -899,7 +899,7 @@
<value>Pac Mode</value> <value>Pac Mode</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>Share Server (Ctrl+D)</value> <value>Share Server (Ctrl+F)</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>Routing</value> <value>Routing</value>
@@ -1022,7 +1022,7 @@
<value>RouteOnly</value> <value>RouteOnly</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>One-click test Latency and speed (Ctrl+E)</value> <value>One-click multi test Latency and speed (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>Delay(ms)</value> <value>Delay(ms)</value>
@@ -1069,4 +1069,67 @@
<data name="TbSettingsEnableDragDropSort" xml:space="preserve"> <data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Enable Server Drag Drop Sort(Require restart)</value> <value>Enable Server Drag Drop Sort(Require restart)</value>
</data> </data>
<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>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS object, e.g. {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</value>
</data>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@@ -130,7 +130,7 @@
<value>配置格式不正确</value> <value>配置格式不正确</value>
</data> </data>
<data name="CustomServerTips" xml:space="preserve"> <data name="CustomServerTips" xml:space="preserve">
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value> <value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value>
</data> </data>
<data name="Downloading" xml:space="preserve"> <data name="Downloading" xml:space="preserve">
<value>下载开始...</value> <value>下载开始...</value>
@@ -148,7 +148,7 @@
<value>生成默认配置文件失败</value> <value>生成默认配置文件失败</value>
</data> </data>
<data name="FailedGetDefaultConfiguration" xml:space="preserve"> <data name="FailedGetDefaultConfiguration" xml:space="preserve">
<value>取默认配置失败</value> <value>取默认配置失败</value>
</data> </data>
<data name="FailedImportedCustomServer" xml:space="preserve"> <data name="FailedImportedCustomServer" xml:space="preserve">
<value>导入自定义配置服务器失败</value> <value>导入自定义配置服务器失败</value>
@@ -449,7 +449,7 @@
<value>未分组服务器</value> <value>未分组服务器</value>
</data> </data>
<data name="AllGroupServers" xml:space="preserve"> <data name="AllGroupServers" xml:space="preserve">
<value>所有服务器</value> <value>所有</value>
</data> </data>
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>请浏览导入服务器配置</value> <value>请浏览导入服务器配置</value>
@@ -548,7 +548,7 @@
<value>暗黑模式</value> <value>暗黑模式</value>
</data> </data>
<data name="TbSettingsLanguage" xml:space="preserve"> <data name="TbSettingsLanguage" xml:space="preserve">
<value>语言</value> <value>语言(重启)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>从剪贴板导入批量URL (Ctrl+V)</value> <value>从剪贴板导入批量URL (Ctrl+V)</value>
@@ -815,7 +815,7 @@
<value>去重时保留序号较小的项</value> <value>去重时保留序号较小的项</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>记录本地日志(默认关闭)</value> <value>启用日志(默认关闭)</value>
</data> </data>
<data name="TbSettingsLogLevel" xml:space="preserve"> <data name="TbSettingsLogLevel" xml:space="preserve">
<value>日志等级</value> <value>日志等级</value>
@@ -899,13 +899,13 @@
<value>Pac模式</value> <value>Pac模式</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>分享服务器 (Ctrl+D)</value> <value>分享服务器 (Ctrl+F)</value>
</data> </data>
<data name="menuRouting" xml:space="preserve"> <data name="menuRouting" xml:space="preserve">
<value>路由</value> <value>路由</value>
</data> </data>
<data name="NotRunAsAdmin" xml:space="preserve"> <data name="NotRunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value> <value>以管理员身份运行</value>
</data> </data>
<data name="RunAsAdmin" xml:space="preserve"> <data name="RunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value> <value>以管理员身份运行</value>
@@ -1022,7 +1022,7 @@
<value>RouteOnly</value> <value>RouteOnly</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>一键测试延迟和速度 (Ctrl+E)</value> <value>一键多线程测试延迟和速度 (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>延迟(ms)</value> <value>延迟(ms)</value>
@@ -1069,4 +1069,67 @@
<data name="TbSettingsEnableDragDropSort" xml:space="preserve"> <data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>启用服务器拖放排序(需重启)</value> <value>启用服务器拖放排序(需重启)</value>
</data> </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>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS对象例如 {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>移至上下</value>
</data>
</root> </root>

View File

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

View File

@@ -14,7 +14,14 @@
{ {
"outboundTag": "proxy", "outboundTag": "proxy",
"ip": [ "ip": [
"geoip:telegram" "geoip:cloudflare",
"geoip:cloudfront",
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
], ],
"domain": [ "domain": [
"geosite:gfw", "geosite:gfw",

View File

@@ -1,32 +1,15 @@
{ {
"dns": { "log": {
"servers": [ "disabled": $log_disabled$,
{ "level": "debug",
"tag": "google", $log_output$
"address": "tls://8.8.8.8" "timestamp": true
},
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
}
],
"rules": [
{
"geosite": "category-ads-all",
"server": "block",
"disable_cache": true
}
],
"strategy": "ipv4_only"
}, },
"dns": $dns_object$ ,
"inbounds": [ "inbounds": [
{ {
"type": "tun", "type": "tun",
"tag": "tun-in",
"interface_name": "singbox_tun", "interface_name": "singbox_tun",
"inet4_address": "172.19.0.1/30", "inet4_address": "172.19.0.1/30",
@@ -106,6 +89,9 @@
} }
$ruleDirectIPs$ $ruleDirectIPs$
$ruleDirectProcess$ $ruleDirectProcess$
$ruleProxyIPs$
$ruleProxyProcess$
$ruleFinally$
] ]
} }
} }

View File

@@ -0,0 +1,31 @@
{
"servers": [
{
"tag": "out_dns",
"address": "8.8.8.8",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
}
],
"rules": [
{
"geosite": "cn",
"server": "local",
"disable_cache": true
},
{
"geosite": "category-ads-all",
"server": "block",
"disable_cache": true
}
],
"strategy": "ipv4_only"
}

View File

@@ -10,8 +10,7 @@ namespace v2rayN.Tool
{ {
try try
{ {
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) File.WriteAllBytes(fileName, content);
fs.Write(content, 0, content.Length);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@@ -25,20 +24,9 @@ namespace v2rayN.Tool
{ {
try try
{ {
// Because the uncompressed size of the file is unknown, using FileStream fs = File.Create(fileName);
// we are using an arbitrary buffer size. using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
byte[] buffer = new byte[4096]; input.CopyTo(fs);
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);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -55,42 +43,38 @@ namespace v2rayN.Tool
{ {
try try
{ {
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (StreamReader sr = new StreamReader(fs, encoding)) using StreamReader sr = new(fs, encoding);
{ return sr.ReadToEnd();
return sr.ReadToEnd();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);
throw ex; throw;
} }
} }
public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName) public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName)
{ {
try 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; continue;
} }
try entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
{ }
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName)) catch (IOException ex)
{ {
continue; Utils.SaveLog(ex.Message, ex);
}
entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
}
catch (IOException ex)
{
Utils.SaveLog(ex.Message, ex);
}
} }
} }
} }

View File

@@ -16,12 +16,12 @@ namespace v2rayN
{ {
handle = CreateJobObject(IntPtr.Zero, null); handle = CreateJobObject(IntPtr.Zero, null);
IntPtr extendedInfoPtr = IntPtr.Zero; IntPtr extendedInfoPtr = IntPtr.Zero;
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
{ {
LimitFlags = 0x2000 LimitFlags = 0x2000
}; };
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
{ {
BasicLimitInformation = info BasicLimitInformation = info
}; };
@@ -100,7 +100,7 @@ namespace v2rayN
#region Interop #region Interop
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] [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)] [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);

View File

@@ -9,8 +9,8 @@ namespace v2rayN.Tool
{ {
public static void Setup() public static void Setup()
{ {
LoggingConfiguration config = new LoggingConfiguration(); LoggingConfiguration config = new();
FileTarget fileTarget = new FileTarget(); FileTarget fileTarget = new();
config.AddTarget("file", fileTarget); config.AddTarget("file", fileTarget);
fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}"; fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt"); fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");

View File

@@ -48,11 +48,10 @@ namespace v2rayN
try try
{ {
Assembly assembly = Assembly.GetExecutingAssembly(); Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(res)) using Stream? stream = assembly.GetManifestResourceStream(res);
using (StreamReader reader = new StreamReader(stream)) ArgumentNullException.ThrowIfNull(stream);
{ using StreamReader reader = new(stream);
result = reader.ReadToEnd(); result = reader.ReadToEnd();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -66,22 +65,18 @@ namespace v2rayN
/// 取得存储资源 /// 取得存储资源
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string LoadResource(string res) public static string? LoadResource(string res)
{ {
string result = string.Empty;
try try
{ {
using (StreamReader reader = new StreamReader(res)) if (!File.Exists(res)) return null;
{ return File.ReadAllText(res);
result = reader.ReadToEnd();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); SaveLog(ex.Message, ex);
} }
return result; return null;
} }
/// <summary> /// <summary>
@@ -90,7 +85,7 @@ namespace v2rayN
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="strJson"></param> /// <param name="strJson"></param>
/// <returns></returns> /// <returns></returns>
public static T FromJson<T>(string strJson) public static T? FromJson<T>(string? strJson)
{ {
try try
{ {
@@ -98,8 +93,7 @@ namespace v2rayN
{ {
return default; return default;
} }
T obj = JsonConvert.DeserializeObject<T>(strJson); return JsonConvert.DeserializeObject<T>(strJson);
return obj;
} }
catch catch
{ {
@@ -112,11 +106,15 @@ namespace v2rayN
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <returns></returns>
public static string ToJson(Object obj, bool indented = true) public static string ToJson(object? obj, bool indented = true)
{ {
string result = string.Empty; string result = string.Empty;
try try
{ {
if (obj == null)
{
return result;
}
if (indented) if (indented)
{ {
result = JsonConvert.SerializeObject(obj, result = JsonConvert.SerializeObject(obj,
@@ -141,25 +139,23 @@ namespace v2rayN
/// <param name="obj"></param> /// <param name="obj"></param>
/// <param name="filePath"></param> /// <param name="filePath"></param>
/// <returns></returns> /// <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; int result;
try try
{ {
using (StreamWriter file = File.CreateText(filePath)) using StreamWriter file = File.CreateText(filePath);
JsonSerializer serializer;
if (nullValue)
{ {
JsonSerializer serializer; serializer = new JsonSerializer() { Formatting = Formatting.Indented };
if (nullValue)
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented };
}
else
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
}
serializer.Serialize(file, obj);
} }
else
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
}
serializer.Serialize(file, obj);
result = 0; result = 0;
} }
catch (Exception ex) catch (Exception ex)
@@ -170,12 +166,11 @@ namespace v2rayN
return result; return result;
} }
public static JObject ParseJson(string strJson) public static JObject? ParseJson(string strJson)
{ {
try try
{ {
JObject obj = JObject.Parse(strJson); return JObject.Parse(strJson);
return obj;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -202,11 +197,11 @@ namespace v2rayN
} }
if (wrap) if (wrap)
{ {
return string.Join("," + Environment.NewLine, lst.ToArray()); return string.Join("," + Environment.NewLine, lst);
} }
else else
{ {
return string.Join(",", lst.ToArray()); return string.Join(",", lst);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -225,7 +220,7 @@ namespace v2rayN
try try
{ {
str = str.Replace(Environment.NewLine, ""); 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) catch (Exception ex)
{ {
@@ -244,8 +239,9 @@ namespace v2rayN
try try
{ {
str = str.Replace(Environment.NewLine, ""); str = str.Replace(Environment.NewLine, "");
List<string> list = new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)); List<string> list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
return list.OrderBy(x => x).ToList(); list.Sort();
return list;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -337,7 +333,7 @@ namespace v2rayN
{ {
try try
{ {
return (obj == null ? string.Empty : obj.ToString()); return obj?.ToString() ?? string.Empty;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -414,10 +410,9 @@ namespace v2rayN
public static string GetMD5(string str) public static string GetMD5(string str)
{ {
var md5 = MD5.Create();
byte[] byteOld = Encoding.UTF8.GetBytes(str); byte[] byteOld = Encoding.UTF8.GetBytes(str);
byte[] byteNew = md5.ComputeHash(byteOld); byte[] byteNew = MD5.HashData(byteOld);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new(32);
foreach (byte b in byteNew) foreach (byte b in byteNew)
{ {
sb.Append(b.ToString("x2")); sb.Append(b.ToString("x2"));
@@ -440,7 +435,7 @@ namespace v2rayN
} }
try try
{ {
Uri uri = new Uri(url); Uri uri = new(url);
if (uri.Host == uri.IdnHost) if (uri.Host == uri.IdnHost)
{ {
return url; return url;
@@ -491,7 +486,7 @@ namespace v2rayN
{ {
return true; return true;
} }
if (text.Equals("null")) if (text == "null")
{ {
return true; return true;
} }
@@ -568,18 +563,14 @@ namespace v2rayN
public static bool IsIpv6(string ip) public static bool IsIpv6(string ip)
{ {
IPAddress address; if (IPAddress.TryParse(ip, out IPAddress? address))
if (IPAddress.TryParse(ip, out address))
{ {
switch (address.AddressFamily) return address.AddressFamily switch
{ {
case AddressFamily.InterNetwork: AddressFamily.InterNetwork => false,
return false; AddressFamily.InterNetworkV6 => true,
case AddressFamily.InterNetworkV6: _ => false,
return true; };
default:
return false;
}
} }
return false; return false;
} }
@@ -642,7 +633,7 @@ namespace v2rayN
string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, ""); string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, "");
string exePath = GetExePath(); string exePath = GetExePath();
if (value?.Equals(exePath) == true || value?.Equals($"\"{exePath}\"") == true) if (value == exePath || value == $"\"{exePath}\"")
{ {
return true; return true;
} }
@@ -682,13 +673,13 @@ namespace v2rayN
return Application.StartupPath; 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 try
{ {
regKey = Registry.CurrentUser.OpenSubKey(path, false); regKey = Registry.CurrentUser.OpenSubKey(path, false);
string value = regKey?.GetValue(name) as string; string? value = regKey?.GetValue(name) as string;
if (IsNullOrEmpty(value)) if (IsNullOrEmpty(value))
{ {
return def; return def;
@@ -711,7 +702,7 @@ namespace v2rayN
public static void RegWriteValue(string path, string name, object value) public static void RegWriteValue(string path, string name, object value)
{ {
RegistryKey regKey = null; RegistryKey? regKey = null;
try try
{ {
regKey = Registry.CurrentUser.CreateSubKey(path); regKey = Registry.CurrentUser.CreateSubKey(path);
@@ -743,14 +734,12 @@ namespace v2rayN
public static bool CheckForDotNetVersion(int release = 528040) public static bool CheckForDotNetVersion(int release = 528040)
{ {
const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; 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?.GetValue("Release") != null)
{ {
if (ndpKey != null && ndpKey.GetValue("Release") != null) return (int)ndpKey.GetValue("Release") >= release;
{
return (int)ndpKey.GetValue("Release") >= release ? true : false;
}
return false;
} }
return false;
} }
/// <summary> /// <summary>
@@ -771,27 +760,29 @@ namespace v2rayN
string taskDescription = description; string taskDescription = description;
string deamonFileName = fileName; string deamonFileName = fileName;
using (var taskService = new TaskService()) using var taskService = new TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
foreach (var t in tasks)
{ {
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName)); taskService.RootFolder.DeleteTask(t.Name);
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.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);
} }
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 #endregion
@@ -900,16 +891,13 @@ namespace v2rayN
public static T DeepCopy<T>(T obj) public static T DeepCopy<T>(T obj)
{ {
object retval; object retval;
using (MemoryStream ms = new MemoryStream()) MemoryStream ms = new MemoryStream();
{ BinaryFormatter bf = new BinaryFormatter();
BinaryFormatter bf = new BinaryFormatter(); //序列化成流
//序列化成流 bf.Serialize(ms, obj);
bf.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin);
ms.Seek(0, SeekOrigin.Begin); //反序列化成对象
//反序列化成对象 retval = bf.Deserialize(ms);
retval = bf.Deserialize(ms);
ms.Close();
}
return (T)retval; return (T)retval;
} }
@@ -917,7 +905,7 @@ namespace v2rayN
/// 获取剪贴板数 /// 获取剪贴板数
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string GetClipboardData() public static string? GetClipboardData()
{ {
string strData = string.Empty; string strData = string.Empty;
try try
@@ -1004,7 +992,7 @@ namespace v2rayN
return fileName; return fileName;
} }
public static IPAddress GetDefaultGateway() public static IPAddress? GetDefaultGateway()
{ {
return NetworkInterface return NetworkInterface
.GetAllNetworkInterfaces() .GetAllNetworkInterfaces()
@@ -1067,14 +1055,11 @@ namespace v2rayN
public static string UnGzip(byte[] buf) public static string UnGzip(byte[] buf)
{ {
MemoryStream sb = new MemoryStream(); using MemoryStream sb = new();
using (GZipStream input = new GZipStream(new MemoryStream(buf), using GZipStream input = new(new MemoryStream(buf), CompressionMode.Decompress, false);
CompressionMode.Decompress, input.CopyTo(sb);
false)) sb.Position = 0;
{ return new StreamReader(sb, Encoding.UTF8).ReadToEnd();
input.CopyTo(sb);
}
return Encoding.UTF8.GetString(sb.ToArray());
} }
public static string GetBackupPath(string filename) public static string GetBackupPath(string filename)
@@ -1117,7 +1102,14 @@ namespace v2rayN
Directory.CreateDirectory(_tempPath); 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 = "") public static string GetLogPath(string filename = "")
{ {
@@ -1135,6 +1127,22 @@ namespace v2rayN
return Path.Combine(_tempPath, filename); 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 #endregion
@@ -1150,7 +1158,7 @@ namespace v2rayN
var logger = LogManager.GetLogger("Log2"); var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}"); logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace); logger.Debug(ex.StackTrace);
if (ex != null && ex.InnerException != null) if (ex?.InnerException != null)
{ {
logger.Error(ex.InnerException); logger.Error(ex.InnerException);
} }
@@ -1167,42 +1175,40 @@ namespace v2rayN
{ {
foreach (Screen screen in Screen.AllScreens) foreach (Screen screen in Screen.AllScreens)
{ {
using (Bitmap fullImage = new Bitmap(screen.Bounds.Width, using Bitmap fullImage = new Bitmap(screen.Bounds.Width,
screen.Bounds.Height)) 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(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new(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, g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
screen.Bounds.Y, cropRect,
0, 0, GraphicsUnit.Pixel);
fullImage.Size,
CopyPixelOperation.SourceCopy);
} }
int maxTry = 10;
for (int i = 0; i < maxTry; i++) BitmapLuminanceSource source = new(target);
BinaryBitmap bitmap = new(new HybridBinarizer(source));
QRCodeReader reader = new();
Result result = reader.decode(bitmap);
if (result != null)
{ {
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry); string ret = result.Text;
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry); return ret;
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;
}
} }
} }
} }

View File

@@ -26,6 +26,7 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> BrowseServerCmd { get; } public ReactiveCommand<Unit, Unit> BrowseServerCmd { get; }
public ReactiveCommand<Unit, Unit> EditServerCmd { get; } public ReactiveCommand<Unit, Unit> EditServerCmd { get; }
public ReactiveCommand<Unit, Unit> SaveServerCmd { get; } public ReactiveCommand<Unit, Unit> SaveServerCmd { get; }
public bool IsModified { get; set; }
public AddServer2ViewModel(ProfileItem profileItem, Window view) public AddServer2ViewModel(ProfileItem profileItem, Window view)
{ {
@@ -105,7 +106,7 @@ namespace v2rayN.ViewModels
{ {
UI.Show(ResUI.CustomServerTips); UI.Show(ResUI.CustomServerTips);
OpenFileDialog fileDialog = new OpenFileDialog OpenFileDialog fileDialog = new()
{ {
Multiselect = false, Multiselect = false,
Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*" Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*"
@@ -120,15 +121,16 @@ namespace v2rayN.ViewModels
return; return;
} }
var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId); var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId);
if (item is null) item ??= SelectedSource;
{
item = SelectedSource;
}
item.address = fileName; item.address = fileName;
if (ConfigHandler.AddCustomServer(ref _config, item, false) == 0) if (ConfigHandler.AddCustomServer(ref _config, item, false) == 0)
{ {
_noticeHandler?.Enqueue(ResUI.SuccessfullyImportedCustomServer); _noticeHandler?.Enqueue(ResUI.SuccessfullyImportedCustomServer);
_view.DialogResult = true; if (!Utils.IsNullOrEmpty(item.indexId))
{
SelectedSource = Utils.DeepCopy(item);
}
IsModified = true;
} }
else else
{ {

View File

@@ -37,8 +37,8 @@ namespace v2rayN.ViewModels
private string _serverFilter = string.Empty; private string _serverFilter = string.Empty;
private static Config _config; private static Config _config;
private NoticeHandler? _noticeHandler; private NoticeHandler? _noticeHandler;
private readonly PaletteHelper _paletteHelper = new PaletteHelper(); private readonly PaletteHelper _paletteHelper = new();
private Dictionary<int, bool> _dicHeaderSort = new(); private Dictionary<string, bool> _dicHeaderSort = new();
private Action<string> _updateView; private Action<string> _updateView;
#endregion #endregion
@@ -84,6 +84,7 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; } public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; } public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
//servers delete //servers delete
public ReactiveCommand<Unit, Unit> EditServerCmd { get; }
public ReactiveCommand<Unit, Unit> RemoveServerCmd { get; } public ReactiveCommand<Unit, Unit> RemoveServerCmd { get; }
public ReactiveCommand<Unit, Unit> RemoveDuplicateServerCmd { get; } public ReactiveCommand<Unit, Unit> RemoveDuplicateServerCmd { get; }
public ReactiveCommand<Unit, Unit> CopyServerCmd { get; } public ReactiveCommand<Unit, Unit> CopyServerCmd { get; }
@@ -174,6 +175,8 @@ namespace v2rayN.ViewModels
[Reactive] [Reactive]
public string RunningServerDisplay { get; set; } public string RunningServerDisplay { get; set; }
[Reactive] [Reactive]
public string RunningServerToolTipText { get; set; }
[Reactive]
public string RunningInfoDisplay { get; set; } public string RunningInfoDisplay { get; set; }
[Reactive] [Reactive]
public string SpeedProxyDisplay { get; set; } public string SpeedProxyDisplay { get; set; }
@@ -188,6 +191,8 @@ namespace v2rayN.ViewModels
public IObservableCollection<Swatch> Swatches => _swatches; public IObservableCollection<Swatch> Swatches => _swatches;
[Reactive] [Reactive]
public Swatch SelectedSwatch { get; set; } public Swatch SelectedSwatch { get; set; }
[Reactive]
public int CurrentFontSize { get; set; }
[Reactive] [Reactive]
public string CurrentLanguage { get; set; } public string CurrentLanguage { get; set; }
@@ -211,10 +216,15 @@ namespace v2rayN.ViewModels
SelectedMoveToGroup = new(); SelectedMoveToGroup = new();
SelectedRouting = new(); SelectedRouting = new();
SelectedServer = new(); SelectedServer = new();
if (_config.tunModeItem.enableTun && Utils.IsAdministrator())
{
EnableTun = true;
}
_subId = _config.subIndexId;
//RefreshServers();
InitSubscriptionView(); InitSubscriptionView();
RefreshRoutingsMenu(); RefreshRoutingsMenu();
RefreshServers();
var canEditRemove = this.WhenAnyValue( var canEditRemove = this.WhenAnyValue(
x => x.SelectedProfile, x => x.SelectedProfile,
@@ -247,7 +257,7 @@ namespace v2rayN.ViewModels
SystemProxySelected = (int)_config.sysProxyType; SystemProxySelected = (int)_config.sysProxyType;
this.WhenAnyValue( this.WhenAnyValue(
x => x.SystemProxySelected, x => x.SystemProxySelected,
y => y != null && y >= 0) y => y >= 0)
.Subscribe(c => DoSystemProxySelected(c)); .Subscribe(c => DoSystemProxySelected(c));
this.WhenAnyValue( this.WhenAnyValue(
@@ -293,6 +303,10 @@ namespace v2rayN.ViewModels
return ScanScreenTaskAsync(); return ScanScreenTaskAsync();
}); });
//servers delete //servers delete
EditServerCmd = ReactiveCommand.Create(() =>
{
EditServer(false, EConfigType.Custom);
}, canEditRemove);
RemoveServerCmd = ReactiveCommand.Create(() => RemoveServerCmd = ReactiveCommand.Create(() =>
{ {
RemoveServer(); RemoveServer();
@@ -354,7 +368,7 @@ namespace v2rayN.ViewModels
}, canEditRemove); }, canEditRemove);
SortServerResultCmd = ReactiveCommand.Create(() => SortServerResultCmd = ReactiveCommand.Create(() =>
{ {
SortServer((int)EServerColName.delay); SortServer(EServerColName.delayVal.ToString());
}); });
//servers export //servers export
Export2ClientConfigCmd = ReactiveCommand.Create(() => Export2ClientConfigCmd = ReactiveCommand.Create(() =>
@@ -495,7 +509,7 @@ namespace v2rayN.ViewModels
//MainFormHandler.Instance.BackupGuiNConfig(_config, true); //MainFormHandler.Instance.BackupGuiNConfig(_config, true);
_coreHandler = new CoreHandler(UpdateHandler); _coreHandler = new CoreHandler(UpdateHandler);
if (_config.enableStatistics) if (_config.guiItem.enableStatistics)
{ {
_statistics = new StatisticsHandler(_config, UpdateStatisticsHandler); _statistics = new StatisticsHandler(_config, UpdateStatisticsHandler);
} }
@@ -521,12 +535,21 @@ namespace v2rayN.ViewModels
{ {
_noticeHandler?.SendMessage(msg); _noticeHandler?.SendMessage(msg);
} }
private async void UpdateTaskHandler(bool success, string msg) private void UpdateTaskHandler(bool success, string msg)
{ {
_noticeHandler?.SendMessage(msg); _noticeHandler?.SendMessage(msg);
if (success) if (success)
{ {
Reload(); var indexIdOld = _config.indexId;
RefreshServers();
if (indexIdOld != _config.indexId)
{
Reload();
}
if (_config.uiItem.enableAutoAdjustMainLvColWidth)
{
_updateView("AdjustMainLvColWidth");
}
} }
} }
private void UpdateStatisticsHandler(ServerSpeedItem update) private void UpdateStatisticsHandler(ServerSpeedItem update)
@@ -555,7 +578,16 @@ namespace v2rayN.ViewModels
item.totalDown = Utils.HumanFy(update.totalDown); item.totalDown = Utils.HumanFy(update.totalDown);
item.totalUp = Utils.HumanFy(update.totalUp); item.totalUp = Utils.HumanFy(update.totalUp);
_profileItems.Replace(item, Utils.DeepCopy(item)); if (SelectedProfile?.indexId == item.indexId)
{
var temp = Utils.DeepCopy(item);
_profileItems.Replace(item, temp);
SelectedProfile = temp;
}
else
{
_profileItems.Replace(item, Utils.DeepCopy(item));
}
} }
} }
} }
@@ -577,7 +609,8 @@ namespace v2rayN.ViewModels
{ {
if (Utils.IsNullOrEmpty(indexId)) if (Utils.IsNullOrEmpty(indexId))
{ {
_noticeHandler?.SendMessage(delay); _noticeHandler?.SendMessage(delay, true);
_noticeHandler?.Enqueue(delay);
return; return;
} }
var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault(); var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault();
@@ -638,6 +671,8 @@ namespace v2rayN.ViewModels
SysProxyHandle.UpdateSysProxy(_config, true); SysProxyHandle.UpdateSysProxy(_config, true);
} }
ProfileExHandler.Instance.SaveTo();
_statistics?.SaveTo(); _statistics?.SaveTo();
_statistics?.Close(); _statistics?.Close();
@@ -663,6 +698,7 @@ namespace v2rayN.ViewModels
return; return;
} }
_subId = SelectedSub?.id; _subId = SelectedSub?.id;
_config.subIndexId = _subId;
RefreshServers(); RefreshServers();
@@ -682,17 +718,19 @@ namespace v2rayN.ViewModels
private void RefreshServers() private void RefreshServers()
{ {
List<ProfileItemModel> lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter); List<ProfileItemModel> lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter);
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel)); ConfigHandler.SetDefaultServer(_config, lstModel);
List<ServerStatItem> lstServerStat = new(); List<ServerStatItem> lstServerStat = new();
if (_statistics != null && _statistics.Enable) if (_statistics != null && _statistics.Enable)
{ {
lstServerStat = _statistics.ServerStat; lstServerStat = _statistics.ServerStat;
} }
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
lstModel = (from t in lstModel lstModel = (from t in lstModel
join t2 in lstServerStat join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
on t.indexId equals t2.indexId into t2b
from t22 in t2b.DefaultIfEmpty() 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 select new ProfileItemModel
{ {
indexId = t.indexId, indexId = t.indexId,
@@ -704,17 +742,17 @@ namespace v2rayN.ViewModels
network = t.network, network = t.network,
streamSecurity = t.streamSecurity, streamSecurity = t.streamSecurity,
subRemarks = t.subRemarks, subRemarks = t.subRemarks,
isActive = t.isActive, isActive = t.indexId == _config.indexId,
delay = t.delay, sort = t33 == null ? 0 : t33.sort,
delayVal = t.delay != 0 ? $"{t.delay} {Global.DelayUnit}" : string.Empty, delay = t33 == null ? 0 : t33.delay,
speedVal = t.speed != 0 ? $"{t.speed} {Global.SpeedUnit}" : string.Empty, 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), todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp), todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown), totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp) totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).ToList(); }).OrderBy(t => t.sort).ToList();
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
ConfigHandler.SetDefaultServer(_config, _lstProfile);
Application.Current.Dispatcher.Invoke((Action)(() => Application.Current.Dispatcher.Invoke((Action)(() =>
{ {
@@ -722,7 +760,15 @@ namespace v2rayN.ViewModels
_profileItems.AddRange(lstModel); _profileItems.AddRange(lstModel);
if (lstModel.Count > 0) 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(); RefreshServersMenu();
@@ -731,7 +777,9 @@ namespace v2rayN.ViewModels
var running = ConfigHandler.GetDefaultServer(ref _config); var running = ConfigHandler.GetDefaultServer(ref _config);
if (running != null) if (running != null)
{ {
RunningServerDisplay = string.Format("{0}:{1}", ResUI.menuServers, running.GetSummary()); var runningSummary = running.GetSummary();
RunningServerDisplay = $"{ResUI.menuServers}:{runningSummary}";
RunningServerToolTipText = runningSummary;
} }
})); }));
} }
@@ -739,7 +787,7 @@ namespace v2rayN.ViewModels
private void RefreshServersMenu() private void RefreshServersMenu()
{ {
_servers.Clear(); _servers.Clear();
if (_lstProfile.Count > _config.trayMenuServersLimit) if (_lstProfile.Count > _config.guiItem.trayMenuServersLimit)
{ {
return; return;
} }
@@ -751,7 +799,7 @@ namespace v2rayN.ViewModels
var item = new ComboItem() { ID = it.indexId, Text = name }; var item = new ComboItem() { ID = it.indexId, Text = name };
_servers.Add(item); _servers.Add(item);
if (_config.indexId.Equals(it.indexId)) if (_config.indexId == it.indexId)
{ {
SelectedServer = item; SelectedServer = item;
} }
@@ -767,7 +815,14 @@ namespace v2rayN.ViewModels
{ {
_subItems.Add(item); _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 #endregion
@@ -776,7 +831,7 @@ namespace v2rayN.ViewModels
private int GetProfileItems(out List<ProfileItem> lstSelecteds) private int GetProfileItems(out List<ProfileItem> lstSelecteds)
{ {
lstSelecteds = new List<ProfileItem>(); lstSelecteds = new List<ProfileItem>();
if (SelectedProfiles == null || SelectedProfiles.Count() <= 0) if (SelectedProfiles == null || SelectedProfiles.Count <= 0)
{ {
return -1; return -1;
} }
@@ -841,6 +896,7 @@ namespace v2rayN.ViewModels
int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData, _subId, false); int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData, _subId, false);
if (ret > 0) if (ret > 0)
{ {
InitSubscriptionView();
RefreshServers(); RefreshServers();
_noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret)); _noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret));
} }
@@ -865,6 +921,7 @@ namespace v2rayN.ViewModels
int ret = ConfigHandler.AddBatchServers(ref _config, result, _subId, false); int ret = ConfigHandler.AddBatchServers(ref _config, result, _subId, false);
if (ret > 0) if (ret > 0)
{ {
InitSubscriptionView();
RefreshServers(); RefreshServers();
_noticeHandler?.Enqueue(ResUI.SuccessfullyImportedServerViaScan); _noticeHandler?.Enqueue(ResUI.SuccessfullyImportedServerViaScan);
} }
@@ -881,12 +938,16 @@ namespace v2rayN.ViewModels
{ {
return; return;
} }
var exists = lstSelecteds.Exists(t => t.indexId == _config.indexId);
ConfigHandler.RemoveServer(_config, lstSelecteds); ConfigHandler.RemoveServer(_config, lstSelecteds);
_noticeHandler?.Enqueue(ResUI.OperationSuccess); _noticeHandler?.Enqueue(ResUI.OperationSuccess);
RefreshServers(); RefreshServers();
Reload(); if (exists)
{
Reload();
}
} }
private void RemoveDuplicateServer() private void RemoveDuplicateServer()
@@ -912,7 +973,7 @@ namespace v2rayN.ViewModels
public void SetDefaultServer() public void SetDefaultServer()
{ {
if (Utils.IsNullOrEmpty(SelectedProfile.indexId)) if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
{ {
return; return;
} }
@@ -935,7 +996,7 @@ namespace v2rayN.ViewModels
return; return;
} }
if (ConfigHandler.SetDefaultServer(ref _config, item) == 0) if (ConfigHandler.SetDefaultServerIndex(ref _config, indexId) == 0)
{ {
RefreshServers(); RefreshServers();
Reload(); Reload();
@@ -982,23 +1043,23 @@ namespace v2rayN.ViewModels
await DialogHost.Show(dialog, "RootDialog"); await DialogHost.Show(dialog, "RootDialog");
} }
public void SortServer(int colIndex) public void SortServer(string colName)
{ {
if (colIndex < 0) if (Utils.IsNullOrEmpty(colName))
{ {
return; return;
} }
if (!_dicHeaderSort.ContainsKey(colIndex)) if (!_dicHeaderSort.ContainsKey(colName))
{ {
_dicHeaderSort.Add(colIndex, true); _dicHeaderSort.Add(colName, true);
} }
_dicHeaderSort.TryGetValue(colIndex, out bool asc); _dicHeaderSort.TryGetValue(colName, out bool asc);
if (ConfigHandler.SortServers(ref _config, _subId, (EServerColName)colIndex, asc) != 0) if (ConfigHandler.SortServers(ref _config, _subId, colName, asc) != 0)
{ {
return; return;
} }
_dicHeaderSort[colIndex] = !asc; _dicHeaderSort[colName] = !asc;
RefreshServers(); RefreshServers();
} }
@@ -1011,7 +1072,7 @@ namespace v2rayN.ViewModels
} }
(new UpdateHandle()).RunAvailabilityCheck((bool success, string msg) => (new UpdateHandle()).RunAvailabilityCheck((bool success, string msg) =>
{ {
_noticeHandler?.SendMessage(msg); _noticeHandler?.SendMessage(msg, true);
Application.Current.Dispatcher.Invoke((Action)(() => Application.Current.Dispatcher.Invoke((Action)(() =>
{ {
if (!Global.ShowInTaskbar) if (!Global.ShowInTaskbar)
@@ -1119,7 +1180,7 @@ namespace v2rayN.ViewModels
return; return;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new();
foreach (var it in lstSelecteds) foreach (var it in lstSelecteds)
{ {
string url = ShareHandler.GetShareUrl(it); string url = ShareHandler.GetShareUrl(it);
@@ -1133,7 +1194,7 @@ namespace v2rayN.ViewModels
if (sb.Length > 0) if (sb.Length > 0)
{ {
Utils.SetClipboardData(sb.ToString()); Utils.SetClipboardData(sb.ToString());
_noticeHandler?.Enqueue(ResUI.BatchExportURLSuccessfully); _noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully);
} }
} }
@@ -1144,10 +1205,10 @@ namespace v2rayN.ViewModels
return; return;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new();
foreach (var it in lstSelecteds) foreach (var it in lstSelecteds)
{ {
string url = ShareHandler.GetShareUrl(it); string? url = ShareHandler.GetShareUrl(it);
if (Utils.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
{ {
continue; continue;
@@ -1158,7 +1219,7 @@ namespace v2rayN.ViewModels
if (sb.Length > 0) if (sb.Length > 0)
{ {
Utils.SetClipboardData(Utils.Base64Encode(sb.ToString())); Utils.SetClipboardData(Utils.Base64Encode(sb.ToString()));
_noticeHandler?.Enqueue(ResUI.BatchExportSubscriptionSuccessfully); _noticeHandler?.SendMessage(ResUI.BatchExportSubscriptionSuccessfully);
} }
} }
@@ -1187,20 +1248,7 @@ namespace v2rayN.ViewModels
private void UpdateSubscriptionProcess(string subId, bool blProxy) private void UpdateSubscriptionProcess(string subId, bool blProxy)
{ {
void _updateUI(bool success, string msg) (new UpdateHandle()).UpdateSubscriptionProcess(_config, subId, blProxy, UpdateTaskHandler);
{
_noticeHandler?.SendMessage(msg);
if (success)
{
RefreshServers();
if (_config.uiItem.enableAutoAdjustMainLvColWidth)
{
_updateView("AdjustMainLvColWidth");
}
}
};
(new UpdateHandle()).UpdateSubscriptionProcess(_config, subId, blProxy, _updateUI);
} }
#endregion #endregion
@@ -1231,7 +1279,7 @@ namespace v2rayN.ViewModels
private void ImportOldGuiConfig() private void ImportOldGuiConfig()
{ {
OpenFileDialog fileDialog = new OpenFileDialog OpenFileDialog fileDialog = new()
{ {
Multiselect = false, Multiselect = false,
Filter = "guiNConfig|*.json|All|*.*" Filter = "guiNConfig|*.json|All|*.*"
@@ -1275,7 +1323,7 @@ namespace v2rayN.ViewModels
MyAppExit(false); MyAppExit(false);
} }
}; };
(new UpdateHandle()).CheckUpdateGuiN(_config, _updateUI, _config.checkPreReleaseUpdate); (new UpdateHandle()).CheckUpdateGuiN(_config, _updateUI, _config.guiItem.checkPreReleaseUpdate);
} }
private void CheckUpdateCore(ECoreType type) private void CheckUpdateCore(ECoreType type)
@@ -1290,7 +1338,7 @@ namespace v2rayN.ViewModels
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(msg)); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(msg));
string toPath = Utils.GetBinPath("", type); string toPath = Utils.GetBinPath("", type);
FileManager.ZipExtractToFile(fileName, toPath, _config.ignoreGeoUpdateCore ? "geo" : ""); FileManager.ZipExtractToFile(fileName, toPath, _config.guiItem.ignoreGeoUpdateCore ? "geo" : "");
_noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfullyMore); _noticeHandler?.SendMessage(ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
@@ -1304,7 +1352,7 @@ namespace v2rayN.ViewModels
} }
} }
}; };
(new UpdateHandle()).CheckUpdateCore(type, _config, _updateUI, _config.checkPreReleaseUpdate); (new UpdateHandle()).CheckUpdateCore(type, _config, _updateUI, _config.guiItem.checkPreReleaseUpdate);
} }
private void CheckUpdateGeo() private void CheckUpdateGeo()
@@ -1323,7 +1371,6 @@ namespace v2rayN.ViewModels
public void Reload() public void Reload()
{ {
Global.reloadCore = true;
_ = LoadV2ray(); _ = LoadV2ray();
} }
@@ -1343,7 +1390,6 @@ namespace v2rayN.ViewModels
{ {
_coreHandler.LoadCore(_config); _coreHandler.LoadCore(_config);
Global.reloadCore = false;
//ConfigHandler.SaveConfig(ref _config, false); //ConfigHandler.SaveConfig(ref _config, false);
ChangeSystemProxyStatus(_config.sysProxyType, false); ChangeSystemProxyStatus(_config.sysProxyType, false);
@@ -1408,7 +1454,7 @@ namespace v2rayN.ViewModels
private void RefreshRoutingsMenu() private void RefreshRoutingsMenu()
{ {
_routingItems.Clear(); _routingItems.Clear();
if (!_config.enableRoutingAdvanced) if (!_config.routingBasicItem.enableRoutingAdvanced)
{ {
BlRouting = false; BlRouting = false;
return; return;
@@ -1419,7 +1465,7 @@ namespace v2rayN.ViewModels
foreach (var item in routings) foreach (var item in routings)
{ {
_routingItems.Add(item); _routingItems.Add(item);
if (item.id.Equals(_config.routingIndexId)) if (item.id == _config.routingBasicItem.routingIndexId)
{ {
SelectedRouting = item; SelectedRouting = item;
} }
@@ -1443,7 +1489,7 @@ namespace v2rayN.ViewModels
{ {
return; return;
} }
if (_config.routingIndexId == item.id) if (_config.routingBasicItem.routingIndexId == item.id)
{ {
return; return;
} }
@@ -1495,7 +1541,7 @@ namespace v2rayN.ViewModels
public void ShowHideWindow(bool? blShow) public void ShowHideWindow(bool? blShow)
{ {
var bl = blShow.HasValue ? blShow.Value : !Global.ShowInTaskbar; var bl = blShow ?? !Global.ShowInTaskbar;
if (bl) if (bl)
{ {
//Application.Current.MainWindow.ShowInTaskbar = true; //Application.Current.MainWindow.ShowInTaskbar = true;
@@ -1544,6 +1590,7 @@ namespace v2rayN.ViewModels
{ {
SelectedSwatch = _swatches.FirstOrDefault(t => t.Name == _config.uiItem.colorPrimaryName); SelectedSwatch = _swatches.FirstOrDefault(t => t.Name == _config.uiItem.colorPrimaryName);
} }
CurrentFontSize = _config.uiItem.currentFontSize;
CurrentLanguage = _config.uiItem.currentLanguage; CurrentLanguage = _config.uiItem.currentLanguage;
this.WhenAnyValue( this.WhenAnyValue(
@@ -1579,6 +1626,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( this.WhenAnyValue(
x => x.CurrentLanguage, x => x.CurrentLanguage,
y => y != null && !y.IsNullOrEmpty()) y => y != null && !y.IsNullOrEmpty())
@@ -1595,7 +1660,7 @@ namespace v2rayN.ViewModels
public void InboundDisplayStaus() public void InboundDisplayStaus()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new();
sb.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}]"); sb.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}]");
sb.Append(" | "); sb.Append(" | ");
//if (_config.sysProxyType == ESysProxyType.ForcedChange) //if (_config.sysProxyType == ESysProxyType.ForcedChange)
@@ -1606,21 +1671,21 @@ namespace v2rayN.ViewModels
//{ //{
sb.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]"); 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].allowLANConn)
{ {
if (_config.inbound[0].newPort4LAN) if (_config.inbound[0].newPort4LAN)
{ {
StringBuilder sb2 = new StringBuilder(); StringBuilder sb2 = new();
sb2.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks2)}]"); sb2.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks2)}]");
sb2.Append(" | "); sb2.Append(" | ");
sb2.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp2)}]"); sb2.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp2)}]");
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2.ToString()}"; InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}";
} }
else else
{ {
InboundLanDisplay = $"{ResUI.LabLAN}:{sb.ToString()}"; InboundLanDisplay = $"{ResUI.LabLAN}:{sb}";
} }
} }
else else
@@ -1651,16 +1716,16 @@ namespace v2rayN.ViewModels
private void AutoHideStartup() private void AutoHideStartup()
{ {
if (_config.autoHideStartup) if (_config.uiItem.autoHideStartup)
{ {
Observable.Range(1, 1) Observable.Range(1, 1)
.Delay(TimeSpan.FromSeconds(1)) .Delay(TimeSpan.FromSeconds(1))
.Subscribe(x => .Subscribe(x =>
{ {
Application.Current.Dispatcher.Invoke((Action)(() => Application.Current.Dispatcher.Invoke(() =>
{ {
ShowHideWindow(false); ShowHideWindow(false);
})); });
}); });
} }
} }

View File

@@ -28,6 +28,8 @@ namespace v2rayN.ViewModels
[Reactive] public bool logEnabled { get; set; } [Reactive] public bool logEnabled { get; set; }
[Reactive] public string loglevel { get; set; } [Reactive] public string loglevel { get; set; }
[Reactive] public bool defAllowInsecure { get; set; } [Reactive] public bool defAllowInsecure { get; set; }
[Reactive] public string defFingerprint { get; set; }
[Reactive] public string defUserAgent { get; set; }
#endregion #endregion
#region Core DNS #region Core DNS
@@ -55,10 +57,15 @@ namespace v2rayN.ViewModels
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; } [Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
[Reactive] public bool AutoHideStartup { get; set; } [Reactive] public bool AutoHideStartup { get; set; }
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; } [Reactive] public bool EnableCheckPreReleaseUpdate { get; set; }
[Reactive] public bool EnableDragDropSort { get; set; } [Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int autoUpdateInterval { get; set; } [Reactive] public int autoUpdateInterval { get; set; }
[Reactive] public int autoUpdateSubInterval { get; set; } [Reactive] public int autoUpdateSubInterval { get; set; }
[Reactive] public int trayMenuServersLimit { 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 #endregion
#region System proxy #region System proxy
@@ -68,12 +75,19 @@ namespace v2rayN.ViewModels
#region Tun mode #region Tun mode
[Reactive] public bool TunShowWindow { get; set; } [Reactive] public bool TunShowWindow { get; set; }
[Reactive] public bool TunEnabledLog { get; set; }
[Reactive] public bool TunStrictRoute { get; set; } [Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; } [Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
[Reactive] public string TunCustomTemplate { 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 TunDirectIP { get; set; }
[Reactive] public string TunDirectProcess { get; set; } [Reactive] public string TunDirectProcess { get; set; }
[Reactive] public string TunDirectDNS { get; set; }
[Reactive] public string TunProxyIP { get; set; }
[Reactive] public string TunProxyProcess { get; set; }
[Reactive] public string TunProxyDNS { get; set; }
#endregion #endregion
#region CoreType #region CoreType
@@ -105,10 +119,12 @@ namespace v2rayN.ViewModels
newPort4LAN = inbound.newPort4LAN; newPort4LAN = inbound.newPort4LAN;
user = inbound.user; user = inbound.user;
pass = inbound.pass; pass = inbound.pass;
muxEnabled = _config.muxEnabled; muxEnabled = _config.coreBasicItem.muxEnabled;
logEnabled = _config.logEnabled; logEnabled = _config.coreBasicItem.logEnabled;
loglevel = _config.loglevel; loglevel = _config.coreBasicItem.loglevel;
defAllowInsecure = _config.defAllowInsecure; defAllowInsecure = _config.coreBasicItem.defAllowInsecure;
defFingerprint = _config.coreBasicItem.defFingerprint;
defUserAgent = _config.coreBasicItem.defUserAgent;
#endregion #endregion
#region Core DNS #region Core DNS
@@ -127,19 +143,24 @@ namespace v2rayN.ViewModels
#endregion #endregion
#region UI #region UI
AutoRun = _config.autoRun; AutoRun = _config.guiItem.autoRun;
EnableStatistics = _config.enableStatistics; EnableStatistics = _config.guiItem.enableStatistics;
StatisticsFreshRate = _config.statisticsFreshRate; StatisticsFreshRate = _config.guiItem.statisticsFreshRate;
KeepOlderDedupl = _config.keepOlderDedupl; KeepOlderDedupl = _config.guiItem.keepOlderDedupl;
IgnoreGeoUpdateCore = _config.ignoreGeoUpdateCore; IgnoreGeoUpdateCore = _config.guiItem.ignoreGeoUpdateCore;
EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth; EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth;
EnableSecurityProtocolTls13 = _config.enableSecurityProtocolTls13; EnableSecurityProtocolTls13 = _config.guiItem.enableSecurityProtocolTls13;
AutoHideStartup = _config.autoHideStartup; AutoHideStartup = _config.uiItem.autoHideStartup;
EnableCheckPreReleaseUpdate = _config.checkPreReleaseUpdate; EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate;
EnableDragDropSort = _config.uiItem.enableDragDropSort; EnableDragDropSort = _config.uiItem.enableDragDropSort;
autoUpdateInterval = _config.autoUpdateInterval; DoubleClick2Activate = _config.uiItem.doubleClick2Activate;
autoUpdateSubInterval = _config.autoUpdateSubInterval; autoUpdateInterval = _config.guiItem.autoUpdateInterval;
trayMenuServersLimit = _config.trayMenuServersLimit; autoUpdateSubInterval = _config.guiItem.autoUpdateSubInterval;
trayMenuServersLimit = _config.guiItem.trayMenuServersLimit;
currentFontFamily = _config.uiItem.currentFontFamily;
SpeedTestTimeout = _config.speedTestItem.speedTestTimeout;
SpeedTestUrl = _config.speedTestItem.speedTestUrl;
#endregion #endregion
#region System proxy #region System proxy
@@ -150,12 +171,21 @@ namespace v2rayN.ViewModels
#region Tun mode #region Tun mode
TunShowWindow = _config.tunModeItem.showWindow; TunShowWindow = _config.tunModeItem.showWindow;
TunEnabledLog = _config.tunModeItem.enabledLog;
TunStrictRoute = _config.tunModeItem.strictRoute; TunStrictRoute = _config.tunModeItem.strictRoute;
TunStack = _config.tunModeItem.stack; TunStack = _config.tunModeItem.stack;
TunMtu = _config.tunModeItem.mtu; TunMtu = _config.tunModeItem.mtu;
TunCustomTemplate = _config.tunModeItem.customTemplate; TunCustomTemplate = _config.tunModeItem.customTemplate;
TunBypassMode = _config.tunModeItem.bypassMode;
TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true); TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true);
TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true); TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true);
TunDirectDNS = _config.tunModeItem.directDNS;
TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true);
TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true);
TunProxyDNS = _config.tunModeItem.proxyDNS;
this.WhenAnyValue(
x => x.TunBypassMode)
.Subscribe(c => TunBypassMode2 = !TunBypassMode);
#endregion #endregion
@@ -227,7 +257,7 @@ namespace v2rayN.ViewModels
} }
var obj = Utils.ParseJson(remoteDNS); var obj = Utils.ParseJson(remoteDNS);
if (obj != null && obj.ContainsKey("servers")) if (obj?.ContainsKey("servers") == true)
{ {
} }
else else
@@ -251,7 +281,7 @@ namespace v2rayN.ViewModels
//} //}
//Core //Core
_config.inbound[0].localPort = Utils.ToInt(localPort); _config.inbound[0].localPort = localPort;
_config.inbound[0].udpEnabled = udpEnabled; _config.inbound[0].udpEnabled = udpEnabled;
_config.inbound[0].sniffingEnabled = sniffingEnabled; _config.inbound[0].sniffingEnabled = sniffingEnabled;
_config.inbound[0].routeOnly = routeOnly; _config.inbound[0].routeOnly = routeOnly;
@@ -263,10 +293,12 @@ namespace v2rayN.ViewModels
{ {
_config.inbound.RemoveAt(1); _config.inbound.RemoveAt(1);
} }
_config.logEnabled = logEnabled; _config.coreBasicItem.logEnabled = logEnabled;
_config.loglevel = loglevel; _config.coreBasicItem.loglevel = loglevel;
_config.muxEnabled = muxEnabled; _config.coreBasicItem.muxEnabled = muxEnabled;
_config.defAllowInsecure = defAllowInsecure; _config.coreBasicItem.defAllowInsecure = defAllowInsecure;
_config.coreBasicItem.defFingerprint = defFingerprint;
_config.coreBasicItem.defUserAgent = defUserAgent;
//DNS //DNS
@@ -286,23 +318,27 @@ namespace v2rayN.ViewModels
//UI //UI
Utils.SetAutoRun(AutoRun); Utils.SetAutoRun(AutoRun);
_config.autoRun = AutoRun; _config.guiItem.autoRun = AutoRun;
_config.enableStatistics = EnableStatistics; _config.guiItem.enableStatistics = EnableStatistics;
_config.statisticsFreshRate = StatisticsFreshRate; _config.guiItem.statisticsFreshRate = StatisticsFreshRate;
if (_config.statisticsFreshRate > 100 || _config.statisticsFreshRate < 1) if (_config.guiItem.statisticsFreshRate > 100 || _config.guiItem.statisticsFreshRate < 1)
{ {
_config.statisticsFreshRate = 1; _config.guiItem.statisticsFreshRate = 1;
} }
_config.keepOlderDedupl = KeepOlderDedupl; _config.guiItem.keepOlderDedupl = KeepOlderDedupl;
_config.ignoreGeoUpdateCore = IgnoreGeoUpdateCore; _config.guiItem.ignoreGeoUpdateCore = IgnoreGeoUpdateCore;
_config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth; _config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth;
_config.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13; _config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.autoHideStartup = AutoHideStartup; _config.uiItem.autoHideStartup = AutoHideStartup;
_config.autoUpdateInterval = autoUpdateInterval; _config.guiItem.autoUpdateInterval = autoUpdateInterval;
_config.autoUpdateSubInterval = autoUpdateSubInterval; _config.guiItem.autoUpdateSubInterval = autoUpdateSubInterval;
_config.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate; _config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.uiItem.enableDragDropSort = EnableDragDropSort; _config.uiItem.enableDragDropSort = EnableDragDropSort;
_config.trayMenuServersLimit = trayMenuServersLimit; _config.uiItem.doubleClick2Activate = DoubleClick2Activate;
_config.guiItem.trayMenuServersLimit = trayMenuServersLimit;
_config.uiItem.currentFontFamily = currentFontFamily;
_config.speedTestItem.speedTestTimeout = SpeedTestTimeout;
_config.speedTestItem.speedTestUrl = SpeedTestUrl;
//systemProxy //systemProxy
_config.systemProxyExceptions = systemProxyExceptions; _config.systemProxyExceptions = systemProxyExceptions;
@@ -310,12 +346,18 @@ namespace v2rayN.ViewModels
//tun mode //tun mode
_config.tunModeItem.showWindow = TunShowWindow; _config.tunModeItem.showWindow = TunShowWindow;
_config.tunModeItem.enabledLog = TunEnabledLog;
_config.tunModeItem.strictRoute = TunStrictRoute; _config.tunModeItem.strictRoute = TunStrictRoute;
_config.tunModeItem.stack = TunStack; _config.tunModeItem.stack = TunStack;
_config.tunModeItem.mtu = TunMtu; _config.tunModeItem.mtu = TunMtu;
_config.tunModeItem.customTemplate = TunCustomTemplate; _config.tunModeItem.customTemplate = TunCustomTemplate;
_config.tunModeItem.bypassMode = TunBypassMode;
_config.tunModeItem.directIP = Utils.String2List(TunDirectIP); _config.tunModeItem.directIP = Utils.String2List(TunDirectIP);
_config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess); _config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess);
_config.tunModeItem.directDNS = Utils.ToJson(Utils.ParseJson(TunDirectDNS));
_config.tunModeItem.proxyIP = Utils.String2List(TunProxyIP);
_config.tunModeItem.proxyProcess = Utils.String2List(TunProxyProcess);
_config.tunModeItem.proxyDNS = Utils.ToJson(Utils.ParseJson(TunProxyDNS));
//coreType //coreType
SaveCoreType(); SaveCoreType();

View File

@@ -299,7 +299,7 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.OperationSuccess); UI.Show(ResUI.OperationSuccess);
} }
} }
private void ImportRulesFromUrl() private async Task ImportRulesFromUrl()
{ {
var url = SelectedRouting.url; var url = SelectedRouting.url;
if (Utils.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
@@ -308,19 +308,16 @@ namespace v2rayN.ViewModels
return; return;
} }
Task.Run(async () => DownloadHandle downloadHandle = new DownloadHandle();
string result = await downloadHandle.TryDownloadString(url, true, "");
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{ {
DownloadHandle downloadHandle = new DownloadHandle(); Application.Current.Dispatcher.Invoke((Action)(() =>
string result = await downloadHandle.DownloadStringAsync(url, false, "");
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{ {
Application.Current.Dispatcher.Invoke((Action)(() => RefreshRulesItems();
{ }));
RefreshRulesItems(); UI.Show(ResUI.OperationSuccess);
})); }
UI.Show(ResUI.OperationSuccess);
}
});
} }
private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData) private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData)
{ {

View File

@@ -71,9 +71,9 @@ namespace v2rayN.ViewModels
ConfigHandler.InitBuiltinRouting(ref _config); ConfigHandler.InitBuiltinRouting(ref _config);
enableRoutingAdvanced = _config.enableRoutingAdvanced; enableRoutingAdvanced = _config.routingBasicItem.enableRoutingAdvanced;
domainStrategy = _config.domainStrategy; domainStrategy = _config.routingBasicItem.domainStrategy;
domainMatcher = _config.domainMatcher; domainMatcher = _config.routingBasicItem.domainMatcher;
RefreshRoutingItems(); RefreshRoutingItems();
@@ -163,7 +163,7 @@ namespace v2rayN.ViewModels
foreach (var item in routings) foreach (var item in routings)
{ {
bool def = false; bool def = false;
if (item.id.Equals(_config.routingIndexId)) if (item.id == _config.routingBasicItem.routingIndexId)
{ {
def = true; def = true;
} }
@@ -176,15 +176,16 @@ namespace v2rayN.ViewModels
remarks = item.remarks, remarks = item.remarks,
url = item.url, url = item.url,
customIcon = item.customIcon, customIcon = item.customIcon,
sort = item.sort,
}; };
_routingItems.Add(it); _routingItems.Add(it);
} }
} }
private void SaveRouting() private void SaveRouting()
{ {
_config.domainStrategy = domainStrategy; _config.routingBasicItem.domainStrategy = domainStrategy;
_config.enableRoutingAdvanced = enableRoutingAdvanced; _config.routingBasicItem.enableRoutingAdvanced = enableRoutingAdvanced;
_config.domainMatcher = domainMatcher; _config.routingBasicItem.domainMatcher = domainMatcher;
EndBindingLockedData(); EndBindingLockedData();

View File

@@ -3,6 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Views="clr-namespace:v2rayN.Views" xmlns:Views="clr-namespace:v2rayN.Views"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:v2rayN" xmlns:local="clr-namespace:v2rayN"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
@@ -15,7 +16,10 @@
Height="500" Height="500"
x:TypeArguments="vms:AddServer2ViewModel" x:TypeArguments="vms:AddServer2ViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -70,7 +74,7 @@
Margin="4" Margin="4"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -88,7 +92,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<StackPanel <StackPanel
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
@@ -122,6 +126,7 @@
Width="200" Width="200"
Margin="4" Margin="4"
HorizontalAlignment="Left" HorizontalAlignment="Left"
FontSize="{DynamicResource StdFontSize}"
MaxDropDownHeight="1000" MaxDropDownHeight="1000"
Style="{StaticResource MaterialDesignOutlinedComboBox}" /> Style="{StaticResource MaterialDesignOutlinedComboBox}" />
@@ -154,7 +159,7 @@
Margin="4" Margin="4"
HorizontalAlignment="Left" HorizontalAlignment="Left"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<StackPanel <StackPanel
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"

View File

@@ -11,6 +11,7 @@ namespace v2rayN.Views
public AddServer2Window(ProfileItem profileItem) public AddServer2Window(ProfileItem profileItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
ViewModel = new AddServer2ViewModel(profileItem, this); ViewModel = new AddServer2ViewModel(profileItem, this);
@@ -44,7 +45,14 @@ namespace v2rayN.Views
} }
private void btnCancel_Click(object sender, System.Windows.RoutedEventArgs e) private void btnCancel_Click(object sender, System.Windows.RoutedEventArgs e)
{ {
this.Close(); if (ViewModel?.IsModified == true)
{
this.DialogResult = true;
}
else
{
this.Close();
}
} }
} }

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.Views.AddServerWindow" x:Class="v2rayN.Views.AddServerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,7 +14,10 @@
Height="800" Height="800"
x:TypeArguments="vms:AddServerViewModel" x:TypeArguments="vms:AddServerViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -80,7 +84,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -94,7 +99,8 @@
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -109,7 +115,8 @@
Grid.Column="1" Grid.Column="1"
Width="100" Width="100"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<Separator <Separator
@@ -145,7 +152,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<Button <Button
x:Name="btnGUID" x:Name="btnGUID"
Grid.Row="1" Grid.Row="1"
@@ -168,7 +176,8 @@
Grid.Column="1" Grid.Column="1"
Width="100" Width="100"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -213,7 +222,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -258,7 +268,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -272,7 +283,8 @@
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<Grid <Grid
@@ -303,7 +315,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<Button <Button
x:Name="btnGUID5" x:Name="btnGUID5"
Grid.Row="1" Grid.Row="1"
@@ -341,7 +354,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<Grid <Grid
x:Name="gridTrojan" x:Name="gridTrojan"
@@ -370,7 +384,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -475,7 +490,8 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
x:Name="tipRequestHost" x:Name="tipRequestHost"
Grid.Row="3" Grid.Row="3"
@@ -497,7 +513,8 @@
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
x:Name="tipPath" x:Name="tipPath"
Grid.Row="4" Grid.Row="4"
@@ -569,7 +586,8 @@
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -599,6 +617,7 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
IsEditable="True"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock

View File

@@ -16,6 +16,7 @@ namespace v2rayN.Views
public AddServerWindow(ProfileItem profileItem) public AddServerWindow(ProfileItem profileItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged; cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged; cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
@@ -184,12 +185,12 @@ namespace v2rayN.Views
return; return;
} }
if (network.Equals(Global.DefaultNetwork)) if (network == Global.DefaultNetwork)
{ {
cmbHeaderType.Items.Add(Global.None); cmbHeaderType.Items.Add(Global.None);
cmbHeaderType.Items.Add(Global.TcpHeaderHttp); cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
} }
else if (network.Equals("kcp") || network.Equals("quic")) else if (network is "kcp" or "quic")
{ {
cmbHeaderType.Items.Add(Global.None); cmbHeaderType.Items.Add(Global.None);
Global.kcpHeaderTypes.ForEach(it => Global.kcpHeaderTypes.ForEach(it =>
@@ -197,7 +198,7 @@ namespace v2rayN.Views
cmbHeaderType.Items.Add(it); cmbHeaderType.Items.Add(it);
}); });
} }
else if (network.Equals("grpc")) else if (network == "grpc")
{ {
cmbHeaderType.Items.Add(Global.GrpcgunMode); cmbHeaderType.Items.Add(Global.GrpcgunMode);
cmbHeaderType.Items.Add(Global.GrpcmultiMode); cmbHeaderType.Items.Add(Global.GrpcmultiMode);
@@ -221,37 +222,34 @@ namespace v2rayN.Views
tipPath.Text = tipPath.Text =
tipHeaderType.Text = string.Empty; tipHeaderType.Text = string.Empty;
if (network.Equals(Global.DefaultNetwork)) switch (network)
{ {
tipRequestHost.Text = ResUI.TransportRequestHostTip1; case Global.DefaultNetwork:
tipHeaderType.Text = ResUI.TransportHeaderTypeTip1; tipRequestHost.Text = ResUI.TransportRequestHostTip1;
} tipHeaderType.Text = ResUI.TransportHeaderTypeTip1;
else if (network.Equals("kcp")) break;
{ case "kcp":
tipHeaderType.Text = ResUI.TransportHeaderTypeTip2; tipHeaderType.Text = ResUI.TransportHeaderTypeTip2;
tipPath.Text = ResUI.TransportPathTip5; tipPath.Text = ResUI.TransportPathTip5;
} break;
else if (network.Equals("ws")) case "ws":
{ tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipRequestHost.Text = ResUI.TransportRequestHostTip2; tipPath.Text = ResUI.TransportPathTip1;
tipPath.Text = ResUI.TransportPathTip1; break;
} case "h2":
else if (network.Equals("h2")) tipRequestHost.Text = ResUI.TransportRequestHostTip3;
{ tipPath.Text = ResUI.TransportPathTip2;
tipRequestHost.Text = ResUI.TransportRequestHostTip3; break;
tipPath.Text = ResUI.TransportPathTip2; case "quic":
} tipRequestHost.Text = ResUI.TransportRequestHostTip4;
else if (network.Equals("quic")) tipPath.Text = ResUI.TransportPathTip3;
{ tipHeaderType.Text = ResUI.TransportHeaderTypeTip3;
tipRequestHost.Text = ResUI.TransportRequestHostTip4; break;
tipPath.Text = ResUI.TransportPathTip3; case "grpc":
tipHeaderType.Text = ResUI.TransportHeaderTypeTip3; tipPath.Text = ResUI.TransportPathTip4;
} tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
else if (network.Equals("grpc")) labHeaderType.Visibility = Visibility.Hidden;
{ break;
tipPath.Text = ResUI.TransportPathTip4;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
labHeaderType.Visibility = Visibility.Hidden;
} }
} }

View File

@@ -3,6 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Views="clr-namespace:v2rayN.Views" xmlns:Views="clr-namespace:v2rayN.Views"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -14,8 +15,11 @@
Height="500" Height="500"
x:TypeArguments="vms:SubEditViewModel" x:TypeArguments="vms:SubEditViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
KeyDown="GlobalHotkeySettingWindow_KeyDown" KeyDown="GlobalHotkeySettingWindow_KeyDown"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -68,7 +72,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -85,7 +89,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -102,7 +106,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
@@ -118,7 +122,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
@@ -134,7 +138,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
</Grid> </Grid>
<TextBlock <TextBlock

View File

@@ -16,6 +16,7 @@ namespace v2rayN.Views
public GlobalHotkeySettingWindow() public GlobalHotkeySettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
if (_config.globalHotkeys == null) if (_config.globalHotkeys == null)
@@ -56,19 +57,21 @@ namespace v2rayN.Views
private void TxtGlobalHotkey_KeyDown(object sender, KeyEventArgs e) private void TxtGlobalHotkey_KeyDown(object sender, KeyEventArgs e)
{ {
var txt = ((TextBox)sender); e.Handled = true;
var index = Utils.ToInt(txt.Name.Substring(txt.Name.Length - 1, 1)); var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt };
if (!_ModifierKeys.Contains(e.Key) && !_ModifierKeys.Contains(e.SystemKey))
{
var txt = ((TextBox)sender);
var index = Utils.ToInt(txt.Name.Substring(txt.Name.Length - 1, 1));
var formsKey = (Forms.Keys)KeyInterop.VirtualKeyFromKey(e.Key == Key.System ? e.SystemKey : e.Key);
if (e.Key == Key.System) lstKey[index].KeyCode = formsKey;
return; lstKey[index].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
var formsKey = (Forms.Keys)KeyInterop.VirtualKeyFromKey(e.Key); lstKey[index].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
lstKey[index].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
lstKey[index].KeyCode = formsKey; BindingData(index);
lstKey[index].Alt = Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt); }
lstKey[index].Control = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
lstKey[index].Shift = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
BindingData(index);
} }
private void BindingData(int index) private void BindingData(int index)
@@ -84,19 +87,19 @@ namespace v2rayN.Views
if (item.Control) if (item.Control)
{ {
keys += $"{Forms.Keys.Control.ToString()} + "; keys += $"{Forms.Keys.Control} + ";
} }
if (item.Alt) if (item.Alt)
{ {
keys += $"{Forms.Keys.Alt.ToString()} + "; keys += $"{Forms.Keys.Alt} + ";
} }
if (item.Shift) if (item.Shift)
{ {
keys += $"{Forms.Keys.Shift.ToString()} + "; keys += $"{Forms.Keys.Shift} + ";
} }
if (item.KeyCode != null) if (item.KeyCode != null)
{ {
keys += $"{item.KeyCode.ToString()}"; keys += $"{item.KeyCode}";
} }
SetText($"txtGlobalHotkey{k}", keys); SetText($"txtGlobalHotkey{k}", keys);
@@ -147,11 +150,11 @@ namespace v2rayN.Views
{ {
foreach (UIElement element in gridText.Children) foreach (UIElement element in gridText.Children)
{ {
if (element is TextBox) if (element is TextBox box)
{ {
if (((TextBox)element).Name == name) if (box.Name == name)
{ {
((TextBox)element).Text = txt; box.Text = txt;
} }
} }
} }

View File

@@ -3,7 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:v2rayN.Base" xmlns: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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:v2rayN.Views" xmlns:local="clr-namespace:v2rayN.Views"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
@@ -19,7 +19,9 @@
MinHeight="600" MinHeight="600"
x:TypeArguments="vms:MainWindowViewModel" x:TypeArguments="vms:MainWindowViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ShowInTaskbar="True" ShowInTaskbar="True"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -31,7 +33,7 @@
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" /> <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
<converters:DelayColorConverter x:Key="DelayColorConverter" /> <conv:DelayColorConverter x:Key="DelayColorConverter" />
</ResourceDictionary> </ResourceDictionary>
</Window.Resources> </Window.Resources>
@@ -47,11 +49,14 @@
VerticalAlignment="Center" VerticalAlignment="Center"
ClipToBounds="True" ClipToBounds="True"
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignToolBar}">
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Server" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Server" />
<TextBlock Text="{x:Static resx:ResUI.menuServers}" /> <TextBlock Text="{x:Static resx:ResUI.menuServers}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -93,11 +98,14 @@
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="BookClockOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="BookClockOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuSubscription}" /> <TextBlock Text="{x:Static resx:ResUI.menuSubscription}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -125,11 +133,14 @@
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="SettingsOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="SettingsOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuSetting}" /> <TextBlock Text="{x:Static resx:ResUI.menuSetting}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -163,22 +174,28 @@
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuReload" Padding="8,0"> <MenuItem x:Name="menuReload" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Reload" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Reload" />
<TextBlock Text="{x:Static resx:ResUI.menuReload}" /> <TextBlock Text="{x:Static resx:ResUI.menuReload}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Update" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Update" />
<TextBlock Text="{x:Static resx:ResUI.menuCheckUpdate}" /> <TextBlock Text="{x:Static resx:ResUI.menuCheckUpdate}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -215,39 +232,48 @@
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuHelp" Padding="8,0"> <MenuItem x:Name="menuHelp" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="HelpCircleOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="HelpCircleOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuHelp}" /> <TextBlock Text="{x:Static resx:ResUI.menuHelp}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem <MenuItem
x:Name="menuPromotion" x:Name="menuPromotion"
Padding="8,0" Padding="8,0"
Click="menuPromotion_Click"> Click="menuPromotion_Click">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="VolumeHigh" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="VolumeHigh" />
<TextBlock Text="{x:Static resx:ResUI.menuPromotion}" /> <TextBlock Text="{x:Static resx:ResUI.menuPromotion}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,8" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem <MenuItem
x:Name="menuClose" x:Name="menuClose"
Padding="8,0" Padding="8,0"
Click="menuClose_Click"> Click="menuClose_Click">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Minimize" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Minimize" />
<TextBlock Text="{x:Static resx:ResUI.menuClose}" /> <TextBlock Text="{x:Static resx:ResUI.menuClose}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -257,73 +283,110 @@
<materialDesign:PopupBox <materialDesign:PopupBox
Padding="8,0" Padding="8,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}"> Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
<StackPanel Margin="8"> <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 <TextBlock
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsColorMode}" /> Text="{x:Static resx:ResUI.TbSettingsColorMode}" />
<ToggleButton x:Name="togDarkMode" Margin="8" /> <ToggleButton
</StackPanel> x:Name="togDarkMode"
<StackPanel Orientation="Horizontal"> Grid.Row="0"
Grid.Column="1"
Margin="8" />
<TextBlock <TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsColor}" /> Text="{x:Static resx:ResUI.TbSettingsColor}" />
<ComboBox <ComboBox
x:Name="cmbSwatches" x:Name="cmbSwatches"
Grid.Row="1"
Grid.Column="1"
Width="100" Width="100"
Margin="8" Margin="8"
DisplayMemberPath="Name" DisplayMemberPath="Name"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock <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" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLanguage}" /> Text="{x:Static resx:ResUI.TbSettingsLanguage}" />
<ComboBox <ComboBox
x:Name="cmbCurrentLanguage" x:Name="cmbCurrentLanguage"
Grid.Row="3"
Grid.Column="1"
Width="100" Width="100"
Margin="8" Margin="8"
materialDesign:HintAssist.Hint="Language" materialDesign:HintAssist.Hint="Language"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</StackPanel>
</Grid>
</StackPanel> </StackPanel>
</materialDesign:PopupBox> </materialDesign:PopupBox>
</ToolBar> </ToolBar>
</ToolBarTray> </ToolBarTray>
<ToolBarTray DockPanel.Dock="Top"> <WrapPanel Margin="2" DockPanel.Dock="Top">
<ToolBar <ListBox
HorizontalAlignment="Center" x:Name="lstGroup"
VerticalAlignment="Center" FontSize="{DynamicResource StdFontSize}"
ClipToBounds="True" ItemContainerStyle="{StaticResource MyChipListBoxItem}"
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
<ListBox x:Name="lstGroup" Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}"> <ListBox.ItemTemplate>
<ListBox.ItemTemplate> <DataTemplate>
<DataTemplate> <TextBlock Text="{Binding remarks}" />
<TextBlock Text="{Binding remarks}" /> </DataTemplate>
</DataTemplate> </ListBox.ItemTemplate>
</ListBox.ItemTemplate> </ListBox>
</ListBox> <Button
<Button x:Name="btnAddSub"
x:Name="btnAddSub" Width="30"
Width="30" Height="30"
Height="30" Margin="4,0"
Margin="8,0" Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"> <materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
<materialDesign:PackIcon Kind="Plus" /> </Button>
</Button> <TextBox
<Separator /> x:Name="txtServerFilter"
<TextBox Width="200"
x:Name="txtServerFilter" Margin="4,0"
Width="200" VerticalContentAlignment="Center"
Margin="8,0" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}" materialDesign:TextFieldAssist.HasClearButton="True"
materialDesign:TextFieldAssist.HasClearButton="True" /> Style="{StaticResource DefTextBox}" />
</ToolBar> </WrapPanel>
</ToolBarTray>
<materialDesign:ColorZone <materialDesign:ColorZone
Height="50" Height="50"
@@ -372,6 +435,7 @@
Width="120" Width="120"
Margin="8,0" Margin="8,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSystemproxy}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSystemproxy}"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFloatingHintComboBox}"> Style="{StaticResource MaterialDesignFloatingHintComboBox}">
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" /> <ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" /> <ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
@@ -385,6 +449,7 @@
Margin="8,0" Margin="8,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
DisplayMemberPath="remarks" DisplayMemberPath="remarks"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFloatingHintComboBox}" /> Style="{StaticResource MaterialDesignFloatingHintComboBox}" />
</StackPanel> </StackPanel>
@@ -402,7 +467,7 @@
</DockPanel> </DockPanel>
</materialDesign:ColorZone> </materialDesign:ColorZone>
<Grid> <Grid x:Name="gridMain">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="1*" /> <RowDefinition Height="1*" />
<RowDefinition Height="10" /> <RowDefinition Height="10" />
@@ -411,7 +476,7 @@
<DataGrid <DataGrid
x:Name="lstProfiles" x:Name="lstProfiles"
Grid.Row="0" Grid.Row="0"
materialDesign:DataGridAssist.CellPadding="1,0" materialDesign:DataGridAssist.CellPadding="2,2"
AutoGenerateColumns="False" AutoGenerateColumns="False"
BorderThickness="1" BorderThickness="1"
CanUserAddRows="False" CanUserAddRows="False"
@@ -419,6 +484,7 @@
CanUserSortColumns="False" CanUserSortColumns="False"
EnableRowVirtualization="True" EnableRowVirtualization="True"
Focusable="True" Focusable="True"
FrozenColumnCount="1"
GridLinesVisibility="All" GridLinesVisibility="All"
HeadersVisibility="All" HeadersVisibility="All"
IsReadOnly="True" IsReadOnly="True"
@@ -431,6 +497,10 @@
</DataGrid.InputBindings> </DataGrid.InputBindings>
<DataGrid.ContextMenu> <DataGrid.ContextMenu>
<ContextMenu Style="{StaticResource DefContextMenu}"> <ContextMenu Style="{StaticResource DefContextMenu}">
<MenuItem
x:Name="menuEditServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuEditServer}" />
<MenuItem <MenuItem
x:Name="menuSetDefaultServer" x:Name="menuSetDefaultServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -452,45 +522,6 @@
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuShareServer}" /> Header="{x:Static resx:ResUI.menuShareServer}" />
<Separator /> <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"
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 <MenuItem
x:Name="menuMixedTestServer" x:Name="menuMixedTestServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -516,6 +547,48 @@
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSortServerResult}" /> Header="{x:Static resx:ResUI.menuSortServerResult}" />
<Separator /> <Separator />
<MenuItem
x:Name="menuMoveToGroup"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveToGroup}">
<MenuItem Height="Auto">
<MenuItem.Header>
<DockPanel>
<ComboBox
x:Name="cmbMoveToGroup"
Width="200"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
DisplayMemberPath="remarks"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilledComboBox}" />
</DockPanel>
</MenuItem.Header>
</MenuItem>
</MenuItem>
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
<MenuItem
x:Name="menuMoveTop"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveTop}" />
<MenuItem
x:Name="menuMoveUp"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveUp}" />
<MenuItem
x:Name="menuMoveDown"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveDown}" />
<MenuItem
x:Name="menuMoveBottom"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}" />
</MenuItem>
<MenuItem
x:Name="menuSelectAll"
Height="{StaticResource MenuItemHeight}"
Click="menuSelectAll_Click"
Header="{x:Static resx:ResUI.menuSelectAll}" />
<Separator />
<MenuItem <MenuItem
x:Name="menuExport2ClientConfig" x:Name="menuExport2ClientConfig"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -556,41 +629,50 @@
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<materialDesign:DataGridTextColumn <base:MyDGTextColumn
Width="80" Width="80"
Binding="{Binding configType}" Binding="{Binding configType}"
ExName="configType"
Header="{x:Static resx:ResUI.LvServiceType}" /> Header="{x:Static resx:ResUI.LvServiceType}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="150" Width="150"
Binding="{Binding remarks}" Binding="{Binding remarks}"
ExName="remarks"
Header="{x:Static resx:ResUI.LvAlias}" /> Header="{x:Static resx:ResUI.LvAlias}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="120" Width="120"
Binding="{Binding address}" Binding="{Binding address}"
ExName="address"
Header="{x:Static resx:ResUI.LvAddress}" /> Header="{x:Static resx:ResUI.LvAddress}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="60" Width="60"
Binding="{Binding port}" Binding="{Binding port}"
ExName="port"
Header="{x:Static resx:ResUI.LvPort}" /> Header="{x:Static resx:ResUI.LvPort}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding security}" Binding="{Binding security}"
ExName="security"
Header="{x:Static resx:ResUI.LvEncryptionMethod}" /> Header="{x:Static resx:ResUI.LvEncryptionMethod}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding network}" Binding="{Binding network}"
ExName="network"
Header="{x:Static resx:ResUI.LvTransportProtocol}" /> Header="{x:Static resx:ResUI.LvTransportProtocol}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding streamSecurity}" Binding="{Binding streamSecurity}"
ExName="streamSecurity"
Header="{x:Static resx:ResUI.LvTLS}" /> Header="{x:Static resx:ResUI.LvTLS}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding subRemarks}" Binding="{Binding subRemarks}"
ExName="subRemarks"
Header="{x:Static resx:ResUI.LvSubscription}" /> Header="{x:Static resx:ResUI.LvSubscription}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding delayVal}" Binding="{Binding delayVal}"
ExName="delayVal"
Header="{x:Static resx:ResUI.LvTestDelay}"> Header="{x:Static resx:ResUI.LvTestDelay}">
<DataGridTextColumn.ElementStyle> <DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"> <Style TargetType="{x:Type TextBlock}">
@@ -598,37 +680,42 @@
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" /> <Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </base:MyDGTextColumn>
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding speedVal}" Binding="{Binding speedVal}"
ExName="speedVal"
Header="{x:Static resx:ResUI.LvTestSpeed}"> Header="{x:Static resx:ResUI.LvTestSpeed}">
<DataGridTextColumn.ElementStyle> <DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"> <Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </base:MyDGTextColumn>
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTodayUp" x:Name="colTodayUp"
Width="100" Width="100"
Binding="{Binding todayUp}" Binding="{Binding todayUp}"
ExName="todayUp"
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" /> Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTodayDown" x:Name="colTodayDown"
Width="100" Width="100"
Binding="{Binding todayDown}" Binding="{Binding todayDown}"
ExName="todayDown"
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" /> Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTotalUp" x:Name="colTotalUp"
Width="100" Width="100"
Binding="{Binding totalUp}" Binding="{Binding totalUp}"
ExName="totalUp"
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" /> Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTotalDown" x:Name="colTotalDown"
Width="100" Width="100"
Binding="{Binding totalDown}" Binding="{Binding totalDown}"
ExName="totalDown"
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" /> Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
</DataGrid.Columns> </DataGrid.Columns>
@@ -650,6 +737,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyClear2" x:Name="menuSystemProxyClear2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" />
</StackPanel> </StackPanel>
@@ -661,6 +749,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxySet2" x:Name="menuSystemProxySet2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" />
</StackPanel> </StackPanel>
@@ -672,6 +761,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyNothing2" x:Name="menuSystemProxyNothing2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" />
</StackPanel> </StackPanel>
@@ -683,6 +773,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyPac2" x:Name="menuSystemProxyPac2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" />
</StackPanel> </StackPanel>
@@ -697,6 +788,7 @@
MaxWidth="300" MaxWidth="300"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
DisplayMemberPath="remarks" DisplayMemberPath="remarks"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilledComboBox}" /> Style="{StaticResource MaterialDesignFilledComboBox}" />
</DockPanel> </DockPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -709,6 +801,7 @@
MaxWidth="300" MaxWidth="300"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}"
DisplayMemberPath="Text" DisplayMemberPath="Text"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilledComboBox}" /> Style="{StaticResource MaterialDesignFilledComboBox}" />
</DockPanel> </DockPanel>
</MenuItem.Header> </MenuItem.Header>

View File

@@ -9,6 +9,7 @@ using System.Windows.Controls.Primitives;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using v2rayN.Base;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx; using v2rayN.Resx;
@@ -45,6 +46,11 @@ namespace v2rayN.Views
ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler); ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); 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 => Global.Languages.ForEach(it =>
{ {
cmbCurrentLanguage.Items.Add(it); cmbCurrentLanguage.Items.Add(it);
@@ -71,6 +77,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
//servers delete //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.RemoveServerCmd, v => v.menuRemoveServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RemoveDuplicateServerCmd, v => v.menuRemoveDuplicateServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RemoveDuplicateServerCmd, v => v.menuRemoveDuplicateServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables);
@@ -151,6 +158,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables);
@@ -172,6 +180,7 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); 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.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.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); this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables);
}); });
@@ -182,6 +191,11 @@ namespace v2rayN.Views
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed; spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed;
if (_config.uiItem.autoHideStartup)
{
WindowState = WindowState.Minimized;
}
} }
#region Event #region Event
@@ -190,13 +204,13 @@ namespace v2rayN.Views
{ {
if (action == "AdjustMainLvColWidth") if (action == "AdjustMainLvColWidth")
{ {
Application.Current.Dispatcher.Invoke((Action)(() => Application.Current.Dispatcher.Invoke(() =>
{ {
foreach (var it in lstProfiles.Columns) foreach (var it in lstProfiles.Columns)
{ {
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
} }
})); });
} }
else if (action == "ProfilesFocus") else if (action == "ProfilesFocus")
{ {
@@ -240,17 +254,25 @@ namespace v2rayN.Views
private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e) 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) private void LstProfiles_ColumnHeader_Click(object sender, RoutedEventArgs e)
{ {
var colHeader = sender as DataGridColumnHeader; var colHeader = sender as DataGridColumnHeader;
if (colHeader == null || colHeader.TabIndex < 0) if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null)
{ {
return; return;
} }
if (colHeader.TabIndex == 0)
if (colHeader.Column.GetType().Name != typeof(MyDGTextColumn).Name)
{ {
foreach (var it in lstProfiles.Columns) foreach (var it in lstProfiles.Columns)
{ {
@@ -260,7 +282,8 @@ namespace v2rayN.Views
return; return;
} }
ViewModel?.SortServer(colHeader.TabIndex); var colName = ((MyDGTextColumn)colHeader.Column).ExName;
ViewModel?.SortServer(colName);
} }
private void menuSelectAll_Click(object sender, RoutedEventArgs e) private void menuSelectAll_Click(object sender, RoutedEventArgs e)
@@ -323,13 +346,17 @@ namespace v2rayN.Views
ViewModel?.Export2ShareUrl(); ViewModel?.Export2ShareUrl();
} }
else if (e.Key == Key.D) else if (e.Key == Key.D)
{
ViewModel?.EditServer(false, EConfigType.Custom);
}
else if (e.Key == Key.F)
{ {
ViewModel?.ShareServer(); ViewModel?.ShareServer();
} }
} }
else else
{ {
if (e.Key == Key.Enter || e.Key == Key.Return) if (e.Key is Key.Enter or Key.Return)
{ {
ViewModel?.SetDefaultServer(); ViewModel?.SetDefaultServer();
} }
@@ -377,7 +404,7 @@ namespace v2rayN.Views
} }
#endregion #endregion
#region UI #region UI
private void RestoreUI() private void RestoreUI()
{ {
@@ -397,13 +424,28 @@ namespace v2rayN.Views
{ {
Height = SystemInformation.WorkingArea.Height * 96 / g.DpiY; Height = SystemInformation.WorkingArea.Height * 96 / g.DpiY;
} }
if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0)
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)); gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
lstProfiles.Columns[k].Width = width; gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
} }
if (!_config.enableStatistics)
var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList();
for (int i = 0; i < lvColumnItem.Count; i++)
{
var item = lvColumnItem[i];
for (int k = 1; k < lstProfiles.Columns.Count; k++)
{
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
if (item2.ExName == item.Name)
{
item2.Width = item.Width;
item2.DisplayIndex = i + 1;
}
}
}
if (!_config.guiItem.enableStatistics)
{ {
colTodayUp.Visibility = Visibility.Hidden; colTodayUp.Visibility = Visibility.Hidden;
colTodayDown.Visibility = Visibility.Hidden; colTodayDown.Visibility = Visibility.Hidden;
@@ -416,10 +458,21 @@ namespace v2rayN.Views
_config.uiItem.mainWidth = this.Width; _config.uiItem.mainWidth = this.Width;
_config.uiItem.mainHeight = this.Height; _config.uiItem.mainHeight = this.Height;
for (int k = 0; k < lstProfiles.Columns.Count; k++) List<ColumnItem> lvColumnItem = new();
for (int k = 1; k < lstProfiles.Columns.Count; k++)
{ {
ConfigHandler.AddformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].ActualWidth)); var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
lvColumnItem.Add(new()
{
Name = item2.ExName,
Width = Convert.ToInt32(item2.ActualWidth),
Index = item2.DisplayIndex
});
} }
_config.uiItem.mainColumnItem = lvColumnItem;
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1);
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1);
} }
private void AddHelpMenuItem() private void AddHelpMenuItem()
@@ -438,9 +491,8 @@ namespace v2rayN.Views
} }
private void MenuItem_Click(object sender, RoutedEventArgs e) private void MenuItem_Click(object sender, RoutedEventArgs e)
{ {
if (sender is MenuItem) if (sender is MenuItem item)
{ {
MenuItem item = (MenuItem)sender;
Utils.ProcessStart(item.Tag.ToString()); Utils.ProcessStart(item.Tag.ToString());
} }
} }
@@ -449,7 +501,7 @@ namespace v2rayN.Views
#endregion #endregion
#region Drag and Drop #region Drag and Drop
private Point startPoint = new Point(); private Point startPoint = new();
private int startIndex = -1; private int startIndex = -1;
private string formatData = "ProfileItemModel"; private string formatData = "ProfileItemModel";
@@ -490,8 +542,7 @@ namespace v2rayN.Views
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{ {
// Get the dragged Item // Get the dragged Item
var listView = sender as DataGrid; if (sender is not DataGrid listView) return;
if (listView == null) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource); var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null) return; // Abort if (listViewItem == null) return; // Abort
// Find the data behind the ListViewItem // Find the data behind the ListViewItem
@@ -499,7 +550,7 @@ namespace v2rayN.Views
if (item == null) return; // Abort if (item == null) return; // Abort
// Initialize the drag & drop operation // Initialize the drag & drop operation
startIndex = lstProfiles.SelectedIndex; startIndex = lstProfiles.SelectedIndex;
DataObject dragData = new DataObject(formatData, item); DataObject dragData = new(formatData, item);
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move); DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
} }
} }
@@ -517,8 +568,7 @@ namespace v2rayN.Views
if (e.Data.GetDataPresent(formatData) && sender == e.Source) if (e.Data.GetDataPresent(formatData) && sender == e.Source)
{ {
// Get the drop Item destination // Get the drop Item destination
var listView = sender as DataGrid; if (sender is not DataGrid listView) return;
if (listView == null) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource); var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null) if (listViewItem == null)
{ {
@@ -543,4 +593,4 @@ namespace v2rayN.Views
} }
} }

View File

@@ -20,20 +20,35 @@
Margin="8,0" Margin="8,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryHueLightBrush}" Foreground="{DynamicResource PrimaryHueLightBrush}"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.MsgInformationTitle}" /> Text="{x:Static resx:ResUI.MsgInformationTitle}" />
<TextBox <ComboBox
x:Name="txtMsgFilter" x:Name="cmbMsgFilter"
Width="200" Width="200"
Margin="8,0" Margin="8,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}" 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> </StackPanel>
<TextBox <TextBox
Name="txtMsg" Name="txtMsg"
BorderThickness="0" BorderThickness="0"
FontSize="11" FontSize="{DynamicResource StdFontSizeMsg}"
HorizontalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
IsReadOnly="True" IsReadOnly="True"
TextAlignment="Left"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Visible"> VerticalScrollBarVisibility="Visible">
<TextBox.ContextMenu> <TextBox.ContextMenu>

View File

@@ -3,37 +3,67 @@ using System.Reactive.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Threading; using System.Windows.Threading;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
namespace v2rayN.Views namespace v2rayN.Views
{ {
public partial class MsgView public partial class MsgView
{ {
private static Config _config;
private string lastMsgFilter;
private bool lastMsgFilterNotAvailable;
public MsgView() public MsgView()
{ {
InitializeComponent(); InitializeComponent();
_config = LazyConfig.Instance.GetConfig();
MessageBus.Current.Listen<string>("MsgView").Subscribe(x => DelegateAppendText(x)); 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) void DelegateAppendText(string msg)
{ {
Dispatcher.BeginInvoke(new Action<string>(AppendText), DispatcherPriority.Send, msg); Dispatcher.BeginInvoke(AppendText, DispatcherPriority.Send, msg);
} }
public void AppendText(string msg) public void AppendText(string msg)
{ {
if (msg.Equals(Global.CommandClearMsg)) if (msg == Global.CommandClearMsg)
{ {
ClearMsg(); ClearMsg();
return; return;
} }
var MsgFilter = txtMsgFilter.Text.TrimEx(); if (togAutoRefresh.IsChecked == false)
if (!Utils.IsNullOrEmpty(MsgFilter))
{ {
if (!Regex.IsMatch(msg, MsgFilter)) return;
}
var MsgFilter = cmbMsgFilter.Text.TrimEx();
if (MsgFilter != lastMsgFilter) lastMsgFilterNotAvailable = false;
if (!string.IsNullOrEmpty(MsgFilter) && !lastMsgFilterNotAvailable)
{
try
{ {
return; if (!Regex.IsMatch(msg, MsgFilter)) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD>
{
return;
}
}
catch (Exception)
{
lastMsgFilterNotAvailable = true;
} }
} }
lastMsgFilter = MsgFilter;
ShowMsg(msg); ShowMsg(msg);
} }
@@ -79,6 +109,10 @@ namespace v2rayN.Views
{ {
ClearMsg(); ClearMsg();
} }
private void cmbMsgFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
_config.uiItem.mainMsgFilter = cmbMsgFilter.Text.TrimEx();
}
} }
} }

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.Views.OptionSettingWindow" x:Class="v2rayN.Views.OptionSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -9,11 +10,14 @@
xmlns:resx="clr-namespace:v2rayN.Resx" xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:vms="clr-namespace:v2rayN.ViewModels" xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuSetting}" Title="{x:Static resx:ResUI.menuSetting}"
Width="900" Width="1000"
Height="700" Height="700"
x:TypeArguments="vms:OptionSettingViewModel" x:TypeArguments="vms:OptionSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -43,196 +47,252 @@
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
</Grid> </Grid>
<TabControl> <TabControl HorizontalContentAlignment="Left">
<TabItem Header="{x:Static resx:ResUI.TbSettingsCore}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCore}">
<Grid Margin="{StaticResource SettingItemMargin}"> <ScrollViewer VerticalScrollBarVisibility="Visible">
<Grid.RowDefinitions> <Grid Margin="{StaticResource SettingItemMargin}">
<RowDefinition Height="Auto" /> <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" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> <RowDefinition Height="Auto" />
<Grid.ColumnDefinitions> <RowDefinition Height="Auto" />
<ColumnDefinition Width="Auto" /> <RowDefinition Height="Auto" />
<ColumnDefinition Width="Auto" /> <RowDefinition Height="Auto" />
</Grid.ColumnDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSocksPort}" /> Text="{x:Static resx:ResUI.TbSettingsSocksPort}" />
<TextBox <TextBox
x:Name="txtlocalPort" x:Name="txtlocalPort"
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> 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 <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsUdpEnabled}" /> Text="{x:Static resx:ResUI.TbSettingsUdpEnabled}" />
<ToggleButton <ToggleButton
x:Name="togudpEnabled" x:Name="togudpEnabled"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSniffingEnabled}" /> Text="{x:Static resx:ResUI.TbSettingsSniffingEnabled}" />
<ToggleButton <ToggleButton
x:Name="togsniffingEnabled" x:Name="togsniffingEnabled"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsRouteOnly}" /> Text="{x:Static resx:ResUI.TbSettingsRouteOnly}" />
<ToggleButton <ToggleButton
x:Name="togrouteOnly" x:Name="togrouteOnly"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsAllowLAN}" /> Text="{x:Static resx:ResUI.TbSettingsAllowLAN}" />
<ToggleButton <ToggleButton
x:Name="togAllowLANConn" x:Name="togAllowLANConn"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsNewPort4LAN}" /> Text="{x:Static resx:ResUI.TbSettingsNewPort4LAN}" />
<ToggleButton <ToggleButton
x:Name="togNewPort4LAN" x:Name="togNewPort4LAN"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="6"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsUser}" /> Text="{x:Static resx:ResUI.TbSettingsUser}" />
<TextBox <TextBox
x:Name="txtuser" x:Name="txtuser"
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsPass}" /> Text="{x:Static resx:ResUI.TbSettingsPass}" />
<TextBox <TextBox
x:Name="txtpass" x:Name="txtpass"
Grid.Row="7" Grid.Row="7"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="8" Grid.Row="8"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" /> Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
<ToggleButton <ToggleButton
x:Name="togmuxEnabled" x:Name="togmuxEnabled"
Grid.Row="8" Grid.Row="8"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="9" Grid.Row="9"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" /> Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" />
<ToggleButton <ToggleButton
x:Name="toglogEnabled" x:Name="toglogEnabled"
Grid.Row="9" Grid.Row="9"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="10" Grid.Row="10"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLogLevel}" /> Text="{x:Static resx:ResUI.TbSettingsLogLevel}" />
<ComboBox <ComboBox
x:Name="cmbloglevel" x:Name="cmbloglevel"
Grid.Row="10" Grid.Row="10"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Width="200"
materialDesign:HintAssist.Hint="Level" /> Margin="{StaticResource SettingItemMargin}"
materialDesign:HintAssist.Hint="Level"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="11" Grid.Row="11"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsDefAllowInsecure}" /> Text="{x:Static resx:ResUI.TbSettingsDefAllowInsecure}" />
<ToggleButton <ToggleButton
x:Name="togdefAllowInsecure" x:Name="togdefAllowInsecure"
Grid.Row="11" Grid.Row="11"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
</Grid>
<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>
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
@@ -246,7 +306,8 @@
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4Freedom" x:Name="cmbdomainStrategy4Freedom"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
</StackPanel> </StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
@@ -270,6 +331,7 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
AcceptsReturn="True" AcceptsReturn="True"
BorderThickness="1" BorderThickness="1"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</DockPanel> </DockPanel>
@@ -303,7 +365,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="mtu" /> Text="mtu" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpmtu" x:Name="txtKcpmtu"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
@@ -317,7 +379,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="tti" /> Text="tti" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcptti" x:Name="txtKcptti"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
@@ -331,7 +393,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="uplinkCapacity" /> Text="uplinkCapacity" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpuplinkCapacity" x:Name="txtKcpuplinkCapacity"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
@@ -345,7 +407,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="downlinkCapacity" /> Text="downlinkCapacity" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpdownlinkCapacity" x:Name="txtKcpdownlinkCapacity"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
@@ -359,7 +421,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="readBufferSize" /> Text="readBufferSize" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpreadBufferSize" x:Name="txtKcpreadBufferSize"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
@@ -373,7 +435,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="writeBufferSize" /> Text="writeBufferSize" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpwriteBufferSize" x:Name="txtKcpwriteBufferSize"
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
@@ -416,10 +478,14 @@
<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.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
@@ -435,6 +501,14 @@
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -462,7 +536,8 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@@ -568,13 +643,13 @@
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsAutoUpdateInterval}" /> Text="{x:Static resx:ResUI.TbSettingsDoubleClick2Activate}" />
<TextBox <ToggleButton
x:Name="txtautoUpdateInterval" x:Name="togDoubleClick2Activate"
Grid.Row="11" Grid.Row="11"
Grid.Column="1" Grid.Column="1"
Width="200" Margin="{StaticResource SettingItemMargin}"
Margin="{StaticResource SettingItemMargin}" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="12" Grid.Row="12"
@@ -582,16 +657,34 @@
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" 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}" /> Text="{x:Static resx:ResUI.TbSettingsAutoUpdate}" />
<TextBox <TextBox
x:Name="txtautoUpdateSubInterval" x:Name="txtautoUpdateSubInterval"
Grid.Row="12" Grid.Row="13"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="13" Grid.Row="14"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -599,10 +692,66 @@
Text="{x:Static resx:ResUI.TbSettingsTrayMenuServersLimit}" /> Text="{x:Static resx:ResUI.TbSettingsTrayMenuServersLimit}" />
<TextBox <TextBox
x:Name="txttrayMenuServersLimit" x:Name="txttrayMenuServersLimit"
Grid.Row="13" Grid.Row="14"
Grid.Column="1" Grid.Column="1"
Width="200" 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}"
TextWrapping="Wrap" />
<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> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@@ -619,8 +768,10 @@
<ComboBox <ComboBox
x:Name="cmbsystemProxyAdvancedProtocol" x:Name="cmbsystemProxyAdvancedProtocol"
Grid.Row="4" Grid.Row="4"
MinWidth="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
materialDesign:HintAssist.Hint="Protocol" /> materialDesign:HintAssist.Hint="Protocol"
Style="{StaticResource DefComboBox}" />
</StackPanel> </StackPanel>
@@ -637,6 +788,7 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
AcceptsReturn="True" AcceptsReturn="True"
BorderThickness="1" BorderThickness="1"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</DockPanel> </DockPanel>
@@ -657,6 +809,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -665,7 +818,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -673,6 +826,20 @@
Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" /> Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" />
<ToggleButton <ToggleButton
x:Name="togShowWindow" 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.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
@@ -705,7 +872,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@@ -720,7 +888,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
@@ -733,10 +902,11 @@
x:Name="txtCustomTemplate" x:Name="txtCustomTemplate"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="600" Width="400"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<Button <Button
x:Name="btnBrowse" x:Name="btnBrowse"
@@ -747,21 +917,50 @@
Click="btnBrowse_Click" Click="btnBrowse_Click"
Content="{x:Static resx:ResUI.TbBrowse}" Content="{x:Static resx:ResUI.TbBrowse}"
Style="{StaticResource DefButton}" /> 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>
<Grid Margin="{StaticResource SettingItemMargin}">
<Grid
x:Name="gridTunModeDirect"
Width="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="10" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectIP}" Header="{x:Static resx:ResUI.TbSettingsTunModeDirectIP}"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDirectIP" Name="txtDirectIP"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -769,14 +968,77 @@
<GroupBox <GroupBox
Grid.Column="2" Grid.Column="2"
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectProcess}" Header="{x:Static resx:ResUI.TbSettingsTunModeDirectProcess}"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDirectProcess" Name="txtDirectProcess"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="4"
Header="{x:Static resx:ResUI.TbSettingsTunModeDNS}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtDirectDNS"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
</Grid> </Grid>
<Grid
x:Name="gridTunModeProxy"
Width="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</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>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="4"
Header="{x:Static resx:ResUI.TbSettingsTunModeDNS}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyDNS"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid>
</DockPanel> </DockPanel>
</TabItem> </TabItem>
@@ -807,7 +1069,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -821,7 +1084,8 @@
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -835,7 +1099,8 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@@ -849,7 +1114,8 @@
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
@@ -863,7 +1129,8 @@
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="6"
@@ -877,7 +1144,8 @@
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
</TabItem> </TabItem>
</TabControl> </TabControl>

View File

@@ -1,15 +1,24 @@
using ReactiveUI; using ReactiveUI;
using System.Globalization;
using System.IO;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows; using System.Windows;
using System.Windows.Media;
using v2rayN.Handler;
using v2rayN.Mode;
using v2rayN.ViewModels; using v2rayN.ViewModels;
namespace v2rayN.Views namespace v2rayN.Views
{ {
public partial class OptionSettingWindow public partial class OptionSettingWindow
{ {
private static Config _config;
public OptionSettingWindow() public OptionSettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = LazyConfig.Instance.GetConfig();
ViewModel = new OptionSettingViewModel(this); ViewModel = new OptionSettingViewModel(this);
@@ -21,6 +30,14 @@ namespace v2rayN.Views
{ {
cmbloglevel.Items.Add(it); cmbloglevel.Items.Add(it);
}); });
Global.fingerprints.ForEach(it =>
{
cmbdefFingerprint.Items.Add(it);
});
Global.userAgent.ForEach(it =>
{
cmbdefUserAgent.Items.Add(it);
});
Global.domainStrategy4Freedoms.ForEach(it => Global.domainStrategy4Freedoms.ForEach(it =>
{ {
cmbdomainStrategy4Freedom.Items.Add(it); cmbdomainStrategy4Freedom.Items.Add(it);
@@ -47,6 +64,56 @@ namespace v2rayN.Views
cmbCoreType6.Items.Add(it); 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 files = Directory.GetFiles(Utils.GetFontsPath(), "*.ttf");
var culture = _config.uiItem.currentLanguage == Global.Languages[0] ? "zh-cn" : "en-us";
var culture2 = "en-us";
foreach (var ttf in files)
{
var families = Fonts.GetFontFamilies(Utils.GetFontsPath(ttf));
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.WhenActivated(disposables =>
{ {
this.Bind(ViewModel, vm => vm.localPort, v => v.txtlocalPort.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.localPort, v => v.txtlocalPort.Text).DisposeWith(disposables);
@@ -63,6 +130,8 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.logEnabled, v => v.toglogEnabled.IsChecked).DisposeWith(disposables); 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.loglevel, v => v.cmbloglevel.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.defAllowInsecure, v => v.togdefAllowInsecure.IsChecked).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); this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);
@@ -88,9 +157,13 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.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.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableDragDropSort, v => v.togEnableDragDropSort.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.autoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.autoUpdateSubInterval, v => v.txtautoUpdateSubInterval.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.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); this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
@@ -98,12 +171,20 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.TunShowWindow, v => v.togShowWindow.IsChecked).DisposeWith(disposables); 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.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).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.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunCustomTemplate, v => v.txtCustomTemplate.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.TunDirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectDNS, v => v.txtDirectDNS.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.TunProxyDNS, v => v.txtProxyDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);

View File

@@ -9,7 +9,7 @@
d:DesignHeight="300" d:DesignHeight="300"
d:DesignWidth="300" d:DesignWidth="300"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid Margin="16"> <Grid Margin="30">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.Views.RoutingRuleDetailsWindow" x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,7 +14,10 @@
Height="700" Height="700"
x:TypeArguments="vms:RoutingRuleDetailsViewModel" x:TypeArguments="vms:RoutingRuleDetailsViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -62,7 +66,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="4" Margin="4"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -77,6 +82,7 @@
Grid.Column="1" Grid.Column="1"
Margin="4" Margin="4"
HorizontalAlignment="Left" HorizontalAlignment="Left"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" /> Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
<TextBlock <TextBlock
@@ -91,6 +97,7 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Margin="4" Margin="4"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" /> Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
<TextBlock <TextBlock
@@ -140,7 +147,7 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center"> VerticalAlignment="Center">
<CheckBox x:Name="chkAutoSort"> <CheckBox x:Name="chkAutoSort">
<TextBlock Text="{x:Static resx:ResUI.TbAutoSort}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.TbAutoSort}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>
<Button <Button
@@ -169,10 +176,11 @@
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
Header="Domain" Header="Domain"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDomain" Name="txtDomain"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -180,10 +188,11 @@
<GroupBox <GroupBox
Grid.Column="2" Grid.Column="2"
Header="IP" Header="IP"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtIP" Name="txtIP"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>

View File

@@ -12,6 +12,7 @@ namespace v2rayN.Views
public RoutingRuleDetailsWindow(RulesItem rulesItem) public RoutingRuleDetailsWindow(RulesItem rulesItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged; clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged; clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.Views.RoutingRuleSettingWindow" x:Class="v2rayN.Views.RoutingRuleSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,7 +14,10 @@
Height="700" Height="700"
x:TypeArguments="vms:RoutingRuleSettingViewModel" x:TypeArguments="vms:RoutingRuleSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -28,28 +32,40 @@
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignToolBar}">
<Button x:Name="menuRuleAdd"> <Button x:Name="menuRuleAdd">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Plus" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Plus" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRuleAdd}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRuleAdd}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuImportRulesFromFile"> <Button x:Name="menuImportRulesFromFile">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Import" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Import" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromFile}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromFile}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuImportRulesFromClipboard"> <Button x:Name="menuImportRulesFromClipboard">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Import" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Import" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromClipboard}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromClipboard}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuImportRulesFromUrl"> <Button x:Name="menuImportRulesFromUrl">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Import" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Import" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromUrl}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromUrl}" />
</StackPanel> </StackPanel>
</Button> </Button>
@@ -89,6 +105,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -111,6 +128,7 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -143,6 +161,7 @@
Margin="4" Margin="4"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -160,6 +179,7 @@
Margin="4" Margin="4"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<Button <Button
x:Name="btnBrowse" x:Name="btnBrowse"
@@ -171,6 +191,23 @@
Content="{x:Static resx:ResUI.TbBrowse}" Content="{x:Static resx:ResUI.TbBrowse}"
Style="{StaticResource DefButton}" /> 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> </Grid>
<TabControl x:Name="tabAdvanced"> <TabControl x:Name="tabAdvanced">

View File

@@ -12,6 +12,7 @@ namespace v2rayN.Views
public RoutingRuleSettingWindow(RoutingItem routingItem) public RoutingRuleSettingWindow(RoutingItem routingItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown; this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
lstRules.SelectionChanged += lstRules_SelectionChanged; 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.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.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.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.RuleAddCmd, v => v.menuRuleAdd).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportRulesFromFileCmd, v => v.menuImportRulesFromFile).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportRulesFromFileCmd, v => v.menuImportRulesFromFile).DisposeWith(disposables);
@@ -75,15 +77,15 @@ namespace v2rayN.Views
{ {
ViewModel?.MoveRule(EMove.Top); ViewModel?.MoveRule(EMove.Top);
} }
else if (e.Key == Key.B) else if (e.Key == Key.U)
{ {
ViewModel?.MoveRule(EMove.Up); ViewModel?.MoveRule(EMove.Up);
} }
else if (e.Key == Key.U) else if (e.Key == Key.D)
{ {
ViewModel?.MoveRule(EMove.Down); ViewModel?.MoveRule(EMove.Down);
} }
else if (e.Key == Key.D) else if (e.Key == Key.B)
{ {
ViewModel?.MoveRule(EMove.Bottom); ViewModel?.MoveRule(EMove.Bottom);
} }

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.Views.RoutingSettingWindow" x:Class="v2rayN.Views.RoutingSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,7 +14,10 @@
Height="700" Height="700"
x:TypeArguments="vms:RoutingSettingViewModel" x:TypeArguments="vms:RoutingSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -35,7 +39,10 @@
<MenuItem x:Name="menuRoutingBasic" Padding="8,0"> <MenuItem x:Name="menuRoutingBasic" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Server" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Server" />
<TextBlock Text="{x:Static resx:ResUI.menuRoutingBasic}" /> <TextBlock Text="{x:Static resx:ResUI.menuRoutingBasic}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -50,7 +57,10 @@
<MenuItem x:Name="menuRoutingAdvanced" Padding="8,0"> <MenuItem x:Name="menuRoutingAdvanced" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Routes" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Routes" />
<TextBlock Text="{x:Static resx:ResUI.menuRoutingAdvanced}" /> <TextBlock Text="{x:Static resx:ResUI.menuRoutingAdvanced}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -194,15 +204,19 @@
Binding="{Binding remarks}" Binding="{Binding remarks}"
Header="{x:Static resx:ResUI.LvAlias}" /> Header="{x:Static resx:ResUI.LvAlias}" />
<DataGridTextColumn <DataGridTextColumn
Width="70" Width="60"
Binding="{Binding ruleNum}" Binding="{Binding ruleNum}"
Header="{x:Static resx:ResUI.LvCount}" /> Header="{x:Static resx:ResUI.LvCount}" />
<DataGridTextColumn <DataGridTextColumn
Width="280" Width="60"
Binding="{Binding sort}"
Header="{x:Static resx:ResUI.LvSort}" />
<DataGridTextColumn
Width="260"
Binding="{Binding url}" Binding="{Binding url}"
Header="{x:Static resx:ResUI.LvUrl}" /> Header="{x:Static resx:ResUI.LvUrl}" />
<DataGridTextColumn <DataGridTextColumn
Width="280" Width="260"
Binding="{Binding customIcon}" Binding="{Binding customIcon}"
Header="{x:Static resx:ResUI.LvCustomIcon}" /> Header="{x:Static resx:ResUI.LvCustomIcon}" />
</DataGrid.Columns> </DataGrid.Columns>
@@ -221,10 +235,11 @@
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
Header="Domain" Header="Domain"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtProxyDomain" Name="txtProxyDomain"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -232,10 +247,11 @@
<GroupBox <GroupBox
Grid.Column="2" Grid.Column="2"
Header="IP" Header="IP"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtProxyIP" Name="txtProxyIP"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -252,10 +268,11 @@
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
Header="Domain" Header="Domain"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDirectDomain" Name="txtDirectDomain"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -263,10 +280,11 @@
<GroupBox <GroupBox
Grid.Column="2" Grid.Column="2"
Header="IP" Header="IP"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDirectIP" Name="txtDirectIP"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -283,10 +301,11 @@
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
Header="Domain" Header="Domain"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtBlockDomain" Name="txtBlockDomain"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -294,10 +313,11 @@
<GroupBox <GroupBox
Grid.Column="2" Grid.Column="2"
Header="IP" Header="IP"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtBlockIP" Name="txtBlockIP"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>

View File

@@ -1,5 +1,6 @@
using ReactiveUI; using ReactiveUI;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.ViewModels; using v2rayN.ViewModels;
@@ -11,6 +12,7 @@ namespace v2rayN.Views
public RoutingSettingWindow() public RoutingSettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Closing += RoutingSettingWindow_Closing; this.Closing += RoutingSettingWindow_Closing;
this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown; this.PreviewKeyDown += RoutingSettingWindow_PreviewKeyDown;
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged; lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.Views.SubEditWindow" x:Class="v2rayN.Views.SubEditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,7 +14,10 @@
Height="550" Height="550"
x:TypeArguments="vms:SubEditViewModel" x:TypeArguments="vms:SubEditViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -66,7 +70,7 @@
Margin="4" Margin="4"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -85,7 +89,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -117,7 +121,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
@@ -136,7 +140,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="6"
@@ -153,7 +157,7 @@
Margin="4" Margin="4"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
</Grid> </Grid>
<Grid <Grid

View File

@@ -11,6 +11,7 @@ namespace v2rayN.Views
public SubEditWindow(SubItem subItem) public SubEditWindow(SubItem subItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
ViewModel = new SubEditViewModel(subItem, this); ViewModel = new SubEditViewModel(subItem, this);

View File

@@ -2,6 +2,7 @@
x:Class="v2rayN.Views.SubSettingWindow" x:Class="v2rayN.Views.SubSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -13,7 +14,10 @@
Height="600" Height="600"
x:TypeArguments="vms:SubSettingViewModel" x:TypeArguments="vms:SubSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
@@ -29,28 +33,40 @@
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignToolBar}">
<Button x:Name="menuSubAdd"> <Button x:Name="menuSubAdd">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Plus" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Plus" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubAdd}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubAdd}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuSubDelete"> <Button x:Name="menuSubDelete">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Delete" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Delete" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubDelete}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubDelete}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuSubEdit"> <Button x:Name="menuSubEdit">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Edit" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Edit" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubEdit}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubEdit}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuSubShare"> <Button x:Name="menuSubShare">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="QrcodePlus" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="QrcodePlus" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubShare}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubShare}" />
</StackPanel> </StackPanel>
</Button> </Button>
@@ -59,7 +75,10 @@
Click="menuClose_Click" Click="menuClose_Click"
IsCancel="True"> IsCancel="True">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Close" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Close" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuClose}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuClose}" />
</StackPanel> </StackPanel>
</Button> </Button>

View File

@@ -1,6 +1,7 @@
using ReactiveUI; using ReactiveUI;
using System.ComponentModel; using System.ComponentModel;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using v2rayN.ViewModels; using v2rayN.ViewModels;
@@ -11,6 +12,7 @@ namespace v2rayN.Views
public SubSettingWindow() public SubSettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
ViewModel = new SubSettingViewModel(this); ViewModel = new SubSettingViewModel(this);
this.Closing += SubSettingWindow_Closing; this.Closing += SubSettingWindow_Closing;

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@@ -9,11 +10,12 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<ApplicationIcon>v2rayN.ico</ApplicationIcon> <ApplicationIcon>v2rayN.ico</ApplicationIcon>
<Copyright>Copyright © 2017-2023 (GPLv3)</Copyright> <Copyright>Copyright © 2017-2023 (GPLv3)</Copyright>
<FileVersion>6.6</FileVersion> <FileVersion>6.15</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <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="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NHotkey" Version="2.1.0" /> <PackageReference Include="NHotkey" Version="2.1.0" />
@@ -25,7 +27,7 @@
<PackageReference Include="ReactiveUI.Fody" Version="18.4.1" /> <PackageReference Include="ReactiveUI.Fody" Version="18.4.1" />
<PackageReference Include="ReactiveUI.Validation" Version="3.0.22" /> <PackageReference Include="ReactiveUI.Validation" Version="3.0.22" />
<PackageReference Include="ReactiveUI.WPF" Version="18.4.1" /> <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" /> <PackageReference Include="System.Reactive" Version="5.0.0" />
</ItemGroup> </ItemGroup>
@@ -34,6 +36,9 @@
<EmbeddedResource Include="Sample\tun_singbox"> <EmbeddedResource Include="Sample\tun_singbox">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Sample\tun_singbox_dns">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Sample\custom_routing_black"> <EmbeddedResource Include="Sample\custom_routing_black">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>
@@ -63,7 +68,7 @@
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Sample\SampleServerConfig"> <EmbeddedResource Include="Sample\SampleServerConfig">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="v2rayN.ico"> <EmbeddedResource Include="v2rayN.ico">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>
@@ -99,6 +104,9 @@
<EmbeddedResource Update="Resx\ResUI.fa-Ir.resx"> <EmbeddedResource Update="Resx\ResUI.fa-Ir.resx">
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Update="Resx\ResUI.ru.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -11,18 +11,22 @@ namespace v2rayUpgrade
public partial class MainForm : Form public partial class MainForm : Form
{ {
private readonly string defaultFilename = "v2ray-windows.zip"; private readonly string defaultFilename = "v2ray-windows.zip";
private string fileName; private string? fileName;
public MainForm(string[] args) public MainForm(string[] args)
{ {
InitializeComponent(); InitializeComponent();
if (args.Length > 0) if (args.Length > 0)
{ {
fileName = string.Join(" ", args); fileName = HttpUtility.UrlDecode(string.Join(" ", args));
fileName = HttpUtility.UrlDecode(fileName); }
else
{
fileName = defaultFilename;
} }
} }
private void showWarn(string message)
private void ShowWarn(string message)
{ {
MessageBox.Show(message, "", MessageBoxButtons.OK, MessageBoxIcon.Warning); MessageBox.Show(message, "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
} }
@@ -34,7 +38,7 @@ namespace v2rayUpgrade
Process[] existing = Process.GetProcessesByName("v2rayN"); Process[] existing = Process.GetProcessesByName("v2rayN");
foreach (Process p in existing) foreach (Process p in existing)
{ {
string path = p.MainModule.FileName; string? path = p.MainModule?.FileName;
if (path == GetPath("v2rayN.exe")) if (path == GetPath("v2rayN.exe"))
{ {
p.Kill(); p.Kill();
@@ -45,72 +49,67 @@ namespace v2rayUpgrade
catch (Exception ex) catch (Exception ex)
{ {
// Access may be denied without admin right. The user may not be an administrator. // Access may be denied without admin right. The user may not be an administrator.
showWarn("Failed to close v2rayN(关闭v2rayN失败).\n" + ShowWarn("Failed to close v2rayN(关闭v2rayN失败).\n" +
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace); "Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace);
} }
StringBuilder sb = new StringBuilder(); if (!File.Exists(fileName))
{
if (File.Exists(defaultFilename))
{
fileName = defaultFilename;
}
else
{
ShowWarn("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
return;
}
}
StringBuilder sb = new();
try try
{ {
if (!File.Exists(fileName)) string thisAppOldFile = $"{Application.ExecutablePath}.tmp";
{
if (File.Exists(defaultFilename))
{
fileName = defaultFilename;
}
else
{
showWarn("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
return;
}
}
string thisAppOldFile = Application.ExecutablePath + ".tmp";
File.Delete(thisAppOldFile); File.Delete(thisAppOldFile);
string startKey = "v2rayN/"; string startKey = "v2rayN/";
using ZipArchive archive = ZipFile.OpenRead(fileName);
using (ZipArchive archive = ZipFile.OpenRead(fileName)) foreach (ZipArchiveEntry entry in archive.Entries)
{ {
foreach (ZipArchiveEntry entry in archive.Entries) try
{ {
try if (entry.Length == 0)
{ {
if (entry.Length == 0) continue;
{
continue;
}
string fullName = entry.FullName;
if (fullName.StartsWith(startKey))
{
fullName = fullName.Substring(startKey.Length, fullName.Length - startKey.Length);
}
if (Application.ExecutablePath.ToLower() == GetPath(fullName).ToLower())
{
File.Move(Application.ExecutablePath, thisAppOldFile);
}
string entryOuputPath = GetPath(fullName);
FileInfo fileInfo = new FileInfo(entryOuputPath);
fileInfo.Directory.Create();
entry.ExtractToFile(entryOuputPath, true);
} }
catch (Exception ex) string fullName = entry.FullName;
if (fullName.StartsWith(startKey))
{ {
sb.Append(ex.StackTrace); fullName = fullName[startKey.Length..];
} }
if (string.Equals(Application.ExecutablePath, GetPath(fullName), StringComparison.OrdinalIgnoreCase))
{
File.Move(Application.ExecutablePath, thisAppOldFile);
}
string entryOuputPath = GetPath(fullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryOuputPath)!);
entry.ExtractToFile(entryOuputPath, true);
}
catch (Exception ex)
{
sb.Append(ex.StackTrace);
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
showWarn("Upgrade Failed(升级失败)." + ex.StackTrace); ShowWarn("Upgrade Failed(升级失败)." + ex.StackTrace);
return; return;
} }
if (sb.Length > 0) if (sb.Length > 0)
{ {
showWarn("Upgrade Failed,Hold ctrl + c to copy to clipboard.\n" + ShowWarn("Upgrade Failed,Hold ctrl + c to copy to clipboard.\n" +
"(升级失败,按住ctrl+c可以复制到剪贴板)." + sb.ToString()); "(升级失败,按住ctrl+c可以复制到剪贴板)." + sb.ToString());
return; return;
} }

View File

@@ -6,5 +6,6 @@
<Copyright>Copyright © 2019-2023 (GPLv3)</Copyright> <Copyright>Copyright © 2019-2023 (GPLv3)</Copyright>
<FileVersion>1.1.0.0</FileVersion> <FileVersion>1.1.0.0</FileVersion>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
</Project> </Project>