mirror of
https://github.com/2dust/v2rayN.git
synced 2025-10-13 20:09:12 +00:00
Compare commits
7 commits
61033675b6
...
228a1b17bf
Author | SHA1 | Date | |
---|---|---|---|
![]() |
228a1b17bf | ||
![]() |
f76fd364a2 | ||
![]() |
0a1d6db9d1 | ||
![]() |
7a750a127e | ||
![]() |
fce4a7b74c | ||
![]() |
fec7353703 | ||
![]() |
40c90d5b3b |
19 changed files with 700 additions and 33 deletions
|
@ -1098,7 +1098,7 @@ public static class ConfigHandler
|
||||||
await SQLiteHelper.Instance.ReplaceAsync(profileItem);
|
await SQLiteHelper.Instance.ReplaceAsync(profileItem);
|
||||||
if (profileGroupItem != null)
|
if (profileGroupItem != null)
|
||||||
{
|
{
|
||||||
profileGroupItem.ParentIndexId = profileItem.IndexId;
|
profileGroupItem.IndexId = profileItem.IndexId;
|
||||||
await ProfileGroupItemManager.Instance.SaveItemAsync(profileGroupItem);
|
await ProfileGroupItemManager.Instance.SaveItemAsync(profileGroupItem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1233,7 +1233,7 @@ public static class ConfigHandler
|
||||||
{
|
{
|
||||||
ChildItems = childProfileIndexId,
|
ChildItems = childProfileIndexId,
|
||||||
MultipleLoad = multipleLoad,
|
MultipleLoad = multipleLoad,
|
||||||
ParentIndexId = indexId,
|
IndexId = indexId,
|
||||||
};
|
};
|
||||||
var ret = await AddGroupServerCommon(config, profile, profileGroup, true);
|
var ret = await AddGroupServerCommon(config, profile, profileGroup, true);
|
||||||
result.Success = ret == 0;
|
result.Success = ret == 0;
|
||||||
|
|
283
v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs
Normal file
283
v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
namespace ServiceLib.Manager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Centralized pre-checks before sensitive actions (set active profile, generate config, etc.).
|
||||||
|
/// </summary>
|
||||||
|
public class ActionPrecheckManager(Config config)
|
||||||
|
{
|
||||||
|
private static readonly Lazy<ActionPrecheckManager> _instance = new(() => new ActionPrecheckManager(AppManager.Instance.Config));
|
||||||
|
public static ActionPrecheckManager Instance => _instance.Value;
|
||||||
|
|
||||||
|
private readonly Config _config = config;
|
||||||
|
|
||||||
|
public async Task<List<string>> CheckBeforeSetActive(string? indexId)
|
||||||
|
{
|
||||||
|
if (indexId.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return [ResUI.PleaseSelectServer];
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = await AppManager.Instance.GetProfileItem(indexId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return [ResUI.PleaseSelectServer];
|
||||||
|
}
|
||||||
|
|
||||||
|
return await CheckBeforeGenerateConfig(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<string>> CheckBeforeGenerateConfig(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return [ResUI.PleaseSelectServer];
|
||||||
|
}
|
||||||
|
|
||||||
|
var errors = new List<string>();
|
||||||
|
|
||||||
|
errors.AddRange(await ValidateCurrentNodeAndCoreSupport(item));
|
||||||
|
errors.AddRange(await ValidateRelatedNodesExistAndValid(item));
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<string>> ValidateCurrentNodeAndCoreSupport(ProfileItem item)
|
||||||
|
{
|
||||||
|
if (item.ConfigType == EConfigType.Custom)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var coreType = AppManager.Instance.GetCoreType(item, item.ConfigType);
|
||||||
|
return await ValidateNodeAndCoreSupport(item, coreType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<string>> ValidateNodeAndCoreSupport(ProfileItem item, ECoreType? coreType = null)
|
||||||
|
{
|
||||||
|
var errors = new List<string>();
|
||||||
|
|
||||||
|
coreType ??= AppManager.Instance.GetCoreType(item, item.ConfigType);
|
||||||
|
|
||||||
|
if (item.ConfigType is EConfigType.Custom)
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.NotSupportProtocol, item.ConfigType.ToString()));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.IsComplex())
|
||||||
|
{
|
||||||
|
if (item.Address.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "Address"));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Port is <= 0 or >= 65536)
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "Port"));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (item.ConfigType)
|
||||||
|
{
|
||||||
|
case EConfigType.VMess:
|
||||||
|
if (item.Id.IsNullOrEmpty() || !Utils.IsGuidByParse(item.Id))
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "Id"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EConfigType.VLESS:
|
||||||
|
if (item.Id.IsNullOrEmpty() || !Utils.IsGuidByParse(item.Id) && item.Id.Length > 30)
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "Id"));
|
||||||
|
if (!Global.Flows.Contains(item.Flow))
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "Flow"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EConfigType.Shadowsocks:
|
||||||
|
if (item.Id.IsNullOrEmpty())
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "Id"));
|
||||||
|
if (string.IsNullOrEmpty(item.Security) || !Global.SsSecuritiesInSingbox.Contains(item.Security))
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "Security"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.ConfigType is EConfigType.VLESS or EConfigType.Trojan
|
||||||
|
&& item.StreamSecurity == Global.StreamSecurityReality
|
||||||
|
&& item.PublicKey.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.InvalidProperty, "PublicKey"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.Count > 0)
|
||||||
|
{
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
|
||||||
|
{
|
||||||
|
ProfileGroupItemManager.Instance.TryGet(item.IndexId, out var group);
|
||||||
|
if (group is null || group.ChildItems.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.GroupEmpty, item.Remarks));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasCycle = ProfileGroupItemManager.HasCycle(item.IndexId);
|
||||||
|
if (hasCycle)
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.GroupSelfReference, item.Remarks));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in Utils.String2List(group.ChildItems))
|
||||||
|
{
|
||||||
|
var childErrors = new List<string>();
|
||||||
|
if (child.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var childItem = await AppManager.Instance.GetProfileItem(child);
|
||||||
|
if (childItem is null)
|
||||||
|
{
|
||||||
|
childErrors.Add(string.Format(ResUI.NodeTagNotExist, child));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childItem.ConfigType is EConfigType.Custom or EConfigType.ProxyChain)
|
||||||
|
{
|
||||||
|
childErrors.Add(string.Format(ResUI.InvalidProperty, childItem.Remarks));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
childErrors.AddRange(await ValidateNodeAndCoreSupport(childItem, coreType));
|
||||||
|
errors.AddRange(childErrors);
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
var net = item.GetNetwork() ?? item.Network;
|
||||||
|
|
||||||
|
if (coreType == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
// sing-box does not support xhttp / kcp
|
||||||
|
// sing-box does not support transports like ws/http/httpupgrade/etc. when the node is not vmess/trojan/vless
|
||||||
|
if (net is nameof(ETransport.kcp) or nameof(ETransport.xhttp))
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.CoreNotSupportNetwork, nameof(ECoreType.sing_box), net));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.ConfigType is not (EConfigType.VMess or EConfigType.VLESS or EConfigType.Trojan))
|
||||||
|
{
|
||||||
|
if (net is nameof(ETransport.ws) or nameof(ETransport.http) or nameof(ETransport.h2) or nameof(ETransport.quic) or nameof(ETransport.httpupgrade))
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.CoreNotSupportProtocolTransport, nameof(ECoreType.sing_box), item.ConfigType.ToString(), net));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (coreType is ECoreType.Xray)
|
||||||
|
{
|
||||||
|
// Xray core does not support these protocols
|
||||||
|
if (!Global.XraySupportConfigType.Contains(item.ConfigType)
|
||||||
|
&& !item.IsComplex())
|
||||||
|
{
|
||||||
|
errors.Add(string.Format(ResUI.CoreNotSupportProtocol, nameof(ECoreType.Xray), item.ConfigType.ToString()));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<string>> ValidateRelatedNodesExistAndValid(ProfileItem? item)
|
||||||
|
{
|
||||||
|
var errors = new List<string>();
|
||||||
|
errors.AddRange(await ValidateProxyChainedNodeExistAndValid(item));
|
||||||
|
errors.AddRange(await ValidateRoutingNodeExistAndValid(item));
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<string>> ValidateProxyChainedNodeExistAndValid(ProfileItem? item)
|
||||||
|
{
|
||||||
|
var errors = new List<string>();
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prev node and next node
|
||||||
|
var subItem = await AppManager.Instance.GetSubItem(item.Subid);
|
||||||
|
if (subItem is null)
|
||||||
|
{
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
|
||||||
|
var nextNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
|
||||||
|
var coreType = AppManager.Instance.GetCoreType(item, item.ConfigType);
|
||||||
|
|
||||||
|
await CollectProxyChainedNodeValidation(prevNode, subItem.PrevProfile, coreType, errors);
|
||||||
|
await CollectProxyChainedNodeValidation(nextNode, subItem.NextProfile, coreType, errors);
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CollectProxyChainedNodeValidation(ProfileItem? node, string tag, ECoreType coreType, List<string> errors)
|
||||||
|
{
|
||||||
|
if (node is not null)
|
||||||
|
{
|
||||||
|
var nodeErrors = await ValidateNodeAndCoreSupport(node, coreType);
|
||||||
|
errors.AddRange(nodeErrors.Select(s => ResUI.ProxyChainedPrefix + s));
|
||||||
|
}
|
||||||
|
else if (tag.IsNotEmpty())
|
||||||
|
{
|
||||||
|
errors.Add(ResUI.ProxyChainedPrefix + string.Format(ResUI.NodeTagNotExist, tag));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<string>> ValidateRoutingNodeExistAndValid(ProfileItem? item)
|
||||||
|
{
|
||||||
|
var errors = new List<string>();
|
||||||
|
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
var coreType = AppManager.Instance.GetCoreType(item, item.ConfigType);
|
||||||
|
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||||
|
if (routing == null)
|
||||||
|
{
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
|
||||||
|
foreach (var ruleItem in rules ?? [])
|
||||||
|
{
|
||||||
|
if (!ruleItem.Enabled)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outboundTag = ruleItem.OutboundTag;
|
||||||
|
if (outboundTag.IsNullOrEmpty() || Global.OutboundTags.Contains(outboundTag))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagItem = await AppManager.Instance.GetProfileItemViaRemarks(outboundTag);
|
||||||
|
if (tagItem is null)
|
||||||
|
{
|
||||||
|
errors.Add(ResUI.RoutingRuleOutboundPrefix + string.Format(ResUI.NodeTagNotExist, outboundTag));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagErrors = await ValidateNodeAndCoreSupport(tagItem, coreType);
|
||||||
|
errors.AddRange(tagErrors.Select(s => ResUI.RoutingRuleOutboundPrefix + s));
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}
|
|
@ -208,13 +208,13 @@ public sealed class AppManager
|
||||||
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(it => it.Remarks == remarks);
|
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(it => it.Remarks == remarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ProfileGroupItem?> GetProfileGroupItem(string parentIndexId)
|
public async Task<ProfileGroupItem?> GetProfileGroupItem(string indexId)
|
||||||
{
|
{
|
||||||
if (parentIndexId.IsNullOrEmpty())
|
if (indexId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().FirstOrDefaultAsync(it => it.ParentIndexId == parentIndexId);
|
return await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().FirstOrDefaultAsync(it => it.IndexId == indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<RoutingItem>?> RoutingItems()
|
public async Task<List<RoutingItem>?> RoutingItems()
|
||||||
|
|
|
@ -38,17 +38,17 @@ public class ProfileGroupItemManager
|
||||||
|
|
||||||
private async Task InitData()
|
private async Task InitData()
|
||||||
{
|
{
|
||||||
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileGroupItem where parentIndexId not in ( select indexId from ProfileItem )");
|
await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileGroupItem where IndexId not in ( select indexId from ProfileItem )");
|
||||||
|
|
||||||
var list = await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().ToListAsync();
|
var list = await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().ToListAsync();
|
||||||
_items = new ConcurrentDictionary<string, ProfileGroupItem>(list.Where(t => !string.IsNullOrEmpty(t.ParentIndexId)).ToDictionary(t => t.ParentIndexId!));
|
_items = new ConcurrentDictionary<string, ProfileGroupItem>(list.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProfileGroupItem AddProfileGroupItem(string indexId)
|
private ProfileGroupItem AddProfileGroupItem(string indexId)
|
||||||
{
|
{
|
||||||
var profileGroupItem = new ProfileGroupItem()
|
var profileGroupItem = new ProfileGroupItem()
|
||||||
{
|
{
|
||||||
ParentIndexId = indexId,
|
IndexId = indexId,
|
||||||
ChildItems = string.Empty,
|
ChildItems = string.Empty,
|
||||||
MultipleLoad = EMultipleLoad.LeastPing
|
MultipleLoad = EMultipleLoad.LeastPing
|
||||||
};
|
};
|
||||||
|
@ -78,19 +78,19 @@ public class ProfileGroupItemManager
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var lstExists = await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().ToListAsync();
|
var lstExists = await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().ToListAsync();
|
||||||
var existsMap = lstExists.Where(t => !string.IsNullOrEmpty(t.ParentIndexId)).ToDictionary(t => t.ParentIndexId!);
|
var existsMap = lstExists.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!);
|
||||||
|
|
||||||
var lstInserts = new List<ProfileGroupItem>();
|
var lstInserts = new List<ProfileGroupItem>();
|
||||||
var lstUpdates = new List<ProfileGroupItem>();
|
var lstUpdates = new List<ProfileGroupItem>();
|
||||||
|
|
||||||
foreach (var item in _items.Values)
|
foreach (var item in _items.Values)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(item.ParentIndexId))
|
if (string.IsNullOrEmpty(item.IndexId))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existsMap.ContainsKey(item.ParentIndexId))
|
if (existsMap.ContainsKey(item.IndexId))
|
||||||
{
|
{
|
||||||
lstUpdates.Add(item);
|
lstUpdates.Add(item);
|
||||||
}
|
}
|
||||||
|
@ -140,16 +140,16 @@ public class ProfileGroupItemManager
|
||||||
throw new ArgumentNullException(nameof(item));
|
throw new ArgumentNullException(nameof(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(item.ParentIndexId))
|
if (string.IsNullOrWhiteSpace(item.IndexId))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("ParentIndexId required", nameof(item));
|
throw new ArgumentException("IndexId required", nameof(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
_items[item.ParentIndexId] = item;
|
_items[item.IndexId] = item;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var lst = await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().Where(t => t.ParentIndexId == item.ParentIndexId).ToListAsync();
|
var lst = await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().Where(t => t.IndexId == item.IndexId).ToListAsync();
|
||||||
if (lst != null && lst.Count > 0)
|
if (lst != null && lst.Count > 0)
|
||||||
{
|
{
|
||||||
await SQLiteHelper.Instance.UpdateAllAsync(new List<ProfileGroupItem> { item });
|
await SQLiteHelper.Instance.UpdateAllAsync(new List<ProfileGroupItem> { item });
|
||||||
|
@ -250,11 +250,11 @@ public class ProfileGroupItemManager
|
||||||
return childProfiles;
|
return childProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<HashSet<string>> GetAllChildDomainAddresses(string parentIndexId)
|
public static async Task<HashSet<string>> GetAllChildDomainAddresses(string indexId)
|
||||||
{
|
{
|
||||||
// include grand children
|
// include grand children
|
||||||
var childAddresses = new HashSet<string>();
|
var childAddresses = new HashSet<string>();
|
||||||
if (!Instance.TryGet(parentIndexId, out var groupItem) || groupItem.ChildItems.IsNullOrEmpty())
|
if (!Instance.TryGet(indexId, out var groupItem) || groupItem.ChildItems.IsNullOrEmpty())
|
||||||
return childAddresses;
|
return childAddresses;
|
||||||
|
|
||||||
var childIds = Utils.String2List(groupItem.ChildItems);
|
var childIds = Utils.String2List(groupItem.ChildItems);
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace ServiceLib.Models;
|
||||||
public class ProfileGroupItem
|
public class ProfileGroupItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string ParentIndexId { get; set; }
|
public string IndexId { get; set; }
|
||||||
|
|
||||||
public string ChildItems { get; set; }
|
public string ChildItems { get; set; }
|
||||||
|
|
||||||
|
|
108
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
108
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
@ -114,6 +114,33 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Core '{0}' does not support network type '{1}'. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string CoreNotSupportNetwork {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CoreNotSupportNetwork", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Core '{0}' does not support protocol '{1}'. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string CoreNotSupportProtocol {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CoreNotSupportProtocol", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Core '{0}' does not support protocol '{1}' when using transport '{2}'. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string CoreNotSupportProtocolTransport {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CoreNotSupportProtocolTransport", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 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. 的本地化字符串。
|
/// 查找类似 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. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -267,6 +294,24 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Group '{0}' is empty. Please add at least one node. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string GroupEmpty {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("GroupEmpty", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 {0} Group cannot reference itself or have a circular reference 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string GroupSelfReference {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("GroupSelfReference", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 This is not the correct configuration, please check 的本地化字符串。
|
/// 查找类似 This is not the correct configuration, please check 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -294,6 +339,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 The {0} property is invalid, please check. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string InvalidProperty {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InvalidProperty", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Invalid address (URL) 的本地化字符串。
|
/// 查找类似 Invalid address (URL) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2004,6 +2058,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Node alias '{0}' does not exist. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string NodeTagNotExist {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NodeTagNotExist", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Non-VMess or SS protocol 的本地化字符串。
|
/// 查找类似 Non-VMess or SS protocol 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2031,6 +2094,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Not support protocol '{0}'. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string NotSupportProtocol {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NotSupportProtocol", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Scan completed, no valid QR code found 的本地化字符串。
|
/// 查找类似 Scan completed, no valid QR code found 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2112,6 +2184,24 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Policy group: 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string PolicyGroupPrefix {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("PolicyGroupPrefix", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Proxy chained: 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string ProxyChainedPrefix {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ProxyChainedPrefix", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Global hotkey {0} registration failed, reason: {1} 的本地化字符串。
|
/// 查找类似 Global hotkey {0} registration failed, reason: {1} 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -2175,6 +2265,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Routing rule outbound: 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string RoutingRuleOutboundPrefix {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("RoutingRuleOutboundPrefix", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Run as Admin 的本地化字符串。
|
/// 查找类似 Run as Admin 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3552,6 +3651,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 If the system does not have a tray function, please do not enable it 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsHide2TrayWhenCloseTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsHide2TrayWhenCloseTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Hysteria Max bandwidth (Up/Down) 的本地化字符串。
|
/// 查找类似 Hysteria Max bandwidth (Up/Down) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1560,4 +1560,40 @@
|
||||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||||
<value>Multi-Configuration Fallback by Xray</value>
|
<value>Multi-Configuration Fallback by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CoreNotSupportNetwork" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support network type '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}' when using transport '{2}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProxyChainedPrefix" xml:space="preserve">
|
||||||
|
<value>Proxy chained: </value>
|
||||||
|
</data>
|
||||||
|
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
||||||
|
<value>Routing rule outbound: </value>
|
||||||
|
</data>
|
||||||
|
<data name="PolicyGroupPrefix" xml:space="preserve">
|
||||||
|
<value>Policy group: </value>
|
||||||
|
</data>
|
||||||
|
<data name="NodeTagNotExist" xml:space="preserve">
|
||||||
|
<value>Node alias '{0}' does not exist.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupEmpty" xml:space="preserve">
|
||||||
|
<value>Group '{0}' is empty. Please add at least one node.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidProperty" xml:space="preserve">
|
||||||
|
<value>The {0} property is invalid, please check.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupSelfReference" xml:space="preserve">
|
||||||
|
<value>{0} Group cannot reference itself or have a circular reference</value>
|
||||||
|
</data>
|
||||||
|
<data name="NotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Not support protocol '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
||||||
|
<value>If the system does not have a tray function, please do not enable it</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1560,4 +1560,40 @@
|
||||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||||
<value>Multi-Configuration Fallback by Xray</value>
|
<value>Multi-Configuration Fallback by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CoreNotSupportNetwork" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support network type '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}' when using transport '{2}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProxyChainedPrefix" xml:space="preserve">
|
||||||
|
<value>Proxy chained: </value>
|
||||||
|
</data>
|
||||||
|
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
||||||
|
<value>Routing rule outbound: </value>
|
||||||
|
</data>
|
||||||
|
<data name="PolicyGroupPrefix" xml:space="preserve">
|
||||||
|
<value>Policy group: </value>
|
||||||
|
</data>
|
||||||
|
<data name="NodeTagNotExist" xml:space="preserve">
|
||||||
|
<value>Node alias '{0}' does not exist.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupEmpty" xml:space="preserve">
|
||||||
|
<value>Group '{0}' is empty. Please add at least one node.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidProperty" xml:space="preserve">
|
||||||
|
<value>The {0} property is invalid, please check.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupSelfReference" xml:space="preserve">
|
||||||
|
<value>{0} Group cannot reference itself or have a circular reference</value>
|
||||||
|
</data>
|
||||||
|
<data name="NotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Not support protocol '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
||||||
|
<value>If the system does not have a tray function, please do not enable it</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1560,4 +1560,40 @@
|
||||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||||
<value>Multi-Configuration Fallback by Xray</value>
|
<value>Multi-Configuration Fallback by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CoreNotSupportNetwork" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support network type '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}' when using transport '{2}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProxyChainedPrefix" xml:space="preserve">
|
||||||
|
<value>Proxy chained: </value>
|
||||||
|
</data>
|
||||||
|
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
||||||
|
<value>Routing rule outbound: </value>
|
||||||
|
</data>
|
||||||
|
<data name="PolicyGroupPrefix" xml:space="preserve">
|
||||||
|
<value>Policy group: </value>
|
||||||
|
</data>
|
||||||
|
<data name="NodeTagNotExist" xml:space="preserve">
|
||||||
|
<value>Node alias '{0}' does not exist.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupEmpty" xml:space="preserve">
|
||||||
|
<value>Group '{0}' is empty. Please add at least one node.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidProperty" xml:space="preserve">
|
||||||
|
<value>The {0} property is invalid, please check.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupSelfReference" xml:space="preserve">
|
||||||
|
<value>{0} Group cannot reference itself or have a circular reference</value>
|
||||||
|
</data>
|
||||||
|
<data name="NotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Not support protocol '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
||||||
|
<value>If the system does not have a tray function, please do not enable it</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1560,4 +1560,40 @@
|
||||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||||
<value>Multi-Configuration Fallback by Xray</value>
|
<value>Multi-Configuration Fallback by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CoreNotSupportNetwork" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support network type '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}' when using transport '{2}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProxyChainedPrefix" xml:space="preserve">
|
||||||
|
<value>Proxy chained: </value>
|
||||||
|
</data>
|
||||||
|
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
||||||
|
<value>Routing rule outbound: </value>
|
||||||
|
</data>
|
||||||
|
<data name="PolicyGroupPrefix" xml:space="preserve">
|
||||||
|
<value>Policy group: </value>
|
||||||
|
</data>
|
||||||
|
<data name="NodeTagNotExist" xml:space="preserve">
|
||||||
|
<value>Node alias '{0}' does not exist.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupEmpty" xml:space="preserve">
|
||||||
|
<value>Group '{0}' is empty. Please add at least one node.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidProperty" xml:space="preserve">
|
||||||
|
<value>The {0} property is invalid, please check.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupSelfReference" xml:space="preserve">
|
||||||
|
<value>{0} Group cannot reference itself or have a circular reference</value>
|
||||||
|
</data>
|
||||||
|
<data name="NotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Not support protocol '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
||||||
|
<value>If the system does not have a tray function, please do not enable it</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1557,4 +1557,40 @@
|
||||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||||
<value>多配置文件故障转移 Xray</value>
|
<value>多配置文件故障转移 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CoreNotSupportNetwork" xml:space="preserve">
|
||||||
|
<value>核心 '{0}' 不支持网络类型 '{1}'。</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
||||||
|
<value>核心 '{0}' 在使用传输方式 '{2}' 时不支持协议 '{1}'。</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>核心 '{0}' 不支持协议 '{1}'。</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProxyChainedPrefix" xml:space="preserve">
|
||||||
|
<value>代理链: </value>
|
||||||
|
</data>
|
||||||
|
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
||||||
|
<value>路由规则出站: </value>
|
||||||
|
</data>
|
||||||
|
<data name="PolicyGroupPrefix" xml:space="preserve">
|
||||||
|
<value>策略组: </value>
|
||||||
|
</data>
|
||||||
|
<data name="NodeTagNotExist" xml:space="preserve">
|
||||||
|
<value>节点别名 '{0}' 不存在。</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupEmpty" xml:space="preserve">
|
||||||
|
<value>组“{0}”为空。请至少添加一个节点。</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidProperty" xml:space="preserve">
|
||||||
|
<value>{0}属性无效,请检查</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupSelfReference" xml:space="preserve">
|
||||||
|
<value>{0} 分组不能引用自身或循环引用</value>
|
||||||
|
</data>
|
||||||
|
<data name="NotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>不支持协议 '{0}'。</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
||||||
|
<value>如果系统没有托盘功能,请不要开启</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1557,4 +1557,40 @@
|
||||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||||
<value>Multi-Configuration Fallback by Xray</value>
|
<value>Multi-Configuration Fallback by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CoreNotSupportNetwork" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support network type '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocolTransport" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}' when using transport '{2}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CoreNotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Core '{0}' does not support protocol '{1}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProxyChainedPrefix" xml:space="preserve">
|
||||||
|
<value>Proxy chained: </value>
|
||||||
|
</data>
|
||||||
|
<data name="RoutingRuleOutboundPrefix" xml:space="preserve">
|
||||||
|
<value>Routing rule outbound: </value>
|
||||||
|
</data>
|
||||||
|
<data name="PolicyGroupPrefix" xml:space="preserve">
|
||||||
|
<value>Policy group: </value>
|
||||||
|
</data>
|
||||||
|
<data name="NodeTagNotExist" xml:space="preserve">
|
||||||
|
<value>Node alias '{0}' does not exist.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupEmpty" xml:space="preserve">
|
||||||
|
<value>Group '{0}' is empty. Please add at least one node.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidProperty" xml:space="preserve">
|
||||||
|
<value>The {0} property is invalid, please check.</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupSelfReference" xml:space="preserve">
|
||||||
|
<value>{0} 分組不能引用自身或循環引用</value>
|
||||||
|
</data>
|
||||||
|
<data name="NotSupportProtocol" xml:space="preserve">
|
||||||
|
<value>Not support protocol '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
|
||||||
|
<value>如果系統沒有托盤功能,請不要開啟</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -26,6 +26,7 @@ public class AddGroupServerViewModel : MyReactiveObject
|
||||||
|
|
||||||
//public ReactiveCommand<Unit, Unit> AddCmd { get; }
|
//public ReactiveCommand<Unit, Unit> AddCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> RemoveCmd { get; }
|
public ReactiveCommand<Unit, Unit> RemoveCmd { get; }
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
|
public ReactiveCommand<Unit, Unit> MoveUpCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
|
public ReactiveCommand<Unit, Unit> MoveDownCmd { get; }
|
||||||
|
@ -143,6 +144,7 @@ public class AddGroupServerViewModel : MyReactiveObject
|
||||||
ChildItemsObs.RemoveAt(index);
|
ChildItemsObs.RemoveAt(index);
|
||||||
ChildItemsObs.Insert(0, selectedChild);
|
ChildItemsObs.Insert(0, selectedChild);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EMove.Up:
|
case EMove.Up:
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
|
@ -151,6 +153,7 @@ public class AddGroupServerViewModel : MyReactiveObject
|
||||||
ChildItemsObs.RemoveAt(index);
|
ChildItemsObs.RemoveAt(index);
|
||||||
ChildItemsObs.Insert(index - 1, selectedChild);
|
ChildItemsObs.Insert(index - 1, selectedChild);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EMove.Down:
|
case EMove.Down:
|
||||||
if (index == ChildItemsObs.Count - 1)
|
if (index == ChildItemsObs.Count - 1)
|
||||||
{
|
{
|
||||||
|
@ -159,6 +162,7 @@ public class AddGroupServerViewModel : MyReactiveObject
|
||||||
ChildItemsObs.RemoveAt(index);
|
ChildItemsObs.RemoveAt(index);
|
||||||
ChildItemsObs.Insert(index + 1, selectedChild);
|
ChildItemsObs.Insert(index + 1, selectedChild);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EMove.Bottom:
|
case EMove.Bottom:
|
||||||
if (index == ChildItemsObs.Count - 1)
|
if (index == ChildItemsObs.Count - 1)
|
||||||
{
|
{
|
||||||
|
@ -167,6 +171,7 @@ public class AddGroupServerViewModel : MyReactiveObject
|
||||||
ChildItemsObs.RemoveAt(index);
|
ChildItemsObs.RemoveAt(index);
|
||||||
ChildItemsObs.Add(selectedChild);
|
ChildItemsObs.Add(selectedChild);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -212,6 +217,14 @@ public class AddGroupServerViewModel : MyReactiveObject
|
||||||
var s when s == ResUI.TbLeastLoad => EMultipleLoad.LeastLoad,
|
var s when s == ResUI.TbLeastLoad => EMultipleLoad.LeastLoad,
|
||||||
_ => EMultipleLoad.LeastPing,
|
_ => EMultipleLoad.LeastPing,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var hasCycle = ProfileGroupItemManager.HasCycle(profileGroup.IndexId);
|
||||||
|
if (hasCycle)
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(string.Format(ResUI.GroupSelfReference, remarks));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (await ConfigHandler.AddGroupServerCommon(_config, SelectedSource, profileGroup, true) == 0)
|
if (await ConfigHandler.AddGroupServerCommon(_config, SelectedSource, profileGroup, true) == 0)
|
||||||
{
|
{
|
||||||
NoticeManager.Instance.Enqueue(ResUI.OperationSuccess);
|
NoticeManager.Instance.Enqueue(ResUI.OperationSuccess);
|
||||||
|
|
|
@ -274,7 +274,6 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
|
|
||||||
BlReloadEnabled = true;
|
BlReloadEnabled = true;
|
||||||
await Reload();
|
await Reload();
|
||||||
await AutoHideStartup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Init
|
#endregion Init
|
||||||
|
@ -576,15 +575,6 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
await CoreManager.Instance.LoadCore(node);
|
await CoreManager.Instance.LoadCore(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AutoHideStartup()
|
|
||||||
{
|
|
||||||
if (_config.UiItem.AutoHideStartup)
|
|
||||||
{
|
|
||||||
AppEvents.ShowHideWindowRequested.Publish(false);
|
|
||||||
}
|
|
||||||
await Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion core job
|
#endregion core job
|
||||||
|
|
||||||
#region Presets
|
#region Presets
|
||||||
|
|
|
@ -605,6 +605,16 @@ public class ProfilesViewModel : MyReactiveObject
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msgs = await ActionPrecheckManager.Instance.CheckBeforeSetActive(indexId);
|
||||||
|
foreach (var msg in msgs)
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.SendMessage(msg);
|
||||||
|
}
|
||||||
|
if (msgs.Count > 0)
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(msgs.First());
|
||||||
|
}
|
||||||
|
|
||||||
if (await ConfigHandler.SetDefaultServerIndex(_config, indexId) == 0)
|
if (await ConfigHandler.SetDefaultServerIndex(_config, indexId) == 0)
|
||||||
{
|
{
|
||||||
await RefreshServers();
|
await RefreshServers();
|
||||||
|
@ -768,6 +778,16 @@ public class ProfilesViewModel : MyReactiveObject
|
||||||
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer);
|
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msgs = await ActionPrecheckManager.Instance.CheckBeforeGenerateConfig(item);
|
||||||
|
foreach (var msg in msgs)
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.SendMessage(msg);
|
||||||
|
}
|
||||||
|
if (msgs.Count > 0)
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(msgs.First());
|
||||||
|
}
|
||||||
if (blClipboard)
|
if (blClipboard)
|
||||||
{
|
{
|
||||||
var result = await CoreConfigHandler.GenerateClientConfig(item, null);
|
var result = await CoreConfigHandler.GenerateClientConfig(item, null);
|
||||||
|
|
|
@ -31,6 +31,12 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
|
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
|
||||||
|
|
||||||
|
if (_config.UiItem.AutoHideStartup)
|
||||||
|
{
|
||||||
|
this.ShowActivated = false;
|
||||||
|
this.WindowState = WindowState.Minimized;
|
||||||
|
}
|
||||||
|
|
||||||
this.KeyDown += MainWindow_KeyDown;
|
this.KeyDown += MainWindow_KeyDown;
|
||||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||||
menuPromotion.Click += menuPromotion_Click;
|
menuPromotion.Click += menuPromotion_Click;
|
||||||
|
@ -406,7 +412,10 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
|
|
||||||
public void ShowHideWindow(bool? blShow)
|
public void ShowHideWindow(bool? blShow)
|
||||||
{
|
{
|
||||||
var bl = blShow ?? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized));
|
var bl = blShow ??
|
||||||
|
Utils.IsLinux()
|
||||||
|
? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized))
|
||||||
|
: !_config.UiItem.ShowInTaskbar;
|
||||||
if (bl)
|
if (bl)
|
||||||
{
|
{
|
||||||
this.Show();
|
this.Show();
|
||||||
|
@ -438,6 +447,10 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnLoaded(sender, e);
|
base.OnLoaded(sender, e);
|
||||||
|
if (_config.UiItem.AutoHideStartup)
|
||||||
|
{
|
||||||
|
ShowHideWindow(false);
|
||||||
|
}
|
||||||
RestoreUI();
|
RestoreUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -355,14 +355,15 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
<!--
|
<TextBlock
|
||||||
<TextBlock
|
x:Name="tbAutoRunTip"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}"
|
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}"
|
||||||
TextWrapping="Wrap" />-->
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
|
@ -467,6 +468,13 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="labHide2TrayWhenCloseTip"
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsHide2TrayWhenCloseTip}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="11"
|
Grid.Row="11"
|
||||||
|
|
|
@ -131,19 +131,25 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||||
|
|
||||||
labHide2TrayWhenClose.IsVisible = false;
|
labHide2TrayWhenClose.IsVisible = false;
|
||||||
togHide2TrayWhenClose.IsVisible = false;
|
togHide2TrayWhenClose.IsVisible = false;
|
||||||
|
labHide2TrayWhenCloseTip.IsVisible = false;
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
else if (Utils.IsLinux())
|
||||||
{
|
{
|
||||||
txbSettingsExceptionTip.IsVisible = false;
|
txbSettingsExceptionTip.IsVisible = false;
|
||||||
panSystemProxyAdvanced.IsVisible = false;
|
panSystemProxyAdvanced.IsVisible = false;
|
||||||
|
|
||||||
|
tbAutoRunTip.IsVisible = false;
|
||||||
}
|
}
|
||||||
else if (Utils.IsOSX())
|
else if (Utils.IsOSX())
|
||||||
{
|
{
|
||||||
txbSettingsExceptionTip.IsVisible = false;
|
txbSettingsExceptionTip.IsVisible = false;
|
||||||
panSystemProxyAdvanced.IsVisible = false;
|
panSystemProxyAdvanced.IsVisible = false;
|
||||||
|
|
||||||
|
tbAutoRunTip.IsVisible = false;
|
||||||
|
|
||||||
labHide2TrayWhenClose.IsVisible = false;
|
labHide2TrayWhenClose.IsVisible = false;
|
||||||
togHide2TrayWhenClose.IsVisible = false;
|
togHide2TrayWhenClose.IsVisible = false;
|
||||||
|
labHide2TrayWhenCloseTip.IsVisible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,12 @@ public partial class MainWindow
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
|
ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||||
|
|
||||||
|
if (_config.UiItem.AutoHideStartup)
|
||||||
|
{
|
||||||
|
this.ShowActivated = false;
|
||||||
|
this.WindowState = WindowState.Minimized;
|
||||||
|
}
|
||||||
|
|
||||||
App.Current.SessionEnding += Current_SessionEnding;
|
App.Current.SessionEnding += Current_SessionEnding;
|
||||||
this.Closing += MainWindow_Closing;
|
this.Closing += MainWindow_Closing;
|
||||||
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
|
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
|
||||||
|
@ -390,6 +396,10 @@ public partial class MainWindow
|
||||||
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
protected override void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnLoaded(sender, e);
|
base.OnLoaded(sender, e);
|
||||||
|
if (_config.UiItem.AutoHideStartup)
|
||||||
|
{
|
||||||
|
ShowHideWindow(false);
|
||||||
|
}
|
||||||
RestoreUI();
|
RestoreUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue