mirror of https://github.com/2dust/v2rayN
Added Hysteria2 support (using sing-box)
parent
4a0902d4c8
commit
7037009ce4
|
@ -1,9 +1,9 @@
|
||||||
<Application
|
<Application
|
||||||
x:Class="v2rayN.App"
|
x:Class="v2rayN.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:conv="clr-namespace:v2rayN.Converters"
|
xmlns:conv="clr-namespace:v2rayN.Converters"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
ShutdownMode="OnExplicitShutdown"
|
ShutdownMode="OnExplicitShutdown"
|
||||||
StartupUri="Views/MainWindow.xaml">
|
StartupUri="Views/MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
|
|
@ -74,6 +74,8 @@
|
||||||
public const string vlessProtocolLite = "vless";
|
public const string vlessProtocolLite = "vless";
|
||||||
public const string trojanProtocol = "trojan://";
|
public const string trojanProtocol = "trojan://";
|
||||||
public const string trojanProtocolLite = "trojan";
|
public const string trojanProtocolLite = "trojan";
|
||||||
|
public const string hysteria2Protocol = "hysteria2://";
|
||||||
|
public const string hysteria2ProtocolLite = "hysteria2";
|
||||||
|
|
||||||
public const string userEMail = "t@t.tt";
|
public const string userEMail = "t@t.tt";
|
||||||
public const string MyRegPath = "Software\\v2rayNGUI";
|
public const string MyRegPath = "Software\\v2rayNGUI";
|
||||||
|
@ -154,7 +156,7 @@
|
||||||
public static readonly List<string> allowInsecures = new() { "true", "false", "" };
|
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> domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
||||||
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
||||||
public static readonly List<string> alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" };
|
public static readonly List<string> alpns = new() { "h2", "http/1.1", "h2,http/1.1", "h3", "" };
|
||||||
public static readonly List<string> LogLevel = new() { "debug", "info", "warning", "error", "none" };
|
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> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
||||||
public static readonly List<string> Protocols = new() { "http", "tls", "bittorrent" };
|
public static readonly List<string> Protocols = new() { "http", "tls", "bittorrent" };
|
||||||
|
|
|
@ -347,7 +347,7 @@ namespace v2rayN.Handler
|
||||||
#region Server
|
#region Server
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加服务器或编辑
|
/// Add or edit server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem"></param>
|
||||||
|
@ -603,7 +603,7 @@ namespace v2rayN.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加服务器或编辑
|
/// Add or edit server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem"></param>
|
||||||
|
@ -623,7 +623,7 @@ namespace v2rayN.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加服务器或编辑
|
/// Add or edit server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem"></param>
|
||||||
|
@ -651,7 +651,7 @@ namespace v2rayN.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加服务器或编辑
|
/// Add or edit server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem"></param>
|
||||||
|
@ -668,7 +668,7 @@ namespace v2rayN.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加服务器或编辑
|
/// Add or edit server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem"></param>
|
||||||
|
@ -693,6 +693,33 @@ namespace v2rayN.Handler
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add or edit server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
/// <param name="profileItem"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int AddHysteria2Server(ref Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
|
{
|
||||||
|
profileItem.configType = EConfigType.Hysteria2;
|
||||||
|
profileItem.coreType = ECoreType.sing_box;
|
||||||
|
|
||||||
|
profileItem.address = profileItem.address.TrimEx();
|
||||||
|
profileItem.id = profileItem.id.TrimEx();
|
||||||
|
if (Utils.IsNullOrEmpty(profileItem.streamSecurity))
|
||||||
|
{
|
||||||
|
profileItem.streamSecurity = Global.StreamSecurity;
|
||||||
|
}
|
||||||
|
if (profileItem.id.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddServerCommon(ref config, profileItem, toFile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static int SortServers(ref Config config, string subId, string colName, 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, "");
|
||||||
|
@ -790,7 +817,7 @@ namespace v2rayN.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加服务器或编辑
|
/// Add or edit server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem"></param>
|
||||||
|
@ -1042,6 +1069,10 @@ namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
addStatus = AddVlessServer(ref config, profileItem, false);
|
addStatus = AddVlessServer(ref config, profileItem, false);
|
||||||
}
|
}
|
||||||
|
else if (profileItem.configType == EConfigType.Hysteria2)
|
||||||
|
{
|
||||||
|
addStatus = AddHysteria2Server(ref config, profileItem, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (addStatus == 0)
|
if (addStatus == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -283,6 +283,14 @@ namespace v2rayN.Handler
|
||||||
|
|
||||||
outboundMux(node, outbound);
|
outboundMux(node, outbound);
|
||||||
}
|
}
|
||||||
|
else if (node.configType == EConfigType.Hysteria2)
|
||||||
|
{
|
||||||
|
outbound.type = Global.hysteria2ProtocolLite;
|
||||||
|
|
||||||
|
outbound.password = node.id;
|
||||||
|
|
||||||
|
outboundMux(node, outbound);
|
||||||
|
}
|
||||||
|
|
||||||
outboundTls(node, outbound);
|
outboundTls(node, outbound);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace v2rayN.Handler
|
||||||
EConfigType.Socks => ShareSocks(item),
|
EConfigType.Socks => ShareSocks(item),
|
||||||
EConfigType.Trojan => ShareTrojan(item),
|
EConfigType.Trojan => ShareTrojan(item),
|
||||||
EConfigType.VLESS => ShareVLESS(item),
|
EConfigType.VLESS => ShareVLESS(item),
|
||||||
|
EConfigType.Hysteria2 => ShareHysteria2(item),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,6 +163,35 @@ namespace v2rayN.Handler
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string ShareHysteria2(ProfileItem item)
|
||||||
|
{
|
||||||
|
string url = string.Empty;
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.sni))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sni", item.sni);
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||||
|
{
|
||||||
|
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||||
|
}
|
||||||
|
dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0");
|
||||||
|
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
item.id,
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.hysteria2Protocol}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetIpv6(string address)
|
private static string GetIpv6(string address)
|
||||||
{
|
{
|
||||||
return Utils.IsIpv6(address) ? $"[{address}]" : address;
|
return Utils.IsIpv6(address) ? $"[{address}]" : address;
|
||||||
|
@ -353,6 +383,12 @@ namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
profileItem = ResolveStdVLESS(result);
|
profileItem = ResolveStdVLESS(result);
|
||||||
}
|
}
|
||||||
|
else if (result.StartsWith(Global.hysteria2Protocol))
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
profileItem = ResolveHysteria2(result);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = ResUI.NonvmessOrssProtocol;
|
msg = ResUI.NonvmessOrssProtocol;
|
||||||
|
@ -758,6 +794,26 @@ namespace v2rayN.Handler
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ProfileItem ResolveHysteria2(string result)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Hysteria2
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(result);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = url.UserInfo;
|
||||||
|
|
||||||
|
var query = HttpUtility.ParseQueryString(url.Query);
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
private static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
private static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
||||||
{
|
{
|
||||||
item.flow = query["flow"] ?? "";
|
item.flow = query["flow"] ?? "";
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
Shadowsocks = 3,
|
Shadowsocks = 3,
|
||||||
Socks = 4,
|
Socks = 4,
|
||||||
VLESS = 5,
|
VLESS = 5,
|
||||||
Trojan = 6
|
Trojan = 6,
|
||||||
|
Hysteria2 = 7
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -53,6 +53,7 @@ namespace v2rayN.Mode
|
||||||
case EConfigType.Socks:
|
case EConfigType.Socks:
|
||||||
case EConfigType.VLESS:
|
case EConfigType.VLESS:
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
|
case EConfigType.Hysteria2:
|
||||||
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
|
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1138,4 +1138,7 @@
|
||||||
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
||||||
<value>Domain</value>
|
<value>Domain</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
|
<value>Add [Trojan] server</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1135,4 +1135,7 @@
|
||||||
<data name="TbRoutingRuleIP" xml:space="preserve">
|
<data name="TbRoutingRuleIP" xml:space="preserve">
|
||||||
<value>IP 或 IP CIDR</value>
|
<value>IP 或 IP CIDR</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
|
<value>添加[Hysteria2]服务器</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -145,6 +145,10 @@ namespace v2rayN.ViewModels
|
||||||
case EConfigType.Trojan:
|
case EConfigType.Trojan:
|
||||||
ret = ConfigHandler.AddTrojanServer(ref _config, item);
|
ret = ConfigHandler.AddTrojanServer(ref _config, item);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EConfigType.Hysteria2:
|
||||||
|
ret = ConfigHandler.AddHysteria2Server(ref _config, item);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
|
|
|
@ -89,6 +89,7 @@ namespace v2rayN.ViewModels
|
||||||
public ReactiveCommand<Unit, Unit> AddShadowsocksServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddShadowsocksServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddSocksServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddSocksServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddTrojanServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddTrojanServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> AddHysteria2ServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
|
||||||
|
@ -337,6 +338,10 @@ namespace v2rayN.ViewModels
|
||||||
{
|
{
|
||||||
EditServer(true, EConfigType.Trojan);
|
EditServer(true, EConfigType.Trojan);
|
||||||
});
|
});
|
||||||
|
AddHysteria2ServerCmd = ReactiveCommand.Create(() =>
|
||||||
|
{
|
||||||
|
EditServer(true, EConfigType.Hysteria2);
|
||||||
|
});
|
||||||
AddCustomServerCmd = ReactiveCommand.Create(() =>
|
AddCustomServerCmd = ReactiveCommand.Create(() =>
|
||||||
{
|
{
|
||||||
EditServer(true, EConfigType.Custom);
|
EditServer(true, EConfigType.Custom);
|
||||||
|
|
|
@ -359,6 +359,9 @@ namespace v2rayN.ViewModels
|
||||||
case 6:
|
case 6:
|
||||||
type = CoreType6;
|
type = CoreType6;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
item.coreType = (ECoreType)Enum.Parse(typeof(ECoreType), type);
|
item.coreType = (ECoreType)Enum.Parse(typeof(ECoreType), type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,13 +399,43 @@
|
||||||
Margin="{StaticResource ServerItemMargin}"
|
Margin="{StaticResource ServerItemMargin}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
x:Name="gridHysteria2"
|
||||||
|
Grid.Row="2"
|
||||||
|
Visibility="Hidden">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="180" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource ServerItemMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbId3}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtId7"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource ServerItemMargin}"
|
||||||
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<Separator
|
<Separator
|
||||||
|
x:Name="sepa2"
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Margin="0,2"
|
Margin="0,2"
|
||||||
Style="{DynamicResource MaterialDesignSeparator}" />
|
Style="{DynamicResource MaterialDesignSeparator}" />
|
||||||
|
|
||||||
<Grid Grid.Row="4">
|
<Grid x:Name="gridTransport" Grid.Row="4">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
|
|
@ -117,6 +117,14 @@ namespace v2rayN.Views
|
||||||
cmbFlow6.Items.Add(it);
|
cmbFlow6.Items.Add(it);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EConfigType.Hysteria2:
|
||||||
|
gridHysteria2.Visibility = Visibility.Visible;
|
||||||
|
sepa2.Visibility = Visibility.Collapsed;
|
||||||
|
gridTransport.Visibility = Visibility.Collapsed;
|
||||||
|
cmbCoreType.IsEnabled = false;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gridTlsMore.Visibility = Visibility.Hidden;
|
gridTlsMore.Visibility = Visibility.Hidden;
|
||||||
|
@ -156,6 +164,10 @@ namespace v2rayN.Views
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId6.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow6.Text).DisposeWith(disposables);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EConfigType.Hysteria2:
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId7.Text).DisposeWith(disposables);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.network, v => v.cmbNetwork.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.network, v => v.cmbNetwork.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.headerType, v => v.cmbHeaderType.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.headerType, v => v.cmbHeaderType.Text).DisposeWith(disposables);
|
||||||
|
|
|
@ -83,6 +83,10 @@
|
||||||
x:Name="menuAddTrojanServer"
|
x:Name="menuAddTrojanServer"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
|
Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuAddHysteria2Server"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuAddHysteria2Server}" />
|
||||||
<Separator Margin="-40,5" />
|
<Separator Margin="-40,5" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuAddServerViaClipboard"
|
x:Name="menuAddServerViaClipboard"
|
||||||
|
|
|
@ -86,6 +86,7 @@ namespace v2rayN.Views
|
||||||
this.BindCommand(ViewModel, vm => vm.AddShadowsocksServerCmd, v => v.menuAddShadowsocksServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddShadowsocksServerCmd, v => v.menuAddShadowsocksServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddSocksServerCmd, v => v.menuAddSocksServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddSocksServerCmd, v => v.menuAddSocksServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddTrojanServerCmd, v => v.menuAddTrojanServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddTrojanServerCmd, v => v.menuAddTrojanServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
||||||
|
|
Loading…
Reference in New Issue