Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Screenbox.Core/Common/ServiceHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static void PopulateCoreServices(ServiceCollection services)
services.AddTransient<PlaylistsPageViewModel>();
services.AddTransient<SelectionViewModel>();
services.AddSingleton<CommonViewModel>(); // Shared between many pages
services.AddSingleton<PlaybackSessionViewModel>(); // Playback customization settings; Avoid thread lock
services.AddSingleton<VolumeViewModel>(); // Avoid thread lock

// Factories
Expand Down
8 changes: 8 additions & 0 deletions Screenbox.Core/Enums/TrackPickerDisplayMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Screenbox.Core.Enums;

public enum TrackPickerDisplayMode
{
Composite,
Audio,
Subtitle,
}
5 changes: 5 additions & 0 deletions Screenbox.Core/Messages/ResetPlaybackSessionMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Screenbox.Core.Messages;

public sealed class ResetPlaybackSessionMessage
{
}
20 changes: 19 additions & 1 deletion Screenbox.Core/ViewModels/CompositeTrackPickerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ public sealed partial class CompositeTrackPickerViewModel : ObservableRecipient,
/// </summary>
[ObservableProperty] public partial int VideoTrackIndex { get; set; }

/// <summary>
/// Gets or sets a value that indicates whether the flyout shows audio, subtitle,
/// or composite options in the picker.
/// </summary>
/// <returns>
/// A value of the enumeration that indicates whether the flyout shows audio, subtitle,
/// or composite options. The default is <b><see cref="TrackPickerDisplayMode.Composite"/></b>.
/// </returns>
[ObservableProperty]
public partial TrackPickerDisplayMode DisplayMode { get; set; } = TrackPickerDisplayMode.Composite;

private readonly IFilesService _filesService;
private readonly ISettingsService _settingsService;
private readonly PlayerContext _playerContext;
Expand All @@ -76,6 +87,7 @@ public CompositeTrackPickerViewModel(PlayerContext playerContext, IFilesService
SubtitleTracks = new ObservableCollection<string>();
AudioTracks = new ObservableCollection<string>();
VideoTracks = new ObservableCollection<string>();
DisplayMode = TrackPickerDisplayMode.Composite;

Messenger.Register<QueueCurrentItemChangedMessage>(this);
}
Expand Down Expand Up @@ -286,7 +298,6 @@ private async Task AddSubtitleAsync()
}
}


