From 79f801ea60e6099974aee4202f3b69f776e2521e Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Mon, 11 Jul 2022 18:10:51 +0200 Subject: [PATCH] Add setting for controls center buttons --- Model/Player/PlayerModel.swift | 89 +++++++++++++++++++++++++++- Shared/Defaults.swift | 5 ++ Shared/Settings/PlayerSettings.swift | 20 +++++++ Shared/YatteeApp.swift | 56 +---------------- 4 files changed, 115 insertions(+), 55 deletions(-) diff --git a/Model/Player/PlayerModel.swift b/Model/Player/PlayerModel.swift index bf037fb5..b720044e 100644 --- a/Model/Player/PlayerModel.swift +++ b/Model/Player/PlayerModel.swift @@ -82,7 +82,7 @@ final class PlayerModel: ObservableObject { @Published var restoredSegments = [Segment]() @Published var musicMode = false - @Published var playbackMode = PlaybackMode.queue { didSet { handlePlaybackModeChange() }} + @Published var playbackMode = PlaybackMode.queue { didSet { handlePlaybackModeChange() } } @Published var autoplayItem: PlayerQueueItem? @Published var autoplayItemSource: Video? @Published var advancing = false @@ -158,6 +158,7 @@ final class PlayerModel: ObservableObject { #endif var onPresentPlayer: (() -> Void)? + private var remoteCommandCenterConfigured = false init( accounts: AccountsModel = AccountsModel(), @@ -537,6 +538,7 @@ final class PlayerModel: ObservableObject { func handleQueueChange() { Defaults[.queue] = queue + updateRemoteCommandCenter() controls.objectWillChange.send() } @@ -561,6 +563,8 @@ final class PlayerModel: ObservableObject { func handlePlaybackModeChange() { Defaults[.playbackMode] = playbackMode + updateRemoteCommandCenter() + guard playbackMode == .related else { autoplayItem = nil return @@ -580,11 +584,94 @@ final class PlayerModel: ObservableObject { self.accounts.api.loadDetails(item, completionHandler: { newItem in guard newItem.videoID == self.autoplayItem?.videoID else { return } self.autoplayItem = newItem + self.updateRemoteCommandCenter() self.controls.objectWillChange.send() }) } } + func updateRemoteCommandCenter() { + let skipForwardCommand = MPRemoteCommandCenter.shared().skipForwardCommand + let skipBackwardCommand = MPRemoteCommandCenter.shared().skipBackwardCommand + let previousTrackCommand = MPRemoteCommandCenter.shared().previousTrackCommand + let nextTrackCommand = MPRemoteCommandCenter.shared().nextTrackCommand + + if !remoteCommandCenterConfigured { + remoteCommandCenterConfigured = true + + #if !os(macOS) + try? AVAudioSession.sharedInstance().setCategory( + .playback, + mode: .moviePlayback + ) + + UIApplication.shared.beginReceivingRemoteControlEvents() + #endif + + let preferredIntervals = [NSNumber(10)] + + skipForwardCommand.preferredIntervals = preferredIntervals + skipBackwardCommand.preferredIntervals = preferredIntervals + + skipForwardCommand.addTarget { [weak self] _ in + self?.backend.seek(relative: .secondsInDefaultTimescale(10)) + return .success + } + + skipBackwardCommand.addTarget { [weak self] _ in + self?.backend.seek(relative: .secondsInDefaultTimescale(-10)) + return .success + } + + previousTrackCommand.addTarget { [weak self] _ in + self?.backend.seek(to: .zero) + return .success + } + + nextTrackCommand.addTarget { [weak self] _ in + self?.advanceToNextItem() + return .success + } + + MPRemoteCommandCenter.shared().playCommand.addTarget { [weak self] _ in + self?.play() + return .success + } + + MPRemoteCommandCenter.shared().pauseCommand.addTarget { [weak self] _ in + self?.pause() + return .success + } + + MPRemoteCommandCenter.shared().togglePlayPauseCommand.addTarget { [weak self] _ in + self?.togglePlay() + return .success + } + + MPRemoteCommandCenter.shared().changePlaybackPositionCommand.addTarget { [weak self] remoteEvent in + guard let event = remoteEvent as? MPChangePlaybackPositionCommandEvent else { return .commandFailed } + + self?.backend.seek(to: event.positionTime) + + return .success + } + } + + switch Defaults[.systemControlsCommands] { + case .seek: + previousTrackCommand.isEnabled = false + nextTrackCommand.isEnabled = false + skipForwardCommand.isEnabled = true + skipBackwardCommand.isEnabled = true + + case .restartAndAdvanceToNext: + skipForwardCommand.isEnabled = false + skipBackwardCommand.isEnabled = false + previousTrackCommand.isEnabled = true + nextTrackCommand.isEnabled = isAdvanceToNextItemAvailable + } + } + func resetAutoplay() { autoplayItem = nil autoplayItemSource = nil diff --git a/Shared/Defaults.swift b/Shared/Defaults.swift index 36e505d0..5d538cb8 100644 --- a/Shared/Defaults.swift +++ b/Shared/Defaults.swift @@ -99,6 +99,7 @@ extension Defaults.Keys { static let playerDetailsPageButtonLabelStyle = Key("playerDetailsPageButtonLabelStyle", default: defaultForPlayerDetailsPageButtonLabelStyle) + static let systemControlsCommands = Key("systemControlsCommands", default: .restartAndAdvanceToNext) static let mpvCacheSecs = Key("mpvCacheSecs", default: "20") static let mpvCachePauseWait = Key("mpvCachePauseWait", default: "2") static let mpvEnableLogging = Key("mpvEnableLogging", default: false) @@ -225,3 +226,7 @@ enum PlayerDetailsPageButtonLabelStyle: String, CaseIterable, Defaults.Serializa enum ThumbnailsQuality: String, CaseIterable, Defaults.Serializable { case highest, medium, low } + +enum SystemControlsCommands: String, CaseIterable, Defaults.Serializable { + case seek, restartAndAdvanceToNext +} diff --git a/Shared/Settings/PlayerSettings.swift b/Shared/Settings/PlayerSettings.swift index 9f93a66e..8a59b59a 100644 --- a/Shared/Settings/PlayerSettings.swift +++ b/Shared/Settings/PlayerSettings.swift @@ -23,6 +23,9 @@ struct PlayerSettings: View { #endif @Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike + @Default(.systemControlsCommands) private var systemControlsCommands + + @EnvironmentObject private var player #if os(iOS) private var idiom: UIUserInterfaceIdiom { @@ -60,6 +63,7 @@ struct PlayerSettings: View { pauseOnEnteringBackgroundToogle #endif closeLastItemOnPlaybackEndToggle + systemControlsCommandsPicker } Section(header: SettingsHeader(text: "Interface")) { @@ -113,6 +117,22 @@ struct PlayerSettings: View { #endif } + private var systemControlsCommandsPicker: some View { + Picker("System controls buttons", selection: $systemControlsCommands) { + Text("10 seconds forwards/backwards").tag(SystemControlsCommands.seek) + Text("Restart/Play next").tag(SystemControlsCommands.restartAndAdvanceToNext) + } + .onChange(of: systemControlsCommands) { _ in + player.updateRemoteCommandCenter() + } + .labelsHidden() + #if os(iOS) + .pickerStyle(.automatic) + #elseif os(tvOS) + .pickerStyle(.inline) + #endif + } + private var qualityPicker: some View { Picker("Quality", selection: $quality) { ForEach(ResolutionSetting.allCases, id: \.self) { resolution in diff --git a/Shared/YatteeApp.swift b/Shared/YatteeApp.swift index 1cff89de..d6b21f4a 100644 --- a/Shared/YatteeApp.swift +++ b/Shared/YatteeApp.swift @@ -168,10 +168,6 @@ struct YatteeApp: App { SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared) SDWebImageManager.defaultImageCache = PINCache(name: "stream.yattee.app") - #if !os(macOS) - configureNowPlayingInfoCenter() - #endif - #if os(iOS) if Defaults[.lockPortraitWhenBrowsing] { Orientation.lockOrientation(.portrait, andRotateTo: .portrait) @@ -236,56 +232,8 @@ struct YatteeApp: App { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { Windows.main.focus() } + #else + player.updateRemoteCommandCenter() #endif } - - func configureNowPlayingInfoCenter() { - #if !os(macOS) - try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback) - - UIApplication.shared.beginReceivingRemoteControlEvents() - #endif - - MPRemoteCommandCenter.shared().playCommand.addTarget { _ in - player.play() - return .success - } - - MPRemoteCommandCenter.shared().pauseCommand.addTarget { _ in - player.pause() - return .success - } - - MPRemoteCommandCenter.shared().previousTrackCommand.isEnabled = false - MPRemoteCommandCenter.shared().nextTrackCommand.isEnabled = false - - MPRemoteCommandCenter.shared().changePlaybackPositionCommand.addTarget { remoteEvent in - guard let event = remoteEvent as? MPChangePlaybackPositionCommandEvent - else { - return .commandFailed - } - - player.backend.seek(to: event.positionTime) - - return .success - } - - let skipForwardCommand = MPRemoteCommandCenter.shared().skipForwardCommand - skipForwardCommand.isEnabled = true - skipForwardCommand.preferredIntervals = [10] - - skipForwardCommand.addTarget { _ in - player.backend.seek(relative: .secondsInDefaultTimescale(10)) - return .success - } - - let skipBackwardCommand = MPRemoteCommandCenter.shared().skipBackwardCommand - skipBackwardCommand.isEnabled = true - skipBackwardCommand.preferredIntervals = [10] - - skipBackwardCommand.addTarget { _ in - player.backend.seek(relative: .secondsInDefaultTimescale(-10)) - return .success - } - } }