// 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.Globalization;
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 TrackViewModel : ObservableObject, ISdkViewModel, ITrack, IArtistCollectionViewModel, IImageCollectionViewModel, IGenreCollectionViewModel
{
private readonly SemaphoreSlim _populateArtistsMutex = 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;
private readonly ITrack _model;
///
/// Creates a new instance of .
///
/// The to wrap.
public TrackViewModel(ITrack track)
{
_syncContext = SynchronizationContext.Current;
_model = track;
if (_model.Album != null)
Album = new AlbumViewModel(_model.Album);
if (_model.RelatedItems != null)
RelatedItems = new PlayableCollectionGroupViewModel(_model.RelatedItems);
Artists = new ObservableCollection();
UnsortedArtists = new ObservableCollection();
Images = new ObservableCollection();
Urls = new ObservableCollection();
Genres = new ObservableCollection();
PlayArtistCollectionAsyncCommand = new AsyncRelayCommand(PlayArtistCollectionAsync);
PauseArtistCollectionAsyncCommand = new AsyncRelayCommand(PauseArtistCollectionAsync);
PlayArtistAsyncCommand = new AsyncRelayCommand((x, y) => _model.PlayArtistCollectionAsync(x ?? ThrowHelper.ThrowArgumentNullException(), y));
ChangeNameAsyncCommand = new AsyncRelayCommand(ChangeNameInternalAsync);
ChangeDescriptionAsyncCommand = new AsyncRelayCommand(ChangeDescriptionAsync);
ChangeDurationAsyncCommand = new AsyncRelayCommand(ChangeDurationAsync);
PopulateMoreArtistsCommand = new AsyncRelayCommand(PopulateMoreArtistsAsync);
PopulateMoreImagesCommand = new AsyncRelayCommand(PopulateMoreImagesAsync);
PopulateMoreGenresCommand = new AsyncRelayCommand(PopulateMoreGenresAsync);
PopulateMoreUrlsCommand = new AsyncRelayCommand(PopulateMoreUrlsAsync);
InitArtistCollectionAsyncCommand = new AsyncRelayCommand(InitArtistCollectionAsync);
InitGenreCollectionAsyncCommand = new AsyncRelayCommand(InitGenreCollectionAsync);
InitImageCollectionAsyncCommand = new AsyncRelayCommand(InitImageCollectionAsync);
ChangeArtistCollectionSortingTypeCommand = new RelayCommand(x => SortArtistCollection(x, CurrentArtistSortingDirection));
ChangeArtistCollectionSortingDirectionCommand = new RelayCommand(x => SortArtistCollection(CurrentArtistSortingType, x));
AttachEvents();
}
private void AttachEvents()
{
AlbumChanged += Track_AlbumChanged;
DescriptionChanged += Track_DescriptionChanged;
IsExplicitChanged += Track_IsExplicitChanged;
LanguageChanged += Track_LanguageChanged;
LyricsChanged += Track_LyricsChanged;
NameChanged += Track_NameChanged;
PlaybackStateChanged += Track_PlaybackStateChanged;
TrackNumberChanged += Track_TrackNumberChanged;
LastPlayedChanged += OnLastPlayedChanged;
DownloadInfoChanged += OnDownloadInfoChanged;
IsPlayArtistCollectionAsyncAvailableChanged += OnIsPlayArtistCollectionAsyncAvailableChanged;
IsPauseArtistCollectionAsyncAvailableChanged += OnIsPauseArtistCollectionAsyncAvailableChanged;
IsChangeNameAsyncAvailableChanged += OnIsChangeNameAsyncAvailableChanged;
IsChangeDurationAsyncAvailableChanged += OnIsChangeDurationAsyncAvailableChanged;
IsChangeDescriptionAsyncAvailableChanged += OnIsChangeDescriptionAsyncAvailableChanged;
ArtistItemsCountChanged += OnArtistItemsCountChanged;
ArtistItemsChanged += TrackViewModel_ArtistItemsChanged;
ImagesCountChanged += OnImagesCountChanged;
ImagesChanged += TrackViewModel_ImagesChanged;
GenresChanged += TrackViewModel_GenresChanged;
GenresCountChanged += OnGenresCountChanged;
UrlsChanged += TrackViewModel_UrlsChanged;
UrlsCountChanged += OnUrlsCountChanged;
_model.PlaybackStateChanged += OnPlaybackStateChanged;
}
private void DetachEvents()
{
AlbumChanged -= Track_AlbumChanged;
DescriptionChanged -= Track_DescriptionChanged;
IsExplicitChanged -= Track_IsExplicitChanged;
LanguageChanged -= Track_LanguageChanged;
LyricsChanged -= Track_LyricsChanged;
NameChanged -= Track_NameChanged;
PlaybackStateChanged -= Track_PlaybackStateChanged;
TrackNumberChanged -= Track_TrackNumberChanged;
LastPlayedChanged -= OnLastPlayedChanged;
DownloadInfoChanged -= OnDownloadInfoChanged;
IsPlayArtistCollectionAsyncAvailableChanged -= OnIsPlayArtistCollectionAsyncAvailableChanged;
IsPauseArtistCollectionAsyncAvailableChanged -= OnIsPauseArtistCollectionAsyncAvailableChanged;
IsChangeNameAsyncAvailableChanged -= OnIsChangeNameAsyncAvailableChanged;
IsChangeDurationAsyncAvailableChanged -= OnIsChangeDurationAsyncAvailableChanged;
IsChangeDescriptionAsyncAvailableChanged -= OnIsChangeDescriptionAsyncAvailableChanged;
ArtistItemsCountChanged -= OnArtistItemsCountChanged;
ArtistItemsChanged -= TrackViewModel_ArtistItemsChanged;
ImagesCountChanged -= OnImagesCountChanged;
ImagesChanged -= TrackViewModel_ImagesChanged;
GenresChanged -= TrackViewModel_GenresChanged;
GenresCountChanged -= OnGenresCountChanged;
UrlsChanged -= TrackViewModel_UrlsChanged;
UrlsCountChanged -= OnUrlsCountChanged;
_model.PlaybackStateChanged -= OnPlaybackStateChanged;
}
///
public event EventHandler? SourcesChanged
{
add => _model.SourcesChanged += value;
remove => _model.SourcesChanged -= value;
}
///
public event EventHandler? PlaybackStateChanged;
///
public event EventHandler? DownloadInfoChanged
{
add => _model.DownloadInfoChanged += value;
remove => _model.DownloadInfoChanged -= value;
}
///
public event EventHandler? AlbumChanged
{
add => _model.AlbumChanged += value;
remove => _model.AlbumChanged -= value;
}
///
public event EventHandler? TrackNumberChanged
{
add => _model.TrackNumberChanged += value;
remove => _model.TrackNumberChanged -= value;
}
///
public event EventHandler? LanguageChanged
{
add => _model.LanguageChanged += value;
remove => _model.LanguageChanged -= value;
}
///
public event EventHandler? LyricsChanged
{
add => _model.LyricsChanged += value;
remove => _model.LyricsChanged -= value;
}
///
public event EventHandler? IsExplicitChanged
{
add => _model.IsExplicitChanged += value;
remove => _model.IsExplicitChanged -= value;
}
///
public event EventHandler? NameChanged
{
add => _model.NameChanged += value;
remove => _model.NameChanged -= value;
}
///
public event EventHandler? DescriptionChanged
{
add => _model.DescriptionChanged += value;
remove => _model.DescriptionChanged -= value;
}
///
public event EventHandler? DurationChanged
{
add => _model.DurationChanged += value;
remove => _model.DurationChanged -= value;
}
///
public event EventHandler? LastPlayedChanged
{
add => _model.LastPlayedChanged += value;
remove => _model.LastPlayedChanged -= value;
}
///
public event EventHandler? IsPlayArtistCollectionAsyncAvailableChanged
{
add => _model.IsPlayArtistCollectionAsyncAvailableChanged += value;
remove => _model.IsPlayArtistCollectionAsyncAvailableChanged -= value;
}
///
public event EventHandler? IsPauseArtistCollectionAsyncAvailableChanged
{
add => _model.IsPauseArtistCollectionAsyncAvailableChanged += value;
remove => _model.IsPauseArtistCollectionAsyncAvailableChanged -= value;
}
///
public event EventHandler? IsChangeNameAsyncAvailableChanged
{
add => _model.IsChangeNameAsyncAvailableChanged += value;
remove => _model.IsChangeNameAsyncAvailableChanged -= value;
}
///
public event EventHandler? IsChangeDescriptionAsyncAvailableChanged
{
add => _model.IsChangeDescriptionAsyncAvailableChanged += value;
remove => _model.IsChangeDescriptionAsyncAvailableChanged -= value;
}
///
public event EventHandler? IsChangeDurationAsyncAvailableChanged
{
add => _model.IsChangeDurationAsyncAvailableChanged += value;
remove => _model.IsChangeDurationAsyncAvailableChanged -= value;
}
///
public event EventHandler? ArtistItemsCountChanged
{
add => _model.ArtistItemsCountChanged += value;
remove => _model.ArtistItemsCountChanged -= value;
}
///
public event CollectionChangedEventHandler? ArtistItemsChanged
{
add => _model.ArtistItemsChanged += value;
remove => _model.ArtistItemsChanged -= value;
}
///
public event EventHandler? ImagesCountChanged
{
add => _model.ImagesCountChanged += value;
remove => _model.ImagesCountChanged -= value;
}
///
public event CollectionChangedEventHandler? ImagesChanged
{
add => _model.ImagesChanged += value;
remove => _model.ImagesChanged -= value;
}
///
public event EventHandler? GenresCountChanged
{
add => _model.GenresCountChanged += value;
remove => _model.GenresCountChanged -= value;
}
///
public event CollectionChangedEventHandler? GenresChanged
{
add => _model.GenresChanged += value;
remove => _model.GenresChanged -= value;
}
///
public event EventHandler? UrlsCountChanged
{
add => _model.UrlsCountChanged += value;
remove => _model.UrlsCountChanged -= value;
}
///
public event CollectionChangedEventHandler? UrlsChanged
{
add => _model.UrlsChanged += value;
remove => _model.UrlsChanged -= value;
}
private void Track_TrackNumberChanged(object sender, int? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TrackNumber)), null);
private void Track_PlaybackStateChanged(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 Track_NameChanged(object sender, string e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Name)), null);
private void Track_LyricsChanged(object sender, ILyrics? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Lyrics)), null);
private void Track_LanguageChanged(object sender, CultureInfo? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Language)), null);
private void Track_IsExplicitChanged(object sender, bool e) => _syncContext.Post(_ => OnPropertyChanged(nameof(IsExplicit)), null);
private void Track_DescriptionChanged(object sender, string? e) => _syncContext.Post(_ => OnPropertyChanged(nameof(Description)), 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 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 Track_AlbumChanged(object sender, IAlbum? e)
{
Album = e is null ? null : new AlbumViewModel(e);
_syncContext.Post(_ => OnPropertyChanged(nameof(Album)), null);
}
private void OnArtistItemsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalArtistItemsCount)), null);
private void OnImagesCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalImageCount)), null);
private void OnGenresCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalGenreCount)), null);
private void OnUrlsCountChanged(object sender, int e) => _syncContext.Post(_ => OnPropertyChanged(nameof(TotalUrlCount)), null);
private void TrackViewModel_ImagesChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ =>
{
Images.ChangeCollection(addedItems, removedItems);
}, null);
private void TrackViewModel_GenresChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ =>
{
Genres.ChangeCollection(addedItems, removedItems);
}, null);
private void TrackViewModel_UrlsChanged(object sender, IReadOnlyList> addedItems, IReadOnlyList> removedItems) => _syncContext.Post(_ =>
{
Urls.ChangeCollection(addedItems, removedItems);
}, null);
private void TrackViewModel_ArtistItemsChanged(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
{
// Preventing index issues during artists emission from the core, also making sure that unordered artists 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()}")
});
// Avoiding direct assignment to prevent effect on UI.
foreach (var item in UnsortedArtists)
{
if (!Artists.Contains(item))
Artists.Add(item);
}
foreach (var item in Artists)
{
if (!UnsortedArtists.Contains(item))
Artists.Remove(item);
}
SortArtistCollection(CurrentArtistSortingType, CurrentArtistSortingDirection);
}
}, null);
private void OnPlaybackStateChanged(object sender, PlaybackState e) => _syncContext.Post(_ =>
{
PlaybackStateChanged?.Invoke(this, PlaybackState);
OnPropertyChanged(nameof(PlaybackState));
}, null);
///
public void SortArtistCollection(ArtistSortingType artistSorting, SortDirection sortDirection)
{
CurrentArtistSortingType = artistSorting;
CurrentArtistSortingDirection = sortDirection;
CollectionSorting.SortArtists(Artists, artistSorting, sortDirection, UnsortedArtists);
}
///
/// The merged sources for this model.
///
public IReadOnlyList Sources => _model.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;
///
/// The artists for this track.
///
public ObservableCollection Artists { get; }
///
public ObservableCollection UnsortedArtists { get; }
///
public ObservableCollection Images { get; }
///
public ObservableCollection Genres { get; }
///
public ObservableCollection Urls { get; }
///
public ArtistSortingType CurrentArtistSortingType { get; private set; }
///
public SortDirection CurrentArtistSortingDirection { get; private set; }
///
public TrackType Type => _model.Type;
///
public TimeSpan Duration => _model.Duration;
///
public DateTime? AddedAt => _model.AddedAt;
///
public DateTime? LastPlayed => _model.LastPlayed;
///
public IPlayableCollectionGroup? RelatedItems { get; }
///
public string Id => _model.Id;
///
public string Name => _model.Name;
///
public int TotalArtistItemsCount => _model.TotalArtistItemsCount;
///
public int TotalImageCount => _model.TotalImageCount;
///
public int TotalGenreCount => _model.TotalGenreCount;
///
public int TotalUrlCount => _model.TotalUrlCount;
///
public AlbumViewModel? Album { get; private set; }
///
IAlbum? ITrack.Album => _model.Album;
///
public int? TrackNumber => _model.TrackNumber;
///
public int? DiscNumber => _model.DiscNumber;
///
public CultureInfo? Language => _model.Language;
///
public ILyrics? Lyrics => _model.Lyrics;
///
public bool IsExplicit => _model.IsExplicit;
///
public string? Description => _model.Description;
///
public PlaybackState PlaybackState => _model.PlaybackState;
///
public DownloadInfo DownloadInfo => _model.DownloadInfo;
///
public bool IsPlayArtistCollectionAsyncAvailable => _model.IsPlayArtistCollectionAsyncAvailable;
///
public bool IsPauseArtistCollectionAsyncAvailable => _model.IsPauseArtistCollectionAsyncAvailable;
///
public bool IsChangeNameAsyncAvailable => _model.IsChangeNameAsyncAvailable;
///
public bool IsChangeDescriptionAsyncAvailable => _model.IsChangeDescriptionAsyncAvailable;
///
public bool IsChangeDurationAsyncAvailable => _model.IsChangeDurationAsyncAvailable;
///
public bool IsChangeAlbumAsyncAvailable => _model.IsChangeAlbumAsyncAvailable;
///
public bool IsChangeTrackNumberAsyncAvailable => _model.IsChangeTrackNumberAsyncAvailable;
///
public bool IsChangeLanguageAsyncAvailable => _model.IsChangeLanguageAsyncAvailable;
///
public bool IsChangeLyricsAsyncAvailable => _model.IsChangeLyricsAsyncAvailable;
///
public bool IsChangeIsExplicitAsyncAvailable => _model.IsChangeIsExplicitAsyncAvailable;
///
public Task IsAddArtistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsAddArtistItemAvailableAsync(index, cancellationToken);
///
public Task IsAddImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsAddImageAvailableAsync(index, cancellationToken);
///
public Task IsAddGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsAddGenreAvailableAsync(index, cancellationToken);
///
public Task IsAddUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsAddUrlAvailableAsync(index, cancellationToken);
///
public Task IsRemoveArtistItemAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsRemoveArtistItemAvailableAsync(index, cancellationToken);
///
public Task IsRemoveImageAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsRemoveImageAvailableAsync(index, cancellationToken);
///
public Task IsRemoveGenreAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsRemoveGenreAvailableAsync(index, cancellationToken);
///
public Task IsRemoveUrlAvailableAsync(int index, CancellationToken cancellationToken = default) => _model.IsRemoveUrlAvailableAsync(index, cancellationToken);
///
public Task ChangeAlbumAsync(IAlbum? album, CancellationToken cancellationToken = default) => _model.ChangeAlbumAsync(album, cancellationToken);
///
public Task ChangeTrackNumberAsync(int? trackNumber, CancellationToken cancellationToken = default) => _model.ChangeTrackNumberAsync(trackNumber, cancellationToken);
///
public Task ChangeLanguageAsync(CultureInfo language, CancellationToken cancellationToken = default) => _model.ChangeLanguageAsync(language, cancellationToken);
///
public Task ChangeLyricsAsync(ILyrics? lyrics, CancellationToken cancellationToken = default) => _model.ChangeLyricsAsync(lyrics, cancellationToken);
///
public Task ChangeIsExplicitAsync(bool isExplicit, CancellationToken cancellationToken = default) => _model.ChangeIsExplicitAsync(isExplicit, cancellationToken);
///
public Task PauseArtistCollectionAsync(CancellationToken cancellationToken = default) => _model.PauseArtistCollectionAsync(cancellationToken);
///
public Task StartDownloadOperationAsync(DownloadOperation operation, CancellationToken cancellationToken = default) => _model.StartDownloadOperationAsync(operation, cancellationToken);
///
public Task ChangeNameAsync(string name, CancellationToken cancellationToken = default) => ChangeNameInternalAsync(name, cancellationToken);
///
public Task ChangeDescriptionAsync(string? description, CancellationToken cancellationToken = default) => _model.ChangeDescriptionAsync(description, cancellationToken);
///
public Task ChangeDurationAsync(TimeSpan duration, CancellationToken cancellationToken = default) => _model.ChangeDurationAsync(duration, cancellationToken);
///
public Task AddArtistItemAsync(IArtistCollectionItem artistItem, int index, CancellationToken cancellationToken = default) => _model.AddArtistItemAsync(artistItem, index, cancellationToken);
///
public Task AddImageAsync(IImage image, int index, CancellationToken cancellationToken = default) => _model.AddImageAsync(image, index, cancellationToken);
///
public Task AddGenreAsync(IGenre genre, int index, CancellationToken cancellationToken = default) => _model.AddGenreAsync(genre, index, cancellationToken);
///
public Task AddUrlAsync(IUrl genre, int index, CancellationToken cancellationToken = default) => _model.AddUrlAsync(genre, index, cancellationToken);
///
public Task RemoveArtistItemAsync(int index, CancellationToken cancellationToken = default) => _model.RemoveArtistItemAsync(index, cancellationToken);
///
public Task RemoveImageAsync(int index, CancellationToken cancellationToken = default) => _model.RemoveImageAsync(index, cancellationToken);
///
public Task RemoveGenreAsync(int index, CancellationToken cancellationToken = default) => _model.RemoveGenreAsync(index, cancellationToken);
///
public Task RemoveUrlAsync(int index, CancellationToken cancellationToken = default) => _model.RemoveUrlAsync(index, cancellationToken);
///
public IAsyncEnumerable GetArtistItemsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _model.GetArtistItemsAsync(limit, offset, cancellationToken);
///
public IAsyncEnumerable GetImagesAsync(int limit, int offset, CancellationToken cancellationToken = default) => _model.GetImagesAsync(limit, offset, cancellationToken);
///
public IAsyncEnumerable GetGenresAsync(int limit, int offset, CancellationToken cancellationToken = default) => _model.GetGenresAsync(limit, offset, cancellationToken);
///
public IAsyncEnumerable GetUrlsAsync(int limit, int offset, CancellationToken cancellationToken = default) => _model.GetUrlsAsync(limit, offset, cancellationToken);
///
public Task PlayArtistCollectionAsync(IArtistCollectionItem artistItem, CancellationToken cancellationToken = default) => _model.PlayArtistCollectionAsync(artistItem, cancellationToken);
///
public Task PlayArtistCollectionAsync(CancellationToken cancellationToken = default) => _model.PlayArtistCollectionAsync(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 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 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 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 GetUrlsAsync(limit, Urls.Count, cancellationToken))
Urls.Add(item);
}, null);
}
}
///
public IAsyncRelayCommand PopulateMoreArtistsCommand { get; }
///
public IAsyncRelayCommand PlayArtistCollectionAsyncCommand { get; }
///
public IRelayCommand ChangeArtistCollectionSortingTypeCommand { get; }
///
public IRelayCommand ChangeArtistCollectionSortingDirectionCommand { get; }
///
public IAsyncRelayCommand PlayArtistAsyncCommand { get; }
///
public IAsyncRelayCommand PauseArtistCollectionAsyncCommand { get; }
///
public IAsyncRelayCommand PopulateMoreImagesCommand { get; }
///
public IAsyncRelayCommand PopulateMoreGenresCommand { get; }
///
public IAsyncRelayCommand PopulateMoreUrlsCommand { 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 InitImageCollectionAsyncCommand { get; }
///
public Task InitImageCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.ImageCollection(this, cancellationToken);
///
public Task InitArtistCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.ArtistCollection(this, cancellationToken);
///
public Task InitGenreCollectionAsync(CancellationToken cancellationToken = default) => CollectionInit.GenreCollection(this, cancellationToken);
///
public IAsyncRelayCommand InitArtistCollectionAsyncCommand { get; }
///
public IAsyncRelayCommand InitGenreCollectionAsyncCommand { get; }
///
public bool Equals(ICoreArtistCollectionItem other) => _model.Equals(other);
///
public bool Equals(ICoreImageCollection other) => _model.Equals(other);
///
public bool Equals(ICoreArtistCollection other) => _model.Equals(other);
///
public bool Equals(ICoreGenreCollection other) => _model.Equals(other);
///
public bool Equals(ICoreUrlCollection other) => _model.Equals(other);
///
public bool Equals(ICoreTrack other) => _model.Equals(other);
private Task ChangeNameInternalAsync(string? name, CancellationToken cancellationToken = default)
{
Guard.IsNotNull(name, nameof(name));
return _model.ChangeNameAsync(name, cancellationToken);
}
///
public ValueTask DisposeAsync()
{
DetachEvents();
return _model.DisposeAsync();
}
///
public async Task InitAsync(CancellationToken cancellationToken = default)
{
if (!IsInitialized)
return;
await Task.WhenAll(InitImageCollectionAsync(cancellationToken), InitArtistCollectionAsync(cancellationToken), InitGenreCollectionAsync(cancellationToken));
IsInitialized = true;
}
///
public bool IsInitialized { get; private set; }
}
}