Skip to content

Commit 53aa01f

Browse files
committed
Feature: Profile filter
1 parent 5a0b11d commit 53aa01f

File tree

8 files changed

+630
-149
lines changed

8 files changed

+630
-149
lines changed

Source/NETworkManager/ViewModels/DNSLookupHostViewModel.cs

Lines changed: 140 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Dragablz;
2-
using MahApps.Metro.Controls.Dialogs;
32
using NETworkManager.Controls;
43
using NETworkManager.Localization.Resources;
54
using NETworkManager.Models;
@@ -22,8 +21,7 @@ namespace NETworkManager.ViewModels;
2221
public class DNSLookupHostViewModel : ViewModelBase, IProfileManager
2322
{
2423
#region Variables
25-
26-
private readonly IDialogCoordinator _dialogCoordinator;
24+
2725
private readonly DispatcherTimer _searchDispatcherTimer = new();
2826

2927
public IInterTabClient InterTabClient { get; }
@@ -129,6 +127,70 @@ public bool IsSearching
129127
OnPropertyChanged();
130128
}
131129
}
130+
131+
private bool _profileFilterIsOpen;
132+
133+
public bool ProfileFilterIsOpen
134+
{
135+
get => _profileFilterIsOpen;
136+
set
137+
{
138+
if (value == _profileFilterIsOpen)
139+
return;
140+
141+
_profileFilterIsOpen = value;
142+
OnPropertyChanged();
143+
}
144+
}
145+
146+
public ICollectionView ProfileFilterTagsView { get; }
147+
148+
private ObservableCollection<ProfileFilterTagsInfo> ProfileFilterTags { get; } = [];
149+
150+
private bool _profileFilterTagsMatchAny = GlobalStaticConfiguration.Profile_TagsMatchAny;
151+
152+
public bool ProfileFilterTagsMatchAny
153+
{
154+
get => _profileFilterTagsMatchAny;
155+
set
156+
{
157+
if (value == _profileFilterTagsMatchAny)
158+
return;
159+
160+
_profileFilterTagsMatchAny = value;
161+
OnPropertyChanged();
162+
}
163+
}
164+
165+
private bool _profileFilterTagsMatchAll;
166+
167+
public bool ProfileFilterTagsMatchAll
168+
{
169+
get => _profileFilterTagsMatchAll;
170+
set
171+
{
172+
if (value == _profileFilterTagsMatchAll)
173+
return;
174+
175+
_profileFilterTagsMatchAll = value;
176+
OnPropertyChanged();
177+
}
178+
}
179+
180+
private bool _isProfileFilterSet;
181+
182+
public bool IsProfileFilterSet
183+
{
184+
get => _isProfileFilterSet;
185+
set
186+
{
187+
if (value == _isProfileFilterSet)
188+
return;
189+
190+
_isProfileFilterSet = value;
191+
OnPropertyChanged();
192+
}
193+
}
132194

133195
private bool _canProfileWidthChange = true;
134196
private double _tempProfileWidth;
@@ -184,14 +246,13 @@ public GridLength ProfileWidth
184246

185247
#region Constructor, load settings
186248

187-
public DNSLookupHostViewModel(IDialogCoordinator instance)
249+
public DNSLookupHostViewModel()
188250
{
189251
_isLoading = true;
190252

191-
_dialogCoordinator = instance;
192253

193254
InterTabClient = new DragablzInterTabClient(ApplicationName.DNSLookup);
194-
InterTabPartition = ApplicationName.DNSLookup.ToString();
255+
InterTabPartition = nameof(ApplicationName.DNSLookup);
195256

196257
var tabId = Guid.NewGuid();
197258

@@ -201,7 +262,12 @@ public DNSLookupHostViewModel(IDialogCoordinator instance)
201262
];
202263

203264
// Profiles
204-
SetProfilesView();
265+
CreateTags();
266+
267+
ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
268+
ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name), ListSortDirection.Ascending));
269+
270+
SetProfilesView(new ProfileFilterInfo());
205271

206272
ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
207273

@@ -298,6 +364,36 @@ private void ClearSearchAction()
298364
Search = string.Empty;
299365
}
300366

