diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index 90721217..685b74c7 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -90,6 +90,22 @@ public class Global public const int Hysteria2DefaultHopInt = 10; + public const string PolicyGroupExcludeKeywords = @"剩余|过期|到期|重置|[Rr]emaining|[Ee]xpir|[Rr]eset"; + + public const string PolicyGroupDefaultAllFilter = $"^(?!.*(?:{PolicyGroupExcludeKeywords})).*$"; + + public static readonly List PolicyGroupDefaultFilterList = + [ + // All nodes (exclude traffic/expiry info) + PolicyGroupDefaultAllFilter, + // Low multiplier nodes, e.g. ×0.1, 0.5x, 0.1倍 + @"^.*(?:[×xX✕*]\s*0\.[0-9]+|0\.[0-9]+\s*[×xX✕*倍]).*$", + // Dedicated line nodes, e.g. IPLC, IEPL + $@"^(?!.*(?:{PolicyGroupExcludeKeywords})).*(?:专线|IPLC|IEPL|中转).*$", + // Japan nodes + $@"^(?!.*(?:{PolicyGroupExcludeKeywords})).*(?:日本|\\b[Jj][Pp]\\b|🇯🇵|[Jj]apan).*$", + ]; + public static readonly List IEProxyProtocols = [ "{ip}:{http_port}", diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index b0bde1df..e5b6fec3 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1165,46 +1165,28 @@ public static class ConfigHandler /// /// Create a group server that combines multiple servers for load balancing - /// Generates a configuration file that references multiple servers + /// Generates a PolicyGroup profile with references to the sub-items /// /// Current configuration - /// Selected servers to combine - /// Core type to use (Xray or sing_box) - /// Load balancing algorithm + /// Sub-item for grouping /// Result object with success state and data - public static async Task AddGroupServer4Multiple(Config config, List selecteds, ECoreType coreType, EMultipleLoad multipleLoad, string? subId) + public static async Task AddGroupAllServer(Config config, SubItem? subItem) { var result = new RetResult(); - var indexId = Utils.GetGuid(false); - var childProfileIndexId = Utils.List2String(selecteds.Select(p => p.IndexId).ToList()); + var subId = subItem?.Id; + if (subId.IsNullOrEmpty()) + { + result.Success = false; + return result; + } - var remark = subId.IsNullOrEmpty() ? string.Empty : $"{(await AppManager.Instance.GetSubItem(subId))?.Remarks} "; - if (coreType == ECoreType.Xray) - { - remark += multipleLoad switch - { - EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerXrayLeastPing, - EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerXrayFallback, - EMultipleLoad.Random => ResUI.menuGenGroupMultipleServerXrayRandom, - EMultipleLoad.RoundRobin => ResUI.menuGenGroupMultipleServerXrayRoundRobin, - EMultipleLoad.LeastLoad => ResUI.menuGenGroupMultipleServerXrayLeastLoad, - _ => ResUI.menuGenGroupMultipleServerXrayRoundRobin, - }; - } - else if (coreType == ECoreType.sing_box) - { - remark += multipleLoad switch - { - EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerSingBoxLeastPing, - EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerSingBoxFallback, - _ => ResUI.menuGenGroupMultipleServerSingBoxLeastPing, - }; - } + var indexId = Utils.GetGuid(false); + var remark = $"{subItem.Remarks} - {ResUI.TbConfigTypePolicyGroup}"; var profile = new ProfileItem { IndexId = indexId, - CoreType = coreType, + CoreType = ECoreType.Xray, ConfigType = EConfigType.PolicyGroup, Remarks = remark, IsSub = false @@ -1215,8 +1197,10 @@ public static class ConfigHandler } var extraItem = new ProtocolExtraItem { - ChildItems = childProfileIndexId, - MultipleLoad = multipleLoad, + MultipleLoad = EMultipleLoad.LeastPing, + GroupType = profile.ConfigType.ToString(), + SubChildItems = subId, + Filter = Global.PolicyGroupDefaultAllFilter, }; profile.SetProtocolExtra(extraItem); var ret = await AddServerCommon(config, profile, true); @@ -1225,6 +1209,92 @@ public static class ConfigHandler return result; } + private static string CombineWithDefaultAllFilter(string regionPattern) + { + return $"^(?!.*(?:{Global.PolicyGroupExcludeKeywords})).*(?:{regionPattern}).*$"; + } + + private static readonly Dictionary PolicyGroupRegionFilters = new() + { + { "JP", "日本|\\b[Jj][Pp]\\b|🇯🇵|[Jj]apan" }, + { "US", "美国|\\b[Uu][Ss]\\b|🇺🇸|[Uu]nited [Ss]tates|\\b[Uu][Ss][Aa]\\b" }, + { "HK", "香港|\\b[Hh][Kk]\\b|🇭🇰|[Hh]ong ?[Kk]ong" }, + { "TW", "台湾|台灣|\\b[Tt][Ww]\\b|🇹🇼|[Tt]aiwan" }, + { "KR", "韩国|\\b[Kk][Rr]\\b|🇰🇷|[Kk]orea" }, + { "SG", "新加坡|\\b[Ss][Gg]\\b|🇸🇬|[Ss]ingapore" }, + { "DE", "德国|\\b[Dd][Ee]\\b|🇩🇪|[Gg]ermany" }, + { "FR", "法国|\\b[Ff][Rr]\\b|🇫🇷|[Ff]rance" }, + { "GB", "英国|\\b[Gg][Bb]\\b|🇬🇧|[Uu]nited [Kk]ingdom|[Bb]ritain" }, + { "CA", "加拿大|🇨🇦|[Cc]anada" }, + { "AU", "澳大利亚|\\b[Aa][Uu]\\b|🇦🇺|[Aa]ustralia" }, + { "RU", "俄罗斯|\\b[Rr][Uu]\\b|🇷🇺|[Rr]ussia" }, + { "BR", "巴西|\\b[Bb][Rr]\\b|🇧🇷|[Bb]razil" }, + { "IN", "印度|🇮🇳|[Ii]ndia" }, + { "VN", "越南|\\b[Vv][Nn]\\b|🇻🇳|[Vv]ietnam" }, + { "ID", "印度尼西亚|\\b[Ii][Dd]\\b|🇮🇩|[Ii]ndonesia" }, + { "MX", "墨西哥|\\b[Mm][Xx]\\b|🇲🇽|[Mm]exico" } + }; + + public static async Task AddGroupRegionServer(Config config, SubItem? subItem) + { + var result = new RetResult(); + var subId = subItem?.Id; + if (subId.IsNullOrEmpty()) + { + result.Success = false; + return result; + } + var childProfiles = await AppManager.Instance.ProfileItems(subId); + List indexIdList = []; + + foreach (var regionFilter in PolicyGroupRegionFilters) + { + var indexId = Utils.GetGuid(false); + var remark = $"{subItem.Remarks} - {ResUI.TbConfigTypePolicyGroup} - {regionFilter.Key}"; + var profile = new ProfileItem + { + IndexId = indexId, + CoreType = ECoreType.Xray, + ConfigType = EConfigType.PolicyGroup, + Remarks = remark, + IsSub = false + }; + if (!subId.IsNullOrEmpty()) + { + profile.Subid = subId; + } + var extraItem = new ProtocolExtraItem + { + MultipleLoad = EMultipleLoad.LeastPing, + GroupType = profile.ConfigType.ToString(), + SubChildItems = subId, + Filter = CombineWithDefaultAllFilter(regionFilter.Value), + }; + profile.SetProtocolExtra(extraItem); + + var matchedChildProfiles = childProfiles?.Where(p => + p != null && + p.IsValid() && + !p.ConfigType.IsComplexType() && + (extraItem.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, extraItem.Filter)) + ) + .ToList() ?? []; + if (matchedChildProfiles.Count == 0) + { + continue; + } + + var ret = await AddServerCommon(config, profile, true); + if (ret == 0) + { + indexIdList.Add(indexId); + } + } + result.Success = indexIdList.Count > 0; + result.Data = indexIdList; + return result; + } + /// /// Get a SOCKS server profile for pre-SOCKS functionality /// Used when TUN mode is enabled or when a custom config has a pre-SOCKS port diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 5e35d3bb..b00bec2d 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -834,6 +834,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 All configurations 的本地化字符串。 + /// + public static string menuAllServers { + get { + return ResourceManager.GetString("menuAllServers", resourceCulture); + } + } + /// /// 查找类似 Backup and Restore 的本地化字符串。 /// @@ -1006,74 +1015,20 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Generate Policy Group from Multiple Profiles 的本地化字符串。 + /// 查找类似 Generate Policy Group 的本地化字符串。 /// - public static string menuGenGroupMultipleServer { + public static string menuGenGroupServer { get { - return ResourceManager.GetString("menuGenGroupMultipleServer", resourceCulture); + return ResourceManager.GetString("menuGenGroupServer", resourceCulture); } } /// - /// 查找类似 Fallback by sing-box 的本地化字符串。 + /// 查找类似 Group by Region 的本地化字符串。 /// - public static string menuGenGroupMultipleServerSingBoxFallback { + public static string menuGenRegionGroup { get { - return ResourceManager.GetString("menuGenGroupMultipleServerSingBoxFallback", resourceCulture); - } - } - - /// - /// 查找类似 LeastPing by sing-box 的本地化字符串。 - /// - public static string menuGenGroupMultipleServerSingBoxLeastPing { - get { - return ResourceManager.GetString("menuGenGroupMultipleServerSingBoxLeastPing", resourceCulture); - } - } - - /// - /// 查找类似 Fallback by Xray 的本地化字符串。 - /// - public static string menuGenGroupMultipleServerXrayFallback { - get { - return ResourceManager.GetString("menuGenGroupMultipleServerXrayFallback", resourceCulture); - } - } - - /// - /// 查找类似 LeastLoad by Xray 的本地化字符串。 - /// - public static string menuGenGroupMultipleServerXrayLeastLoad { - get { - return ResourceManager.GetString("menuGenGroupMultipleServerXrayLeastLoad", resourceCulture); - } - } - - /// - /// 查找类似 LeastPing by Xray 的本地化字符串。 - /// - public static string menuGenGroupMultipleServerXrayLeastPing { - get { - return ResourceManager.GetString("menuGenGroupMultipleServerXrayLeastPing", resourceCulture); - } - } - - /// - /// 查找类似 Random by Xray 的本地化字符串。 - /// - public static string menuGenGroupMultipleServerXrayRandom { - get { - return ResourceManager.GetString("menuGenGroupMultipleServerXrayRandom", resourceCulture); - } - } - - /// - /// 查找类似 RoundRobin by Xray 的本地化字符串。 - /// - public static string menuGenGroupMultipleServerXrayRoundRobin { - get { - return ResourceManager.GetString("menuGenGroupMultipleServerXrayRoundRobin", resourceCulture); + return ResourceManager.GetString("menuGenRegionGroup", resourceCulture); } } diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index 0df75d77..16836861 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1371,24 +1371,6 @@ مخفی و پورت می شود، با کاما (،) جدا می شود - - Generate Policy Group from Multiple Profiles - - - چند سرور تصادفی توسط Xray - - - چند سرور RoundRobin توسط Xray - - - چند سرور LeastPing توسط Xray - - - چند سرور LeastLoad توسط Xray - - - LeastPing چند سرور توسط sing-box - صادر کردن سرور @@ -1533,12 +1515,6 @@ Fallback - - Multi-Configuration Fallback by sing-box - - - Multi-Configuration Fallback by Xray - Core '{0}' does not support network type '{1}' @@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Subscription next proxy {0} not found. Skipping. + + Generate Policy Group + + + All configurations + + + Group by Region + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx index 6c882112..253831ef 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx @@ -1368,24 +1368,6 @@ Écrase le port ; pour plusieurs groupes, séparer par virgules (,) - - Générer un groupe de stratégie depuis plusieurs profils - - - Xray aléatoire (multi-sélection) - - - Xray équilibrage (tourniquet) multi-sélection - - - Xray latence minimale (multi-sélection) - - - Xray le plus stable (multi-sélection) - - - sing-box latence minimale (multi-sélection) - Exporter @@ -1530,12 +1512,6 @@ Basculement (failover) - - sing-box basculement (multi-sélection) - - - Xray basculement (multi-sélection) - Le cœur « {0} » ne prend pas en charge le type de réseau « {1} » @@ -1683,4 +1659,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Subscription next proxy {0} not found. Skipping. + + Generate Policy Group + + + All configurations + + + Group by Region + diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index dd7d22f4..a29d8987 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1371,24 +1371,6 @@ A portot lefedi, vesszővel (,) elválasztva - - Generate Policy Group from Multiple Profiles - - - Több konfiguráció véletlenszerűen Xray szerint - - - Több konfiguráció RoundRobin Xray szerint - - - Több konfiguráció legkisebb pinggel Xray szerint - - - Több konfiguráció legkisebb terheléssel Xray szerint - - - Több konfiguráció legkisebb pinggel sing-box szerint - Konfiguráció exportálása @@ -1533,12 +1515,6 @@ Fallback - - Multi-Configuration Fallback by sing-box - - - Multi-Configuration Fallback by Xray - Core '{0}' does not support network type '{1}' @@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Subscription next proxy {0} not found. Skipping. + + Generate Policy Group + + + All configurations + + + Group by Region + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index fa53ccc8..17416125 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1371,24 +1371,6 @@ Will cover the port, separate with commas (,) - - Generate Policy Group from Multiple Profiles - - - Random by Xray - - - RoundRobin by Xray - - - LeastPing by Xray - - - LeastLoad by Xray - - - LeastPing by sing-box - Export @@ -1533,12 +1515,6 @@ Fallback - - Fallback by sing-box - - - Fallback by Xray - Core '{0}' does not support network type '{1}' @@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Subscription next proxy {0} not found. Skipping. + + Generate Policy Group + + + All configurations + + + Group by Region + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index b33a10e3..d8a174d5 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1371,24 +1371,6 @@ Заменит указанный порт, перечисляйте через запятую (,) - - Generate Policy Group from Multiple Profiles - - - Случайный (Xray) - - - Круговой (Xray) - - - Минимальное RTT (минимальное время туда-обратно) (Xray) - - - Минимальная нагрузка (Xray) - - - Минимальное RTT (минимальное время туда-обратно) (sing-box) - Экспортировать конфигурацию @@ -1533,12 +1515,6 @@ Fallback - - Multi-Configuration Fallback by sing-box - - - Multi-Configuration Fallback by Xray - Core '{0}' does not support network type '{1}' @@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Subscription next proxy {0} not found. Skipping. + + Generate Policy Group + + + All configurations + + + Group by Region + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index be76525e..3a4e4924 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1368,24 +1368,6 @@ 会覆盖端口,多组时用逗号 (,) 隔开 - - 多选生成策略组 - - - 多选随机 Xray - - - 多选负载均衡 Xray - - - 多选最低延迟 Xray - - - 多选最稳定 Xray - - - 多选最低延迟 sing-box - 导出 @@ -1530,12 +1512,6 @@ 故障转移 - - 多选故障转移 sing-box - - - 多选故障转移 Xray - 核心 '{0}' 不支持网络类型 '{1}' @@ -1683,4 +1659,13 @@ 订阅后置节点 {0} 未找到,已跳过。 + + 一键生成策略组 + + + 全部配置项 + + + 按地区分组 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx index 4132a27b..330a36e2 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1368,24 +1368,6 @@ 會覆蓋埠,多組時用逗號 (,) 隔開 - - 多選生成策略組 - - - 多選隨機 Xray - - - 多選負載平衡 Xray - - - 多選最低延遲 Xray - - - 多選最穩定 Xray - - - 多選最低延遲 sing-box - 匯出 @@ -1530,12 +1512,6 @@ 容錯移轉 - - 多選容錯移轉 sing-box - - - 多選容錯移轉 Xray - 核心 '{0}' 不支援網路類型 '{1}' @@ -1683,4 +1659,13 @@ Subscription next proxy {0} not found. Skipping. + + Generate Policy Group + + + All configurations + + + Group by Region + \ No newline at end of file diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index 1cc6f46e..91c745d6 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -8,6 +8,7 @@ public class ProfilesViewModel : MyReactiveObject private string _serverFilter = string.Empty; private Dictionary _dicHeaderSort = new(); private SpeedtestService? _speedtestService; + private string? _pendingSelectIndexId; #endregion private prop @@ -43,13 +44,8 @@ public class ProfilesViewModel : MyReactiveObject public ReactiveCommand CopyServerCmd { get; } public ReactiveCommand SetDefaultServerCmd { get; } public ReactiveCommand ShareServerCmd { get; } - public ReactiveCommand GenGroupMultipleServerXrayRandomCmd { get; } - public ReactiveCommand GenGroupMultipleServerXrayRoundRobinCmd { get; } - public ReactiveCommand GenGroupMultipleServerXrayLeastPingCmd { get; } - public ReactiveCommand GenGroupMultipleServerXrayLeastLoadCmd { get; } - public ReactiveCommand GenGroupMultipleServerXrayFallbackCmd { get; } - public ReactiveCommand GenGroupMultipleServerSingBoxLeastPingCmd { get; } - public ReactiveCommand GenGroupMultipleServerSingBoxFallbackCmd { get; } + public ReactiveCommand GenGroupAllServerCmd { get; } + public ReactiveCommand GenGroupRegionServerCmd { get; } //servers move public ReactiveCommand MoveTopCmd { get; } @@ -134,33 +130,13 @@ public class ProfilesViewModel : MyReactiveObject { await ShareServerAsync(); }, canEditRemove); - GenGroupMultipleServerXrayRandomCmd = ReactiveCommand.CreateFromTask(async () => + GenGroupAllServerCmd = ReactiveCommand.CreateFromTask(async () => { - await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.Random); + await GenGroupAllServer(); }, canEditRemove); - GenGroupMultipleServerXrayRoundRobinCmd = ReactiveCommand.CreateFromTask(async () => + GenGroupRegionServerCmd = ReactiveCommand.CreateFromTask(async () => { - await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.RoundRobin); - }, canEditRemove); - GenGroupMultipleServerXrayLeastPingCmd = ReactiveCommand.CreateFromTask(async () => - { - await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.LeastPing); - }, canEditRemove); - GenGroupMultipleServerXrayLeastLoadCmd = ReactiveCommand.CreateFromTask(async () => - { - await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.LeastLoad); - }, canEditRemove); - GenGroupMultipleServerXrayFallbackCmd = ReactiveCommand.CreateFromTask(async () => - { - await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.Fallback); - }, canEditRemove); - GenGroupMultipleServerSingBoxLeastPingCmd = ReactiveCommand.CreateFromTask(async () => - { - await GenGroupMultipleServer(ECoreType.sing_box, EMultipleLoad.LeastPing); - }, canEditRemove); - GenGroupMultipleServerSingBoxFallbackCmd = ReactiveCommand.CreateFromTask(async () => - { - await GenGroupMultipleServer(ECoreType.sing_box, EMultipleLoad.Fallback); + await GenGroupRegionServer(); }, canEditRemove); //servers move @@ -392,15 +368,14 @@ public class ProfilesViewModel : MyReactiveObject ProfileItems.AddRange(lstModel); if (lstModel.Count > 0) { - var selected = lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId); - if (selected != null) + ProfileItemModel? selected = null; + if (!_pendingSelectIndexId.IsNullOrEmpty()) { - SelectedProfile = selected; - } - else - { - SelectedProfile = lstModel.First(); + selected = lstModel.FirstOrDefault(t => t.IndexId == _pendingSelectIndexId); + _pendingSelectIndexId = null; } + selected ??= lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId); + SelectedProfile = selected ?? lstModel.First(); } await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null); @@ -641,29 +616,29 @@ public class ProfilesViewModel : MyReactiveObject await _updateView?.Invoke(EViewAction.ShareServer, url); } - private async Task GenGroupMultipleServer(ECoreType coreType, EMultipleLoad multipleLoad) + private async Task GenGroupAllServer() { - var lstSelected = await GetProfileItems(true); - if (lstSelected == null) - { - return; - } - - var ret = await ConfigHandler.AddGroupServer4Multiple(_config, lstSelected, coreType, multipleLoad, SelectedSub?.Id); + var ret = await ConfigHandler.AddGroupAllServer(_config, SelectedSub); if (ret.Success != true) { NoticeManager.Instance.Enqueue(ResUI.OperationFailed); return; } - if (ret?.Data?.ToString() == _config.IndexId) + _pendingSelectIndexId = ret.Data?.ToString(); + await RefreshServers(); + } + + private async Task GenGroupRegionServer() + { + var ret = await ConfigHandler.AddGroupRegionServer(_config, SelectedSub); + if (ret.Success != true) { - await RefreshServers(); - Reload(); - } - else - { - await SetDefaultServer(ret?.Data?.ToString()); + NoticeManager.Instance.Enqueue(ResUI.OperationFailed); + return; } + var indexIdList = ret.Data as List; + _pendingSelectIndexId = indexIdList?.FirstOrDefault(); + await RefreshServers(); } public async Task SortServer(string colName) diff --git a/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml index c036bb03..c042868c 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml @@ -117,7 +117,8 @@ Grid.Column="2" Margin="{StaticResource Margin4}" VerticalAlignment="Center" - Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" /> + Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" + TextWrapping="Wrap" /> - + VerticalAlignment="Center" + IsEditable="True" /> diff --git a/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs index 142f9d6b..06784ac0 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs @@ -29,6 +29,7 @@ public partial class AddGroupServerWindow : WindowBase ResUI.TbRoundRobin, ResUI.TbLeastLoad, }; + cmbFilter.ItemsSource = Global.PolicyGroupDefaultFilterList; switch (profileItem.ConfigType) { @@ -53,7 +54,7 @@ public partial class AddGroupServerWindow : WindowBase this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.SelectedValue).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbSubChildItems.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSubItem, v => v.cmbSubChildItems.SelectedItem).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.Filter, v => v.txtFilter.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Filter, v => v.cmbFilter.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedChild, v => v.lstChild.SelectedItem).DisposeWith(disposables); diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml index 116f35fa..e0751ca1 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml @@ -193,14 +193,9 @@ - - - - - - - - + + + diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs index aaebb518..4ca8e793 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs @@ -60,12 +60,8 @@ public partial class ProfilesView : ReactiveUserControl this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRandomCmd, v => v.menuGenGroupMultipleServerXrayRandom).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRoundRobinCmd, v => v.menuGenGroupMultipleServerXrayRoundRobin).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastPingCmd, v => v.menuGenGroupMultipleServerXrayLeastPing).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastLoadCmd, v => v.menuGenGroupMultipleServerXrayLeastLoad).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxLeastPingCmd, v => v.menuGenGroupMultipleServerSingBoxLeastPing).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxFallbackCmd, v => v.menuGenGroupMultipleServerSingBoxFallback).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.GenGroupAllServerCmd, v => v.menuGenGroupAllServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.GenGroupRegionServerCmd, v => v.menuGenGroupRegionServer).DisposeWith(disposables); //servers move //this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml b/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml index baaa0114..bbbf29c6 100644 --- a/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml +++ b/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml @@ -173,7 +173,8 @@ Margin="{StaticResource Margin4}" VerticalAlignment="Center" Style="{StaticResource ToolbarTextBlock}" - Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" /> + Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" + TextWrapping="Wrap" /> - + IsEditable="True" + Style="{StaticResource DefComboBox}" /> diff --git a/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs b/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs index 4b1642d2..965b19d9 100644 --- a/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs @@ -24,6 +24,7 @@ public partial class AddGroupServerWindow ResUI.TbRoundRobin, ResUI.TbLeastLoad, }; + cmbFilter.ItemsSource = Global.PolicyGroupDefaultFilterList; switch (profileItem.ConfigType) { @@ -48,7 +49,7 @@ public partial class AddGroupServerWindow this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbSubChildItems.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSubItem, v => v.cmbSubChildItems.SelectedItem).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.Filter, v => v.txtFilter.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Filter, v => v.cmbFilter.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.ChildItemsObs, v => v.lstChild.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedChild, v => v.lstChild.SelectedItem).DisposeWith(disposables); diff --git a/v2rayN/v2rayN/Views/ProfilesView.xaml b/v2rayN/v2rayN/Views/ProfilesView.xaml index 6cf0d159..fd984306 100644 --- a/v2rayN/v2rayN/Views/ProfilesView.xaml +++ b/v2rayN/v2rayN/Views/ProfilesView.xaml @@ -240,32 +240,15 @@ Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" /> - + + Header="{x:Static resx:ResUI.menuAllServers}" /> - - - - - + Header="{x:Static resx:ResUI.menuGenRegionGroup}" /> diff --git a/v2rayN/v2rayN/Views/ProfilesView.xaml.cs b/v2rayN/v2rayN/Views/ProfilesView.xaml.cs index 58b468a4..46def3e2 100644 --- a/v2rayN/v2rayN/Views/ProfilesView.xaml.cs +++ b/v2rayN/v2rayN/Views/ProfilesView.xaml.cs @@ -54,12 +54,8 @@ public partial class ProfilesView this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRandomCmd, v => v.menuGenGroupMultipleServerXrayRandom).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRoundRobinCmd, v => v.menuGenGroupMultipleServerXrayRoundRobin).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastPingCmd, v => v.menuGenGroupMultipleServerXrayLeastPing).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastLoadCmd, v => v.menuGenGroupMultipleServerXrayLeastLoad).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxLeastPingCmd, v => v.menuGenGroupMultipleServerSingBoxLeastPing).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxFallbackCmd, v => v.menuGenGroupMultipleServerSingBoxFallback).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.GenGroupAllServerCmd, v => v.menuGenGroupAllServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.GenGroupRegionServerCmd, v => v.menuGenGroupRegionServer).DisposeWith(disposables); //servers move this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);