mirror of
https://github.com/2dust/v2rayN.git
synced 2025-11-05 06:52:52 +00:00
In the policy group, automatically add filtered configurations from the subscription group.
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
https://github.com/2dust/v2rayN/issues/8214
This commit is contained in:
parent
d727ff40bb
commit
7b5686cd8f
16 changed files with 184 additions and 16 deletions
|
|
@ -115,7 +115,7 @@ public class ActionPrecheckManager(Config config)
|
|||
if (item.ConfigType.IsGroupType())
|
||||
{
|
||||
ProfileGroupItemManager.Instance.TryGet(item.IndexId, out var group);
|
||||
if (group is null || group.ChildItems.IsNullOrEmpty())
|
||||
if (group is null || group.NotHasChild())
|
||||
{
|
||||
errors.Add(string.Format(ResUI.GroupEmpty, item.Remarks));
|
||||
return errors;
|
||||
|
|
@ -128,7 +128,11 @@ public class ActionPrecheckManager(Config config)
|
|||
return errors;
|
||||
}
|
||||
|
||||
foreach (var child in Utils.String2List(group.ChildItems))
|
||||
var childIds = Utils.String2List(group.ChildItems) ?? [];
|
||||
var subItems = await ProfileGroupItemManager.GetSubChildProfileItems(group);
|
||||
childIds.AddRange(subItems.Select(p => p.IndexId));
|
||||
|
||||
foreach (var child in childIds)
|
||||
{
|
||||
var childErrors = new List<string>();
|
||||
if (child.IsNullOrEmpty())
|
||||
|
|
|
|||
|
|
@ -220,11 +220,14 @@ public class ProfileGroupItemManager
|
|||
public static async Task<(List<ProfileItem> Items, ProfileGroupItem? Group)> GetChildProfileItems(string? indexId)
|
||||
{
|
||||
Instance.TryGet(indexId, out var profileGroupItem);
|
||||
if (profileGroupItem == null || profileGroupItem.ChildItems.IsNullOrEmpty())
|
||||
if (profileGroupItem == null || profileGroupItem.NotHasChild())
|
||||
{
|
||||
return (new List<ProfileItem>(), profileGroupItem);
|
||||
}
|
||||
var items = await GetChildProfileItems(profileGroupItem);
|
||||
var subItems = await GetSubChildProfileItems(profileGroupItem);
|
||||
items.AddRange(subItems);
|
||||
|
||||
return (items, profileGroupItem);
|
||||
}
|
||||
|
||||
|
|
@ -248,14 +251,39 @@ public class ProfileGroupItemManager
|
|||
return childProfiles;
|
||||
}
|
||||
|
||||
public static async Task<List<ProfileItem>> GetSubChildProfileItems(ProfileGroupItem? group)
|
||||
{
|
||||
if (group == null || group.SubChildItems.IsNullOrEmpty())
|
||||
{
|
||||
return new();
|
||||
}
|
||||
var childProfiles = await AppManager.Instance.ProfileItems(group.SubChildItems);
|
||||
|
||||
return childProfiles.Where(p =>
|
||||
p != null &&
|
||||
p.IsValid() &&
|
||||
!p.ConfigType.IsComplexType() &&
|
||||
(group.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, group.Filter))
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static async Task<HashSet<string>> GetAllChildDomainAddresses(string indexId)
|
||||
{
|
||||
// include grand children
|
||||
var childAddresses = new HashSet<string>();
|
||||
if (!Instance.TryGet(indexId, out var groupItem) || groupItem.ChildItems.IsNullOrEmpty())
|
||||
if (!Instance.TryGet(indexId, out var groupItem) || groupItem == null)
|
||||
{
|
||||
return childAddresses;
|
||||
}
|
||||
|
||||
var childIds = Utils.String2List(groupItem.ChildItems);
|
||||
if (groupItem.SubChildItems.IsNotEmpty())
|
||||
{
|
||||
var subItems = await GetSubChildProfileItems(groupItem);
|
||||
subItems.ForEach(p => childAddresses.Add(p.Address));
|
||||
}
|
||||
|
||||
var childIds = Utils.String2List(groupItem.ChildItems) ?? [];
|
||||
|
||||
foreach (var childId in childIds)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,5 +8,14 @@ public class ProfileGroupItem
|
|||
|
||||
public string ChildItems { get; set; }
|
||||
|
||||
public string? SubChildItems { get; set; }
|
||||
|
||||
public string? Filter { get; set; }
|
||||
|
||||
public EMultipleLoad MultipleLoad { get; set; } = EMultipleLoad.LeastPing;
|
||||
|
||||
public bool NotHasChild()
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(ChildItems) && string.IsNullOrWhiteSpace(SubChildItems);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
11
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -19,7 +19,7 @@ namespace ServiceLib.Resx {
|
|||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class ResUI {
|
||||
|
|
@ -2958,6 +2958,15 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Auto add filtered configuration from subscription groups 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbPolicyGroupSubChildTip {
|
||||
get {
|
||||
return ResourceManager.GetString("TbPolicyGroupSubChildTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Policy Group Type 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1599,4 +1599,7 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>Test real delay</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>Auto add filtered configuration from subscription groups</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1596,4 +1596,7 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>Test 1-clic de latence réelle</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>Auto add filtered configuration from subscription groups</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1599,4 +1599,7 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>Test real delay</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>Auto add filtered configuration from subscription groups</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1599,4 +1599,7 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>Test real delay</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>Auto add filtered configuration from subscription groups</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1599,4 +1599,7 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>Test real delay</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>Auto add filtered configuration from subscription groups</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1596,4 +1596,7 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>一键测试真连接延迟</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>自动从订阅分组添加过滤后的配置</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1596,4 +1596,7 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>一鍵測試真連線延遲</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>自動從訂閱分組新增過濾後的配置</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -17,6 +17,14 @@ public class AddGroupServerViewModel : MyReactiveObject
|
|||
[Reactive]
|
||||
public string? PolicyGroupType { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public SubItem? SelectedSubItem { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string? Filter { get; set; }
|
||||
|
||||
public IObservableCollection<SubItem> SubItems { get; } = new ObservableCollectionExtended<SubItem>();
|
||||
|
||||
public IObservableCollection<ProfileItem> ChildItemsObs { get; } = new ObservableCollectionExtended<ProfileItem>();
|
||||
|
||||
//public ReactiveCommand<Unit, Unit> AddCmd { get; }
|
||||
|
|
@ -64,10 +72,14 @@ public class AddGroupServerViewModel : MyReactiveObject
|
|||
});
|
||||
|
||||
SelectedSource = profileItem.IndexId.IsNullOrEmpty() ? profileItem : JsonUtils.DeepCopy(profileItem);
|
||||
|
||||
CoreType = (SelectedSource?.CoreType ?? ECoreType.Xray).ToString();
|
||||
|
||||
ProfileGroupItemManager.Instance.TryGet(profileItem.IndexId, out var profileGroup);
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
public async Task Init()
|
||||
{
|
||||
ProfileGroupItemManager.Instance.TryGet(SelectedSource.IndexId, out var profileGroup);
|
||||
PolicyGroupType = (profileGroup?.MultipleLoad ?? EMultipleLoad.LeastPing) switch
|
||||
{
|
||||
EMultipleLoad.LeastPing => ResUI.TbLeastPing,
|
||||
|
|
@ -78,15 +90,16 @@ public class AddGroupServerViewModel : MyReactiveObject
|
|||
_ => ResUI.TbLeastPing,
|
||||
};
|
||||
|
||||
_ = Init();
|
||||
}
|
||||
var subs = await AppManager.Instance.SubItems();
|
||||
subs.Add(new SubItem());
|
||||
SubItems.AddRange(subs);
|
||||
SelectedSubItem = SubItems.Where(s => s.Id == profileGroup?.SubChildItems).FirstOrDefault();
|
||||
Filter = profileGroup?.Filter;
|
||||
|
||||
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);
|
||||
var childIndexIds = Utils.String2List(childItemMulti.ChildItems) ?? [];
|
||||
foreach (var item in childIndexIds)
|
||||
{
|
||||
var child = await AppManager.Instance.GetProfileItem(item);
|
||||
|
|
@ -181,7 +194,7 @@ public class AddGroupServerViewModel : MyReactiveObject
|
|||
NoticeManager.Instance.Enqueue(ResUI.PleaseFillRemarks);
|
||||
return;
|
||||
}
|
||||
if (ChildItemsObs.Count == 0)
|
||||
if (ChildItemsObs.Count == 0 && SelectedSubItem?.Id.IsNullOrEmpty() == true)
|
||||
{
|
||||
NoticeManager.Instance.Enqueue(ResUI.PleaseAddAtLeastOneServer);
|
||||
return;
|
||||
|
|
@ -213,6 +226,9 @@ public class AddGroupServerViewModel : MyReactiveObject
|
|||
_ => EMultipleLoad.LeastPing,
|
||||
};
|
||||
|
||||
profileGroup.SubChildItems = SelectedSubItem?.Id;
|
||||
profileGroup.Filter = Filter;
|
||||
|
||||
var hasCycle = ProfileGroupItemManager.HasCycle(profileGroup.IndexId);
|
||||
if (hasCycle)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
<Grid
|
||||
Grid.Row="0"
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
|
|
@ -88,6 +88,40 @@
|
|||
Width="200"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.menuSubscription}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSubChildItems"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DisplayMemberBinding="{Binding Remarks}"
|
||||
ItemsSource="{Binding SubItems}" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.LvFilter}" />
|
||||
<TextBox
|
||||
x:Name="txtFilter"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<TabControl>
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
||||
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.OneWayBind(ViewModel, vm => vm.ChildItemsObs, v => v.lstChild.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedChild, v => v.lstChild.SelectedItem).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
|
|
@ -130,6 +132,45 @@
|
|||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbPolicyGroupType}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.menuSubscription}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSubChildItems"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DisplayMemberPath="Remarks"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.LvFilter}" />
|
||||
<TextBox
|
||||
x:Name="txtFilter"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<TabControl>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ public partial class AddGroupServerWindow
|
|||
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.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.OneWayBind(ViewModel, vm => vm.ChildItemsObs, v => v.lstChild.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedChild, v => v.lstChild.SelectedItem).DisposeWith(disposables);
|
||||
|
|
|
|||
Loading…
Reference in a new issue