mirror of
https://github.com/2dust/v2rayN.git
synced 2025-12-01 04:03:00 +00:00
Compare commits
6 commits
5a493372d8
...
640edb5eb2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
640edb5eb2 | ||
|
|
c14a0e33b7 | ||
|
|
ebb47ee516 | ||
|
|
5cc9ab5327 | ||
|
|
bd7b7ca1e8 | ||
|
|
7b5686cd8f |
21 changed files with 406 additions and 91 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
36
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
36
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -87,6 +87,24 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Certificate not set 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string CertNotSet {
|
||||
get {
|
||||
return ResourceManager.GetString("CertNotSet", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Certificate set 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string CertSet {
|
||||
get {
|
||||
return ResourceManager.GetString("CertSet", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Please check the Configuration settings first. 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
@ -2301,6 +2319,15 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Please set a valid domain 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string ServerNameMustBeValidDomain {
|
||||
get {
|
||||
return ResourceManager.GetString("ServerNameMustBeValidDomain", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 {0} : {1}/s↑ | {2}/s↓ 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
@ -2995,6 +3022,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,6 +1599,9 @@
|
|||
<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>
|
||||
<data name="TbCertPinning" xml:space="preserve">
|
||||
<value>Certificate Pinning</value>
|
||||
</data>
|
||||
|
|
@ -1612,4 +1615,13 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled.</val
|
|||
<data name="TbFetchCertChain" xml:space="preserve">
|
||||
<value>Fetch Certificate Chain</value>
|
||||
</data>
|
||||
<data name="ServerNameMustBeValidDomain" xml:space="preserve">
|
||||
<value>Please set a valid domain</value>
|
||||
</data>
|
||||
<data name="CertNotSet" xml:space="preserve">
|
||||
<value>Certificate not set</value>
|
||||
</data>
|
||||
<data name="CertSet" xml:space="preserve">
|
||||
<value>Certificate set</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1596,6 +1596,9 @@
|
|||
<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>
|
||||
<data name="TbCertPinning" xml:space="preserve">
|
||||
<value>Certificate Pinning</value>
|
||||
</data>
|
||||
|
|
@ -1609,4 +1612,13 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled.</val
|
|||
<data name="TbFetchCertChain" xml:space="preserve">
|
||||
<value>Fetch Certificate Chain</value>
|
||||
</data>
|
||||
<data name="ServerNameMustBeValidDomain" xml:space="preserve">
|
||||
<value>Please set a valid domain</value>
|
||||
</data>
|
||||
<data name="CertNotSet" xml:space="preserve">
|
||||
<value>Certificate not set</value>
|
||||
</data>
|
||||
<data name="CertSet" xml:space="preserve">
|
||||
<value>Certificate set</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1599,6 +1599,9 @@
|
|||
<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>
|
||||
<data name="TbCertPinning" xml:space="preserve">
|
||||
<value>Certificate Pinning</value>
|
||||
</data>
|
||||
|
|
@ -1612,4 +1615,13 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled.</val
|
|||
<data name="TbFetchCertChain" xml:space="preserve">
|
||||
<value>Fetch Certificate Chain</value>
|
||||
</data>
|
||||
<data name="ServerNameMustBeValidDomain" xml:space="preserve">
|
||||
<value>Please set a valid domain</value>
|
||||
</data>
|
||||
<data name="CertNotSet" xml:space="preserve">
|
||||
<value>Certificate not set</value>
|
||||
</data>
|
||||
<data name="CertSet" xml:space="preserve">
|
||||
<value>Certificate set</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1599,6 +1599,9 @@
|
|||
<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>
|
||||
<data name="TbCertPinning" xml:space="preserve">
|
||||
<value>Certificate Pinning</value>
|
||||
</data>
|
||||
|
|
@ -1612,4 +1615,13 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled.</val
|
|||
<data name="TbFetchCertChain" xml:space="preserve">
|
||||
<value>Fetch Certificate Chain</value>
|
||||
</data>
|
||||
<data name="ServerNameMustBeValidDomain" xml:space="preserve">
|
||||
<value>Please set a valid domain</value>
|
||||
</data>
|
||||
<data name="CertNotSet" xml:space="preserve">
|
||||
<value>Certificate not set</value>
|
||||
</data>
|
||||
<data name="CertSet" xml:space="preserve">
|
||||
<value>Certificate set</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1599,6 +1599,9 @@
|
|||
<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>
|
||||
<data name="TbCertPinning" xml:space="preserve">
|
||||
<value>Certificate Pinning</value>
|
||||
</data>
|
||||
|
|
@ -1612,4 +1615,13 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled.</val
|
|||
<data name="TbFetchCertChain" xml:space="preserve">
|
||||
<value>Fetch Certificate Chain</value>
|
||||
</data>
|
||||
<data name="ServerNameMustBeValidDomain" xml:space="preserve">
|
||||
<value>Please set a valid domain</value>
|
||||
</data>
|
||||
<data name="CertNotSet" xml:space="preserve">
|
||||
<value>Certificate not set</value>
|
||||
</data>
|
||||
<data name="CertSet" xml:space="preserve">
|
||||
<value>Certificate set</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1596,6 +1596,9 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>一键测试真连接延迟</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>自动从订阅分组添加过滤后的配置</value>
|
||||
</data>
|
||||
<data name="TbCertPinning" xml:space="preserve">
|
||||
<value>固定证书</value>
|
||||
</data>
|
||||
|
|
@ -1609,4 +1612,13 @@
|
|||
<data name="TbFetchCertChain" xml:space="preserve">
|
||||
<value>获取证书链</value>
|
||||
</data>
|
||||
<data name="ServerNameMustBeValidDomain" xml:space="preserve">
|
||||
<value>请设置有效的域名</value>
|
||||
</data>
|
||||
<data name="CertNotSet" xml:space="preserve">
|
||||
<value>证书未设置</value>
|
||||
</data>
|
||||
<data name="CertSet" xml:space="preserve">
|
||||
<value>证书已设置</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1596,6 +1596,9 @@
|
|||
<data name="menuFastRealPing" xml:space="preserve">
|
||||
<value>一鍵測試真連線延遲</value>
|
||||
</data>
|
||||
<data name="TbPolicyGroupSubChildTip" xml:space="preserve">
|
||||
<value>自動從訂閱分組新增過濾後的配置</value>
|
||||
</data>
|
||||
<data name="TbCertPinning" xml:space="preserve">
|
||||
<value>Certificate Pinning</value>
|
||||
</data>
|
||||
|
|
@ -1609,4 +1612,13 @@ Do not use the "Fetch Certificate" button when "Allow Insecure" is enabled.</val
|
|||
<data name="TbFetchCertChain" xml:space="preserve">
|
||||
<value>Fetch Certificate Chain</value>
|
||||
</data>
|
||||
<data name="ServerNameMustBeValidDomain" xml:space="preserve">
|
||||
<value>Please set a valid domain</value>
|
||||
</data>
|
||||
<data name="CertNotSet" xml:space="preserve">
|
||||
<value>Certificate not set</value>
|
||||
</data>
|
||||
<data name="CertSet" xml:space="preserve">
|
||||
<value>Certificate set</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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ namespace ServiceLib.ViewModels;
|
|||
|
||||
public class AddServerViewModel : MyReactiveObject
|
||||
{
|
||||
private string _certError = string.Empty;
|
||||
|
||||
[Reactive]
|
||||
public ProfileItem SelectedSource { get; set; }
|
||||
|
||||
|
|
@ -11,6 +13,9 @@ public class AddServerViewModel : MyReactiveObject
|
|||
[Reactive]
|
||||
public string Cert { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string CertTip { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> FetchCertCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> FetchCertChainCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||
|
|
@ -33,6 +38,9 @@ public class AddServerViewModel : MyReactiveObject
|
|||
await SaveServerAsync();
|
||||
});
|
||||
|
||||
this.WhenAnyValue(x => x.Cert)
|
||||
.Subscribe(_ => UpdateCertTip());
|
||||
|
||||
if (profileItem.IndexId.IsNullOrEmpty())
|
||||
{
|
||||
profileItem.Network = Global.DefaultNetwork;
|
||||
|
|
@ -104,6 +112,13 @@ public class AddServerViewModel : MyReactiveObject
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateCertTip()
|
||||
{
|
||||
CertTip = _certError.IsNullOrEmpty()
|
||||
? (Cert.IsNullOrEmpty() ? ResUI.CertNotSet : ResUI.CertSet)
|
||||
: _certError;
|
||||
}
|
||||
|
||||
private async Task FetchCert()
|
||||
{
|
||||
if (SelectedSource.StreamSecurity != Global.StreamSecurity)
|
||||
|
|
@ -111,9 +126,20 @@ public class AddServerViewModel : MyReactiveObject
|
|||
return;
|
||||
}
|
||||
var domain = SelectedSource.Address;
|
||||
var serverName = SelectedSource.Sni.IsNullOrEmpty() ? SelectedSource.Address : SelectedSource.Sni;
|
||||
var serverName = SelectedSource.Sni;
|
||||
if (serverName.IsNullOrEmpty())
|
||||
{
|
||||
serverName = SelectedSource.RequestHost;
|
||||
}
|
||||
if (serverName.IsNullOrEmpty())
|
||||
{
|
||||
serverName = SelectedSource.Address;
|
||||
}
|
||||
if (!Utils.IsDomain(serverName))
|
||||
{
|
||||
_certError = ResUI.ServerNameMustBeValidDomain;
|
||||
UpdateCertTip();
|
||||
_certError = string.Empty;
|
||||
return;
|
||||
}
|
||||
if (SelectedSource.Port > 0)
|
||||
|
|
@ -130,9 +156,20 @@ public class AddServerViewModel : MyReactiveObject
|
|||
return;
|
||||
}
|
||||
var domain = SelectedSource.Address;
|
||||
var serverName = SelectedSource.Sni.IsNullOrEmpty() ? SelectedSource.Address : SelectedSource.Sni;
|
||||
var serverName = SelectedSource.Sni;
|
||||
if (serverName.IsNullOrEmpty())
|
||||
{
|
||||
serverName = SelectedSource.RequestHost;
|
||||
}
|
||||
if (serverName.IsNullOrEmpty())
|
||||
{
|
||||
serverName = SelectedSource.Address;
|
||||
}
|
||||
if (!Utils.IsDomain(serverName))
|
||||
{
|
||||
_certError = ResUI.ServerNameMustBeValidDomain;
|
||||
UpdateCertTip();
|
||||
_certError = string.Empty;
|
||||
return;
|
||||
}
|
||||
if (SelectedSource.Port > 0)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -775,50 +775,59 @@
|
|||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbCertPinning}" />
|
||||
<Button
|
||||
<StackPanel
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="IconButton">
|
||||
<Button.Content>
|
||||
<PathIcon Data="{StaticResource SemiIconMore}">
|
||||
<PathIcon.RenderTransform>
|
||||
<RotateTransform Angle="90" />
|
||||
</PathIcon.RenderTransform>
|
||||
</PathIcon>
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbCertPinningTips}" />
|
||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnFetchCert"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
x:Name="labCertPinning"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center" />
|
||||
<Button
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="IconButton">
|
||||
<Button.Content>
|
||||
<PathIcon Data="{StaticResource SemiIconMore}">
|
||||
<PathIcon.RenderTransform>
|
||||
<RotateTransform Angle="90" />
|
||||
</PathIcon.RenderTransform>
|
||||
</PathIcon>
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCert}" />
|
||||
<Button
|
||||
x:Name="btnFetchCertChain"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbCertPinningTips}" />
|
||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnFetchCert"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCert}" />
|
||||
<Button
|
||||
x:Name="btnFetchCertChain"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCertChain}" />
|
||||
</StackPanel>
|
||||
<TextBox
|
||||
x:Name="txtCert"
|
||||
Width="400"
|
||||
MinHeight="100"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCertChain}" />
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Classes="TextArea"
|
||||
MinLines="6"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<TextBox
|
||||
x:Name="txtCert"
|
||||
Width="400"
|
||||
MinHeight="100"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Classes="TextArea"
|
||||
MinLines="6"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
|
||||
//reality
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).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);
|
||||
|
|
|
|||
|
|
@ -1004,45 +1004,54 @@
|
|||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbCertPinning}" />
|
||||
|
||||
<materialDesign:PopupBox
|
||||
<StackPanel
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
StaysOpen="True"
|
||||
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbCertPinningTips}"
|
||||
TextWrapping="Wrap" />
|
||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnFetchCert"
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCert}"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
x:Name="btnFetchCertChain"
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCertChain}"
|
||||
Style="{StaticResource DefButton}" />
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
x:Name="labCertPinning"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}" />
|
||||
<materialDesign:PopupBox
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
StaysOpen="True"
|
||||
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbCertPinningTips}"
|
||||
TextWrapping="Wrap" />
|
||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnFetchCert"
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCert}"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
x:Name="btnFetchCertChain"
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight4}"
|
||||
Content="{x:Static resx:ResUI.TbFetchCertChain}"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
<TextBox
|
||||
x:Name="txtCert"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
MinLines="6"
|
||||
Style="{StaticResource MyOutlinedTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<TextBox
|
||||
x:Name="txtCert"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
MinLines="6"
|
||||
Style="{StaticResource MyOutlinedTextBox}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</materialDesign:PopupBox>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
<Grid
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ public partial class AddServerWindow
|
|||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Fingerprint, v => v.cmbFingerprint.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Alpn, v => v.cmbAlpn.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
|
||||
//reality
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI2.Text).DisposeWith(disposables);
|
||||
|
|
|
|||
Loading…
Reference in a new issue