// 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.BaseModels; 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 ArtistViewModel : ObservableObject, IArtist, ISdkViewModel, IAlbumCollectionViewModel, ITrackCollectionViewModel, IImageCollectionViewModel, IGenreCollectionViewModel, IUrlCollectionViewModel { private readonly IArtist _artist; private readonly SemaphoreSlim _populateTracksMutex = new(1, 1); private readonly SemaphoreSlim _populateAlbumsMutex = new(1, 1); private readonly SemaphoreSlim _populateImagesMutex = new(1, 1); private readonly SemaphoreSlim _populateGenresMutex = new(1, 1); private readonly SemaphoreSlim _populateUrlsMutex = new(1, 1); private readonly SynchronizationContext _syncContext; /// /// Initializes a new instance of the class. /// /// The to wrap. public ArtistViewModel(IArtist artist) { _syncContext = SynchronizationContext.Current; _artist = artist; if (_artist.RelatedItems != null) RelatedItems = new PlayableCollectionGroupViewModel(_artist.RelatedItems); UnsortedTracks = new ObservableCollection(); UnsortedAlbums = new ObservableCollection(); Tracks = new ObservableCollection(); Albums = new ObservableCollection(); Images = new ObservableCollection(); Genres = new ObservableCollection(); Urls = new ObservableCollection(); PlayTrackCollectionAsyncCommand = new AsyncRelayCommand(PlayTrackCollectionAsync); PauseTrackCollectionAsyncCommand = new AsyncRelayCommand(PauseTrackCollectionAsync); PlayAlbumCollectionAsyncCommand = new AsyncRelayCommand(PlayAlbumCollectionAsync); PauseAlbumCollectionAsyncCommand = new AsyncRelayCommand(PauseAlbumCollectionAsync); PlayTrackAsyncCommand = new AsyncRelayCommand((x, y) => _artist.PlayTrackCollectionAsync(x ?? ThrowHelper.ThrowArgumentNullException(nameof(x)), y)); PlayAlbumAsyncCommand = new AsyncRelayCommand((x, y) => _artist.PlayAlbumCollectionAsync(x ?? ThrowHelper.ThrowArgumentNullException(nameof(x)), y)); ChangeNameAsyncCommand = new AsyncRelayCommand(ChangeNameInternalAsync); ChangeDescriptionAsyncCommand = new AsyncRelayCommand(ChangeDescriptionAsync); ChangeDurationAsyncCommand = new AsyncRelayCommand(ChangeDurationAsync); PopulateMoreAlbumsCommand = new AsyncRelayCommand(PopulateMoreAlbumsAsync); PopulateMoreTracksCommand = new AsyncRelayCommand(PopulateMoreTracksAsync); PopulateMoreImagesCommand = new AsyncRelayCommand(PopulateMoreImagesAsync); PopulateMoreGenresCommand = new AsyncRelayCommand(PopulateMoreGenresAsync); PopulateMoreUrlsCommand = new AsyncRelayCommand(PopulateMoreUrlsAsync); InitAlbumCollectionAsyncCommand = new AsyncRelayCommand(InitAlbumCollectionAsync); InitGenreCollectionAsyncCommand = new AsyncRelayCommand(InitGenreCollectionAsync); InitImageCollectionAsyncCommand = new AsyncRelayCommand(InitImageCollectionAsync); InitTrackCollectionAsyncCommand = new AsyncRelayCommand(InitTrackCollectionAsync); ChangeAlbumCollectionSortingTypeCommand = new RelayCommand(x => SortAlbumCollection(x, CurrentAlbumSortingDirection)); ChangeAlbumCollectionSortingDirectionCommand = new RelayCommand(x => SortAlbumCollection(CurrentAlbumSortingType, x)); ChangeTrackCollectionSortingTypeCommand = new RelayCommand(x => SortTrackCollection(x, CurrentTracksSortingDirection)); ChangeTrackCollectionSortingDirectionCommand = new RelayCommand(x => SortTrackCollection(CurrentTracksSortingType, x)); AttachEvents(); } private void AttachEvents() { PlaybackStateChanged += ArtistPlaybackStateChanged; DescriptionChanged += ArtistDescriptionChanged; NameChanged += ArtistNameChanged; LastPlayedChanged += OnLastPlayedChanged; DownloadInfoChanged += OnDownloadInfoChanged; IsPlayTrackCollectionAsyncAvailableChanged += OnIsPlayTrackCollectionAsyncAvailableChanged; IsPauseTrackCollectionAsyncAvailableChanged += OnIsPauseTrackCollectionAsyncAvailableChanged; IsPlayAlbumCollectionAsyncAvailableChanged += OnIsPlayAlbumCollectionAsyncAvailableChanged; IsPauseAlbumCollectionAsyncAvailableChanged += OnIsPauseAlbumCollectionAsyncAvailableChanged; IsChangeNameAsyncAvailableChanged += OnIsChangeNameAsyncAvailableChanged; IsChangeDurationAsyncAvailableChanged += OnIsChangeDurationAsyncAvailableChanged; IsChangeDescriptionAsyncAvailableChanged += OnIsChangeDescriptionAsyncAvailableChanged; AlbumItemsCountChanged += Artist_AlbumItemsCountChanged; TracksCountChanged += ArtistOnTrackItemsCountChanged; ImagesCountChanged += ArtistViewModel_ImagesCountChanged; GenresCountChanged += ArtistViewModel_GenresCountChanged; UrlsCountChanged += ArtistViewModel_UrlsCountChanged; AlbumItemsChanged += ArtistViewModel_AlbumItemsChanged; TracksChanged += ArtistViewModel_TrackItemsChanged; ImagesChanged += ArtistViewModel_ImagesChanged; GenresChanged += ArtistViewModel_GenresChanged; ImagesChanged += ArtistViewModel_ImagesChanged; } private void DetachEvents() { PlaybackStateChanged -= ArtistPlaybackStateChanged; DescriptionChanged -= ArtistDescriptionChanged; NameChanged -= ArtistNameChanged; LastPlayedChanged -= OnLastPlayedChanged; DownloadInfoChanged -= OnDownloadInfoChanged; IsPlayTrackCollectionAsyncAvailableChanged -= OnIsPlayTrackCollectionAsyncAvailableChanged; IsPauseTrackCollectionAsyncAvailableChanged -= OnIsPauseTrackCollectionAsyncAvailableChanged; IsPlayAlbumCollectionAsyncAvailableChanged -= OnIsPlayAlbumCollectionAsyncAvailableChanged; IsPauseAlbumCollectionAsyncAvailableChanged -= OnIsPauseAlbumCollectionAsyncAvailableChanged; IsChangeNameAsyncAvailableChanged -= OnIsChangeNameAsyncAvailableChanged; IsChangeDurationAsyncAvailableChanged -= OnIsChangeDurationAsyncAvailableChanged; IsChangeDescriptionAsyncAvailableChanged -= OnIsChangeDescriptionAsyncAvailableChanged; AlbumItemsCountChanged -= Artist_AlbumItemsCountChanged; TracksCountChanged -= ArtistOnTrackItemsCountChanged; ImagesCountChanged -= ArtistViewModel_ImagesCountChanged; GenresCountChanged -= ArtistViewModel_GenresCountChanged; AlbumItemsChanged -= ArtistViewModel_AlbumItemsChanged; TracksChanged -= ArtistViewModel_TrackItemsChanged; ImagesChanged -= ArtistViewModel_ImagesChanged; GenresChanged -= ArtistViewModel_GenresChanged; } /// public event EventHandler? SourcesChanged { add => _artist.SourcesChanged += value; remove => _artist.SourcesChanged -= value; } /// public event EventHandler? DurationChanged { add => _artist.DurationChanged += value; remove => _artist.DurationChanged -= value; } /// public event EventHandler? LastPlayedChanged { add => _artist.LastPlayedChanged += value; remove => _artist.LastPlayedChanged -= value; } /// public event EventHandler? IsPlayTrackCollectionAsyncAvailableChanged { add => _artist.IsPlayTrackCollectionAsyncAvailableChanged += value; remove => _artist.IsPlayTrackCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? IsPauseTrackCollectionAsyncAvailableChanged { add => _artist.IsPauseTrackCollectionAsyncAvailableChanged += value; remove => _artist.IsPauseTrackCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? IsPlayAlbumCollectionAsyncAvailableChanged { add => _artist.IsPlayAlbumCollectionAsyncAvailableChanged += value; remove => _artist.IsPlayAlbumCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? IsPauseAlbumCollectionAsyncAvailableChanged { add => _artist.IsPauseAlbumCollectionAsyncAvailableChanged += value; remove => _artist.IsPauseAlbumCollectionAsyncAvailableChanged -= value; } /// public event EventHandler? IsChangeNameAsyncAvailableChanged { add => _artist.IsChangeNameAsyncAvailableChanged += value; remove => _artist.IsChangeNameAsyncAvailableChanged -= value; } /// public event EventHandler? IsChangeDescriptionAsyncAvailableChanged { add => _artist.IsChangeDescriptionAsyncAvailableChanged += value; remove => _artist.IsChangeDescriptionAsyncAvailableChanged -= value; } /// public event EventHandler? IsChangeDurationAsyncAvailableChanged { add => _artist.IsChangeDurationAsyncAvailableChanged += value; remove => _artist.IsChangeDurationAsyncAvailableChanged -= value; } /// public event EventHandler? PlaybackStateChanged { add => _artist.PlaybackStateChanged += value; remove => _artist.PlaybackStateChanged -= value; } /// public event EventHandler? DownloadInfoChanged { add => _artist.DownloadInfoChanged += value; remove => _artist.DownloadInfoChanged -= value; } /// public event EventHandler? NameChanged { add => _artist.NameChanged += value; remove => _artist.NameChanged -= value; } /// public event EventHandler? DescriptionChanged { add => _artist.DescriptionChanged += value; remove => _artist.DescriptionChanged -= value; } /// public event CollectionChangedEventHandler? AlbumItemsChanged { add => _artist.AlbumItemsChanged += value; remove => _artist.AlbumItemsChanged -= value; } /// public event EventHandler? AlbumItemsCountChanged { add => _artist.AlbumItemsCountChanged += value; remove => _artist.AlbumItemsCountChanged -= value; } /// public event CollectionChangedEventHandler? TracksChanged { add => _artist.TracksChanged += value; remove => _artist.TracksChanged -= value; } /// public event EventHandler? TracksCountChanged { add => _artist.TracksCountChanged += value; remove => _artist.TracksCountChanged -= value; } /// public event EventHandler? ImagesCountChanged { add => _artist.ImagesCountChanged += value; remove => _artist.ImagesCountChanged -= value; } /// public event CollectionChangedEventHandler? ImagesChanged { add => _artist.ImagesChanged += value; remove => _artist.ImagesChanged -= value; } /// public event CollectionChangedEventHandler? GenresChanged { add => _artist.GenresChanged += value; remove => _artist.GenresChanged -= value; } /// public event EventHandler? GenresCountChanged { add => _artist.GenresCountChanged += value; remove => _artist.GenresCountChanged -= value; } /// public event CollectionChangedEventHandler? UrlsChanged { add => _artist.UrlsChanged += value; remove => _artist.UrlsChanged -= value; } /// public event EventHandler? UrlsCountChanged { add => _artist.UrlsCountChanged += value; remove => _artist.UrlsCountChanged -= value; } private void ArtistNameChanged(object sender, string e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Name)), null); private void ArtistDescriptionChanged(object sender, string? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Description)), null); private void ArtistPlaybackStateChanged(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 ArtistOnTrackItemsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalTrackCount)), null); private void Artist_AlbumItemsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalAlbumItemsCount)), null); private void ArtistViewModel_ImagesCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalImageCount)), null); private void ArtistViewModel_UrlsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalUrlCount)), null); private void ArtistViewModel_GenresCountChanged(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 OnIsPauseAlbumCollectionAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsPauseAlbumCollectionAsyncAvailable)), null); private void OnIsPlayAlbumCollectionAsyncAvailableChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsPlayAlbumCollectionAsyncAvailable)), null); private void ArtistViewModel_ImagesChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => { Images.ChangeCollection(addedItems, removedItems); }, null); private void ArtistViewModel_GenresChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => { Genres.ChangeCollection(addedItems, removedItems); }, null); private void ArtistViewModel_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 ArtistViewModel_AlbumItemsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ => { if (CurrentAlbumSortingType == AlbumSortingType.Unsorted) { Albums.ChangeCollection(addedItems, removedItems, item => item.Data switch { IAlbum album => new AlbumViewModel(album), IAlbumCollection collection => new AlbumCollectionViewModel(collection), _ => ThrowHelper.ThrowNotSupportedException( $"{item.Data.GetType()} not supported for adding to {GetType()}") }); } else { // Make sure both ordered and unordered albums are updated. UnsortedAlbums.ChangeCollection(addedItems, removedItems, item => item.Data switch { IAlbum album => new AlbumViewModel(album), IAlbumCollection collection => new AlbumCollectionViewModel(collection), _ => ThrowHelper.ThrowNotSupportedException( $"{item.Data.GetType()} not supported for adding to {GetType()}") }); foreach (var item in UnsortedAlbums) { if (!Albums.Contains(item)) Albums.Add(item); } foreach (var item in Albums.ToArray()) { if (!UnsortedAlbums.Contains(item)) Albums.Remove(item); } SortAlbumCollection(CurrentAlbumSortingType, CurrentAlbumSortingDirection); } }, null); /// /// The sources that were merged to form this member. /// public IReadOnlyList Sources => _artist.GetSources(); /// 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 string Id => _artist.Id; /// public TimeSpan Duration => _artist.Duration; /// public DateTime? LastPlayed => _artist.LastPlayed; /// public DateTime? AddedAt => _artist.AddedAt; /// public bool IsInitialized { get; private set; } /// public IPlayableCollectionGroup? RelatedItems { get; } /// public TrackSortingType CurrentTracksSortingType { get; private set; } /// public SortDirection CurrentTracksSortingDirection { get; private set; } /// public AlbumSortingType CurrentAlbumSortingType { get; private set; } /// public SortDirection CurrentAlbumSortingDirection { get; private set; } /// public ObservableCollection Tracks { get; set; } /// public ObservableCollection UnsortedTracks { get; } /// public ObservableCollection Albums { get; } /// public ObservableCollection UnsortedAlbums { get; } /// public ObservableCollection Images { get; } /// public ObservableCollection Genres { get; } /// public ObservableCollection Urls { get; } /// public string Name => _artist.Name; /// public int TotalAlbumItemsCount => _artist.TotalAlbumItemsCount; /// public int TotalTrackCount => _artist.TotalTrackCount; /// public int TotalImageCount => _artist.TotalImageCount; /// public int TotalGenreCount => _artist.TotalGenreCount; /// public int TotalUrlCount => _artist.TotalTrackCount; /// public string? Description => _artist.Description; /// public PlaybackState PlaybackState => _artist.PlaybackState; /// public DownloadInfo DownloadInfo => _artist.DownloadInfo; /// public bool IsPlayTrackCollectionAsyncAvailable => _artist.IsPlayTrackCollectionAsyncAvailable; /// public bool IsPauseTrackCollectionAsyncAvailable => _artist.IsPauseTrackCollectionAsyncAvailable; /// public bool IsPlayAlbumCollectionAsyncAvailable => _artist.IsPlayAlbumCollectionAsyncAvailable; /// public bool IsPauseAlbumCollectionAsyncAvailable => _artist.IsPauseAlbumCollectionAsyncAvailable; /// public bool IsChangeNameAsyncAvailable => _artist.IsChangeNameAsyncAvailable; /// public bool IsChangeDescriptionAsyncAvailable => _artist.IsChangeDescriptionAsyncAvailable; /// public bool IsChangeDurationAsyncAvailable => _artist.IsChangeDurationAsyncAvailable; /// public Task PlayTrackCollectionAsync(CancellationToken cancellationToken = default) => _artist.PlayTrackCollectionAsync(cancellationToken); /// public Task PlayAlbumCollectionAsync(CancellationToken cancellationToken = default) => _artist.PlayAlbumCollectionAsync(cancellationToken); /// public Task PauseTrackCollectionAsync(CancellationToken cancellationToken = default) => _artist.PauseTrackCollectionAsync(cancellationToken); /// public Task PauseAlbumCollectionAsync(CancellationToken cancellationToken = default) => _artist.PauseAlbumCollectionAsync(cancellationToken); /// public Task ChangeNameAsync(string name, CancellationToken cancellationToken = default) => ChangeNameInternalAsync(name, cancellationToken); /// public Task ChangeDescriptionAsync(string? description, CancellationToken cancellationToken = default) => _artist.ChangeDescriptionAsync(description, cancellationToken); /// public Task ChangeDurationAsync(TimeSpan duration, CancellationToken cancellationToken = default) => _artist.ChangeDurationAsync(duration, cancellationToken); /// public Task StartDownloadOperationAsync(DownloadOperation operation, CancellationToken cancellationToken = default) => _artist.StartDownloadOperationAsync(operation, cancellationToken); /// public Task IsAddAlbumItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddAlbumItemAvailableAsync(index, cancellationToken); /// public Task IsAddTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddTrackAvailableAsync(index, cancellationToken); /// public Task IsAddGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddGenreAvailableAsync(index, cancellationToken); /// public Task IsAddImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddImageAvailableAsync(index, cancellationToken); /// public Task IsAddUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsAddUrlAvailableAsync(index, cancellationToken); /// public Task IsRemoveTrackAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveTrackAvailableAsync(index, cancellationToken); /// public Task IsRemoveAlbumItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveAlbumItemAvailableAsync(index, cancellationToken); /// public Task IsRemoveGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveGenreAvailableAsync(index, cancellationToken); /// public Task IsRemoveImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveImageAvailableAsync(index, cancellationToken); /// public Task IsRemoveUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _artist.IsRemoveUrlAvailableAsync(index, cancellationToken); /// public Task PlayAlbumCollectionAsync(IAlbumCollectionItem albumItem, CancellationToken cancellationToken = default) => _artist.PlayAlbumCollectionAsync(albumItem, cancellationToken); /// public Task PlayTrackCollectionAsync(ITrack track, CancellationToken cancellationToken = default) => _artist.PlayTrackCollectionAsync(track, cancellationToken); /// public IAsyncEnumerable GetTracksAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetTracksAsync(limit, offset, cancellationToken); /// public IAsyncEnumerable GetAlbumItemsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetAlbumItemsAsync(limit, offset, cancellationToken); /// public IAsyncEnumerable GetImagesAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetImagesAsync(limit, offset, cancellationToken); /// public IAsyncEnumerable GetGenresAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetGenresAsync(limit, offset, cancellationToken); /// public IAsyncEnumerable GetUrlsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _artist.GetUrlsAsync(limit, offset, cancellationToken); /// public void SortAlbumCollection(AlbumSortingType albumSorting, SortDirection sortDirection) { CurrentAlbumSortingType = albumSorting; CurrentAlbumSortingDirection = sortDirection; CollectionSorting.SortAlbums(Albums, albumSorting, sortDirection, UnsortedAlbums); } /// public void SortTrackCollection(TrackSortingType trackSorting, SortDirection sortDirection) { CurrentTracksSortingType = trackSorting; CurrentTracksSortingDirection = sortDirection; CollectionSorting.SortTracks(Tracks, trackSorting, sortDirection, UnsortedTracks); } /// public async Task PopulateMoreAlbumsAsync(int limit, CancellationToken cancellationToken = default) { using (await Flow.EasySemaphore(_populateAlbumsMutex)) { using var releaseReg = cancellationToken.Register(() => _populateAlbumsMutex.Release()); _syncContext.Post(async _ => { await foreach (var item in _artist.GetAlbumItemsAsync(limit, Albums.Count, cancellationToken)) { switch (item) { case IAlbum album: var avm = new AlbumViewModel(album); Albums.Add(avm); UnsortedAlbums.Add(avm); break; case IAlbumCollection collection: var acvm = new AlbumCollectionViewModel(collection); Albums.Add(acvm); UnsortedAlbums.Add(acvm); break; } } }, null); } } /// 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 GetTracksAsync(limit, Tracks.Count, cancellationToken)) { var tvm = new TrackViewModel(item); Tracks.Add(tvm); UnsortedTracks.Add(tvm); } }, 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 _artist.GetImagesAsync(limit, Images.Count, cancellationToken)) Images.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 _artist.GetGenresAsync(limit, Genres.Count, cancellationToken)) Genres.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 _artist.GetUrlsAsync(limit, Urls.Count, cancellationToken)) { Urls.Add(item); } }, null); } } /// public Task AddTrackAsync(ITrack track, int index, CancellationToken cancellationToken = default) => _artist.AddTrackAsync(track, index, cancellationToken); /// public Task AddAlbumItemAsync(IAlbumCollectionItem album, int index, CancellationToken cancellationToken = default) => _artist.AddAlbumItemAsync(album, index, cancellationToken); /// public Task AddGenreAsync(IGenre genre, int index, CancellationToken cancellationToken = default) => _artist.AddGenreAsync(genre, index, cancellationToken); /// public Task AddImageAsync(IImage image, int index, CancellationToken cancellationToken = default) => _artist.AddImageAsync(image, index, cancellationToken); /// public Task AddUrlAsync(IUrl image, int index, CancellationToken cancellationToken = default) => _artist.AddUrlAsync(image, index, cancellationToken); /// public Task RemoveTrackAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveTrackAsync(index, cancellationToken); /// public Task RemoveAlbumItemAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveAlbumItemAsync(index, cancellationToken); /// public Task RemoveGenreAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveGenreAsync(index, cancellationToken); /// public Task RemoveImageAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveImageAsync(index, cancellationToken); /// public Task RemoveUrlAsync(int index, CancellationToken cancellationToken = default) => _artist.RemoveUrlAsync(index, cancellationToken); /// public IAsyncRelayCommand PlayAlbumAsyncCommand { get; } /// public IAsyncRelayCommand PlayAlbumCollectionAsyncCommand { get; } /// public IAsyncRelayCommand PauseAlbumCollectionAsyncCommand { get; } /// public IAsyncRelayCommand PlayTrackAsyncCommand { get; } /// public IAsyncRelayCommand PlayTrackCollectionAsyncCommand { get; } /// public IAsyncRelayCommand PauseTrackCollectionAsyncCommand { get; } /// public IRelayCommand ChangeTrackCollectionSortingTypeCommand { get; } /// public IRelayCommand ChangeTrackCollectionSortingDirectionCommand { get; } /// public IRelayCommand ChangeAlbumCollectionSortingTypeCommand { get; } /// public IRelayCommand ChangeAlbumCollectionSortingDirectionCommand { get; } /// /// Command to change the name. It triggers . /// public IAsyncRelayCommand ChangeNameAsyncCommand { get; } /// /// Command to change the description. It triggers . /// public IAsyncRelayCommand ChangeDescriptionAsyncCommand { get; } /// /// Command to change the duration. It triggers . /// public IAsyncRelayCommand ChangeDurationAsyncCommand { get; } /// public IAsyncRelayCommand PopulateMoreTracksCommand { get; } /// public IAsyncRelayCommand PopulateMoreAlbumsCommand { get; } /// public IAsyncRelayCommand PopulateMoreGenresCommand { get; } /// public IAsyncRelayCommand PopulateMoreImagesCommand { get; } /// public IAsyncRelayCommand PopulateMoreUrlsCommand { get; } /// public IAsyncRelayCommand InitAlbumCollectionAsyncCommand { get; } /// public IAsyncRelayCommand InitTrackCollectionAsyncCommand { get; } /// public IAsyncRelayCommand InitGenreCollectionAsyncCommand { get; } /// public IAsyncRelayCommand InitImageCollectionAsyncCommand { get; } /// public Task InitImageCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.ImageCollection(this, cancellationToken); /// public Task InitAlbumCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.AlbumCollection(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(ICoreArtistCollectionItem other) => _artist.Equals(other); /// public bool Equals(ICoreAlbumCollectionItem other) => _artist.Equals(other); /// public bool Equals(ICoreAlbumCollection other) => _artist.Equals(other); /// public bool Equals(ICoreTrackCollection other) => _artist.Equals(other); /// public bool Equals(ICoreGenreCollection other) => _artist.Equals(other); /// public bool Equals(ICoreImageCollection other) => _artist.Equals(other); /// public bool Equals(ICoreUrlCollection other) => _artist.Equals(other); /// public bool Equals(ICoreArtist other) => _artist.Equals(other); /// public Task InitAsync(CancellationToken cancellationToken = default) { if (IsInitialized) return Task.CompletedTask; IsInitialized = true; return Task.WhenAll(InitAlbumCollectionAsync(cancellationToken), InitGenreCollectionAsync(cancellationToken), InitImageCollectionAsync(cancellationToken), InitTrackCollectionAsync(cancellationToken)); } private Task ChangeNameInternalAsync(string? name, CancellationToken cancellationToken = default) { Guard.IsNotNull(name, nameof(name)); return _artist.ChangeNameAsync(name, cancellationToken); } /// public ValueTask DisposeAsync() { DetachEvents(); return _artist.DisposeAsync(); } } }