2021-09-25 13:48:22 +05:30
import Defaults
import SwiftUI
2022-01-06 20:32:53 +05:30
struct PlayerSettings : View {
2021-11-04 05:10:01 +05:30
@ Default ( . instances ) private var instances
@ Default ( . playerInstanceID ) private var playerInstanceID
2022-01-06 20:32:53 +05:30
2021-11-04 04:30:17 +05:30
@ Default ( . playerSidebar ) private var playerSidebar
2022-08-28 22:48:49 +05:30
@ Default ( . playerControlsLayout ) private var playerControlsLayout
@ Default ( . fullScreenPlayerControlsLayout ) private var fullScreenPlayerControlsLayout
@ Default ( . horizontalPlayerGestureEnabled ) private var horizontalPlayerGestureEnabled
@ Default ( . seekGestureSpeed ) private var seekGestureSpeed
2022-08-29 17:37:27 +05:30
@ Default ( . seekGestureSensitivity ) private var seekGestureSensitivity
2021-11-04 04:44:09 +05:30
@ Default ( . showKeywords ) private var showKeywords
2021-12-19 22:47:04 +05:30
@ Default ( . pauseOnHidingPlayer ) private var pauseOnHidingPlayer
2022-01-03 01:13:30 +05:30
#if os ( iOS )
2022-11-13 17:19:39 +05:30
@ Default ( . honorSystemOrientationLock ) private var honorSystemOrientationLock
2022-01-03 01:13:30 +05:30
@ Default ( . enterFullscreenInLandscape ) private var enterFullscreenInLandscape
2022-08-07 17:18:50 +05:30
@ Default ( . rotateToPortraitOnExitFullScreen ) private var rotateToPortraitOnExitFullScreen
2022-01-03 01:13:30 +05:30
#endif
2021-12-19 22:47:04 +05:30
@ Default ( . closePiPOnNavigation ) private var closePiPOnNavigation
@ Default ( . closePiPOnOpeningPlayer ) private var closePiPOnOpeningPlayer
2022-08-27 01:47:21 +05:30
@ Default ( . closePlayerOnOpeningPiP ) private var closePlayerOnOpeningPiP
2021-12-19 22:47:04 +05:30
#if ! os ( macOS )
2022-06-30 15:16:20 +05:30
@ Default ( . pauseOnEnteringBackground ) private var pauseOnEnteringBackground
2021-12-19 22:47:04 +05:30
@ Default ( . closePiPAndOpenPlayerOnEnteringForeground ) private var closePiPAndOpenPlayerOnEnteringForeground
#endif
2021-11-04 04:30:17 +05:30
2022-03-21 02:01:19 +05:30
@ Default ( . enableReturnYouTubeDislike ) private var enableReturnYouTubeDislike
2022-07-11 21:40:51 +05:30
@ Default ( . systemControlsCommands ) private var systemControlsCommands
2022-12-19 00:09:03 +05:30
@ Default ( . openWatchNextOnClose ) private var openWatchNextOnClose
@ Default ( . openWatchNextOnFinishedWatching ) private var openWatchNextOnFinishedWatching
@ Default ( . openWatchNextOnFinishedWatchingDelay ) private var openWatchNextOnFinishedWatchingDelay
2022-12-19 16:38:27 +05:30
@ Default ( . buttonBackwardSeekDuration ) private var buttonBackwardSeekDuration
@ Default ( . buttonForwardSeekDuration ) private var buttonForwardSeekDuration
@ Default ( . gestureBackwardSeekDuration ) private var gestureBackwardSeekDuration
@ Default ( . gestureForwardSeekDuration ) private var gestureForwardSeekDuration
@ Default ( . systemControlsSeekDuration ) private var systemControlsSeekDuration
2022-12-19 15:59:18 +05:30
@ Default ( . actionButtonShareEnabled ) private var actionButtonShareEnabled
@ Default ( . actionButtonSubscribeEnabled ) private var actionButtonSubscribeEnabled
@ Default ( . actionButtonNextEnabled ) private var actionButtonNextEnabled
@ Default ( . actionButtonCloseEnabled ) private var actionButtonCloseEnabled
@ Default ( . actionButtonAddToPlaylistEnabled ) private var actionButtonAddToPlaylistEnabled
@ Default ( . actionButtonSettingsEnabled ) private var actionButtonSettingsEnabled
@ Default ( . actionButtonHideEnabled ) private var actionButtonHideEnabled
@ Default ( . actionButtonNextQueueCountEnabled ) private var actionButtonNextQueueCountEnabled
2022-12-19 16:38:27 +05:30
2022-11-25 02:06:05 +05:30
@ ObservedObject private var accounts = AccountsModel . shared
private var player = PlayerModel . shared
2022-03-21 02:01:19 +05:30
2021-11-04 04:30:17 +05:30
#if os ( iOS )
private var idiom : UIUserInterfaceIdiom {
UIDevice . current . userInterfaceIdiom
}
#endif
2021-09-25 13:48:22 +05:30
var body : some View {
2021-11-05 03:31:27 +05:30
Group {
2022-01-06 20:32:53 +05:30
#if os ( macOS )
sections
2021-12-19 22:47:04 +05:30
2022-01-06 20:32:53 +05:30
Spacer ( )
2021-11-05 03:31:27 +05:30
#else
2022-01-06 20:32:53 +05:30
List {
sections
2021-11-05 03:31:27 +05:30
}
2022-01-06 20:32:53 +05:30
#endif
}
#if os ( tvOS )
. frame ( maxWidth : 1000 )
#elseif os ( iOS )
. listStyle ( . insetGrouped )
#endif
. navigationTitle ( " Player " )
}
2021-11-04 05:10:01 +05:30
2022-01-06 20:32:53 +05:30
private var sections : some View {
Group {
2022-09-04 20:58:30 +05:30
Section ( header : SettingsHeader ( text : " Playback " . localized ( ) ) ) {
2022-11-12 01:04:20 +05:30
if ! accounts . isEmpty {
sourcePicker
}
2022-01-06 20:32:53 +05:30
pauseOnHidingPlayerToggle
2022-06-30 15:16:20 +05:30
#if ! os ( macOS )
pauseOnEnteringBackgroundToogle
#endif
2022-07-11 21:40:51 +05:30
systemControlsCommandsPicker
2022-01-06 20:32:53 +05:30
}
2021-11-04 04:44:09 +05:30
2022-12-19 16:38:27 +05:30
Section ( header : SettingsHeader ( text : " Seeking " ) , footer : seekingGestureSection ) {
seekingSection
}
2022-12-19 15:59:18 +05:30
#if ! os ( tvOS )
Section ( header : SettingsHeader ( text : " Actions Buttons " ) ) {
actionButtonToggles
}
actionButtonNextQueueCountEnabledToggle
#endif
2022-12-19 00:09:03 +05:30
Section ( header : SettingsHeader ( text : " Watch Next " ) ) {
openWatchNextOnFinishedWatchingToggle
openWatchNextOnFinishedWatchingDelayTextField
openWatchNextOnCloseToggle
}
2022-08-29 17:37:27 +05:30
#if ! os ( tvOS )
2022-09-04 20:58:30 +05:30
Section ( header : SettingsHeader ( text : " Controls " . localized ( ) ) , footer : controlsLayoutFooter ) {
2022-08-28 22:48:49 +05:30
horizontalPlayerGestureEnabledToggle
2022-09-04 20:58:30 +05:30
SettingsHeader ( text : " Seek gesture sensitivity " . localized ( ) , secondary : true )
2022-08-29 17:37:27 +05:30
seekGestureSensitivityPicker
2022-09-04 20:58:30 +05:30
SettingsHeader ( text : " Seek gesture speed " . localized ( ) , secondary : true )
2022-08-28 22:48:49 +05:30
seekGestureSpeedPicker
2022-09-04 20:58:30 +05:30
SettingsHeader ( text : " Regular size " . localized ( ) , secondary : true )
2022-08-28 22:48:49 +05:30
playerControlsLayoutPicker
2022-09-04 20:58:30 +05:30
SettingsHeader ( text : " Fullscreen size " . localized ( ) , secondary : true )
2022-08-29 17:37:27 +05:30
fullScreenPlayerControlsLayoutPicker
}
#endif
2022-08-28 22:48:49 +05:30
2022-11-19 03:34:49 +05:30
let interface = Section ( header : SettingsHeader ( text : " Interface " . localized ( ) ) ) {
2022-01-06 20:32:53 +05:30
#if os ( iOS )
if idiom = = . pad {
2021-11-05 03:31:27 +05:30
sidebarPicker
}
#endif
2022-01-06 20:32:53 +05:30
#if os ( macOS )
sidebarPicker
#endif
2022-11-12 01:04:20 +05:30
if ! accounts . isEmpty {
keywordsToggle
2022-10-26 16:41:35 +05:30
returnYouTubeDislikeToggle
}
2022-01-06 20:32:53 +05:30
}
2021-12-19 22:47:04 +05:30
2022-11-19 03:34:49 +05:30
#if os ( tvOS )
if ! accounts . isEmpty {
interface
}
#elseif os ( macOS )
interface
#elseif os ( iOS )
if idiom = = . pad || ! accounts . isEmpty {
interface
}
#endif
2022-01-06 20:32:53 +05:30
#if os ( iOS )
2022-09-04 20:58:30 +05:30
Section ( header : SettingsHeader ( text : " Orientation " . localized ( ) ) ) {
2022-01-06 20:32:53 +05:30
if idiom = = . pad {
enterFullscreenInLandscapeToggle
}
2022-08-07 17:18:50 +05:30
rotateToPortraitOnExitFullScreenToggle
2022-11-13 17:19:39 +05:30
honorSystemOrientationLockToggle
2021-12-19 22:47:04 +05:30
}
2021-11-05 03:31:27 +05:30
#endif
2022-08-07 17:18:50 +05:30
2022-09-04 20:58:30 +05:30
Section ( header : SettingsHeader ( text : " Picture in Picture " . localized ( ) ) ) {
2022-08-07 17:18:50 +05:30
closePiPOnNavigationToggle
closePiPOnOpeningPlayerToggle
2022-08-27 01:47:21 +05:30
closePlayerOnOpeningPiPToggle
2022-08-07 17:18:50 +05:30
#if ! os ( macOS )
closePiPAndOpenPlayerOnEnteringForegroundToggle
#endif
}
2022-01-06 20:32:53 +05:30
}
2021-11-04 04:44:09 +05:30
}
2022-11-14 04:06:46 +05:30
private var videoDetailsHeaderPadding : Double {
#if os ( macOS )
5.0
#else
0.0
#endif
}
2021-11-05 03:31:27 +05:30
private var sourcePicker : some View {
Picker ( " Source " , selection : $ playerInstanceID ) {
2022-09-04 20:58:30 +05:30
Text ( " Instance of current account " ) . tag ( String ? . none )
2021-11-04 05:10:01 +05:30
2021-11-05 03:31:27 +05:30
ForEach ( instances ) { instance in
2021-12-05 01:05:41 +05:30
Text ( instance . description ) . tag ( Optional ( instance . id ) )
2021-11-04 05:10:01 +05:30
}
}
2022-08-06 19:58:05 +05:30
. modifier ( SettingsPickerModifier ( ) )
2022-07-11 21:40:51 +05:30
}
private var systemControlsCommandsPicker : some View {
2022-07-11 23:31:27 +05:30
func labelText ( _ label : String ) -> String {
#if os ( macOS )
2022-09-04 20:58:30 +05:30
String ( format : " System controls show buttons for %@ " . localized ( ) , label )
2022-07-11 23:31:27 +05:30
#else
label
#endif
}
return Picker ( " System controls buttons " , selection : $ systemControlsCommands ) {
2022-09-04 20:58:30 +05:30
Text ( labelText ( " 10 seconds forwards/backwards " . localized ( ) ) ) . tag ( SystemControlsCommands . seek )
Text ( labelText ( " Restart/Play next " . localized ( ) ) ) . tag ( SystemControlsCommands . restartAndAdvanceToNext )
2022-07-11 21:40:51 +05:30
}
. onChange ( of : systemControlsCommands ) { _ in
player . updateRemoteCommandCenter ( )
}
2022-08-06 19:58:05 +05:30
. modifier ( SettingsPickerModifier ( ) )
2021-11-04 05:10:01 +05:30
}
2022-12-19 00:09:03 +05:30
private var openWatchNextOnCloseToggle : some View {
Toggle ( " Open after manual close of video " , isOn : $ openWatchNextOnClose )
}
private var openWatchNextOnFinishedWatchingToggle : some View {
Toggle ( " Open after watching video " , isOn : $ openWatchNextOnFinishedWatching )
}
private var openWatchNextOnFinishedWatchingDelayTextField : some View {
HStack {
Text ( " Autoplay delay " )
. frame ( minWidth : 140 , alignment : . leading )
#if ! os ( iOS )
Spacer ( )
#endif
TextField ( " Delay " , text : $ openWatchNextOnFinishedWatchingDelay )
#if ! os ( iOS )
. frame ( maxWidth : 100 , alignment : . trailing )
#endif
. labelsHidden ( )
#if ! os ( macOS )
. keyboardType ( . numberPad )
#endif
}
. multilineTextAlignment ( . trailing )
}
2022-12-19 16:38:27 +05:30
@ ViewBuilder private var seekingSection : some View {
seekingDurationSetting ( " System controls " , $ systemControlsSeekDuration )
. foregroundColor ( systemControlsCommands = = . restartAndAdvanceToNext ? . secondary : . primary )
. disabled ( systemControlsCommands = = . restartAndAdvanceToNext )
seekingDurationSetting ( " Controls button: backwards " , $ buttonBackwardSeekDuration )
seekingDurationSetting ( " Controls button: forwards " , $ buttonForwardSeekDuration )
seekingDurationSetting ( " Gesture: backwards " , $ gestureBackwardSeekDuration )
seekingDurationSetting ( " Gesture: fowards " , $ gestureForwardSeekDuration )
}
private var seekingGestureSection : some View {
#if os ( iOS )
Text ( " Gesture settings control skipping interval for double tap gesture on left/right side of the player. Changing system controls settings requires restart. " )
#elseif os ( macOS )
Text ( " Gesture settings control skipping interval for double click on left/right side of the player. Changing system controls settings requires restart. " )
#else
Text ( " Gesture settings control skipping interval for remote arrow buttons (for 2nd generation Siri Remote or newer). Changing system controls settings requires restart. " )
#endif
}
private func seekingDurationSetting ( _ name : String , _ value : Binding < String > ) -> some View {
HStack {
Text ( name )
. frame ( minWidth : 140 , alignment : . leading )
Spacer ( )
TextField ( " Duration " , text : value )
. frame ( maxWidth : 50 , alignment : . trailing )
. multilineTextAlignment ( . trailing )
. labelsHidden ( )
#if ! os ( macOS )
. keyboardType ( . numberPad )
#endif
}
}
2022-12-19 15:59:18 +05:30
@ ViewBuilder private var actionButtonToggles : some View {
actionButtonToggle ( " Share " , $ actionButtonShareEnabled )
actionButtonToggle ( " Add to Playlist " , $ actionButtonAddToPlaylistEnabled )
actionButtonToggle ( " Subscribe/Unsubscribe " , $ actionButtonSubscribeEnabled )
actionButtonToggle ( " Settings " , $ actionButtonSettingsEnabled )
actionButtonToggle ( " Watch Next " , $ actionButtonNextEnabled )
actionButtonToggle ( " Hide player " , $ actionButtonHideEnabled )
actionButtonToggle ( " Close video " , $ actionButtonCloseEnabled )
}
private func actionButtonToggle ( _ name : String , _ value : Binding < Bool > ) -> some View {
Toggle ( name , isOn : value )
}
var actionButtonNextQueueCountEnabledToggle : some View {
Toggle ( " Show queue items count in Watch Next button label " , isOn : $ actionButtonNextQueueCountEnabled )
}
2021-11-04 04:44:09 +05:30
private var sidebarPicker : some View {
Picker ( " Sidebar " , selection : $ playerSidebar ) {
#if os ( macOS )
2022-01-06 20:32:53 +05:30
Text ( " Show sidebar " ) . tag ( PlayerSidebarSetting . always )
2021-11-04 04:44:09 +05:30
#endif
2021-11-04 04:30:17 +05:30
#if os ( iOS )
2021-11-04 04:44:09 +05:30
Text ( " Show sidebar when space permits " ) . tag ( PlayerSidebarSetting . whenFits )
2021-09-25 13:48:22 +05:30
#endif
2021-11-04 04:44:09 +05:30
2022-01-06 20:32:53 +05:30
Text ( " Hide sidebar " ) . tag ( PlayerSidebarSetting . never )
2021-09-25 13:48:22 +05:30
}
2022-08-06 19:58:05 +05:30
. modifier ( SettingsPickerModifier ( ) )
2021-09-25 13:48:22 +05:30
}
2021-11-05 03:31:27 +05:30
2022-08-28 22:48:49 +05:30
private var horizontalPlayerGestureEnabledToggle : some View {
Toggle ( " Seek with horizontal swipe on video " , isOn : $ horizontalPlayerGestureEnabled )
}
private var seekGestureSpeedPicker : some View {
2022-08-29 17:37:27 +05:30
Picker ( " Seek gesture speed " , selection : $ seekGestureSpeed ) {
2022-08-28 22:48:49 +05:30
ForEach ( [ 1 , 0.75 , 0.66 , 0.5 , 0.33 , 0.25 , 0.1 ] , id : \ . self ) { value in
Text ( String ( format : " %.0f%% " , value * 100 ) ) . tag ( value )
}
}
. disabled ( ! horizontalPlayerGestureEnabled )
. modifier ( SettingsPickerModifier ( ) )
}
2022-08-29 17:37:27 +05:30
private var seekGestureSensitivityPicker : some View {
Picker ( " Seek gesture sensitivity " , selection : $ seekGestureSensitivity ) {
Text ( " Highest " ) . tag ( 1.0 )
Text ( " High " ) . tag ( 10.0 )
Text ( " Normal " ) . tag ( 30.0 )
Text ( " Low " ) . tag ( 50.0 )
Text ( " Lowest " ) . tag ( 100.0 )
}
. disabled ( ! horizontalPlayerGestureEnabled )
. modifier ( SettingsPickerModifier ( ) )
}
2022-08-28 22:48:49 +05:30
@ ViewBuilder private var controlsLayoutFooter : some View {
#if os ( iOS )
2022-08-29 18:11:21 +05:30
Text ( " Large layout is not suitable for all devices and using it may cause controls not to fit on the screen. " )
2022-08-28 22:48:49 +05:30
#endif
}
private var playerControlsLayoutPicker : some View {
Picker ( " Regular Size " , selection : $ playerControlsLayout ) {
2022-08-29 18:11:21 +05:30
ForEach ( PlayerControlsLayout . allCases . filter ( \ . available ) , id : \ . self ) { layout in
2022-08-28 22:48:49 +05:30
Text ( layout . description ) . tag ( layout . rawValue )
}
}
. modifier ( SettingsPickerModifier ( ) )
}
private var fullScreenPlayerControlsLayoutPicker : some View {
2022-09-27 18:52:40 +05:30
Picker ( " Fullscreen size " , selection : $ fullScreenPlayerControlsLayout ) {
2022-08-29 18:11:21 +05:30
ForEach ( PlayerControlsLayout . allCases . filter ( \ . available ) , id : \ . self ) { layout in
2022-08-28 22:48:49 +05:30
Text ( layout . description ) . tag ( layout . rawValue )
}
}
. modifier ( SettingsPickerModifier ( ) )
}
2021-11-05 03:31:27 +05:30
private var keywordsToggle : some View {
2022-01-06 20:32:53 +05:30
Toggle ( " Show keywords " , isOn : $ showKeywords )
2021-11-05 03:31:27 +05:30
}
2021-12-18 01:31:05 +05:30
2022-03-21 02:01:19 +05:30
private var returnYouTubeDislikeToggle : some View {
Toggle ( " Enable Return YouTube Dislike " , isOn : $ enableReturnYouTubeDislike )
}
2021-12-19 22:47:04 +05:30
private var pauseOnHidingPlayerToggle : some View {
Toggle ( " Pause when player is closed " , isOn : $ pauseOnHidingPlayer )
}
2022-06-30 15:16:20 +05:30
#if ! os ( macOS )
private var pauseOnEnteringBackgroundToogle : some View {
Toggle ( " Pause when entering background " , isOn : $ pauseOnEnteringBackground )
}
#endif
2022-01-03 01:13:30 +05:30
#if os ( iOS )
2022-11-13 17:19:39 +05:30
private var honorSystemOrientationLockToggle : some View {
Toggle ( " Honor orientation lock " , isOn : $ honorSystemOrientationLock )
. disabled ( ! enterFullscreenInLandscape )
}
2022-01-03 01:13:30 +05:30
private var enterFullscreenInLandscapeToggle : some View {
Toggle ( " Enter fullscreen in landscape " , isOn : $ enterFullscreenInLandscape )
}
2022-08-07 17:18:50 +05:30
private var rotateToPortraitOnExitFullScreenToggle : some View {
Toggle ( " Rotate to portrait when exiting fullscreen " , isOn : $ rotateToPortraitOnExitFullScreen )
}
2022-01-03 01:13:30 +05:30
#endif
2021-12-19 22:47:04 +05:30
private var closePiPOnNavigationToggle : some View {
Toggle ( " Close PiP when starting playing other video " , isOn : $ closePiPOnNavigation )
}
private var closePiPOnOpeningPlayerToggle : some View {
Toggle ( " Close PiP when player is opened " , isOn : $ closePiPOnOpeningPlayer )
}
2022-08-27 01:47:21 +05:30
private var closePlayerOnOpeningPiPToggle : some View {
Toggle ( " Close player when starting PiP " , isOn : $ closePlayerOnOpeningPiP )
}
2021-12-19 22:47:04 +05:30
#if ! os ( macOS )
private var closePiPAndOpenPlayerOnEnteringForegroundToggle : some View {
Toggle ( " Close PiP and open player when application enters foreground " , isOn : $ closePiPAndOpenPlayerOnEnteringForeground )
}
#endif
2021-11-05 03:31:27 +05:30
}
2022-08-07 16:45:27 +05:30
struct PlayerSettings_Previews : PreviewProvider {
2021-11-05 03:31:27 +05:30
static var previews : some View {
2022-06-17 15:57:01 +05:30
VStack ( alignment : . leading ) {
PlayerSettings ( )
}
2022-11-14 04:06:46 +05:30
. frame ( minHeight : 800 )
2022-06-17 15:57:01 +05:30
. injectFixtureEnvironmentObjects ( )
2021-11-05 03:31:27 +05:30
}
2021-09-25 13:48:22 +05:30
}