Added tracking/capturing/restoration of audio playback state and position.
This commit is contained in:
@@ -58,7 +58,7 @@ public partial class App : Application
|
|||||||
await sessionService.LoadAsync();
|
await sessionService.LoadAsync();
|
||||||
|
|
||||||
ISessionRestorer sessionRestorer = ServiceProvider.GetRequiredService<ISessionRestorer>();
|
ISessionRestorer sessionRestorer = ServiceProvider.GetRequiredService<ISessionRestorer>();
|
||||||
sessionRestorer.Restore();
|
await sessionRestorer.RestoreAsync();
|
||||||
|
|
||||||
ISessionTracker sessionTracker = ServiceProvider.GetRequiredService<ISessionTracker>();
|
ISessionTracker sessionTracker = ServiceProvider.GetRequiredService<ISessionTracker>();
|
||||||
sessionTracker.Start();
|
sessionTracker.Start();
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ public sealed partial class MainWindow : Window
|
|||||||
private const string ApplicationTitle = "Harmonia";
|
private const string ApplicationTitle = "Harmonia";
|
||||||
|
|
||||||
private readonly ISessionService _sessionService;
|
private readonly ISessionService _sessionService;
|
||||||
|
private readonly ISessionTracker _sessionTracker;
|
||||||
|
|
||||||
private bool _isSaved;
|
private bool _isSaved;
|
||||||
|
|
||||||
public MainWindow(ISessionService sessionService)
|
public MainWindow(ISessionService sessionService, ISessionTracker sessionTracker)
|
||||||
{
|
{
|
||||||
_sessionService = sessionService;
|
_sessionService = sessionService;
|
||||||
|
_sessionTracker = sessionTracker;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializeTitleBar();
|
InitializeTitleBar();
|
||||||
@@ -57,6 +59,7 @@ public sealed partial class MainWindow : Window
|
|||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
|
|
||||||
|
_sessionTracker.Capture();
|
||||||
await _sessionService.SaveAsync();
|
await _sessionService.SaveAsync();
|
||||||
|
|
||||||
_isSaved = true;
|
_isSaved = true;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
namespace Harmonia.WinUI.Session;
|
using Harmonia.Core.Engine;
|
||||||
|
|
||||||
|
namespace Harmonia.WinUI.Session;
|
||||||
|
|
||||||
public partial class AudioPlayerState
|
public partial class AudioPlayerState
|
||||||
{
|
{
|
||||||
public string? PlaylistUID { get; set; }
|
public string? PlaylistUID { get; set; }
|
||||||
public string? PlaylistSongUID { get; set; }
|
public string? PlaylistSongUID { get; set; }
|
||||||
public double Position { get; set; } = 0.0;
|
public double Position { get; set; } = 0.0;
|
||||||
public string? PlaybackState { get; set; }
|
public AudioPlaybackState PlaybackState { get; set; } = AudioPlaybackState.Stopped;
|
||||||
public double Volume { get; set; } = 1.0;
|
public double Volume { get; set; } = 1.0;
|
||||||
public bool IsMuted { get; set; }
|
public bool IsMuted { get; set; }
|
||||||
public string? RepeatState { get; set; }
|
public string? RepeatState { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
namespace Harmonia.WinUI.Session;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Harmonia.WinUI.Session;
|
||||||
|
|
||||||
public interface ISessionRestorer
|
public interface ISessionRestorer
|
||||||
{
|
{
|
||||||
void Restore();
|
Task RestoreAsync();
|
||||||
}
|
}
|
||||||
@@ -3,4 +3,5 @@ namespace Harmonia.WinUI.Session;
|
|||||||
public interface ISessionTracker
|
public interface ISessionTracker
|
||||||
{
|
{
|
||||||
void Start();
|
void Start();
|
||||||
|
void Capture();
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
using Harmonia.Core.Player;
|
using Harmonia.Core.Engine;
|
||||||
|
using Harmonia.Core.Player;
|
||||||
using Harmonia.Core.Playlists;
|
using Harmonia.Core.Playlists;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Harmonia.WinUI.Session;
|
namespace Harmonia.WinUI.Session;
|
||||||
|
|
||||||
@@ -10,10 +12,10 @@ public class SessionRestorer(
|
|||||||
IPlaylistManager playlistManager,
|
IPlaylistManager playlistManager,
|
||||||
IAudioPlayer audioPlayer) : ISessionRestorer
|
IAudioPlayer audioPlayer) : ISessionRestorer
|
||||||
{
|
{
|
||||||
public void Restore()
|
public async Task RestoreAsync()
|
||||||
{
|
{
|
||||||
RestorePlaylist();
|
RestorePlaylist();
|
||||||
RestoreAudioPlayer();
|
await RestoreAudioPlayerAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestorePlaylist()
|
private void RestorePlaylist()
|
||||||
@@ -31,7 +33,7 @@ public class SessionRestorer(
|
|||||||
playlistManager.CurrentPlaylist = playlist;
|
playlistManager.CurrentPlaylist = playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RestoreAudioPlayer()
|
private async Task RestoreAudioPlayerAsync()
|
||||||
{
|
{
|
||||||
AudioPlayerState audioPlayerState = sessionService.Session.Player;
|
AudioPlayerState audioPlayerState = sessionService.Session.Player;
|
||||||
|
|
||||||
@@ -43,13 +45,27 @@ public class SessionRestorer(
|
|||||||
if (playlist is null)
|
if (playlist is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PlaylistSong? song = playlist.Songs.FirstOrDefault(s => s.UID == audioPlayerState.PlaylistSongUID);
|
PlaylistSong? playlistSong = playlist.Songs.FirstOrDefault(s => s.UID == audioPlayerState.PlaylistSongUID);
|
||||||
|
|
||||||
if (song is null)
|
if (playlistSong is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//PlaybackMode playbackMode = audioPlayerState.PlaybackState
|
await audioPlayer.LoadAsync(playlistSong, PlaybackMode.LoadOnly);
|
||||||
|
|
||||||
audioPlayer.LoadAsync(song, PlaybackMode.LoadOnly);
|
if (audioPlayerState.Position > 0 && audioPlayerState.Position <= playlistSong.Song.Length.TotalSeconds)
|
||||||
|
audioPlayer.Position = audioPlayerState.Position;
|
||||||
|
|
||||||
|
switch (audioPlayerState.PlaybackState)
|
||||||
|
{
|
||||||
|
case AudioPlaybackState.Playing:
|
||||||
|
audioPlayer.Play();
|
||||||
|
break;
|
||||||
|
case AudioPlaybackState.Paused:
|
||||||
|
audioPlayer.Pause();
|
||||||
|
break;
|
||||||
|
case AudioPlaybackState.Stopped:
|
||||||
|
audioPlayer.Stop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ public class SessionTracker(
|
|||||||
{
|
{
|
||||||
playlistManager.CurrentPlaylistChanged += OnCurrentPlaylistChanged;
|
playlistManager.CurrentPlaylistChanged += OnCurrentPlaylistChanged;
|
||||||
audioPlayer.PlayingSongChanged += OnPlayingSongChanged;
|
audioPlayer.PlayingSongChanged += OnPlayingSongChanged;
|
||||||
|
audioPlayer.PropertyChanged += OnAudioPlayerPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCurrentPlaylistChanged(object? sender, EventArgs e)
|
private void OnCurrentPlaylistChanged(object? sender, EventArgs e)
|
||||||
@@ -26,4 +27,19 @@ public class SessionTracker(
|
|||||||
AudioPlayerState audioPlayerState = sessionService.Session.Player;
|
AudioPlayerState audioPlayerState = sessionService.Session.Player;
|
||||||
audioPlayerState.PlaylistSongUID = e.NewSong?.UID;
|
audioPlayerState.PlaylistSongUID = e.NewSong?.UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAudioPlayerPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.PropertyName)
|
||||||
|
{
|
||||||
|
case nameof(IAudioPlayer.State):
|
||||||
|
sessionService.Session.Player.PlaybackState = audioPlayer.State;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Capture()
|
||||||
|
{
|
||||||
|
sessionService.Session.Player.Position = audioPlayer.Position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,6 +225,20 @@ public partial class PlayerViewModel : ViewModelBase
|
|||||||
_timer.Tick += TickTock;
|
_timer.Tick += TickTock;
|
||||||
|
|
||||||
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
|
||||||
|
TryRestore();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryRestore()
|
||||||
|
{
|
||||||
|
if (_audioPlayer.PlayingSong is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Song = _audioPlayer.PlayingSong.Song;
|
||||||
|
Position = _audioPlayer.Position;
|
||||||
|
CurrentPosition = _audioPlayer.Position;
|
||||||
|
|
||||||
|
Task.Run(UpdateImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event Handlers
|
#region Event Handlers
|
||||||
|
|||||||
@@ -50,6 +50,17 @@ public partial class PlayingSongViewModel : ViewModelBase
|
|||||||
|
|
||||||
_audioBitmapImageCache = audioBitmapImageCache;
|
_audioBitmapImageCache = audioBitmapImageCache;
|
||||||
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
|
||||||
|
TryRestore();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryRestore()
|
||||||
|
{
|
||||||
|
if (_audioPlayer.PlayingSong is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Song = _audioPlayer.PlayingSong.Song;
|
||||||
|
Task.Run(UpdateImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAudioPlayerPlayingSongChanged(object? sender, PlayingSongChangedEventArgs e)
|
private void OnAudioPlayerPlayingSongChanged(object? sender, PlayingSongChangedEventArgs e)
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ public partial class PlaylistDetailViewModel : ViewModelBase
|
|||||||
FilteredPlaylistSongs.CollectionChanged += OnFilteredPlaylistSongsCollectionChanged;
|
FilteredPlaylistSongs.CollectionChanged += OnFilteredPlaylistSongsCollectionChanged;
|
||||||
|
|
||||||
Playlist = _playlistManager.CurrentPlaylist; // Testing
|
Playlist = _playlistManager.CurrentPlaylist; // Testing
|
||||||
|
PlayingSong = _audioPlayer.PlayingSong; // Testing
|
||||||
|
|
||||||
UpdateFilteredSongs();
|
UpdateFilteredSongs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,16 @@ public sealed partial class PlaylistDetailView : UserControl
|
|||||||
SortSelectedByMenuFlyoutSubItem.IsEnabled = _viewModel.SortSelectedCommand.CanExecute(null);
|
SortSelectedByMenuFlyoutSubItem.IsEnabled = _viewModel.SortSelectedCommand.CanExecute(null);
|
||||||
|
|
||||||
SortSelectedByMenuFlyoutSubItem.IsEnabled = _viewModel.SortSelectedCommand.CanExecute(null);
|
SortSelectedByMenuFlyoutSubItem.IsEnabled = _viewModel.SortSelectedCommand.CanExecute(null);
|
||||||
|
|
||||||
|
Loaded += OnLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Loaded -= OnLoaded;
|
||||||
|
|
||||||
|
// Defer until the ListView has completed its first layout/container realization pass.
|
||||||
|
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, BringPlayingSongIntoView);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnViewModelPropertyChanging(object? sender, PropertyChangingEventArgs e)
|
private void OnViewModelPropertyChanging(object? sender, PropertyChangingEventArgs e)
|
||||||
@@ -274,7 +284,7 @@ public sealed partial class PlaylistDetailView : UserControl
|
|||||||
if (args.NewValue is not PlaylistSong playlistSong)
|
if (args.NewValue is not PlaylistSong playlistSong)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool isPlaying = playlistSong == _viewModel.PlayingSong;
|
bool isPlaying = playlistSong.UID == _viewModel.PlayingSong?.UID;
|
||||||
|
|
||||||
UpdateListViewItemStyle(sender, isPlaying);
|
UpdateListViewItemStyle(sender, isPlaying);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user