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

View File

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