From 109536e1393776876746b5774f904ae4d679a602 Mon Sep 17 00:00:00 2001 From: United600 Date: Mon, 15 Sep 2025 18:59:34 +0100 Subject: [PATCH 1/5] combine player controls options into a settings expander --- Screenbox/Pages/SettingsPage.xaml | 23 ++++++++++++----------- Screenbox/Strings/en-US/Resources.resw | 6 ++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Screenbox/Pages/SettingsPage.xaml b/Screenbox/Pages/SettingsPage.xaml index 3715519ed..1ed1ddc9c 100644 --- a/Screenbox/Pages/SettingsPage.xaml +++ b/Screenbox/Pages/SettingsPage.xaml @@ -401,19 +401,20 @@ - - - - - - - + + + + + + + + + Allow the maximum volume to go above 100% + + Overlay controls + + + Change the appearance and behavior of the on-screen player controls + Gestures From 172eec772c851226a87ce67a242fe30390e56fd4 Mon Sep 17 00:00:00 2001 From: United600 Date: Mon, 15 Sep 2025 20:16:33 +0100 Subject: [PATCH 2/5] add player controls hide delay option --- Screenbox.Core/Services/ISettingsService.cs | 1 + Screenbox.Core/Services/SettingsService.cs | 8 ++++++ .../ViewModels/PlayerPageViewModel.cs | 6 +++-- .../ViewModels/SettingsPageViewModel.cs | 25 +++++++++++++++++++ Screenbox/Pages/SettingsPage.xaml | 17 +++++++++++++ Screenbox/Strings/en-US/Resources.resw | 18 +++++++++++++ 6 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Screenbox.Core/Services/ISettingsService.cs b/Screenbox.Core/Services/ISettingsService.cs index cf456da4e..beccce782 100644 --- a/Screenbox.Core/Services/ISettingsService.cs +++ b/Screenbox.Core/Services/ISettingsService.cs @@ -12,6 +12,7 @@ public interface ISettingsService bool PlayerTapGesture { get; set; } bool PlayerShowControls { get; set; } bool PlayerShowChapters { get; set; } + int PlayerControlsHideDelay { get; set; } int PersistentVolume { get; set; } string PersistentSubtitleLanguage { get; set; } bool ShowRecent { get; set; } diff --git a/Screenbox.Core/Services/SettingsService.cs b/Screenbox.Core/Services/SettingsService.cs index 7aed0928b..946eb5b0e 100644 --- a/Screenbox.Core/Services/SettingsService.cs +++ b/Screenbox.Core/Services/SettingsService.cs @@ -20,6 +20,7 @@ public sealed class SettingsService : ISettingsService private const string PlayerSeekGestureKey = "Player/Gesture/Seek"; private const string PlayerTapGestureKey = "Player/Gesture/Tap"; private const string PlayerShowControlsKey = "Player/ShowControls"; + private const string PlayerControlsHideDelayKey = "Player/ControlsHideDelay"; private const string PlayerLivelyPathKey = "Player/Lively/Path"; private const string LibrariesUseIndexerKey = "Libraries/UseIndexer"; private const string LibrariesSearchRemovableStorageKey = "Libraries/SearchRemovableStorage"; @@ -114,6 +115,12 @@ public bool PlayerShowControls set => SetValue(PlayerShowControlsKey, value); } + public int PlayerControlsHideDelay + { + get => GetValue(PlayerControlsHideDelayKey); + set => SetValue(PlayerControlsHideDelayKey, value); + } + public bool SearchRemovableStorage { get => GetValue(LibrariesSearchRemovableStorageKey); @@ -169,6 +176,7 @@ public SettingsService() SetDefault(PlayerSeekGestureKey, true); SetDefault(PlayerTapGestureKey, true); SetDefault(PlayerShowControlsKey, true); + SetDefault(PlayerControlsHideDelayKey, 3); SetDefault(PersistentVolumeKey, 100); SetDefault(MaxVolumeKey, 100); SetDefault(LibrariesUseIndexerKey, true); diff --git a/Screenbox.Core/ViewModels/PlayerPageViewModel.cs b/Screenbox.Core/ViewModels/PlayerPageViewModel.cs index 6cb387ea2..e68345f1f 100644 --- a/Screenbox.Core/ViewModels/PlayerPageViewModel.cs +++ b/Screenbox.Core/ViewModels/PlayerPageViewModel.cs @@ -576,9 +576,11 @@ public bool TryHideControls(bool skipFocusCheck = false) return true; } - private void DelayHideControls(int delayInSeconds = 3) + private void DelayHideControls() { if (PlayerVisibility != PlayerVisibilityState.Visible || AudioOnly) return; + + int delayInSeconds = _settingsService.PlayerControlsHideDelay; _controlsVisibilityTimer.Debounce(() => TryHideControls(), TimeSpan.FromSeconds(delayInSeconds)); } @@ -592,7 +594,7 @@ private void FocusManagerOnFocusChanged(object sender, FocusManagerGotFocusEvent { if (_visibilityOverride) return; ControlsHidden = false; - DelayHideControls(4); + DelayHideControls(); } private async void ProcessOpeningMedia(MediaViewModel? current) diff --git a/Screenbox.Core/ViewModels/SettingsPageViewModel.cs b/Screenbox.Core/ViewModels/SettingsPageViewModel.cs index 839bda72f..33189bc6c 100644 --- a/Screenbox.Core/ViewModels/SettingsPageViewModel.cs +++ b/Screenbox.Core/ViewModels/SettingsPageViewModel.cs @@ -29,6 +29,7 @@ public sealed partial class SettingsPageViewModel : ObservableRecipient [ObservableProperty] private bool _playerTapGesture; [ObservableProperty] private bool _playerShowControls; [ObservableProperty] private bool _playerShowChapters; + [ObservableProperty] private int _playerControlsHideDelay; [ObservableProperty] private int _volumeBoost; [ObservableProperty] private bool _useIndexer; [ObservableProperty] private bool _showRecent; @@ -99,6 +100,15 @@ public SettingsPageViewModel(ISettingsService settingsService, ILibraryService l _playerTapGesture = _settingsService.PlayerTapGesture; _playerShowControls = _settingsService.PlayerShowControls; _playerShowChapters = _settingsService.PlayerShowChapters; + _playerControlsHideDelay = _settingsService.PlayerControlsHideDelay switch + { + 1 => 0, + 2 => 1, + 3 => 2, + 4 => 3, + 5 => 4, + _ => 2 // Default to 3 seconds (Index 2) + }; _useIndexer = _settingsService.UseIndexer; _showRecent = _settingsService.ShowRecent; _theme = ((int)_settingsService.Theme + 2) % 3; @@ -187,6 +197,21 @@ partial void OnPlayerShowChaptersChanged(bool value) Messenger.Send(new SettingsChangedMessage(nameof(PlayerShowChapters), typeof(SettingsPageViewModel))); } + partial void OnPlayerControlsHideDelayChanged(int value) + { + _settingsService.PlayerControlsHideDelay = value switch + { + // Index => Seconds + 0 => 1, + 1 => 2, + 2 => 3, + 3 => 4, + 4 => 5, + _ => 3 + }; + Messenger.Send(new SettingsChangedMessage(nameof(PlayerControlsHideDelay), typeof(SettingsPageViewModel))); + } + partial void OnUseIndexerChanged(bool value) { _settingsService.UseIndexer = value; diff --git a/Screenbox/Pages/SettingsPage.xaml b/Screenbox/Pages/SettingsPage.xaml index 1ed1ddc9c..1ecaaf9ea 100644 --- a/Screenbox/Pages/SettingsPage.xaml +++ b/Screenbox/Pages/SettingsPage.xaml @@ -413,6 +413,23 @@ + + + + + + + + HideDelay1s + HideDelay2s + HideDelay3s + HideDelay4s + HideDelay5s + + diff --git a/Screenbox/Strings/en-US/Resources.resw b/Screenbox/Strings/en-US/Resources.resw index d075c68a2..ffe6e62b4 100644 --- a/Screenbox/Strings/en-US/Resources.resw +++ b/Screenbox/Strings/en-US/Resources.resw @@ -944,6 +944,24 @@ Display chapter name when available + + Dismiss controls after this amount of time without interaction + + + 1 second + + + 2 seconds + + + 3 seconds + + + 4 seconds + + + 5 seconds + App language From a76b7893dd9c74ee29a44f543990724f484396d9 Mon Sep 17 00:00:00 2001 From: United600 Date: Wed, 17 Sep 2025 17:34:32 +0100 Subject: [PATCH 3/5] refactor player controls delay and improve localization --- .../ViewModels/SettingsPageViewModel.cs | 23 +----- .../Converters/IntToUnitStringConverter.cs | 76 +++++++++++++++++++ Screenbox/Pages/SettingsPage.xaml | 13 ++-- Screenbox/Screenbox.csproj | 1 + Screenbox/Strings/en-US/Resources.resw | 19 ++--- 5 files changed, 92 insertions(+), 40 deletions(-) create mode 100644 Screenbox/Converters/IntToUnitStringConverter.cs diff --git a/Screenbox.Core/ViewModels/SettingsPageViewModel.cs b/Screenbox.Core/ViewModels/SettingsPageViewModel.cs index 33189bc6c..77b8e0e8c 100644 --- a/Screenbox.Core/ViewModels/SettingsPageViewModel.cs +++ b/Screenbox.Core/ViewModels/SettingsPageViewModel.cs @@ -52,6 +52,8 @@ public sealed partial class SettingsPageViewModel : ObservableRecipient public List AvailableLanguages { get; } + public int[] PlayerControlsHideDelayOptions { get; } = { 1, 2, 3, 4, 5 }; + private readonly ISettingsService _settingsService; private readonly ILibraryService _libraryService; private readonly DispatcherQueue _dispatcherQueue; @@ -100,15 +102,7 @@ public SettingsPageViewModel(ISettingsService settingsService, ILibraryService l _playerTapGesture = _settingsService.PlayerTapGesture; _playerShowControls = _settingsService.PlayerShowControls; _playerShowChapters = _settingsService.PlayerShowChapters; - _playerControlsHideDelay = _settingsService.PlayerControlsHideDelay switch - { - 1 => 0, - 2 => 1, - 3 => 2, - 4 => 3, - 5 => 4, - _ => 2 // Default to 3 seconds (Index 2) - }; + _playerControlsHideDelay = _settingsService.PlayerControlsHideDelay; _useIndexer = _settingsService.UseIndexer; _showRecent = _settingsService.ShowRecent; _theme = ((int)_settingsService.Theme + 2) % 3; @@ -199,16 +193,7 @@ partial void OnPlayerShowChaptersChanged(bool value) partial void OnPlayerControlsHideDelayChanged(int value) { - _settingsService.PlayerControlsHideDelay = value switch - { - // Index => Seconds - 0 => 1, - 1 => 2, - 2 => 3, - 3 => 4, - 4 => 5, - _ => 3 - }; + _settingsService.PlayerControlsHideDelay = value; Messenger.Send(new SettingsChangedMessage(nameof(PlayerControlsHideDelay), typeof(SettingsPageViewModel))); } diff --git a/Screenbox/Converters/IntToUnitStringConverter.cs b/Screenbox/Converters/IntToUnitStringConverter.cs new file mode 100644 index 000000000..fd2c822be --- /dev/null +++ b/Screenbox/Converters/IntToUnitStringConverter.cs @@ -0,0 +1,76 @@ +#nullable enable + +using System; +using Windows.UI.Xaml.Data; + +namespace Screenbox.Converters; + +/// +/// Defines the unit types for formatting numeric values with localized and pluralized resource strings. +/// +/// This enumeration is used by the property. +public enum UnitType +{ + None = 0, + Albums = 1, + Songs = 2, + Seconds = 4, + Items = 11, +} + +/// +/// Converts an integer representing a quantity into a localized string representation for a specified unit, +/// automatically adjusting for singular or plural forms based on the value. +/// +public sealed class IntToUnitStringConverter : IValueConverter +{ + /// + /// Gets or sets the unit type used to represent the count. + /// + public UnitType Unit { get; set; } = UnitType.None; + + /// + /// Converts an value to a localized , + /// using the appropriate singular or plural resource for the specified unit type. + /// + /// The being passed to the target. + /// The type of the target property. Not used. + /// An optional parameter to be used in the converter logic. Not used. + /// The language of the conversion. Not used. + /// The representing the amount and its unit; otherwise, the value as a . + public object Convert(object value, Type targetType, object parameter, string language) + { + if (value is int quantity && Unit is not UnitType.None) + { + return GetLocalizedCountAndUnit(quantity, Unit); + } + + return value?.ToString() ?? string.Empty; + } + + /// + /// Not implemented. + /// + /// The target data being passed to the source. + /// The type of the target property. + /// An optional parameter to be used in the converter logic. + /// The language of the conversion. + /// The value to be passed to the source object. + /// + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } + + private string GetLocalizedCountAndUnit(int value, UnitType unit) + { + return unit switch + { + UnitType.Albums => Strings.Resources.AlbumsCount(value), + UnitType.Songs => Strings.Resources.SongsCount(value), + UnitType.Seconds => Strings.Resources.SecondsCount(value), + UnitType.Items => Strings.Resources.ItemsCount(value), + _ => $"{value} {unit.ToString().ToLowerInvariant()}" + }; + } +} diff --git a/Screenbox/Pages/SettingsPage.xaml b/Screenbox/Pages/SettingsPage.xaml index 1ecaaf9ea..66f4a6ebc 100644 --- a/Screenbox/Pages/SettingsPage.xaml +++ b/Screenbox/Pages/SettingsPage.xaml @@ -32,6 +32,7 @@ +