Removed "PlaylistSongs" field, in order to maintain one source of truth (Playlist.Songs). No not allow reordering when a filter is present on the playlist.

This commit is contained in:
2026-07-26 23:44:06 -04:00
parent c334a4166f
commit a85c65e833
2 changed files with 44 additions and 69 deletions

View File

@@ -56,19 +56,6 @@ public partial class PlaylistDetailViewModel : ViewModelBase
}
}
private ObservableCollection<PlaylistSong> _playlistSongs = [];
public ObservableCollection<PlaylistSong> PlaylistSongs
{
get
{
return _playlistSongs;
}
set
{
SetProperty(ref _playlistSongs, value);
}
}
private string? _filter;
public string? Filter
{
@@ -79,10 +66,13 @@ public partial class PlaylistDetailViewModel : ViewModelBase
set
{
SetProperty(ref _filter, value);
OnPropertyChanged(nameof(CanReorderSongs));
RestartFilterTimer();
}
}
public bool CanReorderSongs => string.IsNullOrWhiteSpace(Filter);
private ObservableCollection<PlaylistSong> _filteredPlaylistSongs = [];
public ObservableCollection<PlaylistSong> FilteredPlaylistSongs
{
@@ -123,6 +113,8 @@ public partial class PlaylistDetailViewModel : ViewModelBase
public bool IsUserUpdating { get; set; }
private bool _isUserInitiatingSongChange;
private PlaylistSong? _pendingMovedSong;
private int _pendingMovedSongIndex = -1;
public event EventHandler? PlayingSongChangedAutomatically;
@@ -152,10 +144,7 @@ public partial class PlaylistDetailViewModel : ViewModelBase
FilteredPlaylistSongs.CollectionChanged += OnFilteredPlaylistSongsCollectionChanged;
Playlist = _playlistManager.CurrentPlaylist; // Testing
UpdatePlaylistSongs(Playlist);
// Testing
//Task.Run(() => PlayDemoSong(playlistRepository));
UpdateFilteredSongs();
}
private void OnFilteredPlaylistSongsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@@ -163,47 +152,42 @@ public partial class PlaylistDetailViewModel : ViewModelBase
if (IsUserUpdating == false)
return;
int x = 1;
// A drag-reorder in the ListView raises a Remove followed by an Add for the same item.
// Reordering is only enabled while unfiltered, so view indices map 1:1 to Playlist.Songs.
switch (e.Action)
{
case NotifyCollectionChangedAction.Remove:
_pendingMovedSong = e.OldItems?.Cast<PlaylistSong>().FirstOrDefault();
_pendingMovedSongIndex = e.OldStartingIndex;
break;
case NotifyCollectionChangedAction.Add:
PlaylistSong? addedSong = e.NewItems?.Cast<PlaylistSong>().FirstOrDefault();
if (addedSong != null && addedSong == _pendingMovedSong)
{
MoveSongInPlaylist(_pendingMovedSongIndex, e.NewStartingIndex);
}
//private async Task PlayDemoSong(IPlaylistRepository playlistRepository)
//{
// if (playlistRepository.Get().Count == 0)
// {
// playlistRepository.AddPlaylist();
// }
_pendingMovedSong = null;
_pendingMovedSongIndex = -1;
break;
}
}
// Playlist playlist = playlistRepository.Get().First();
// if (playlist.Songs.Count > 0)
// await _audioPlayer.LoadAsync(playlist.Songs[0], PlaybackMode.LoadOnly);
//}
private void UpdatePlaylistSongs(Playlist? playlist)
private void MoveSongInPlaylist(int oldIndex, int newIndex)
{
PlaylistSong[] playlistSongs = playlist?.Songs.ToArray() ?? [];
if (Playlist == null || oldIndex < 0 || oldIndex == newIndex)
return;
PlaylistSongs = [.. playlistSongs];
UpdateFilteredSongs();
Playlist.MoveSong(oldIndex, newIndex);
}
private void OnPlaylistChanged(object? sender, EventArgs e)
{
if (Playlist != null)
{
Playlist.PlaylistUpdated -= OnPlaylistUpdated;
}
Playlist?.PlaylistUpdated -= OnPlaylistUpdated;
Playlist = _audioPlayer.Playlist;
Playlist?.PlaylistUpdated += OnPlaylistUpdated;
if (Playlist != null)
{
Playlist.PlaylistUpdated += OnPlaylistUpdated;
}
PlaylistSong[] playlistSongs = _audioPlayer.Playlist?.Songs.ToArray() ?? [];
PlaylistSongs = [.. playlistSongs];
UpdateFilteredSongs();
}
@@ -215,32 +199,23 @@ public partial class PlaylistDetailViewModel : ViewModelBase
switch (e.Action)
{
case PlaylistUpdateAction.Add:
_dispatcherQueue.TryEnqueue(() => AddSongs(e.Songs, e.Index));
break;
case PlaylistUpdateAction.Remove:
_dispatcherQueue.TryEnqueue(() => RemoveSongsFromCollection(e.Songs));
_dispatcherQueue.TryEnqueue(UpdateFilteredSongs);
break;
case PlaylistUpdateAction.Move:
case PlaylistUpdateAction.Reset:
_dispatcherQueue.TryEnqueue(() => ApplyReorderedSongs(e.Songs));
break;
}
}
private void AddSongs(PlaylistSong[] playlistSongs, int index = 0)
private void ApplyReorderedSongs(PlaylistSong[] playlistSongs)
{
// TODO: Performance improvements
int currentIndex = index;
// UpdateFilteredSongs assumes the projection order matches Playlist.Songs order,
// so remove reordered songs first to let them be reinserted at their new positions.
foreach (PlaylistSong playlistSong in playlistSongs)
{
PlaylistSongs.Insert(currentIndex++, playlistSong);
}
UpdateFilteredSongs();
}
private void RemoveSongsFromCollection(PlaylistSong[] playlistSongs)
{
foreach (PlaylistSong playlistSong in playlistSongs)
{
PlaylistSongs.Remove(playlistSong);
FilteredPlaylistSongs.Remove(playlistSong);
}
UpdateFilteredSongs();

View File

@@ -184,11 +184,11 @@
Name="PlaylistListView"
ItemsSource="{Binding FilteredPlaylistSongs}"
ItemTemplate="{StaticResource SongTemplate}"
CanReorderItems="True"
CanDragItems="True"
CanReorderItems="{Binding CanReorderSongs, Mode=OneWay}"
CanDragItems="{Binding CanReorderSongs, Mode=OneWay}"
DragItemsStarting="PlaylistListView_DragItemsStarting"
DragItemsCompleted="PlaylistListView_DragItemsCompleted"
AllowDrop="True"
AllowDrop="{Binding CanReorderSongs, Mode=OneWay}"
SelectionMode="Extended"
SelectionChanged="PlaylistListView_SelectionChanged">
<ListView.ContextFlyout>