367+
public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
368+
369+
private void OpenProfileFilterAction()
370+
{
371+
ProfileFilterIsOpen = true;
372+
}
373+
374+
public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
375+
376+
private void ApplyProfileFilterAction()
377+
{
378+
RefreshProfiles();
379+
380+
IsProfileFilterSet = true;
381+
ProfileFilterIsOpen = false;
382+
}
383+
384+
public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
385+
386+
private void ClearProfileFilterAction()
387+
{
388+
foreach (var tag in ProfileFilterTags)
389+
tag.IsSelected = false;
390+
391+
RefreshProfiles();
392+
393+
IsProfileFilterSet = false;
394+
ProfileFilterIsOpen = false;
395+
}
396+
301397
public ItemActionCallback CloseItemCommand => CloseItemAction;
302398

303399
private static void CloseItemAction(ItemActionCallbackArgs<TabablzControl> args)
@@ -360,38 +456,42 @@ public void OnViewHide()
360456
_isViewActive = false;
361457
}
362458

363-
private void SetProfilesView(ProfileInfo profile = null)
459+
private void CreateTags()
364460
{
365-
Profiles = new CollectionViewSource
366-
{
367-
Source = ProfileManager.Groups.SelectMany(x => x.Profiles).Where(x => x.DNSLookup_Enabled)
368-
.OrderBy(x => x.Group).ThenBy(x => x.Name)
369-
}.View;
461+
var tags = ProfileManager.Groups.SelectMany(x => x.Profiles).Where(x => x.DNSLookup_Enabled).SelectMany(x => x.TagsCollection).Distinct().ToList();
370462

371-
Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
463+
var tagSet = new HashSet<string>(tags);
372464

373-
Profiles.Filter = o =>
465+
for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
374466
{
375-
if (string.IsNullOrEmpty(Search))
376-
return true;
377-
378-
if (o is not ProfileInfo info)
379-
return false;
380-
381-
467+
if (!tagSet.Contains(ProfileFilterTags[i].Name))
468+
ProfileFilterTags.RemoveAt(i);
469+
}
382470

383-
var search = Search.Trim();
471+
var existingTagNames = new HashSet<string>(ProfileFilterTags.Select(ft => ft.Name));
384472

385-
// Search by: Tag=xxx (exact match, ignore case)
386-
/*
387-
if (search.StartsWith(ProfileManager.TagIdentifier, StringComparison.OrdinalIgnoreCase))
388-
return !string.IsNullOrEmpty(info.Tags) && info.PingMonitor_Enabled && info.Tags.Replace(" ", "").Split(';').Any(str => search.Substring(ProfileManager.TagIdentifier.Length, search.Length - ProfileManager.TagIdentifier.Length).Equals(str, StringComparison.OrdinalIgnoreCase));
389-
*/
473+
foreach (var tag in tags.Where(tag => !existingTagNames.Contains(tag)))
474+
{
475+
ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
476+
}
477+
}
478+
479+
private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
480+
{
481+
Profiles = new CollectionViewSource
482+
{
483+
Source = ProfileManager.Groups.SelectMany(x => x.Profiles).Where(x => x.DNSLookup_Enabled && (
484+
string.IsNullOrEmpty(filter.Search) || x.Name.IndexOf(filter.Search, StringComparison.Ordinal) > -1 || x.DNSLookup_Host.IndexOf(filter.Search, StringComparison.Ordinal) > -1) && (
485+
// If no tags are selected, show all profiles
486+
(!filter.Tags.Any()) ||
487+
// Any tag can match
488+
(filter.TagsFilterMatch == ProfileFilterTagsMatch.Any && filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
489+
// All tags must match
490+
(filter.TagsFilterMatch == ProfileFilterTagsMatch.All && filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
491+
).OrderBy(x => x.Group).ThenBy(x => x.Name)
492+
}.View;
390493

391-
// Search by: Name, DNSLookup_Host
392-
return info.Name.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1 ||
393-
info.DNSLookup_Host.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1;
394-
};
494+
Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
395495

396496
// Set specific profile or first if null
397497
SelectedProfile = null;
@@ -408,7 +508,12 @@ private void RefreshProfiles()
408508
if (!_isViewActive)
409509
return;
410510

411-
SetProfilesView(SelectedProfile);
511+
SetProfilesView(new ProfileFilterInfo
512+
{
513+
Search = Search,
514+
Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
515+
TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
516+
}, SelectedProfile);
412517
}
413518

414519
#endregion
@@ -417,6 +522,8 @@ private void RefreshProfiles()
417522

418523
private void ProfileManager_OnProfilesUpdated(object sender, EventArgs e)
419524
{
525+
CreateTags();
526+
420527
RefreshProfiles();
421528
}
422529

0 commit comments

Comments
 (0)