using Avalonia.Media.Imaging; using Avalonia.Threading; using Harmonia.Core.Caching; using Harmonia.Core.Imaging; using Harmonia.Core.Models; using Harmonia.Core.Player; using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Harmonia.UI.ViewModels; public class PlayingSongInfoViewModel : ViewModelBase, IDisposable { private readonly IAudioPlayer _audioPlayer; private readonly IAudioImageCache _audioImageCache; private CancellationTokenSource? _audioImageCancellationTokenSource; private Song? _song; public Song? Song { get { return _song; } private set { _song = value; OnPropertyChanged(); } } private Bitmap? _songImageSource; public Bitmap? SongImageSource { get { return _songImageSource; } private set { _songImageSource?.Dispose(); _songImageSource = value; OnPropertyChanged(); } } public PlayingSongInfoViewModel(IAudioPlayer audioPlayer, IAudioImageCache audioImageCache) { _audioPlayer = audioPlayer; _audioPlayer.PlayingSongChanged += OnAudioPlayerPlayingSongChanged; _audioImageCache = audioImageCache; } private void OnAudioPlayerPlayingSongChanged(object? sender, EventArgs e) { Song = _audioPlayer.PlayingSong?.Song; Task.Run(UpdateImage); } private async Task UpdateImage() { // TODO: Show default picture if (Song == null) return; if (_audioImageCancellationTokenSource != null) await _audioImageCancellationTokenSource.CancelAsync(); _audioImageCancellationTokenSource = new(); CancellationToken cancellationToken = _audioImageCancellationTokenSource.Token; SongPictureInfo? songPictureInfo = await _audioImageCache.GetAsync(Song, cancellationToken); if (songPictureInfo == null) return; await Dispatcher.UIThread.InvokeAsync(() => SetSongImageSource(songPictureInfo)); } private void SetSongImageSource(SongPictureInfo songPictureInfo) { if (songPictureInfo.Data.Length == 0) return; using MemoryStream stream = new(songPictureInfo.Data); SongImageSource = new(stream); } public void Dispose() { SongImageSource?.Dispose(); GC.SuppressFinalize(this); } }