From cb001afb0285bcdabc713c3ef55a4d3e708ea483 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sat, 28 Feb 2026 16:26:39 +0800 Subject: [PATCH 1/2] Relax group type restrictions --- .../v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs | 9 +-------- v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs | 4 ++-- v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs | 9 +-------- v2rayN/v2rayN/Views/SubEditWindow.xaml.cs | 4 ++-- 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs index 142f9d6b..2f24b197 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs @@ -147,14 +147,7 @@ public partial class AddGroupServerWindow : WindowBase private async void MenuAddChild_Click(object? sender, RoutedEventArgs e) { var selectWindow = new ProfilesSelectWindow(); - if (ViewModel?.SelectedSource?.ConfigType == EConfigType.PolicyGroup) - { - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom }, exclude: true); - } - else - { - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true); - } + selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true); selectWindow.AllowMultiSelect(true); var result = await selectWindow.ShowDialog(this); if (result == true) diff --git a/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs index 9d749ba8..2d7358d0 100644 --- a/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs @@ -59,7 +59,7 @@ public partial class SubEditWindow : WindowBase private async void BtnSelectPrevProfile_Click(object? sender, RoutedEventArgs e) { var selectWindow = new ProfilesSelectWindow(); - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true); + selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true); var result = await selectWindow.ShowDialog(this); if (result == true) { @@ -74,7 +74,7 @@ public partial class SubEditWindow : WindowBase private async void BtnSelectNextProfile_Click(object? sender, RoutedEventArgs e) { var selectWindow = new ProfilesSelectWindow(); - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true); + selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true); var result = await selectWindow.ShowDialog(this); if (result == true) { diff --git a/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs b/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs index 4b1642d2..9c98fb06 100644 --- a/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs @@ -127,14 +127,7 @@ public partial class AddGroupServerWindow private async void MenuAddChild_Click(object sender, RoutedEventArgs e) { var selectWindow = new ProfilesSelectWindow(); - if (ViewModel?.SelectedSource?.ConfigType == EConfigType.PolicyGroup) - { - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom }, exclude: true); - } - else - { - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true); - } + selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true); selectWindow.AllowMultiSelect(true); if (selectWindow.ShowDialog() == true) { diff --git a/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs b/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs index d1451a9c..6323034a 100644 --- a/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs @@ -53,7 +53,7 @@ public partial class SubEditWindow private async void BtnSelectPrevProfile_Click(object sender, RoutedEventArgs e) { var selectWindow = new ProfilesSelectWindow(); - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true); + selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true); if (selectWindow.ShowDialog() == true) { var profile = await selectWindow.ProfileItem; @@ -67,7 +67,7 @@ public partial class SubEditWindow private async void BtnSelectNextProfile_Click(object sender, RoutedEventArgs e) { var selectWindow = new ProfilesSelectWindow(); - selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true); + selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true); if (selectWindow.ShowDialog() == true) { var profile = await selectWindow.ProfileItem; From 6852cd287b93aaa0104d39c1a3b357c65ed842c1 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sat, 28 Feb 2026 16:37:12 +0800 Subject: [PATCH 2/2] Optimize db read --- v2rayN/ServiceLib/Manager/AppManager.cs | 24 +++++++++++++++++ .../ServiceLib/Manager/GroupProfileManager.cs | 27 +++---------------- .../ViewModels/AddGroupServerViewModel.cs | 11 ++------ .../ViewModels/ProfilesSelectViewModel.cs | 14 +--------- .../ViewModels/ProfilesViewModel.cs | 9 +------ 5 files changed, 32 insertions(+), 53 deletions(-) diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index e773c2ef..43c5611d 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -242,6 +242,30 @@ public sealed class AppManager .ToListAsync(); } + public async Task> GetProfileItemsByIndexIdsAsMap(IEnumerable indexIds) + { + var items = await GetProfileItemsByIndexIds(indexIds); + return items.ToDictionary(it => it.IndexId); + } + + public async Task> GetProfileItemsOrderedByIndexIds(IEnumerable indexIds) + { + var idList = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); + if (idList.Count == 0) + { + return []; + } + + var items = await SQLiteHelper.Instance.TableAsync() + .Where(it => idList.Contains(it.IndexId)) + .ToListAsync(); + var itemMap = items.ToDictionary(it => it.IndexId); + + return idList.Select(id => itemMap.GetValueOrDefault(id)) + .Where(item => item != null) + .ToList(); + } + public async Task GetProfileItemViaRemarks(string? remarks) { if (remarks.IsNullOrEmpty()) diff --git a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs index 510667dd..8a7389a0 100644 --- a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs +++ b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs @@ -52,10 +52,10 @@ public class GroupProfileManager return false; } - foreach (var child in childIds) + var childItems = await AppManager.Instance.GetProfileItemsByIndexIds(childIds); + foreach (var childItem in childItems) { - var childItem = await AppManager.Instance.GetProfileItem(child); - if (await HasCycle(child, childItem?.GetProtocolExtra(), visited, stack)) + if (await HasCycle(childItem.IndexId, childItem?.GetProtocolExtra(), visited, stack)) { return true; } @@ -103,26 +103,7 @@ public class GroupProfileManager return []; } - var childProfiles = await AppManager.Instance.GetProfileItemsByIndexIds(childProfileIds); - if (childProfiles == null || childProfiles.Count == 0) - { - return []; - } - - var profileMap = childProfiles - .Where(p => p != null && !p.IndexId.IsNullOrEmpty()) - .GroupBy(p => p!.IndexId!) - .ToDictionary(g => g.Key, g => g.First()); - - var ordered = new List(childProfileIds.Count); - foreach (var id in childProfileIds) - { - if (id != null && profileMap.TryGetValue(id, out var item) && item != null) - { - ordered.Add(item); - } - } - + var ordered = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(childProfileIds); return ordered; } diff --git a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs index d30917ec..7d4d0948 100644 --- a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs @@ -99,15 +99,8 @@ public class AddGroupServerViewModel : MyReactiveObject Filter = protocolExtra?.Filter; var childIndexIds = Utils.String2List(protocolExtra?.ChildItems) ?? []; - foreach (var item in childIndexIds) - { - var child = await AppManager.Instance.GetProfileItem(item); - if (child == null) - { - continue; - } - ChildItemsObs.Add(child); - } + var childItemList = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(childIndexIds); + ChildItemsObs.AddRange(childItemList); } public async Task ChildRemoveAsync() diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs index ce349cb4..eb010c58 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs @@ -255,19 +255,7 @@ public class ProfilesSelectViewModel : MyReactiveObject { return null; } - var lst = new List(); - foreach (var sp in SelectedProfiles) - { - if (string.IsNullOrEmpty(sp?.IndexId)) - { - continue; - } - var item = await AppManager.Instance.GetProfileItem(sp.IndexId); - if (item != null) - { - lst.Add(item); - } - } + var lst = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(SelectedProfiles.Select(sp => sp?.IndexId)); if (lst.Count == 0) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index 1cc6f46e..dbcf457c 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -481,14 +481,7 @@ public class ProfilesViewModel : MyReactiveObject var orderProfiles = SelectedProfiles?.OrderBy(t => t.Sort); if (latest) { - foreach (var profile in orderProfiles) - { - var item = await AppManager.Instance.GetProfileItem(profile.IndexId); - if (item is not null) - { - lstSelected.Add(item); - } - } + lstSelected.AddRange(await AppManager.Instance.GetProfileItemsOrderedByIndexIds(orderProfiles.Select(sp => sp?.IndexId))); } else {