public void AllArtistViewModelIsSortedFirst() { var allArtists = new ArtistViewModel("All Artists"); var otherArtist = new ArtistViewModel("Aaa", Enumerable.Empty<LocalSong>()); var list = new List<ArtistViewModel> { otherArtist, allArtists }; list.Sort(); Assert.Equal(allArtists, list[0]); Assert.Equal(otherArtist, list[1]); }
private void UpdateSelectableSongs() { IEnumerable <Song> filtered = this.Library.Songs.FilterSongs(this.SearchText).ToList(); var artistInfos = filtered .GroupBy(song => song.Artist) .Select(group => new ArtistViewModel(group.Key, group.Select(song => song.Album).Distinct().Count(), group.Count())) .ToDictionary(model => model.Name); List <string> removableArtists = this.artists .Where(pair => !artistInfos.ContainsKey(pair.Key)) .Select(pair => pair.Key) .ToList(); foreach (string artist in removableArtists) { this.artists.Remove(artist); } foreach (ArtistViewModel artist in artistInfos.Values) { if (this.artists.ContainsKey(artist.Name)) { ArtistViewModel updated = this.artists[artist.Name]; updated.AlbumCount = artist.AlbumCount; updated.SongCount = artist.SongCount; } else { this.artists.Add(artist.Name, artist); } } this.NotifyOfPropertyChange(() => this.Artists); this.allArtistsViewModel.ArtistCount = artistInfos.Count; this.SelectableSongs = filtered .Where(song => this.SelectedArtist.IsAllArtists || song.Artist == this.SelectedArtist.Name) .Select(song => new LocalSongViewModel(song)) .OrderBy(this.SongOrderFunc) .ToList(); this.SelectedSongs = this.SelectableSongs.Take(1); }
public void CertainPrefixesAreSortedCorrectly() { var aPrefixBig = new ArtistViewModel("A b", Enumerable.Empty<LocalSong>()); var aPrefixSmall = new ArtistViewModel("a c", Enumerable.Empty<LocalSong>()); var thePrefixBig = new ArtistViewModel("The d", Enumerable.Empty<LocalSong>()); var thePrefixSmall = new ArtistViewModel("the e", Enumerable.Empty<LocalSong>()); var firstArtist = new ArtistViewModel("Aa", Enumerable.Empty<LocalSong>()); var lastArtist = new ArtistViewModel("Zz", Enumerable.Empty<LocalSong>()); var correctList = new List<ArtistViewModel> { firstArtist, aPrefixBig, aPrefixSmall, thePrefixBig, thePrefixSmall, lastArtist }; var incorrectList = correctList.ToList(); incorrectList.Reverse(); incorrectList.Sort(); Assert.Equal(correctList, incorrectList); }
public LocalViewModel(Library library) : base(library) { library.Updated += (sender, args) => { this.NotifyOfPropertyChange(() => this.Artists); this.UpdateSelectableSongs(); }; this.StatusViewModel = new StatusViewModel(library); this.searchText = String.Empty; this.artists = new Dictionary <string, ArtistViewModel>(); this.allArtistsViewModel = new ArtistViewModel("All Artists"); // We need a default sorting order this.OrderByArtist(); this.SelectedArtist = this.Artists.First(); }
private void UpdateArtists() { var groupedByArtist = this.Library.Songs .ToLookup(x => x.Artist, StringComparer.InvariantCultureIgnoreCase); List <ArtistViewModel> artistsToRemove = this.allArtists.Where(x => !groupedByArtist.Contains(x.Name)).ToList(); artistsToRemove.Remove(this.allArtistsViewModel); this.allArtists.RemoveAll(artistsToRemove); foreach (ArtistViewModel artistViewModel in artistsToRemove) { artistViewModel.Dispose(); } // We use this reverse ordered list of artists so we can priorize the loading of album // covers of artists that we display first in the artist list. This way we can "fake" a // fast loading of all covers, as the user doesn't see most of the artists down the // list. The higher the number, the higher the prioritization. List <string> orderedArtists = groupedByArtist.Select(x => x.Key) .OrderByDescending(SortHelpers.RemoveArtistPrefixes) .ToList(); foreach (var songs in groupedByArtist) { ArtistViewModel model = this.allArtists.FirstOrDefault(x => x.Name.Equals(songs.Key, StringComparison.OrdinalIgnoreCase)); if (model == null) { int priority = orderedArtists.IndexOf(songs.Key) + 1; this.allArtists.Add(new ArtistViewModel(songs.Key, songs, priority)); } else { model.UpdateSongs(songs); } } }
public LocalViewModel(Library library, ViewSettings viewSettings, CoreSettings coreSettings, Guid accessToken) : base(library, coreSettings, accessToken) { if (viewSettings == null) { throw new ArgumentNullException(nameof(viewSettings)); } this.viewSettings = viewSettings; this.artistUpdateSignal = new Subject <Unit>(); this.allArtistsViewModel = new ArtistViewModel("All Artists"); this.allArtists = new ReactiveList <ArtistViewModel> { this.allArtistsViewModel }; this.Artists = this.allArtists.CreateDerivedCollection(x => x, x => x.IsAllArtists || this.filteredSongs.Contains(x.Name), (x, y) => x.CompareTo(y), this.artistUpdateSignal); // We need a default sorting order this.ApplyOrder(SortHelpers.GetOrderByArtist <LocalSongViewModel>, ref this.artistOrder); this.SelectedArtist = this.allArtistsViewModel; var gate = new object(); this.Library.SongsUpdated .Buffer(TimeSpan.FromSeconds(1), RxApp.TaskpoolScheduler) .Where(x => x.Any()) .Select(_ => Unit.Default) .Merge(this.WhenAny(x => x.SearchText, _ => Unit.Default) .Do(_ => this.SelectedArtist = this.allArtistsViewModel)) .Synchronize(gate) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => { this.UpdateSelectableSongs(); this.UpdateArtists(); }); this.WhenAnyValue(x => x.SelectedArtist) .Skip(1) .Synchronize(gate) .Subscribe(_ => this.UpdateSelectableSongs()); this.playNowCommand = ReactiveCommand.CreateAsyncTask(this.Library.LocalAccessControl.ObserveAccessPermission(accessToken) .Select(x => x == AccessPermission.Admin || !coreSettings.LockPlayPause), _ => { int songIndex = this.SelectableSongs.TakeWhile(x => x.Model != this.SelectedSongs.First().Model).Count(); return(this.Library.PlayInstantlyAsync(this.SelectableSongs.Skip(songIndex).Select(x => x.Model), accessToken)); }); this.showAddSongsHelperMessage = this.Library.SongsUpdated .StartWith(Unit.Default) .Select(_ => this.Library.Songs.Count == 0) .TakeWhile(x => x) .Concat(Observable.Return(false)) .ToProperty(this, x => x.ShowAddSongsHelperMessage); this.isUpdating = this.Library.WhenAnyValue(x => x.IsUpdating) .ToProperty(this, x => x.IsUpdating); this.OpenTagEditor = ReactiveCommand.Create(this.WhenAnyValue(x => x.SelectedSongs, x => x.Any())); }