// Copyright (c) Arlo Godfrey. All Rights Reserved. // Licensed under the GNU Lesser General Public License, Version 3.0 with additional terms. // See the LICENSE, LICENSE.LESSER and LICENSE.ADDITIONAL files in the project root for more information. using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Diagnostics; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using OwlCore; using OwlCore.Events; using OwlCore.Extensions; using StrixMusic.Sdk.AdapterModels; using StrixMusic.Sdk.AppModels; using StrixMusic.Sdk.CoreModels; using StrixMusic.Sdk.Extensions; using StrixMusic.Sdk.MediaPlayback; using StrixMusic.Sdk.ViewModels.Helpers; namespace StrixMusic.Sdk.ViewModels { /// /// A ViewModel for . /// public sealed class AlbumViewModel : ObservableObject, ISdkViewModel, IAlbum, IArtistCollectionViewModel, ITrackCollectionViewModel, IImageCollectionViewModel, IUrlCollectionViewModel, IGenreCollectionViewModel { private readonly IAlbum _album; private readonly SemaphoreSlim _populateTracksMutex = new(1, 1); private readonly SemaphoreSlim _populateArtistsMutex = new(1, 1); private readonly SemaphoreSlim _populateImagesMutex = new(1, 1); private readonly SemaphoreSlim _populateUrlsMutex = new(1, 1); private readonly SemaphoreSlim _populateGenresMutex = new(1, 1); private readonly SynchronizationContext _syncContext; /// /// Initializes a new instance of the class. /// /// public AlbumViewModel(IAlbum album) { _syncContext = SynchronizationContext.Current; _album = album; Tracks = new ObservableCollection(); Artists = new ObservableCollection(); UnsortedTracks = new ObservableCollection(); UnsortedArtists = new ObservableCollection(); Images = new ObservableCollection(); Genres = new ObservableCollection(); Urls = new ObservableCollection(); if (album.RelatedItems != null) RelatedItems = new PlayableCollectionGroupViewModel(album.RelatedItems); PauseTrackCollectionAsyncCommand = new AsyncRelayCommand(PauseTrackCollectionAsync); PlayTrackCollectionAsyncCommand = new AsyncRelayCommand(PlayTrackCollectionAsync); PauseArtistCollectionAsyncCommand = new AsyncRelayCommand(PauseArtistCollectionAsync); PlayArtistCollectionAsyncCommand = new AsyncRelayCommand(PlayArtistCollectionAsync); PlayTrackAsyncCommand = new AsyncRelayCommand((x, y) => _album.PlayTrackCollectionAsync(x ?? ThrowHelper.ThrowArgumentNullException(nameof(x)), y)); PlayArtistAsyncCommand = new AsyncRelayCommand((x, y) => _album.PlayArtistCollectionAsync(x ?? ThrowHelper.ThrowArgumentNullException(nameof(x)), y)); ChangeNameAsyncCommand = new AsyncRelayCommand(ChangeNameInternalAsync); ChangeDescriptionAsyncCommand = new AsyncRelayCommand(ChangeDescriptionAsync); ChangeDurationAsyncCommand = new AsyncRelayCommand(ChangeDurationAsync); PopulateMoreTracksCommand = new AsyncRelayCommand(PopulateMoreTracksAsync); PopulateMoreImagesCommand = new AsyncRelayCommand(PopulateMoreImagesAsync); PopulateMoreArtistsCommand = new AsyncRelayCommand(PopulateMoreArtistsAsync); PopulateMoreGenresCommand = new AsyncRelayCommand(PopulateMoreGenresAsync); PopulateMoreUrlsCommand = new AsyncRelayCommand(PopulateMoreUrlsAsync); InitImageCollectionAsyncCommand = new AsyncRelayCommand(InitImageCollectionAsync); InitTrackCollectionAsyncCommand = new AsyncRelayCommand(InitTrackCollectionAsync); InitGenreCollectionAsyncCommand = new AsyncRelayCommand(InitGenreCollectionAsync); InitArtistCollectionAsyncCommand = new AsyncRelayCommand(InitArtistCollectionAsync); ChangeTrackCollectionSortingTypeCommand = new RelayCommand(x => SortTrackCollection(x, CurrentTracksSortingDirection)); ChangeTrackCollectionSortingDirectionCommand = new RelayCommand(x => SortTrackCollection(CurrentTracksSortingType, x)); ChangeArtistCollectionSortingTypeCommand = new RelayCommand(x => SortArtistCollection(x, CurrentArtistSortingDirection)); ChangeArtistCollectionSortingDirectionCommand = new RelayCommand(x => SortArtistCollection(CurrentArtistSortingType, x)); AttachEvents(); } private void AttachEvents() { PlaybackStateChanged += AlbumPlaybackStateChanged; DescriptionChanged += AlbumDescriptionChanged; DatePublishedChanged += AlbumDatePublishedChanged; NameChanged += AlbumNameChanged; LastPlayedChanged += OnLastPlayedChanged; DownloadInfoChanged += OnDownloadInfoChanged; IsPlayTrackCollectionAsyncAvailableChanged += OnIsPlayTrackCollectionAsyncAvailableChanged; IsPauseTrackCollectionAsyncAvailableChanged += OnIsPauseTrackCollectionAsyncAvailableChanged; IsPlayArtistCollectionAsyncAvailableChanged += OnIsPlayArtistCollectionAsyncAvailableChanged; IsPauseArtistCollectionAsyncAvailableChanged += OnIsPauseArtistCollectionAsyncAvailableChanged; IsChangeNameAsyncAvailableChanged += OnIsChangeNameAsyncAvailableChanged; IsChangeDurationAsyncAvailableChanged += OnIsChangeDurationAsyncAvailableChanged; IsChangeDescriptionAsyncAvailableChanged += OnIsChangeDescriptionAsyncAvailableChanged; IsChangeDatePublishedAsyncAvailableChanged += OnIsChangeDatePublishedAsyncAvailableChanged; TracksCountChanged += OnTrackItemsCountChanged; TracksChanged += AlbumViewModel_TrackItemsChanged; ArtistItemsCountChanged += OnArtistItemsCountChanged; ArtistItemsChanged += OnArtistItemsChanged; ImagesCountChanged += OnImagesCountChanged; ImagesChanged += AlbumViewModel_ImagesChanged; GenresCountChanged += OnGenresItemsCountChanged; GenresChanged += OnGenresChanged; UrlsCountChanged += OnUrlsCountChanged; UrlsChanged += OnUrlsChanged; } private void DetachEvents() { PlaybackStateChanged -= AlbumPlaybackStateChanged; DescriptionChanged -= AlbumDescriptionChanged; DatePublishedChanged -= AlbumDatePublishedChanged; NameChanged -= AlbumNameChanged; LastPlayedChanged -= OnLastPlayedChanged; DownloadInfoChanged -= OnDownloadInfoChanged; IsPlayTrackCollectionAsyncAvailableChanged -= OnIsPlayTrackCollectionAsyncAvailableChanged; IsPauseTrackCollectionAsyncAvailableChanged -= OnIsPauseTrackCollectionAsyncAvailableChanged; IsPlayArtistCollectionAsyncAvailableChanged -= OnIsPlayArtistCollectionAsyncAvailableChanged; IsPauseArtistCollectionAsyncAvailableChanged -= OnIsPauseArtistCollectionAsyncAvailableChanged; IsChangeNameAsyncAvailableChanged -= OnIsChangeNameAsyncAvailableChanged; IsChangeDurationAsyncAvailableChanged -= OnIsChangeDurationAsyncAvailableChanged; IsChangeDescriptionAsyncAvailableChanged -= OnIsChangeDescriptionAsyncAvailableChanged; IsChangeDatePublishedAsyncAvailableChanged -= OnIsChangeDatePublishedAsyncAvailableChanged; TracksCountChanged += OnTrackItemsCountChanged; TracksChanged -= AlbumViewModel_TrackItemsChanged; ArtistItemsCountChanged -= OnArtistItemsCountChanged; ArtistItemsChanged -= OnArtistItemsChanged; ImagesCountChanged -= OnImagesCountChanged; ImagesChanged -= AlbumViewModel_ImagesChanged; GenresCountChanged -= OnGenresItemsCountChanged; GenresChanged -= OnGenresChanged; } /// public event EventHandler? SourcesChanged { add => _album.SourcesChanged += value; remove => _album.SourcesChanged -= value; } /// public event EventHandler? PlaybackStateChanged { add => _album.PlaybackStateChanged += value; remove => _album.PlaybackStateChanged -= value; } /// public event EventHandler? DownloadInfoChanged { add => _album.DownloadInfoChanged += value; remove => _album.DownloadInfoChanged -= value; } /// public event EventHandler? NameChanged { add => _album.NameChanged += value; remove => _album.NameChanged -= value; } /// public event EventHandler? DescriptionChanged { add => _album.DescriptionChanged += value; remove => _album.DescriptionChanged -= value; } /// public event EventHandler? DurationChanged { add => _album.DurationChanged += value; remove => _album.DurationChanged -= value; } /// public event EventHandler? LastPlayedChanged { add => _album.LastPlayedChanged += value; remove => _album.LastPlayedChanged -= value; } /// public event EventHandler? IsChangeNameAsyncAvailableChanged { add => _album.IsChangeNameAsyncAvailableChanged += value; remove => _album.IsChangeNameAsyncAvailableChanged -= value; } /// public event EventHandler? IsChangeDescriptionAsyncAvailableChanged { add => _album.IsChangeDescriptionAsyncAvailableChanged += value; remove => _album.IsChangeDescriptionAsyncAvailableChanged -= value; } /// public event EventHandler? IsChangeDurationAsyncAvailableChanged { add => _album.IsChangeDurationAsyncAvailableChanged += value; remove => _album.IsChangeDurationAsyncAvailableChanged -= value; } /// public event EventHandler? IsChangeDatePublishedAsyncAvailableChanged { add => _album.IsChangeDatePublishedAsyncAvailableChanged += value; remove => _album.IsChangeDatePublishedAsyncAvailableChanged -= value; } /// public event EventHandler? DatePublishedChanged { add => _album.DatePublishedChanged += value; remove => _album.DatePublishedChanged -= value; } /// public event EventHandler? IsPauseTrackCollectionAsyncAvailableChanged { add => _album.IsPauseTrackCollectionAsyncAvailableChanged += value; remove => _album.IsPauseTrackCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? IsPlayTrackCollectionAsyncAvailableChanged { add => _album.IsPlayTrackCollectionAsyncAvailableChanged += value; remove => _album.IsPlayTrackCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? IsPlayArtistCollectionAsyncAvailableChanged { add => _album.IsPlayArtistCollectionAsyncAvailableChanged += value; remove => _album.IsPlayArtistCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? IsPauseArtistCollectionAsyncAvailableChanged { add => _album.IsPauseArtistCollectionAsyncAvailableChanged += value; remove => _album.IsPauseArtistCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? TracksCountChanged { add => _album.TracksCountChanged += value; remove => _album.TracksCountChanged -= value; } /// public event CollectionChangedEventHandler? TracksChanged { add => _album.TracksChanged += value; remove => _album.TracksChanged -= value; } /// public event CollectionChangedEventHandler? ImagesChanged { add => _album.ImagesChanged += value; remove => _album.ImagesChanged -= value; } /// public event EventHandler? ImagesCountChanged { add => _album.ImagesCountChanged += value; remove => _album.ImagesCountChanged -= value; } /// public event CollectionChangedEventHandler? UrlsChanged { add => _album.UrlsChanged += value; remove => _album.UrlsChanged -= value; } /// public event EventHandler? UrlsCountChanged { add => _album.UrlsCountChanged += value; remove => _album.UrlsCountChanged -= value; } /// public event EventHandler? ArtistItemsCountChanged { add => _album.ArtistItemsCountChanged += value; remove => _album.ArtistItemsCountChanged -= value; } /// public event CollectionChangedEventHandler? ArtistItemsChanged { add => _album.ArtistItemsChanged += value; remove => _album.ArtistItemsChanged -= value; } /// public event CollectionChangedEventHandler? GenresChanged { add => _album.GenresChanged += value; remove => _album.GenresChanged -= value; } /// public event EventHandler? GenresCountChanged { add => _album.GenresCountChanged += value; remove => _album.GenresCountChanged -= value; } private void AlbumNameChanged(object sender, string e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Name)), null); private void AlbumDescriptionChanged(object sender, string? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Description)), null); private void AlbumPlaybackStateChanged(object sender, PlaybackState e) => _syncContext.Post(_ => OnPropertyChanged(nameof(PlaybackState)), null); private void OnDownloadInfoChanged(object sender, DownloadInfo e) => _syncContext.Post(_ => OnPropertyChanged(nameof(DownloadInfo)), null); private void AlbumDatePublishedChanged(object sender, DateTime? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(DatePublished)), null); private void OnTrackItemsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalTrackCount)), null); private void OnImagesCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalImageCount)), null); private void OnUrlsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalUrlCount)), null); private void OnArtistItemsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalArtistItemsCount)), null); private void OnGenresItemsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalGenreCount)), null); private void OnLastPlayedChanged(object sender, DateTime? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(LastPlayed)), null); private void OnIsChangeDescriptionAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsChangeDescriptionAsyncAvailable)), null); private void OnIsChangeDurationAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsChangeDurationAsyncAvailable)), null); private void OnIsChangeNameAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsChangeNameAsyncAvailable)), null); private void OnIsPauseTrackCollectionAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsPauseTrackCollectionAsyncAvailable)), null); private void OnIsPlayTrackCollectionAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsPlayTrackCollectionAsyncAvailable)), null); private void OnIsPauseArtistCollectionAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsPauseArtistCollectionAsyncAvailable)), null); private void OnIsPlayArtistCollectionAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsPlayArtistCollectionAsyncAvailable)), null); private void OnIsChangeDatePublishedAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsChangeDatePublishedAsyncAvailableChanged)), null); private void AlbumViewModel_TrackItemsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => { if (CurrentTracksSortingType == TrackSortingType.Unsorted) { Tracks.ChangeCollection(addedItems, removedItems, x => new TrackViewModel(x.Data)); } else { // Make sure both ordered and unordered tracks are updated. UnsortedTracks.ChangeCollection(addedItems, removedItems, x => new TrackViewModel(x.Data)); foreach (var item in UnsortedTracks) { if (!Tracks.Contains(item)) Tracks.Add(item); } foreach (var item in Tracks.ToArray()) { if (!UnsortedTracks.Contains(item)) Tracks.Remove(item); } SortTrackCollection(CurrentTracksSortingType, CurrentTracksSortingDirection); } }, null); private void OnArtistItemsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => { if (CurrentArtistSortingType == ArtistSortingType.Unsorted) { Artists.ChangeCollection(addedItems, removedItems, item => item.Data switch { IArtist artist => new ArtistViewModel(artist), IArtistCollection collection => new ArtistCollectionViewModel(collection), _ => ThrowHelper.ThrowNotSupportedException( $"{item.Data.GetType()} not supported for adding to {GetType()}") }); } else { // Make sure both ordered and unordered artists are updated. UnsortedArtists.ChangeCollection(addedItems, removedItems, item => item.Data switch { IArtist artist => new ArtistViewModel(artist), IArtistCollection collection => new ArtistCollectionViewModel(collection), _ => ThrowHelper.ThrowNotSupportedException( $"{item.Data.GetType()} not supported for adding to {GetType()}") }); foreach (var item in UnsortedArtists) { if (!Artists.Contains(item)) Artists.Add(item); } foreach (var item in Artists.ToArray()) { if (!UnsortedArtists.Contains(item)) Artists.Remove(item); } SortArtistCollection(CurrentArtistSortingType, CurrentArtistSortingDirection); } }, null); private void AlbumViewModel_ImagesChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => Images.ChangeCollection(addedItems, removedItems), null); private void OnGenresChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => Genres.ChangeCollection(addedItems, removedItems), null); private void OnUrlsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => Urls.ChangeCollection(addedItems, removedItems), null); /// public string Id => _album.Id; /// /// The merged sources for this album. /// public IReadOnlyList Sources => _album.GetSources(); /// /// The merged sources for this album. /// IReadOnlyList IMerged.Sources => Sources; /// IReadOnlyList IMerged.Sources => Sources; /// IReadOnlyList IMerged.Sources => Sources; /// IReadOnlyList IMerged.Sources => Sources; /// IReadOnlyList IMerged.Sources => Sources; /// IReadOnlyList IMerged.Sources => Sources; /// IReadOnlyList IMerged.Sources => Sources; /// IReadOnlyList IMerged.Sources => Sources; /// public TimeSpan Duration => _album.Duration; /// public DateTime? LastPlayed => _album.LastPlayed; /// public DateTime? AddedAt => _album.AddedAt; /// public IPlayableCollectionGroup? RelatedItems { get; } /// /// The tracks for this album. /// public ObservableCollection Tracks { get; } /// public ObservableCollection UnsortedTracks { get; } /// public ObservableCollection UnsortedArtists { get; } /// public ObservableCollection Artists { get; } /// public ObservableCollection Genres { get; } /// public ObservableCollection Images { get; } /// public ObservableCollection Urls { get; } /// public string Name => _album.Name; /// public int TotalTrackCount => _album.TotalTrackCount; /// public int TotalArtistItemsCount => _album.TotalArtistItemsCount; /// public int TotalImageCount => _album.TotalImageCount; /// public int TotalGenreCount => _album.TotalGenreCount; /// public int TotalUrlCount => _album.TotalUrlCount; /// public bool IsPlayTrackCollectionAsyncAvailable => _album.IsPlayTrackCollectionAsyncAvailable; /// public bool IsPauseTrackCollectionAsyncAvailable => _album.IsPauseTrackCollectionAsyncAvailable; /// public bool IsPlayArtistCollectionAsyncAvailable => _album.IsPlayArtistCollectionAsyncAvailable; /// public bool IsPauseArtistCollectionAsyncAvailable => _album.IsPauseArtistCollectionAsyncAvailable; /// public Task PlayTrackCollectionAsync(CancellationToken cancellationToken = default) => _album.PlayTrackCollectionAsync(cancellationToken); /// public Task PauseTrackCollectionAsync(CancellationToken cancellationToken = default) => _album.PauseTrackCollectionAsync(cancellationToken); /// public Task PlayArtistCollectionAsync(CancellationToken cancellationToken = default) => _album.PlayArtistCollectionAsync(cancellationToken); /// public Task PauseArtistCollectionAsync(CancellationToken cancellationToken = default) => _album.PauseArtistCollectionAsync(cancellationToken); /// public Task PlayTrackCollectionAsync(ITrack track, CancellationToken cancellationToken = default) => _album.PlayTrackCollectionAsync(track, cancellationToken); /// public Task PlayArtistCollectionAsync(IArtistCollectionItem artistItem, CancellationToken cancellationToken = default) => _album.PlayArtistCollectionAsync(artistItem, cancellationToken); /// public DateTime? DatePublished => _album.DatePublished; /// public string? Description => _album.Description; /// public PlaybackState PlaybackState => _album.PlaybackState; /// public DownloadInfo DownloadInfo => _album.DownloadInfo; /// public bool IsChangeNameAsyncAvailable => _album.IsChangeNameAsyncAvailable; /// public bool IsChangeDescriptionAsyncAvailable => _album.IsChangeDescriptionAsyncAvailable; /// public bool IsChangeDatePublishedAsyncAvailable => _album.IsChangeDatePublishedAsyncAvailable; /// public bool IsChangeDurationAsyncAvailable => _album.IsChangeDurationAsyncAvailable; /// public Task ChangeNameAsync(string name, CancellationToken cancellationToken = default) => ChangeNameInternalAsync(name, cancellationToken); /// public Task ChangeDescriptionAsync(string? description, CancellationToken cancellationToken = default) => _album.ChangeDescriptionAsync(description, cancellationToken); /// public Task ChangeDurationAsync(TimeSpan duration, CancellationToken cancellationToken = default) => _album.ChangeDurationAsync(duration, cancellationToken); /// public Task IsAddImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsAddImageAvailableAsync(index, cancellationToken); /// public Task IsAddTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsAddTrackAvailableAsync(index, cancellationToken); /// public Task IsAddArtistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsAddArtistItemAvailableAsync(index, cancellationToken); /// public Task IsAddGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsAddGenreAvailableAsync(index, cancellationToken); /// public Task IsAddUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsAddUrlAvailableAsync(index, cancellationToken); /// public Task IsRemoveArtistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsRemoveArtistItemAvailableAsync(index, cancellationToken); /// public Task IsRemoveImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsRemoveImageAvailableAsync(index, cancellationToken); /// public Task IsRemoveGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsRemoveGenreAvailableAsync(index, cancellationToken); /// public Task IsRemoveTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsRemoveTrackAvailableAsync(index, cancellationToken); /// public Task IsRemoveUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _album.IsRemoveUrlAvailableAsync(index, cancellationToken); /// public Task ChangeDatePublishedAsync(DateTime datePublished, CancellationToken cancellationToken = default) => _album.ChangeDatePublishedAsync(datePublished, cancellationToken); /// public Task StartDownloadOperationAsync(DownloadOperation operation, CancellationToken cancellationToken = default) => _album.StartDownloadOperationAsync(operation, cancellationToken); /// public Task AddTrackAsync(ITrack track, int index, CancellationToken cancellationToken = default) => _album.AddTrackAsync(track, index, cancellationToken); /// public Task RemoveTrackAsync(int index, CancellationToken cancellationToken = default) => _album.RemoveTrackAsync(index, cancellationToken); /// public Task AddImageAsync(IImage image, int index, CancellationToken cancellationToken = default) => _album.AddImageAsync(image, index, cancellationToken); /// public Task RemoveImageAsync(int index, CancellationToken cancellationToken = default) => _album.RemoveImageAsync(index, cancellationToken); /// public Task AddArtistItemAsync(IArtistCollectionItem artistItem, int index, CancellationToken cancellationToken = default) => _album.AddArtistItemAsync(artistItem, index, cancellationToken); /// public Task RemoveArtistItemAsync(int index, CancellationToken cancellationToken = default) => _album.RemoveArtistItemAsync(index, cancellationToken); /// public Task AddGenreAsync(IGenre genre, int index, CancellationToken cancellationToken = default) => _album.AddGenreAsync(genre, index, cancellationToken); /// public Task RemoveGenreAsync(int index, CancellationToken cancellationToken = default) => _album.RemoveGenreAsync(index, cancellationToken); /// public Task AddUrlAsync(IUrl url, int index, CancellationToken cancellationToken = default) => _album.AddUrlAsync(url, index, cancellationToken); /// public Task RemoveUrlAsync(int index, CancellationToken cancellationToken = default) => _album.RemoveUrlAsync(index, cancellationToken); /// public void SortTrackCollection(TrackSortingType trackSorting, SortDirection sortDirection) { CurrentTracksSortingType = trackSorting; CurrentTracksSortingDirection = sortDirection; CollectionSorting.SortTracks(Tracks, trackSorting, sortDirection, UnsortedTracks); } /// public void SortArtistCollection(ArtistSortingType artistSorting, SortDirection sortDirection) { CurrentArtistSortingType = artistSorting; CurrentArtistSortingDirection = sortDirection; CollectionSorting.SortArtists(Artists, artistSorting, sortDirection, UnsortedArtists); } /// public IAsyncEnumerable GetTracksAsync(int limit, int offset, CancellationToken cancellationToken = default) => _album.GetTracksAsync(limit, offset, cancellationToken); /// public async Task PopulateMoreTracksAsync(int limit, CancellationToken cancellationToken = default) { using (await Flow.EasySemaphore(_populateTracksMutex)) { using var releaseReg = cancellationToken.Register(() => _populateTracksMutex.Release()); _syncContext.Post(async _ => { await foreach (var item in _album.GetTracksAsync(limit, Tracks.Count, cancellationToken)) { var tvm = new TrackViewModel(item); Tracks.Add(tvm); UnsortedTracks.Add(tvm); } }, null); } } /// public IAsyncEnumerable GetImagesAsync(int limit, int offset, CancellationToken cancellationToken = default) => _album.GetImagesAsync(limit, offset, cancellationToken); /// public IAsyncEnumerable GetArtistItemsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _album.GetArtistItemsAsync(limit, offset, cancellationToken); /// public IAsyncEnumerable GetGenresAsync(int limit, int offset, CancellationToken cancellationToken = default) => _album.GetGenresAsync(limit, offset, cancellationToken); /// public IAsyncEnumerable GetUrlsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _album.GetUrlsAsync(limit, offset, cancellationToken); /// public async Task PopulateMoreArtistsAsync(int limit, CancellationToken cancellationToken = default) { using (await Flow.EasySemaphore(_populateArtistsMutex)) { using var releaseReg = cancellationToken.Register(() => _populateArtistsMutex.Release()); _syncContext.Post(async _ => { await foreach (var item in _album.GetArtistItemsAsync(limit, Artists.Count, cancellationToken)) { switch (item) { case IArtist artist: var avm = new ArtistViewModel(artist); Artists.Add(avm); UnsortedArtists.Add(avm); break; case IArtistCollection collection: var acvm = new ArtistCollectionViewModel(collection); Artists.Add(acvm); UnsortedArtists.Add(acvm); break; } } }, null); } } /// public async Task PopulateMoreImagesAsync(int limit, CancellationToken cancellationToken = default) { using (await Flow.EasySemaphore(_populateImagesMutex)) { using var releaseReg = cancellationToken.Register(() => _populateImagesMutex.Release()); _syncContext.Post(async _ => { await foreach (var item in _album.GetImagesAsync(limit, Images.Count, cancellationToken)) Images.Add(item); }, null); } } /// public async Task PopulateMoreUrlsAsync(int limit, CancellationToken cancellationToken = default) { using (await Flow.EasySemaphore(_populateUrlsMutex)) { using var releaseReg = cancellationToken.Register(() => _populateUrlsMutex.Release()); _syncContext.Post(async _ => { await foreach (var item in _album.GetUrlsAsync(limit, Urls.Count, cancellationToken)) Urls.Add(item); }, null); } } /// public async Task PopulateMoreGenresAsync(int limit, CancellationToken cancellationToken = default) { using (await Flow.EasySemaphore(_populateGenresMutex)) { using var releaseReg = cancellationToken.Register(() => _populateGenresMutex.Release()); _syncContext.Post(async _ => { await foreach (var item in _album.GetGenresAsync(limit, Genres.Count, cancellationToken)) Genres.Add(item); }, null); } } /// public TrackSortingType CurrentTracksSortingType { get; private set; } /// public SortDirection CurrentTracksSortingDirection { get; private set; } /// public ArtistSortingType CurrentArtistSortingType { get; private set; } /// public SortDirection CurrentArtistSortingDirection { get; private set; } /// public IRelayCommand ChangeTrackCollectionSortingTypeCommand { get; } /// public IRelayCommand ChangeTrackCollectionSortingDirectionCommand { get; } /// public IRelayCommand ChangeArtistCollectionSortingTypeCommand { get; } /// public IRelayCommand ChangeArtistCollectionSortingDirectionCommand { get; } /// public IAsyncRelayCommand PopulateMoreTracksCommand { get; } /// public IAsyncRelayCommand PopulateMoreImagesCommand { get; } /// public IAsyncRelayCommand PopulateMoreGenresCommand { get; } /// public IAsyncRelayCommand PopulateMoreUrlsCommand { get; } /// public IAsyncRelayCommand PlayTrackCollectionAsyncCommand { get; } /// public IAsyncRelayCommand PlayTrackAsyncCommand { get; } /// public IAsyncRelayCommand PauseTrackCollectionAsyncCommand { get; } /// public IAsyncRelayCommand PopulateMoreArtistsCommand { get; } /// public IAsyncRelayCommand PlayArtistCollectionAsyncCommand { get; } /// public IAsyncRelayCommand PlayArtistAsyncCommand { get; } /// public IAsyncRelayCommand PauseArtistCollectionAsyncCommand { get; } /// /// Attempts to change the name of the album, if supported. /// public IAsyncRelayCommand ChangeNameAsyncCommand { get; } /// /// Attempts to change the description of the album, if supported. /// public IAsyncRelayCommand ChangeDescriptionAsyncCommand { get; } /// /// Attempts to change the duration of the album, if supported. /// public IAsyncRelayCommand ChangeDurationAsyncCommand { get; } /// public IAsyncRelayCommand InitArtistCollectionAsyncCommand { get; } /// public IAsyncRelayCommand InitImageCollectionAsyncCommand { get; } /// public IAsyncRelayCommand InitTrackCollectionAsyncCommand { get; } /// public IAsyncRelayCommand InitGenreCollectionAsyncCommand { get; } /// public Task InitArtistCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.ArtistCollection(this, cancellationToken); /// public Task InitImageCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.ImageCollection(this, cancellationToken); /// public Task InitTrackCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.TrackCollection(this, cancellationToken); /// public Task InitGenreCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.GenreCollection(this, cancellationToken); /// public bool Equals(ICoreAlbumCollectionItem other) => _album.Equals(other); /// public bool Equals(ICoreArtistCollectionItem other) => _album.Equals(other); /// public bool Equals(ICoreImageCollection other) => _album.Equals(other); /// public bool Equals(ICoreArtistCollection other) => _album.Equals(other); /// public bool Equals(ICoreTrackCollection other) => _album.Equals(other); /// public bool Equals(ICoreGenreCollection other) => _album.Equals(other); /// public bool Equals(ICoreUrlCollection other) => _album.Equals(other); /// public bool Equals(ICoreAlbum other) => _album.Equals(other); /// public Task InitAsync(CancellationToken cancellationToken = default) { if (IsInitialized) return Task.CompletedTask; IsInitialized = true; return Task.WhenAll(InitImageCollectionAsync(cancellationToken), InitTrackCollectionAsync(cancellationToken), InitGenreCollectionAsync(cancellationToken), InitArtistCollectionAsync(cancellationToken)); } /// public bool IsInitialized { get; private set; } private Task ChangeNameInternalAsync(string? name, CancellationToken cancellationToken = default) { Guard.IsNotNull(name, nameof(name)); return _album.ChangeNameAsync(name, cancellationToken); } /// public ValueTask DisposeAsync() { DetachEvents(); return _album.DisposeAsync(); } } }