/// <summary> /// Add the songs from the playlist to the Now Playing list /// If this set is replacing the current contents (clearFirst == true ) then clear the Now Playimng list /// first. /// If a resume has been selected and the current contents are being replaced then add all of the /// playlist's songs but set the current song to the resume point. If resume has been selected and the playlist is /// being added to then only add the playlist songs from its resume point. Don't change the resume point in the source playlist. /// If resume has not been selected then add all the playlist's contents and reset the playlist's restore point /// </summary> /// <param name="playlistToAdd"></param> /// <param name="clearFirst"></param> /// <param name="resume"></param> public static void AddPlaylistToNowPlayingList(Playlist playlistToAdd, bool clearFirst, bool resume) { // Should the Now Playing playlist be cleared first if (clearFirst == true) { ClearNowPlayingList(); } // Assume we're going to play a new list from the start int newCurrentIndex = 0; if (resume == true) { if (clearFirst == true) { NowPlayingViewModel.NowPlayingPlaylist.AddSongs(playlistToAdd.GetSongsForPlayback(false)); newCurrentIndex = playlistToAdd.InProgressIndex; } else { NowPlayingViewModel.NowPlayingPlaylist.AddSongs(playlistToAdd.GetSongsForPlayback(true)); } } else { NowPlayingViewModel.NowPlayingPlaylist.AddSongs(ApplyShuffle(playlistToAdd.GetSongsForPlayback(false))); playlistToAdd.SongIndex = 0; } // If the Now Playing list was cleared then play the specified song SetStartingPointForNewList(clearFirst, newCurrentIndex); // Report change to UI DataReporter?.DataAvailable(); }
/// <summary> /// Called when a AlbumPlayedStateChangedMessage had been received. /// If the album is in the library being displayed then refresh the display /// </summary> /// <param name="message"></param> private static void AlbumChanged(Album changedAlbum) { // Only process this album if it is in the same library as is being displayed // It may be in another library if this is being called as part of a library synchronisation process if (changedAlbum.LibraryId == ArtistsViewModel.LibraryId) { DataReporter?.DataAvailable(); } }
/// <summary> /// Called when a AlbumPlayedStateChangedMessage had been received. /// If this album is being displayed then inform the adapter of the data change /// </summary> /// <param name="changedAlbum"></param> private static void AlbumChanged(Album changedAlbum) { // Only process this if this album is in the library being displayed if (changedAlbum.LibraryId == AlbumsViewModel.LibraryId) { // Is this album being displayed if (AlbumsViewModel.Albums.Any(album => album.Id == changedAlbum.Id) == true) { DataReporter?.DataAvailable(); } } }
/// <summary> /// Sort the Artists according to the currently selected sort order /// </summary> public static void SortArtists() => Task.Run(() => { // Clear the indexing collections (in case they are not used in the new sort order) ArtistsViewModel.FastScrollSections = null; ArtistsViewModel.FastScrollSectionLookup = null; switch (ArtistsViewModel.BaseModel.SortSelector.CurrentSortOrder) { case SortSelector.SortOrder.alphaDescending: case SortSelector.SortOrder.alphaAscending: { if (ArtistsViewModel.BaseModel.SortSelector.CurrentSortOrder == SortSelector.SortOrder.alphaAscending) { ArtistsViewModel.Artists.Sort((a, b) => a.Name.RemoveThe().CompareTo(b.Name.RemoveThe())); } else { ArtistsViewModel.Artists.Sort((a, b) => b.Name.RemoveThe().CompareTo(a.Name.RemoveThe())); } // Prepare the combined Artist/ArtistAlbum list - this has to be done after the Artists have been sorted but before the scroll indexing PrepareCombinedList(); // Generate the fast scroll data for alpha sorting GenerateIndex((artist) => artist.Name.RemoveThe().Substring(0, 1).ToUpper()); break; } case SortSelector.SortOrder.idAscending: case SortSelector.SortOrder.idDescending: { if (ArtistsViewModel.BaseModel.SortSelector.CurrentSortOrder == SortSelector.SortOrder.idAscending) { ArtistsViewModel.Artists.Sort((a, b) => a.Id.CompareTo(b.Id)); } else { ArtistsViewModel.Artists.Sort((a, b) => b.Id.CompareTo(a.Id)); } // Prepare the combined Artist/ArtistAlbum list - this has to be done after the Artists have been sorted. // No fast scroll indexing is required for Id sort order PrepareCombinedList(); break; } } // Publish the data DataReporter?.DataAvailable(); });
/// <summary> /// Called when the SongPlaylist data is available to be displayed, or needs to be refreshed /// </summary> private static void StorageDataAvailable() { // Save the libray being used locally to detect changes NowPlayingViewModel.LibraryId = ConnectionDetailsModel.LibraryId; // Get the NowPlaying playlist. NowPlayingViewModel.NowPlayingPlaylist = ( SongPlaylist )Playlists.GetNowPlayingPlaylist(NowPlayingViewModel.LibraryId); // Let the playback manager know the current song but don't play it yet NowPlayingViewModel.CurrentSongIndex = Playlists.CurrentSongIndex; new PlaySongMessage() { SongToPlay = NowPlayingViewModel.CurrentSong, DontPlay = true }.Send(); DataReporter?.DataAvailable(); }
/// <summary> /// Add a list of Songs to the Now Playing list /// </summary> /// <param name="songsToAdd"></param> /// <param name="clearFirst"></param> public static void AddSongsToNowPlayingList(IEnumerable <Song> songsToAdd, bool clearFirst) { // Should the Now Playing playlist be cleared first if (clearFirst == true) { ClearNowPlayingList(); } // Add the songs to the playlist. Shuffled if necessary NowPlayingViewModel.NowPlayingPlaylist.AddSongs(ApplyShuffle(songsToAdd.ToList())); // If the Now Playing list was cleared then play the first song SetStartingPointForNewList(clearFirst, 0); // Report change to UI DataReporter?.DataAvailable(); }
/// <summary> /// Called during startup, or library change, when the storage data is available /// </summary> /// <param name="message"></param> private static async void StorageDataAvailable() { // Save the libray being used locally to detect changes PlaylistsViewModel.LibraryId = ConnectionDetailsModel.LibraryId; // Get the Playlists and playlist names. Make sure a copy of the list is used as we're going to sort it PlaylistsViewModel.Playlists = Playlists.GetPlaylistsForLibrary(PlaylistsViewModel.LibraryId).ToList(); PlaylistsViewModel.PlaylistNames = PlaylistsViewModel.Playlists.Select(i => i.Name).ToList(); // To generate the data to be displayed the Playlists need to be sorted. Not a simple sort of course, but the SongPlaylists followed by the // AlbumPlaylists await Task.Run(() => { PlaylistsViewModel.AlbumPlaylists.Clear(); PlaylistsViewModel.SongPlaylists.Clear(); foreach (Playlist playlist in PlaylistsViewModel.Playlists) { if (playlist is SongPlaylist songPlaylist) { PlaylistsViewModel.SongPlaylists.Add(songPlaylist); } else { PlaylistsViewModel.AlbumPlaylists.Add(( AlbumPlaylist )playlist); } } // Sort the playlists by name PlaylistsViewModel.SongPlaylists.Sort((a, b) => a.Name.CompareTo(b.Name)); PlaylistsViewModel.AlbumPlaylists.Sort((a, b) => a.Name.CompareTo(b.Name)); // Now copy to the combined list PlaylistsViewModel.Playlists.Clear(); PlaylistsViewModel.Playlists.AddRange(PlaylistsViewModel.SongPlaylists); PlaylistsViewModel.Playlists.AddRange(PlaylistsViewModel.AlbumPlaylists); }); DataReporter?.DataAvailable(); }
/// <summary> /// Called to delete one or more items from the Now Playing playlist. /// We need to determine the affect that this deletion may have on the index of the currently playing song. /// This can be done by examining the track numbers of the items to be deleted /// </summary> /// <param name="items"></param> public static void DeleteNowPlayingItems(IEnumerable <PlaylistItem> items) { // Record the currently selected song so its track number can be checked after the delete PlaylistItem currentPlaylistItem = null; // If the currently selected song is going to be deleted then invalidate it now // Only carry out these checks if a song has been selected if (NowPlayingViewModel.CurrentSongIndex != -1) { // Check if the items to delete contains the currently selected song if (items.Any(item => (item.Index == NowPlayingViewModel.CurrentSongIndex)) == true) { // The currently selected song is going to be deleted. Set it to invalid NowPlayingViewModel.CurrentSongIndex = -1; new PlaySongMessage() { SongToPlay = NowPlayingViewModel.CurrentSong }.Send(); } else { // Save the current item currentPlaylistItem = NowPlayingViewModel.NowPlayingPlaylist.PlaylistItems[NowPlayingViewModel.CurrentSongIndex]; } } // Delete the entries and report that the list has been updated NowPlayingViewModel.NowPlayingPlaylist.DeletePlaylistItems(items); // Adjust the track numbers NowPlayingViewModel.NowPlayingPlaylist.AdjustTrackNumbers(); // Determine the index of the currently selected song from it's possibly new track number AdjustSelectedSongIndex(currentPlaylistItem); // Report change to UI DataReporter?.DataAvailable(); }
/// <summary> /// Sort the available data according to the current sort option /// </summary> public static void SortData() => Task.Run(() => { // Use the sort order stored in the model SortSelector.SortOrder sortOrder = AlbumsViewModel.BaseModel.SortSelector.CurrentSortOrder; // Clear the indexing collections (in case they are not used in the new sort order) AlbumsViewModel.FastScrollSections = null; AlbumsViewModel.FastScrollSectionLookup = null; // Now do the sorting and indexing according to the sort order switch (sortOrder) { case SortSelector.SortOrder.alphaAscending: case SortSelector.SortOrder.alphaDescending: { if (sortOrder == SortSelector.SortOrder.alphaAscending) { AlbumsViewModel.FilteredAlbums.Sort((a, b) => a.Name.RemoveThe().CompareTo(b.Name.RemoveThe())); } else { AlbumsViewModel.FilteredAlbums.Sort((a, b) => b.Name.RemoveThe().CompareTo(a.Name.RemoveThe())); } AlbumsViewModel.Albums = AlbumsViewModel.FilteredAlbums; GenerateIndex((album, index) => album.Name.RemoveThe().Substring(0, 1).ToUpper()); break; } case SortSelector.SortOrder.idAscending: case SortSelector.SortOrder.idDescending: { // If these entries are filtered then order them by the tag id rather than the album id if (AlbumsViewModel.FilterSelector.CurrentFilter == null) { if (sortOrder == SortSelector.SortOrder.idAscending) { AlbumsViewModel.FilteredAlbums.Sort((a, b) => a.Id.CompareTo(b.Id)); } else { AlbumsViewModel.FilteredAlbums.Sort((a, b) => b.Id.CompareTo(a.Id)); } } else { // Form a lookup table from album identity to index in tagged albums. Dictionary <int, int> albumIdLookup = AlbumsViewModel.FilterSelector.CurrentFilter.TaggedAlbums .Select((ta, index) => new { ta.AlbumId, index }).ToDictionary(pair => pair.AlbumId, pair => pair.index); // Order the albums by the album id list if (sortOrder == SortSelector.SortOrder.idAscending) { AlbumsViewModel.FilteredAlbums = AlbumsViewModel.FilteredAlbums.OrderBy(album => albumIdLookup[album.Id]).ToList(); } else { AlbumsViewModel.FilteredAlbums = AlbumsViewModel.FilteredAlbums.OrderByDescending(album => albumIdLookup[album.Id]).ToList(); } } // No index required when sorted by Id AlbumsViewModel.Albums = AlbumsViewModel.FilteredAlbums; break; } case SortSelector.SortOrder.yearAscending: case SortSelector.SortOrder.yearDescending: { if (sortOrder == SortSelector.SortOrder.yearAscending) { AlbumsViewModel.FilteredAlbums.Sort((a, b) => a.Year.CompareTo(b.Year)); } else { AlbumsViewModel.FilteredAlbums.Sort((a, b) => b.Year.CompareTo(a.Year)); } AlbumsViewModel.Albums = AlbumsViewModel.FilteredAlbums; GenerateIndex((album, index) => album.Year.ToString()); break; } case SortSelector.SortOrder.genreAscending: case SortSelector.SortOrder.genreDescending: { // If there is no GenreSortAlbums collection then make one now if (AlbumsViewModel.GenreSortedAlbums == null) { GenerateGenreAlbumList(); } // We want to keep the AlbumsViewModel.GenreSortedAlbums in ascending order. // So rather than sort the AlbumsViewModel.GenreSortedAlbums we copy it and sort the copy. AlbumsViewModel.Albums = AlbumsViewModel.GenreSortedAlbums.ToList(); // We only need to sort if the order is descending if (sortOrder == SortSelector.SortOrder.genreDescending) { // Reverse it AlbumsViewModel.Albums.Reverse(); } // Generate the fast lookup indexes. If in reverse order do the genre lookup in reverse order as well GenerateIndex((album, index) => AlbumsViewModel.AlbumIndexToGenreLookup[ sortOrder == SortSelector.SortOrder.genreAscending ? index : AlbumsViewModel.Albums.Count - 1 - index]); break; } } // Publish the data DataReporter?.DataAvailable(); });