diff --git a/v2rayN/ServiceLib/Common/StringEx.cs b/v2rayN/ServiceLib/Common/StringEx.cs index 008af348..eb9bdafe 100644 --- a/v2rayN/ServiceLib/Common/StringEx.cs +++ b/v2rayN/ServiceLib/Common/StringEx.cs @@ -14,6 +14,11 @@ namespace ServiceLib.Common return string.IsNullOrWhiteSpace(value); } + public static bool IsNotEmpty([NotNullWhen(false)] this string? value) + { + return !string.IsNullOrEmpty(value); + } + public static bool BeginWithAny(this string s, IEnumerable chars) { if (s.IsNullOrEmpty()) return false; diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 7248e789..edb0a9d9 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -105,6 +105,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Host filter 的本地化字符串。 + /// + public static string ConnectionsHostFilterTitle { + get { + return ResourceManager.GetString("ConnectionsHostFilterTitle", resourceCulture); + } + } + /// /// 查找类似 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. 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 2d51cec7..c9e7d71b 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1318,4 +1318,7 @@ Invalid backup file + + Host filter + \ 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 c7ae08e2..b88be0c5 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1315,4 +1315,7 @@ 无效备份文件 + + 主机过滤器 + \ 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 367aabcb..913705fb 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1195,4 +1195,7 @@ 無效備份文件 + + 主機過濾器 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs b/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs index 5adf7fc9..290a4e2e 100644 --- a/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs @@ -19,6 +19,9 @@ namespace ServiceLib.ViewModels public ReactiveCommand ConnectionCloseCmd { get; } public ReactiveCommand ConnectionCloseAllCmd { get; } + [Reactive] + public string HostFilter { get; set; } + [Reactive] public int SortingSelected { get; set; } @@ -77,7 +80,7 @@ namespace ServiceLib.ViewModels { var lastTime = DateTime.Now; - Observable.Interval(TimeSpan.FromSeconds(10)) + Observable.Interval(TimeSpan.FromSeconds(5)) .Subscribe(x => { if (!(AutoRefresh && _config.uiItem.showInTaskbar && _config.IsRunningCore(ECoreType.clash))) @@ -118,12 +121,18 @@ namespace ServiceLib.ViewModels var lstModel = new List(); foreach (var item in connections ?? []) { + var host = $"{(string.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}"; + if (HostFilter.IsNotEmpty() && !host.Contains(HostFilter)) + { + continue; + } + ClashConnectionModel model = new(); model.id = item.id; model.network = item.metadata.network; model.type = item.metadata.type; - model.host = $"{(string.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}"; + model.host = host; var sp = (dtNow - item.start); model.time = sp.TotalSeconds < 0 ? 1 : sp.TotalSeconds; model.upload = item.upload; diff --git a/v2rayN/v2rayN/Views/ClashConnectionsView.xaml b/v2rayN/v2rayN/Views/ClashConnectionsView.xaml index 4a000135..b9e3ef5e 100644 --- a/v2rayN/v2rayN/Views/ClashConnectionsView.xaml +++ b/v2rayN/v2rayN/Views/ClashConnectionsView.xaml @@ -1,11 +1,11 @@ + + vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);