Added view models and storage providers.
This commit is contained in:
303
Harmonia.WinUI/ViewModels/PlayerViewModel.cs
Normal file
303
Harmonia.WinUI/ViewModels/PlayerViewModel.cs
Normal file
@@ -0,0 +1,303 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Harmonia.Core.Models;
|
||||
using Harmonia.Core.Player;
|
||||
using Harmonia.WinUI.Caching;
|
||||
using Harmonia.WinUI.Models;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Harmonia.WinUI.ViewModels;
|
||||
|
||||
public partial class PlayerViewModel : ViewModelBase
|
||||
{
|
||||
private readonly IAudioPlayer _audioPlayer;
|
||||
private readonly IAudioBitmapImageCache _audioBitmapImageCache;
|
||||
private readonly DispatcherTimer _timer;
|
||||
|
||||
private CancellationTokenSource? _songImageCancellationTokenSource;
|
||||
|
||||
private Song? _song;
|
||||
public Song? Song
|
||||
{
|
||||
get
|
||||
{
|
||||
return _song;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetProperty(ref _song, value);
|
||||
|
||||
CurrentPosition = 0; // What if player is being loaded and returning to save state?
|
||||
Position = 0;
|
||||
MaxPosition = value?.Length.TotalSeconds ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
private BitmapImage? _songImageSource;
|
||||
public BitmapImage? SongImageSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return _songImageSource;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetProperty(ref _songImageSource, value);
|
||||
}
|
||||
}
|
||||
|
||||
private double _currentPosition;
|
||||
public double CurrentPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _currentPosition, value);
|
||||
|
||||
if (_isPositionChangeInProgress)
|
||||
_audioPlayer.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
private double _position;
|
||||
public double Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
private set
|
||||
{
|
||||
SetProperty(ref _position, value);
|
||||
}
|
||||
}
|
||||
|
||||
private double _maxPosition;
|
||||
public double MaxPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _maxPosition, value);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isPositionChangeInProgress;
|
||||
public bool IsPositionChangeInProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isPositionChangeInProgress;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _isPositionChangeInProgress, value);
|
||||
}
|
||||
}
|
||||
|
||||
public double Volume
|
||||
{
|
||||
get
|
||||
{
|
||||
return _audioPlayer.Volume;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (IsMuted)
|
||||
IsMuted = false;
|
||||
|
||||
_audioPlayer.Volume = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(VolumeState));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMuted
|
||||
{
|
||||
get
|
||||
{
|
||||
return _audioPlayer.IsMuted;
|
||||
}
|
||||
set
|
||||
{
|
||||
_audioPlayer.IsMuted = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(VolumeState));
|
||||
}
|
||||
}
|
||||
|
||||
public VolumeState VolumeState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsMuted)
|
||||
return VolumeState.Muted;
|
||||
|
||||
if (Volume == 0)
|
||||
return VolumeState.Off;
|
||||
|
||||
if (Volume < .33)
|
||||
return VolumeState.Low;
|
||||
|
||||
if (Volume < .66)
|
||||
return VolumeState.Medium;
|
||||
|
||||
return VolumeState.High;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRandom
|
||||
{
|
||||
get
|
||||
{
|
||||
return _audioPlayer.IsRandom;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_audioPlayer.IsRandom = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public RepeatState RepeatState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _audioPlayer.RepeatState;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_audioPlayer.RepeatState = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand PlaySongCommand => new RelayCommand(Play);
|
||||
public ICommand PauseSongCommand => new RelayCommand(Pause);
|
||||
public ICommand StopSongCommand => new RelayCommand(Stop);
|
||||
public ICommand PreviousSongCommand => new RelayCommand(Previous);
|
||||
public ICommand NextSongCommand => new RelayCommand(Next);
|
||||
public ICommand ToggleMuteCommand => new RelayCommand(ToggleMute);
|
||||
public ICommand ToggleRandomizerCommand => new RelayCommand(ToggleRandomizer);
|
||||
public ICommand ToggleRepeatCommand => new RelayCommand(ToggleRepeat);
|
||||
|
||||
public PlayerViewModel(IAudioPlayer audioPlayer, IAudioBitmapImageCache audioBitmapCache)
|
||||
{
|
||||
_audioPlayer = audioPlayer;
|
||||
_audioPlayer.PlayingSongChanged += OnPlayingSongChanged;
|
||||
|
||||
_audioBitmapImageCache = audioBitmapCache;
|
||||
|
||||
_timer = new()
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(100)
|
||||
};
|
||||
|
||||
_timer.Tick += TickTock;
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void OnPlayingSongChanged(object? sender, EventArgs e)
|
||||
{
|
||||
Song = _audioPlayer.PlayingSong?.Song;
|
||||
Task.Run(UpdateImage);
|
||||
}
|
||||
|
||||
private async Task UpdateImage()
|
||||
{
|
||||
// TODO: Show default picture
|
||||
if (Song == null)
|
||||
return;
|
||||
|
||||
if (_songImageCancellationTokenSource != null)
|
||||
await _songImageCancellationTokenSource.CancelAsync();
|
||||
|
||||
_songImageCancellationTokenSource = new();
|
||||
CancellationToken cancellationToken = _songImageCancellationTokenSource.Token;
|
||||
|
||||
BitmapImage? bitmapImage = await _audioBitmapImageCache.GetAsync(Song, cancellationToken);
|
||||
|
||||
DispatcherQueue.GetForCurrentThread().TryEnqueue(() => SongImageSource = bitmapImage);
|
||||
}
|
||||
|
||||
private void TickTock(object? sender, object e)
|
||||
{
|
||||
Position = _audioPlayer.Position;
|
||||
|
||||
if (IsPositionChangeInProgress)
|
||||
return;
|
||||
|
||||
CurrentPosition = _audioPlayer.Position;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public void ToggleMute()
|
||||
{
|
||||
IsMuted = !IsMuted;
|
||||
}
|
||||
|
||||
public void ToggleRandomizer()
|
||||
{
|
||||
IsRandom = !IsRandom;
|
||||
}
|
||||
|
||||
public void ToggleRepeat()
|
||||
{
|
||||
RepeatState = GetNextRepeatState();
|
||||
}
|
||||
|
||||
private RepeatState GetNextRepeatState()
|
||||
{
|
||||
return _audioPlayer.RepeatState switch
|
||||
{
|
||||
RepeatState.Off => RepeatState.RepeatAll,
|
||||
RepeatState.RepeatAll => RepeatState.RepeatOne,
|
||||
RepeatState.RepeatOne => RepeatState.Off,
|
||||
_ => _audioPlayer.RepeatState,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user