public void OnFlyoutOpening()
{
UpdateSubtitleTrackList();
Expand All @@ -302,6 +313,13 @@ public void OnFlyoutOpening()
public void OnFlyoutClosed()
{
_flyoutOpened = false;
DisplayMode = TrackPickerDisplayMode.Composite;
}

[RelayCommand]
private void SetDisplayMode(TrackPickerDisplayMode value)
{
DisplayMode = value;
}

private void UpdateAudioTrackList()
Expand Down
134 changes: 134 additions & 0 deletions Screenbox.Core/ViewModels/PlaybackSessionViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using Screenbox.Core.Contexts;
using Screenbox.Core.Events;
using Screenbox.Core.Messages;
using Screenbox.Core.Playback;
using Windows.System;

namespace Screenbox.Core.ViewModels;

public sealed partial class PlaybackSessionViewModel : ObservableRecipient,
IRecipient<ChangePlaybackRateRequestMessage>,
IRecipient<PropertyChangedMessage<IMediaPlayer?>>,
IRecipient<ResetPlaybackSessionMessage>
{
[ObservableProperty]
public partial double PlaybackRate { get; set; }

[ObservableProperty]
public partial double AudioTimingOffset { get; set; }

[ObservableProperty]
public partial double SubtitleTimingOffset { get; set; }

private IMediaPlayer? MediaPlayer => _playerContext.MediaPlayer;

private readonly PlayerContext _playerContext;
private readonly DispatcherQueue _dispatcherQueue;

public PlaybackSessionViewModel(PlayerContext playerContext)
{
_playerContext = playerContext;
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();

PlaybackRate = 1.0;
AudioTimingOffset = 0.0;
SubtitleTimingOffset = 0.0;

Messenger.Register<ChangePlaybackRateRequestMessage>(this);
Messenger.Register<PropertyChangedMessage<IMediaPlayer?>>(this);
Messenger.Register<ResetPlaybackSessionMessage>(this);
}

public void Receive(PropertyChangedMessage<IMediaPlayer?> message)
{
if (message.Sender is not PlayerContext)
return;

if (message.OldValue is { } oldPlayer)
{
oldPlayer.PlaybackRateChanged -= OnPlaybackRateChanged;
}

if (MediaPlayer is not null)
{
MediaPlayer.PlaybackRateChanged += OnPlaybackRateChanged;
}
}

public void Receive(ChangePlaybackRateRequestMessage message)
{
SetPlaybackRate(message.Value);
message.Reply(PlaybackRate);
}

public void Receive(ResetPlaybackSessionMessage message)
{
ResetTimingOffsets();
}

partial void OnPlaybackRateChanged(double value)
{
if (MediaPlayer is null)
return;

MediaPlayer.PlaybackRate = value;
}

partial void OnAudioTimingOffsetChanged(double value)
{
if (MediaPlayer is null)
return;

if (MediaPlayer is VlcMediaPlayer vlcMediaPlayer)
{
vlcMediaPlayer.AudioDelay = value;
}
}

partial void OnSubtitleTimingOffsetChanged(double value)
{
if (MediaPlayer is null)
return;

if (MediaPlayer is VlcMediaPlayer vlcMediaPlayer)
{
vlcMediaPlayer.SubtitleDelay = value;
}
}

[RelayCommand]
private void SetPlaybackRate(double rate)
{
PlaybackRate = rate;
}

[RelayCommand]
private void AdjustAudioTimingOffset(double delta)
{
AudioTimingOffset += delta;
}

[RelayCommand]
private void AdjustSubtitleTimingOffset(double delta)
{
SubtitleTimingOffset += delta;
}

private void OnPlaybackRateChanged(IMediaPlayer sender, ValueChangedEventArgs<double> args)
{
_dispatcherQueue.TryEnqueue(() =>
{
sender.PlaybackRate = PlaybackRate;
});
}

private void ResetTimingOffsets()
{
AudioTimingOffset = 0.0;
SubtitleTimingOffset = 0.0;
}
}
49 changes: 1 addition & 48 deletions Screenbox.Core/ViewModels/PlayerControlsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public sealed partial class PlayerControlsViewModel : ObservableRecipient,
IRecipient<PropertyChangedMessage<IMediaPlayer?>>,
IRecipient<SettingsChangedMessage>,
IRecipient<TogglePlayPauseMessage>,
IRecipient<ChangePlaybackRateRequestMessage>,
IRecipient<PropertyChangedMessage<PlayerVisibilityState>>,
IRecipient<PropertyChangedMessage<WindowViewMode>>
{
Expand All @@ -39,9 +38,6 @@ public sealed partial class PlayerControlsViewModel : ObservableRecipient,
[ObservableProperty] public partial bool IsPlaying { get; set; }
[ObservableProperty] public partial bool IsFullscreen { get; set; }
[ObservableProperty] public partial string? TitleName { get; set; } // TODO: Handle VLC title name
[ObservableProperty] public partial double PlaybackRate { get; set; }
[ObservableProperty] public partial double AudioTimingOffset { get; set; }
[ObservableProperty] public partial double SubtitleTimingOffset { get; set; }
[ObservableProperty] public partial bool IsAdvancedModeActive { get; set; }
[ObservableProperty] public partial bool IsMinimal { get; set; }
[ObservableProperty] public partial bool PlayerShowChapters { get; set; }
Expand Down Expand Up @@ -84,9 +80,6 @@ public PlayerControlsViewModel(
_playerContext = playerContext;
_filesService = filesService;
_coordinator = coordinator;
PlaybackRate = 1.0;
AudioTimingOffset = 0.0;
SubtitleTimingOffset = 0.0;
IsAdvancedModeActive = settingsService.AdvancedMode;
IsMinimal = true;
IsDisplayingRemainingTime = settingsService.PersistentShowRemainingTime;
Expand All @@ -104,7 +97,6 @@ public PlayerControlsViewModel(
Messenger.Register<PropertyChangedMessage<IMediaPlayer?>>(this);
Messenger.Register<SettingsChangedMessage>(this);
Messenger.Register<TogglePlayPauseMessage>(this);
Messenger.Register<ChangePlaybackRateRequestMessage>(this);
Messenger.Register<PropertyChangedMessage<PlayerVisibilityState>>(this);
Messenger.Register<PropertyChangedMessage<WindowViewMode>>(this);
}
Expand Down Expand Up @@ -151,12 +143,6 @@ public void Receive(TogglePlayPauseMessage message)
}
}

public void Receive(ChangePlaybackRateRequestMessage message)
{
SetPlaybackRate(message.Value);
message.Reply(PlaybackRate);
}

public void Receive(PropertyChangedMessage<PlayerVisibilityState> message)
{
IsMinimal = message.NewValue != PlayerVisibilityState.Visible;
Expand Down Expand Up @@ -262,40 +248,13 @@ partial void OnIsDisplayingRemainingTimeChanged(bool value)
_settingsService.PersistentShowRemainingTime = value;
}

partial void OnPlaybackRateChanged(double value)
{
if (MediaPlayer == null) return;
MediaPlayer.PlaybackRate = value;
}

partial void OnAudioTimingOffsetChanged(double value)
{
if (MediaPlayer == null) return;

if (MediaPlayer is VlcMediaPlayer vlcMediaPlayer)
{
vlcMediaPlayer.AudioDelay = value;
}
}

partial void OnSubtitleTimingOffsetChanged(double value)
{
if (MediaPlayer == null) return;

if (MediaPlayer is VlcMediaPlayer vlcMediaPlayer)
{
vlcMediaPlayer.SubtitleDelay = value;
}
}

private void PlayQueueOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(PlayQueueContext.CurrentItem):
HasActiveItem = PlayQueue.CurrentItem is not null;
SubtitleTimingOffset = 0;
AudioTimingOffset = 0;
Messenger.Send(new ResetPlaybackSessionMessage());
break;
}
}
Expand Down Expand Up @@ -364,12 +323,6 @@ private void ResetMediaPlayback()
});
}

[RelayCommand]
private void SetPlaybackRate(double rate)
{
PlaybackRate = rate;
}

[RelayCommand]
private void SetAspectRatio(string aspect)
{
Expand Down
Loading