From aa9861162dd0305da7b8161fbdba030c9aae229d Mon Sep 17 00:00:00 2001 From: Brian Bicknell Date: Sun, 26 Jul 2026 17:07:49 -0400 Subject: [PATCH] Optimized filtering playlist songs. --- .../ViewModels/PlaylistViewModel.cs | 76 ++++++++----------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/Harmonia.WinUI/ViewModels/PlaylistViewModel.cs b/Harmonia.WinUI/ViewModels/PlaylistViewModel.cs index 5320bef..617bf03 100644 --- a/Harmonia.WinUI/ViewModels/PlaylistViewModel.cs +++ b/Harmonia.WinUI/ViewModels/PlaylistViewModel.cs @@ -20,11 +20,10 @@ using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using System.Timers; using System.Windows.Input; using Windows.ApplicationModel.DataTransfer; using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue; -using Timer = System.Timers.Timer; +using DispatcherQueueTimer = Microsoft.UI.Dispatching.DispatcherQueueTimer; namespace Harmonia.WinUI.ViewModels; @@ -40,7 +39,7 @@ public partial class PlaylistViewModel : ViewModelBase private readonly DispatcherQueue _dispatcherQueue; private readonly ConcurrentDictionary _imageCancellationTokens = []; - private Timer? _filterTimer; + private DispatcherQueueTimer? _filterTimer; public Playlist? Playlist { get; private set; } @@ -300,26 +299,19 @@ public partial class PlaylistViewModel : ViewModelBase { if (_filterTimer == null) { - _filterTimer = new Timer(300); - _filterTimer.Elapsed += OnFilterTimerElapsed; - _filterTimer.Start(); + _filterTimer = _dispatcherQueue.CreateTimer(); + _filterTimer.Interval = TimeSpan.FromMilliseconds(300); + _filterTimer.IsRepeating = false; + _filterTimer.Tick += OnFilterTimerTick; } - else - { - _filterTimer.Interval = 300; - } - } - - private void OnFilterTimerElapsed(object? sender, ElapsedEventArgs e) - { - if (_filterTimer == null) - return; _filterTimer.Stop(); - _filterTimer.Dispose(); - _filterTimer = null; + _filterTimer.Start(); + } - _dispatcherQueue.TryEnqueue(UpdateFilteredSongs); + private void OnFilterTimerTick(DispatcherQueueTimer sender, object args) + { + UpdateFilteredSongs(); } private void UpdateFilteredSongs() @@ -327,61 +319,59 @@ public partial class PlaylistViewModel : ViewModelBase if (Playlist == null) return; - List filteredPlaylistSongs = [.. Playlist.Songs.Where(playlistSong => IsFiltered(playlistSong.Song))]; - //FilteredPlaylistSongs = [.. filteredPlaylistSongs]; + string? filter = Filter; + HashSet updatedFilterSet = [.. Playlist.Songs.Where(playlistSong => IsFiltered(playlistSong.Song, filter))]; for (int i = FilteredPlaylistSongs.Count - 1; i >= 0; i--) { PlaylistSong playlistSong = FilteredPlaylistSongs[i]; - bool inPlaylist = Playlist.Songs.Contains(playlistSong); - bool inFilter = filteredPlaylistSongs.Contains(playlistSong); + bool inFilterSet = updatedFilterSet.Contains(playlistSong); - if (!inPlaylist || !inFilter) - { - FilteredPlaylistSongs.Remove(playlistSong); - } + if (!inFilterSet) + FilteredPlaylistSongs.RemoveAt(i); } + HashSet currentSet = [.. FilteredPlaylistSongs]; int insertionIndex = 0; foreach (PlaylistSong playlistSong in Playlist.Songs) { - bool inFilter = filteredPlaylistSongs.Contains(playlistSong); - bool inCurrentFilteredList = FilteredPlaylistSongs.Contains(playlistSong); + bool inFilterSet = updatedFilterSet.Contains(playlistSong); + bool inCurrentSet = currentSet.Contains(playlistSong); - if (inFilter) + if (!inFilterSet) + continue; + + if (!inCurrentSet) { - if (!inCurrentFilteredList) - { - FilteredPlaylistSongs.Insert(insertionIndex, playlistSong); - } - - insertionIndex++; + FilteredPlaylistSongs.Insert(insertionIndex, playlistSong); } + + insertionIndex++; } } - private bool IsFiltered(Song song) + private static bool IsFiltered(Song song, string? filter) { - if (string.IsNullOrWhiteSpace(Filter)) + if (string.IsNullOrWhiteSpace(filter)) return true; var shortFileName = Path.GetFileName(song.FileName); - if (shortFileName.Contains(Filter, StringComparison.OrdinalIgnoreCase)) + if (shortFileName.Contains(filter, StringComparison.OrdinalIgnoreCase)) return true; - if (string.IsNullOrWhiteSpace(song.Title) == false && song.Title.Contains(Filter, StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrWhiteSpace(song.Title) == false && song.Title.Contains(filter, StringComparison.OrdinalIgnoreCase)) return true; - if (string.IsNullOrWhiteSpace(song.Album) == false && song.Album.Contains(Filter, StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrWhiteSpace(song.Album) == false && song.Album.Contains(filter, StringComparison.OrdinalIgnoreCase)) return true; - if (song.AlbumArtists.Any(x => x.Contains(Filter, StringComparison.OrdinalIgnoreCase))) + if (song.AlbumArtists.Any(x => x.Contains(filter, StringComparison.OrdinalIgnoreCase))) return true; - if (song.Artists.Any(x => x.Contains(Filter, StringComparison.OrdinalIgnoreCase))) + if (song.Artists.Any(x => x.Contains(filter, StringComparison.OrdinalIgnoreCase))) return true; return false;