Files
harmonia/Harmonia.UI/ViewModels/PlaybackBarViewModel.cs

205 lines
4.6 KiB
C#

using Avalonia.Controls;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
using Harmonia.Core.Caching;
using Harmonia.Core.Imaging;
using Harmonia.Core.Models;
using Harmonia.Core.Player;
using Harmonia.Core.Playlists;
using Harmonia.Core.Scanner;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Harmonia.UI.ViewModels;
public partial class PlaybackBarViewModel : ViewModelBase
{
private readonly IAudioPlayer _audioPlayer;
private readonly IAudioImageCache _audioImageCache;
private readonly DispatcherTimer _timer;
private CancellationTokenSource? _audioImageCancellationTokenSource;
private Song? _song;
public Song? Song
{
get
{
return _song;
}
private set
{
_song = value;
OnPropertyChanged();
CurrentPosition = 0; // What if player is being loaded and returning to save state?
Position = 0;
MaxPosition = value?.Length.TotalSeconds ?? 0;
}
}
private Bitmap? _songImageSource;
public Bitmap? SongImageSource
{
get
{
return _songImageSource;
}
private set
{
_songImageSource = value;
OnPropertyChanged();
}
}
private double _currentPosition;
public double CurrentPosition
{
get
{
return _currentPosition;
}
set
{
_currentPosition = value;
OnPropertyChanged();
if (_isPositionChangeInProgress)
_audioPlayer.Position = value;
}
}
private double _position;
public double Position
{
get
{
return _position;
}
private set
{
_position = value;
OnPropertyChanged();
}
}
private double _maxPosition;
public double MaxPosition
{
get
{
return _maxPosition;
}
set
{
_maxPosition = value;
OnPropertyChanged();
}
}
private bool _isPositionChangeInProgress;
public bool IsPositionChangeInProgress
{
get { return _isPositionChangeInProgress; }
set
{
_isPositionChangeInProgress = value;
OnPropertyChanged();
}
}
public bool IsRandom
{
get
{
return _audioPlayer.IsRandom;
}
private set
{
_audioPlayer.IsRandom = value;
OnPropertyChanged();
}
}
public string Greeting => "Welcome to Harmonia!";
public PlaybackBarViewModel(IAudioPlayer audioPlayer, IAudioImageCache audioImageCache, IPlaylistRepository playlistRepository, IAudioFileScanner audioFileScanner)
{
_audioPlayer = audioPlayer;
_audioPlayer.PlayingSongChanged += OnAudioPlayerPlayingSongChanged;
_audioImageCache = audioImageCache;
_timer = new(TimeSpan.FromMilliseconds(100), DispatcherPriority.Default, TickTock);
}
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)
{
SongImageSource = new(songPictureInfo.Stream);
}
private void TickTock(object? sender, object e)
{
Position = _audioPlayer.Position;
if (IsPositionChangeInProgress)
return;
CurrentPosition = _audioPlayer.Position;
}
public void Play()
{
_audioPlayer.Play();
}
public void Pause()
{
_audioPlayer.Pause();
}
public void Stop()
{
_audioPlayer.Stop();
CurrentPosition = 0;
Position = 0;
}
public void Previous()
{
_audioPlayer.PreviousAsync();
}
public void Next()
{
_audioPlayer.NextAsync();
}
}