Skip to content

Commit 9b2bb36

Browse files
committed
Feature: Profile filter
1 parent db8405e commit 9b2bb36

File tree

2 files changed

+272
-37
lines changed

2 files changed

+272
-37
lines changed

Source/NETworkManager/ViewModels/NetworkInterfaceViewModel.cs

Lines changed: 135 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,70 @@ public bool IsSearching
516516
}
517517
}
518518

519+
private bool _profileFilterIsOpen;
520+
521+
public bool ProfileFilterIsOpen
522+
{
523+
get => _profileFilterIsOpen;
524+
set
525+
{
526+
if (value == _profileFilterIsOpen)
527+
return;
528+
529+
_profileFilterIsOpen = value;
530+
OnPropertyChanged();
531+
}
532+
}
533+
534+
public ICollectionView ProfileFilterTagsView { get; set; }
535+
536+
public ObservableCollection<ProfileFilterTagsInfo> ProfileFilterTags { get; set; } = [];
537+
538+
private bool _profileFilterTagsMatchAny = GlobalStaticConfiguration.Profile_TagsMatchAny;
539+
540+
public bool ProfileFilterTagsMatchAny
541+
{
542+
get => _profileFilterTagsMatchAny;
543+
set
544+
{
545+
if (value == _profileFilterTagsMatchAny)
546+
return;
547+
548+
_profileFilterTagsMatchAny = value;
549+
OnPropertyChanged();
550+
}
551+
}
552+
553+
private bool _profileFilterTagsMatchAll;
554+
555+
public bool ProfileFilterTagsMatchAll
556+
{
557+
get => _profileFilterTagsMatchAll;
558+
set
559+
{
560+
if (value == _profileFilterTagsMatchAll)
561+
return;
562+
563+
_profileFilterTagsMatchAll = value;
564+
OnPropertyChanged();
565+
}
566+
}
567+
568+
private bool _isProfileFilterSet;
569+
570+
public bool IsProfileFilterSet
571+
{
572+
get => _isProfileFilterSet;
573+
set
574+
{
575+
if (value == _isProfileFilterSet)
576+
return;
577+
578+
_isProfileFilterSet = value;
579+
OnPropertyChanged();
580+
}
581+
}
582+
519583
private bool _canProfileWidthChange = true;
520584
private double _tempProfileWidth;
521585

@@ -581,7 +645,12 @@ public NetworkInterfaceViewModel(IDialogCoordinator instance)
581645
InitialBandwidthChart();
582646

583647
// Profiles
584-
SetProfilesView();
648+
CreateTags();
649+
650+
ProfileFilterTagsView = CollectionViewSource.GetDefaultView(ProfileFilterTags);
651+
ProfileFilterTagsView.SortDescriptions.Add(new SortDescription(nameof(ProfileFilterTagsInfo.Name), ListSortDirection.Ascending));
652+
653+
SetProfilesView(new ProfileFilterInfo());
585654

586655
ProfileManager.OnProfilesUpdated += ProfileManager_OnProfilesUpdated;
587656

@@ -801,6 +870,36 @@ private void ClearSearchAction()
801870
Search = string.Empty;
802871
}
803872

873+
public ICommand OpenProfileFilterCommand => new RelayCommand(_ => OpenProfileFilterAction());
874+
875+
private void OpenProfileFilterAction()
876+
{
877+
ProfileFilterIsOpen = true;
878+
}
879+
880+
public ICommand ApplyProfileFilterCommand => new RelayCommand(_ => ApplyProfileFilterAction());
881+
882+
private void ApplyProfileFilterAction()
883+
{
884+
RefreshProfiles();
885+
886+
IsProfileFilterSet = true;
887+
ProfileFilterIsOpen = false;
888+
}
889+
890+
public ICommand ClearProfileFilterCommand => new RelayCommand(_ => ClearProfileFilterAction());
891+
892+
private void ClearProfileFilterAction()
893+
{
894+
foreach (var tag in ProfileFilterTags)
895+
tag.IsSelected = false;
896+
897+
RefreshProfiles();
898+
899+
IsProfileFilterSet = false;
900+
ProfileFilterIsOpen = false;
901+
}
902+
804903
#region Additional commands
805904

806905
private bool AdditionalCommands_CanExecute(object parameter)
@@ -1326,35 +1425,43 @@ public void OnViewHide()
13261425
_isViewActive = false;
13271426
}
13281427

1329-
private void SetProfilesView(ProfileInfo profile = null)
1428+
private void CreateTags()
13301429
{
1331-
Profiles = new CollectionViewSource
1332-
{
1333-
Source = ProfileManager.Groups.SelectMany(x => x.Profiles).Where(x => x.NetworkInterface_Enabled)
1334-
.OrderBy(x => x.Group).ThenBy(x => x.Name)
1335-
}.View;
1430+
var tags = ProfileManager.Groups.SelectMany(x => x.Profiles).Where(x => x.NetworkInterface_Enabled).SelectMany(x => x.TagsCollection).Distinct().ToList();
13361431

1337-
Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
1432+
var tagSet = new HashSet<string>(tags);
13381433

1339-
Profiles.Filter = o =>
1434+
for (var i = ProfileFilterTags.Count - 1; i >= 0; i--)
13401435
{
1341-
if (string.IsNullOrEmpty(Search))
1342-
return true;
1436+
if (!tagSet.Contains(ProfileFilterTags[i].Name))
1437+
ProfileFilterTags.RemoveAt(i);
1438+
}
13431439

1344-
if (o is not ProfileInfo info)
1345-
return false;
1440+
var existingTagNames = new HashSet<string>(ProfileFilterTags.Select(ft => ft.Name));
13461441

1347-
var search = Search.Trim();
1442+
foreach (var tag in tags)
1443+
{
1444+
if (!existingTagNames.Contains(tag))
1445+
ProfileFilterTags.Add(new ProfileFilterTagsInfo(false, tag));
1446+
}
1447+
}
13481448

1349-
// Search by: Tag=xxx (exact match, ignore case)
1350-
/*
1351-
if (search.StartsWith(ProfileManager.TagIdentifier, StringComparison.OrdinalIgnoreCase))
1352-
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));
1353-
*/
1449+
private void SetProfilesView(ProfileFilterInfo filter, ProfileInfo profile = null)
1450+
{
1451+
Profiles = new CollectionViewSource
1452+
{
1453+
Source = ProfileManager.Groups.SelectMany(x => x.Profiles).Where(x => x.NetworkInterface_Enabled && (
1454+
string.IsNullOrEmpty(filter.Search) || x.Name.IndexOf(filter.Search) > -1) && (
1455+
// If no tags are selected, show all profiles
1456+
(!filter.Tags.Any()) ||
1457+
// Any tag can match
1458+
(filter.TagsFilterMatch == ProfileFilterTagsMatch.Any && filter.Tags.Any(tag => x.TagsCollection.Contains(tag))) ||
1459+
// All tags must match
1460+
(filter.TagsFilterMatch == ProfileFilterTagsMatch.All && filter.Tags.All(tag => x.TagsCollection.Contains(tag))))
1461+
).OrderBy(x => x.Group).ThenBy(x => x.Name)
1462+
}.View;
13541463

1355-
// Search by: Name
1356-
return info.Name.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1;
1357-
};
1464+
Profiles.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ProfileInfo.Group)));
13581465

13591466
// Set specific profile or first if null
13601467
SelectedProfile = null;
@@ -1371,7 +1478,12 @@ private void RefreshProfiles()
13711478
if (!_isViewActive)
13721479
return;
13731480

1374-
SetProfilesView(SelectedProfile);
1481+
SetProfilesView(new ProfileFilterInfo
1482+
{
1483+
Search = Search,
1484+
Tags = [.. ProfileFilterTags.Where(x => x.IsSelected).Select(x => x.Name)],
1485+
TagsFilterMatch = ProfileFilterTagsMatchAny ? ProfileFilterTagsMatch.Any : ProfileFilterTagsMatch.All
1486+
}, SelectedProfile);
13751487
}
13761488

13771489
#endregion

0 commit comments

Comments
 (0)