mirror of
https://github.com/2dust/v2rayN.git
synced 2025-10-13 20:09:12 +00:00
VM and wpf
This commit is contained in:
parent
55de37e5f3
commit
dd2bfd9511
17 changed files with 917 additions and 6 deletions
|
@ -23,6 +23,7 @@ public enum EViewAction
|
||||||
RoutingRuleDetailsWindow,
|
RoutingRuleDetailsWindow,
|
||||||
AddServerWindow,
|
AddServerWindow,
|
||||||
AddServer2Window,
|
AddServer2Window,
|
||||||
|
AddGroupServerWindow,
|
||||||
DNSSettingWindow,
|
DNSSettingWindow,
|
||||||
RoutingSettingWindow,
|
RoutingSettingWindow,
|
||||||
OptionSettingWindow,
|
OptionSettingWindow,
|
||||||
|
|
|
@ -19,10 +19,21 @@ public class ProfileGroupItemManager
|
||||||
await InitData();
|
await InitData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ConcurrentBag<ProfileGroupItem>> GetProfileGroupItemList()
|
// Read-only getters: do not create or mark dirty
|
||||||
|
public bool TryGet(string indexId, out ProfileGroupItem? item)
|
||||||
{
|
{
|
||||||
var bag = new ConcurrentBag<ProfileGroupItem>(_items.Values);
|
item = null;
|
||||||
return Task.FromResult(bag);
|
if (string.IsNullOrWhiteSpace(indexId))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _items.TryGetValue(indexId, out item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileGroupItem? GetOrDefault(string indexId)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(indexId) ? null : (_items.TryGetValue(indexId, out var v) ? v : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitData()
|
private async Task InitData()
|
||||||
|
@ -50,7 +61,7 @@ public class ProfileGroupItemManager
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(indexId))
|
if (string.IsNullOrEmpty(indexId))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(indexId));
|
indexId = Utils.GetGuid(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _items.GetOrAdd(indexId, AddProfileGroupItem);
|
return _items.GetOrAdd(indexId, AddProfileGroupItem);
|
||||||
|
|
108
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
108
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
@ -672,6 +672,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Add Child Configuration 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuAddChildServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuAddChildServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add a custom configuration Configuration 的本地化字符串。
|
/// 查找类似 Add a custom configuration Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -699,6 +708,24 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Add Policy Group Configuration 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuAddPolicyGroupServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuAddPolicyGroupServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Add Proxy Chain Configuration 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuAddProxyChainServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuAddProxyChainServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Import Share Links from clipboard (Ctrl+V) 的本地化字符串。
|
/// 查找类似 Import Share Links from clipboard (Ctrl+V) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1320,6 +1347,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remove Child Configuration 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoveChildServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoveChildServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove duplicate Configurations 的本地化字符串。
|
/// 查找类似 Remove duplicate Configurations 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1995,6 +2031,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Please Add At Least One Configuration 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string PleaseAddAtLeastOneServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("PleaseAddAtLeastOneServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please fill Remarks 的本地化字符串。
|
/// 查找类似 Please fill Remarks 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2373,6 +2418,24 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Policy Group 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbConfigTypePolicyGroup {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbConfigTypePolicyGroup", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Proxy Chain 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbConfigTypeProxyChain {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbConfigTypeProxyChain", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Confirm 的本地化字符串。
|
/// 查找类似 Confirm 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2643,6 +2706,24 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Most Stable 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbLeastLoad {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbLeastLoad", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Lowest Latency 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbLeastPing {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbLeastPing", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Address (IPv4, IPv6) 的本地化字符串。
|
/// 查找类似 Address (IPv4, IPv6) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2697,6 +2778,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Policy Group Type 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbPolicyGroupType {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbPolicyGroupType", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Port 的本地化字符串。
|
/// 查找类似 Port 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2769,6 +2859,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Random 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbRandom {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbRandom", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 v2ray Full Config Template 的本地化字符串。
|
/// 查找类似 v2ray Full Config Template 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2832,6 +2931,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Round Robin 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbRoundRobin {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbRoundRobin", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 socks: local port, socks2: second local port, socks3: LAN port 的本地化字符串。
|
/// 查找类似 socks: local port, socks2: second local port, socks3: LAN port 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1512,4 +1512,40 @@
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
||||||
|
<value>Policy Group</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
||||||
|
<value>Proxy Chain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastPing" xml:space="preserve">
|
||||||
|
<value>Lowest Latency</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRandom" xml:space="preserve">
|
||||||
|
<value>Random</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoundRobin" xml:space="preserve">
|
||||||
|
<value>Round Robin</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastLoad" xml:space="preserve">
|
||||||
|
<value>Most Stable</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPolicyGroupType" xml:space="preserve">
|
||||||
|
<value>Policy Group Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||||
|
<value>Add Policy Group Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||||
|
<value>Add Proxy Chain Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddChildServer" xml:space="preserve">
|
||||||
|
<value>Add Child Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||||
|
<value>Remove Child Configuration</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1512,4 +1512,40 @@
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
||||||
|
<value>Policy Group</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
||||||
|
<value>Proxy Chain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastPing" xml:space="preserve">
|
||||||
|
<value>Lowest Latency</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRandom" xml:space="preserve">
|
||||||
|
<value>Random</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoundRobin" xml:space="preserve">
|
||||||
|
<value>Round Robin</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastLoad" xml:space="preserve">
|
||||||
|
<value>Most Stable</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPolicyGroupType" xml:space="preserve">
|
||||||
|
<value>Policy Group Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||||
|
<value>Add Policy Group Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||||
|
<value>Add Proxy Chain Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddChildServer" xml:space="preserve">
|
||||||
|
<value>Add Child Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||||
|
<value>Remove Child Configuration</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1512,4 +1512,40 @@
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
||||||
|
<value>Policy Group</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
||||||
|
<value>Proxy Chain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastPing" xml:space="preserve">
|
||||||
|
<value>Lowest Latency</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRandom" xml:space="preserve">
|
||||||
|
<value>Random</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoundRobin" xml:space="preserve">
|
||||||
|
<value>Round Robin</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastLoad" xml:space="preserve">
|
||||||
|
<value>Most Stable</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPolicyGroupType" xml:space="preserve">
|
||||||
|
<value>Policy Group Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||||
|
<value>Add Policy Group Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||||
|
<value>Add Proxy Chain Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddChildServer" xml:space="preserve">
|
||||||
|
<value>Add Child Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||||
|
<value>Remove Child Configuration</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1512,4 +1512,40 @@
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
||||||
|
<value>Policy Group</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
||||||
|
<value>Proxy Chain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastPing" xml:space="preserve">
|
||||||
|
<value>Lowest Latency</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRandom" xml:space="preserve">
|
||||||
|
<value>Random</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoundRobin" xml:space="preserve">
|
||||||
|
<value>Round Robin</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastLoad" xml:space="preserve">
|
||||||
|
<value>Most Stable</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPolicyGroupType" xml:space="preserve">
|
||||||
|
<value>Policy Group Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||||
|
<value>Add Policy Group Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||||
|
<value>Add Proxy Chain Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddChildServer" xml:space="preserve">
|
||||||
|
<value>Add Child Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||||
|
<value>Remove Child Configuration</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1509,4 +1509,40 @@
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>默认全局生效,内置 FakeIP 过滤,仅在 sing-box 中生效</value>
|
<value>默认全局生效,内置 FakeIP 过滤,仅在 sing-box 中生效</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
|
<value>请至少添加一个配置文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
||||||
|
<value>策略组</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
||||||
|
<value>链式代理</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastPing" xml:space="preserve">
|
||||||
|
<value>最低延迟</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRandom" xml:space="preserve">
|
||||||
|
<value>随机</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoundRobin" xml:space="preserve">
|
||||||
|
<value>负载均衡</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastLoad" xml:space="preserve">
|
||||||
|
<value>最稳定</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPolicyGroupType" xml:space="preserve">
|
||||||
|
<value>策略组类型</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||||
|
<value>添加策略组配置文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||||
|
<value>添加链式代理配置文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddChildServer" xml:space="preserve">
|
||||||
|
<value>添加子配置文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||||
|
<value>删除子配置文件</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1509,4 +1509,40 @@
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypePolicyGroup" xml:space="preserve">
|
||||||
|
<value>Policy Group</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConfigTypeProxyChain" xml:space="preserve">
|
||||||
|
<value>Proxy Chain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastPing" xml:space="preserve">
|
||||||
|
<value>Lowest Latency</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRandom" xml:space="preserve">
|
||||||
|
<value>Random</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoundRobin" xml:space="preserve">
|
||||||
|
<value>Round Robin</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLeastLoad" xml:space="preserve">
|
||||||
|
<value>Most Stable</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPolicyGroupType" xml:space="preserve">
|
||||||
|
<value>Policy Group Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||||
|
<value>Add Policy Group Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||||
|
<value>Add Proxy Chain Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddChildServer" xml:space="preserve">
|
||||||
|
<value>Add Child Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||||
|
<value>Remove Child Configuration</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
|
using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
|
||||||
|
@ -9,9 +10,203 @@ public class AddGroupServerViewModel : MyReactiveObject
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public ProfileItem SelectedSource { get; set; }
|
public ProfileItem SelectedSource { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public ProfileItem SelectedChild { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public IList<ProfileItem> SelectedChildren { get; set; }
|
public IList<ProfileItem> SelectedChildren { get; set; }
|
||||||
|
|
||||||
//[Reactive]
|
[Reactive]
|
||||||
//public
|
public string? CoreType { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string? PolicyGroupType { get; set; }
|
||||||
|
|
||||||
|
public IObservableCollection<ProfileItem> ChildItemsObs { get; } = new ObservableCollectionExtended<ProfileItem>();
|
||||||
|
|
||||||
|
//public ReactiveCommand<Unit, Unit> AddCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> RemoveCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveBottomCmd { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||||
|
|
||||||
|
public AddGroupServerViewModel(ProfileItem profileItem, Func<EViewAction, object?, Task<bool>>? updateView)
|
||||||
|
{
|
||||||
|
_config = AppManager.Instance.Config;
|
||||||
|
_updateView = updateView;
|
||||||
|
|
||||||
|
RemoveCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await ChildRemoveAsync();
|
||||||
|
});
|
||||||
|
MoveTopCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await MoveServer(EMove.Top);
|
||||||
|
});
|
||||||
|
MoveUpCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await MoveServer(EMove.Up);
|
||||||
|
});
|
||||||
|
MoveDownCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await MoveServer(EMove.Down);
|
||||||
|
});
|
||||||
|
MoveBottomCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await MoveServer(EMove.Bottom);
|
||||||
|
});
|
||||||
|
SaveCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await SaveServerAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
SelectedSource = profileItem.IndexId.IsNullOrEmpty() ? profileItem : JsonUtils.DeepCopy(profileItem);
|
||||||
|
|
||||||
|
CoreType = (SelectedSource?.CoreType ?? ECoreType.Xray).ToString();
|
||||||
|
|
||||||
|
ProfileGroupItemManager.Instance.TryGet(profileItem.IndexId, out var profileGroup);
|
||||||
|
PolicyGroupType = (profileGroup?.MultipleLoad ?? EMultipleLoad.LeastPing) switch
|
||||||
|
{
|
||||||
|
EMultipleLoad.LeastPing => ResUI.TbLeastPing,
|
||||||
|
EMultipleLoad.Random => ResUI.TbRandom,
|
||||||
|
EMultipleLoad.RoundRobin => ResUI.TbRoundRobin,
|
||||||
|
EMultipleLoad.LeastLoad => ResUI.TbLeastLoad,
|
||||||
|
_ => ResUI.TbLeastPing,
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Init()
|
||||||
|
{
|
||||||
|
var childItemMulti = ProfileGroupItemManager.Instance.GetOrCreateAndMarkDirty(SelectedSource?.IndexId);
|
||||||
|
if (childItemMulti != null)
|
||||||
|
{
|
||||||
|
var childIndexIds = childItemMulti.ChildItems.IsNullOrEmpty() ? new List<string>() : Utils.String2List(childItemMulti.ChildItems);
|
||||||
|
foreach (var item in childIndexIds)
|
||||||
|
{
|
||||||
|
var child = await AppManager.Instance.GetProfileItem(item);
|
||||||
|
if (child == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ChildItemsObs.Add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ChildRemoveAsync()
|
||||||
|
{
|
||||||
|
if (SelectedChild == null || SelectedChild.IndexId.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ChildItemsObs.Remove(SelectedChild);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MoveServer(EMove eMove)
|
||||||
|
{
|
||||||
|
if (SelectedChild == null || SelectedChild.IndexId.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var index = ChildItemsObs.IndexOf(SelectedChild);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (eMove)
|
||||||
|
{
|
||||||
|
case EMove.Top:
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ChildItemsObs.RemoveAt(index);
|
||||||
|
ChildItemsObs.Insert(0, SelectedChild);
|
||||||
|
break;
|
||||||
|
case EMove.Up:
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ChildItemsObs.RemoveAt(index);
|
||||||
|
ChildItemsObs.Insert(index - 1, SelectedChild);
|
||||||
|
break;
|
||||||
|
case EMove.Down:
|
||||||
|
if (index == ChildItemsObs.Count - 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ChildItemsObs.RemoveAt(index);
|
||||||
|
ChildItemsObs.Insert(index + 1, SelectedChild);
|
||||||
|
break;
|
||||||
|
case EMove.Bottom:
|
||||||
|
if (index == ChildItemsObs.Count - 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ChildItemsObs.RemoveAt(index);
|
||||||
|
ChildItemsObs.Add(SelectedChild);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveServerAsync()
|
||||||
|
{
|
||||||
|
var remarks = SelectedSource.Remarks;
|
||||||
|
if (remarks.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.PleaseFillRemarks);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ChildItemsObs.Count == 0)
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.PleaseAddAtLeastOneServer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SelectedSource.CoreType = CoreType.IsNullOrEmpty() ? ECoreType.Xray : (ECoreType)Enum.Parse(typeof(ECoreType), CoreType);
|
||||||
|
if (SelectedSource.CoreType is not (ECoreType.Xray or ECoreType.sing_box) ||
|
||||||
|
SelectedSource.ConfigType is not (EConfigType.ProxyChain or EConfigType.PolicyGroup))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var childIndexIds = new List<string>();
|
||||||
|
foreach (var item in ChildItemsObs)
|
||||||
|
{
|
||||||
|
if (item.IndexId.IsNotEmpty())
|
||||||
|
{
|
||||||
|
childIndexIds.Add(item.IndexId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SelectedSource.Address = Utils.List2String(childIndexIds);
|
||||||
|
var profileGroup = ProfileGroupItemManager.Instance.GetOrCreateAndMarkDirty(SelectedSource.IndexId);
|
||||||
|
profileGroup.ChildItems = Utils.List2String(childIndexIds);
|
||||||
|
profileGroup.MultipleLoad = PolicyGroupType switch
|
||||||
|
{
|
||||||
|
var s when s == ResUI.TbLeastPing => EMultipleLoad.LeastPing,
|
||||||
|
var s when s == ResUI.TbRandom => EMultipleLoad.Random,
|
||||||
|
var s when s == ResUI.TbRoundRobin => EMultipleLoad.RoundRobin,
|
||||||
|
var s when s == ResUI.TbLeastLoad => EMultipleLoad.LeastLoad,
|
||||||
|
_ => EMultipleLoad.LeastPing,
|
||||||
|
};
|
||||||
|
if (await ConfigHandler.AddGroupServerCommon(_config, SelectedSource, profileGroup, true) == 0)
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.OperationSuccess);
|
||||||
|
_updateView?.Invoke(EViewAction.CloseWindow, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.OperationFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> AddPolicyGroupServerCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> AddProxyChainServerCmd { 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; }
|
||||||
public ReactiveCommand<Unit, Unit> AddServerViaImageCmd { get; }
|
public ReactiveCommand<Unit, Unit> AddServerViaImageCmd { get; }
|
||||||
|
@ -122,6 +124,14 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
await AddServerAsync(true, EConfigType.Custom);
|
await AddServerAsync(true, EConfigType.Custom);
|
||||||
});
|
});
|
||||||
|
AddPolicyGroupServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await AddServerAsync(true, EConfigType.PolicyGroup);
|
||||||
|
});
|
||||||
|
AddProxyChainServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await AddServerAsync(true, EConfigType.ProxyChain);
|
||||||
|
});
|
||||||
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
await AddServerViaClipboardAsync(null);
|
await AddServerViaClipboardAsync(null);
|
||||||
|
@ -341,6 +351,10 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
ret = await _updateView?.Invoke(EViewAction.AddServer2Window, item);
|
ret = await _updateView?.Invoke(EViewAction.AddServer2Window, item);
|
||||||
}
|
}
|
||||||
|
else if (eConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
|
||||||
|
{
|
||||||
|
ret = await _updateView?.Invoke(EViewAction.AddGroupServerWindow, item);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = await _updateView?.Invoke(EViewAction.AddServerWindow, item);
|
ret = await _updateView?.Invoke(EViewAction.AddServerWindow, item);
|
||||||
|
|
|
@ -500,6 +500,10 @@ public class ProfilesViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
ret = await _updateView?.Invoke(EViewAction.AddServer2Window, item);
|
ret = await _updateView?.Invoke(EViewAction.AddServer2Window, item);
|
||||||
}
|
}
|
||||||
|
else if (eConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
|
||||||
|
{
|
||||||
|
ret = await _updateView?.Invoke(EViewAction.AddGroupServerWindow, item);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = await _updateView?.Invoke(EViewAction.AddServerWindow, item);
|
ret = await _updateView?.Invoke(EViewAction.AddServerWindow, item);
|
||||||
|
|
216
v2rayN/v2rayN/Views/AddGroupServerWindow.xaml
Normal file
216
v2rayN/v2rayN/Views/AddGroupServerWindow.xaml
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
<base:WindowBase
|
||||||
|
x:Class="v2rayN.Views.AddGroupServerWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:base="clr-namespace:v2rayN.Base"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
|
Title="{x:Static resx:ResUI.menuServers}"
|
||||||
|
Width="900"
|
||||||
|
Height="700"
|
||||||
|
x:TypeArguments="vms:AddGroupServerViewModel"
|
||||||
|
ShowInTaskbar="False"
|
||||||
|
Style="{StaticResource WindowGlobal}"
|
||||||
|
WindowStartupLocation="CenterScreen"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
|
<StackPanel
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
DockPanel.Dock="Bottom"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
x:Name="btnSave"
|
||||||
|
Width="100"
|
||||||
|
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||||
|
IsDefault="True"
|
||||||
|
Style="{StaticResource DefButton}" />
|
||||||
|
<Button
|
||||||
|
x:Name="btnCancel"
|
||||||
|
Width="100"
|
||||||
|
Margin="{StaticResource MarginLeftRight8}"
|
||||||
|
Content="{x:Static resx:ResUI.TbCancel}"
|
||||||
|
IsCancel="true"
|
||||||
|
Style="{StaticResource DefButton}" />
|
||||||
|
</StackPanel>
|
||||||
|
<ScrollViewer
|
||||||
|
materialDesign:ScrollViewerAssist.IsAutoHideEnabled="True"
|
||||||
|
HorizontalScrollBarVisibility="Auto"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="180" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Style="{StaticResource ModuleTitle}"
|
||||||
|
Text="{x:Static resx:ResUI.menuServers}" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtRemarks"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
Style="{StaticResource DefTextBox}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbCoreType}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbCoreType"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbCoreType}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
x:Name="gridPolicyGroup"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="3">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="180" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbPolicyGroupType}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbPolicyGroupType"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbPolicyGroupType}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<DataGrid
|
||||||
|
x:Name="lstChild"
|
||||||
|
Grid.Row="1"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
BorderThickness="1"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
CanUserResizeRows="False"
|
||||||
|
CanUserSortColumns="False"
|
||||||
|
EnableRowVirtualization="True"
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
IsReadOnly="True"
|
||||||
|
Style="{StaticResource DefDataGrid}">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuAddChildServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Click="MenuAddChild_Click"
|
||||||
|
Header="{x:Static resx:ResUI.menuAddChildServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRemoveChildServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRemoveChildServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuSelectAllChild"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||||
|
<Separator />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveTop"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveTop}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveUp"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveUp}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveDown"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveDown}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuMoveBottom"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuMoveBottom}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="150"
|
||||||
|
Binding="{Binding ConfigType}"
|
||||||
|
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="150"
|
||||||
|
Binding="{Binding Remarks}"
|
||||||
|
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="120"
|
||||||
|
Binding="{Binding Address}"
|
||||||
|
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding Port}"
|
||||||
|
Header="{x:Static resx:ResUI.LvPort}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding Network}"
|
||||||
|
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding StreamSecurity}"
|
||||||
|
Header="{x:Static resx:ResUI.LvTLS}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DockPanel>
|
||||||
|
</base:WindowBase>
|
126
v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs
Normal file
126
v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using ReactiveUI;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
|
||||||
|
namespace v2rayN.Views;
|
||||||
|
|
||||||
|
public partial class AddGroupServerWindow
|
||||||
|
{
|
||||||
|
public AddGroupServerWindow(ProfileItem profileItem)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.Owner = Application.Current.MainWindow;
|
||||||
|
this.Loaded += Window_Loaded;
|
||||||
|
this.PreviewKeyDown += AddGroupServerWindow_PreviewKeyDown;
|
||||||
|
|
||||||
|
ViewModel = new AddGroupServerViewModel(profileItem, UpdateViewHandler);
|
||||||
|
|
||||||
|
cmbCoreType.ItemsSource = Global.CoreTypes;
|
||||||
|
cmbPolicyGroupType.ItemsSource = new List<string>
|
||||||
|
{
|
||||||
|
ResUI.TbLeastPing,
|
||||||
|
ResUI.TbRandom,
|
||||||
|
ResUI.TbRoundRobin,
|
||||||
|
ResUI.TbLeastLoad,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (profileItem.ConfigType)
|
||||||
|
{
|
||||||
|
case EConfigType.PolicyGroup:
|
||||||
|
this.Title = ResUI.TbConfigTypePolicyGroup;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EConfigType.ProxyChain:
|
||||||
|
this.Title = ResUI.TbConfigTypeProxyChain;
|
||||||
|
gridPolicyGroup.Visibility = Visibility.Collapsed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.WhenActivated(disposables =>
|
||||||
|
{
|
||||||
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.ChildItemsObs, v => v.lstChild.ItemsSource).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RemoveCmd, v => v.menuRemoveChildServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case EViewAction.CloseWindow:
|
||||||
|
this.DialogResult = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return await Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
txtRemarks.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddGroupServerWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (!lstChild.IsKeyboardFocusWithin)
|
||||||
|
return;
|
||||||
|
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||||
|
{
|
||||||
|
if (e.Key == Key.A)
|
||||||
|
{
|
||||||
|
lstChild.SelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (e.Key == Key.T)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Top);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.U)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Up);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.D)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Down);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.B)
|
||||||
|
{
|
||||||
|
ViewModel?.MoveServer(EMove.Bottom);
|
||||||
|
}
|
||||||
|
else if (e.Key == Key.Delete)
|
||||||
|
{
|
||||||
|
ViewModel?.ChildRemoveAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void MenuAddChild_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var selectWindow = new ProfilesSelectWindow();
|
||||||
|
if (selectWindow.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
var profile = await selectWindow.ProfileItem;
|
||||||
|
if (profile != null)
|
||||||
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.ChildItemsObs.Add(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,6 +71,14 @@
|
||||||
x:Name="menuAddCustomServer"
|
x:Name="menuAddCustomServer"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuAddCustomServer}" />
|
Header="{x:Static resx:ResUI.menuAddCustomServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuAddPolicyGroupServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuAddPolicyGroupServer}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuAddProxyChainServer"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuAddProxyChainServer}" />
|
||||||
<Separator Margin="-40,5" />
|
<Separator Margin="-40,5" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuAddVmessServer"
|
x:Name="menuAddVmessServer"
|
||||||
|
|
|
@ -79,6 +79,8 @@ public partial class MainWindow
|
||||||
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).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.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).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);
|
||||||
this.BindCommand(ViewModel, vm => vm.AddServerViaImageCmd, v => v.menuAddServerViaImage).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.AddServerViaImageCmd, v => v.menuAddServerViaImage).DisposeWith(disposables);
|
||||||
|
@ -195,6 +197,11 @@ public partial class MainWindow
|
||||||
return false;
|
return false;
|
||||||
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
|
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
|
||||||
|
|
||||||
|
case EViewAction.AddGroupServerWindow:
|
||||||
|
if (obj is null)
|
||||||
|
return false;
|
||||||
|
return (new AddGroupServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.DNSSettingWindow:
|
case EViewAction.DNSSettingWindow:
|
||||||
return (new DNSSettingWindow().ShowDialog() ?? false);
|
return (new DNSSettingWindow().ShowDialog() ?? false);
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,11 @@ public partial class ProfilesView
|
||||||
return false;
|
return false;
|
||||||
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
|
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
|
||||||
|
|
||||||
|
case EViewAction.AddGroupServerWindow:
|
||||||
|
if (obj is null)
|
||||||
|
return false;
|
||||||
|
return (new AddGroupServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
|
||||||
|
|
||||||
case EViewAction.ShareServer:
|
case EViewAction.ShareServer:
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue