From ccc1cc89ad5121b3c44d03d7c2b08f3e7665ad7a Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sun, 29 May 2022 16:38:37 +0200 Subject: [PATCH] Add Open in PiP option (fix #137) --- Model/Player/PiPDelegate.swift | 5 ++++- Model/Player/PlayerControlsModel.swift | 23 ++++++++++++++++++++ Model/Player/PlayerModel.swift | 11 ++++++++-- Shared/Player/Controls/PlayerControls.swift | 20 +---------------- Shared/Views/VideoContextMenuView.swift | 24 +++++++++++++++++++++ 5 files changed, 61 insertions(+), 22 deletions(-) diff --git a/Model/Player/PiPDelegate.swift b/Model/Player/PiPDelegate.swift index 9ac10894..c34ec797 100644 --- a/Model/Player/PiPDelegate.swift +++ b/Model/Player/PiPDelegate.swift @@ -37,6 +37,9 @@ final class PiPDelegate: NSObject, AVPictureInPictureControllerDelegate { _: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void ) { - completionHandler(true) + player?.show() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + completionHandler(true) + } } } diff --git a/Model/Player/PlayerControlsModel.swift b/Model/Player/PlayerControlsModel.swift index af6b2064..5c460a82 100644 --- a/Model/Player/PlayerControlsModel.swift +++ b/Model/Player/PlayerControlsModel.swift @@ -109,6 +109,29 @@ final class PlayerControlsModel: ObservableObject { } } + func startPiP(startImmediately: Bool = true) { + if player.activeBackend == .mpv { + player.avPlayerBackend.switchToMPVOnPipClose = true + } + + #if !os(macOS) + player.exitFullScreen() + #endif + + if player.activeBackend != PlayerBackendType.appleAVPlayer { + player.saveTime { [weak player] in + player?.changeActiveBackend(from: .mpv, to: .appleAVPlayer) + } + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak player] in + player?.avPlayerBackend.startPictureInPictureOnPlay = true + if startImmediately { + player?.pipController?.startPictureInPicture() + } + } + } + func removeTimer() { timer?.invalidate() timer = nil diff --git a/Model/Player/PlayerModel.swift b/Model/Player/PlayerModel.swift index cd06e5b2..3ab50f25 100644 --- a/Model/Player/PlayerModel.swift +++ b/Model/Player/PlayerModel.swift @@ -205,7 +205,7 @@ final class PlayerModel: ObservableObject { backend.pause() } - func play(_ video: Video, at time: CMTime? = nil) { + func play(_ video: Video, at time: CMTime? = nil, showingPlayer: Bool = true) { var delay = 0.0 #if !os(macOS) delay = 0.3 @@ -223,7 +223,9 @@ final class PlayerModel: ObservableObject { return } - show() + if showingPlayer { + show() + } } func playStream( @@ -268,6 +270,7 @@ final class PlayerModel: ObservableObject { func saveTime(completionHandler: @escaping () -> Void = {}) { guard let currentTime = backend.currentTime, currentTime.seconds > 0 else { + completionHandler() return } @@ -341,6 +344,10 @@ final class PlayerModel: ObservableObject { } func changeActiveBackend(from: PlayerBackendType, to: PlayerBackendType) { + guard activeBackend != to else { + return + } + Defaults[.activeBackend] = to self.activeBackend = to diff --git a/Shared/Player/Controls/PlayerControls.swift b/Shared/Player/Controls/PlayerControls.swift index 9bac8841..38d400f8 100644 --- a/Shared/Player/Controls/PlayerControls.swift +++ b/Shared/Player/Controls/PlayerControls.swift @@ -265,25 +265,7 @@ struct PlayerControls: View { private var pipButton: some View { button("PiP", systemImage: "pip") { - if player.activeBackend == .mpv { - player.avPlayerBackend.switchToMPVOnPipClose = true - } - - #if !os(macOS) - player.exitFullScreen() - #endif - - if player.activeBackend != PlayerBackendType.appleAVPlayer { - player.saveTime { - player.changeActiveBackend(from: .mpv, to: .appleAVPlayer) - } - } - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { - print(player.pipController?.isPictureInPicturePossible ?? false ? "possible" : "NOT possible") - player.avPlayerBackend.startPictureInPictureOnPlay = true - player.pipController?.startPictureInPicture() - } + model.startPiP() } } diff --git a/Shared/Views/VideoContextMenuView.swift b/Shared/Views/VideoContextMenuView.swift index 16f03e68..d8b84387 100644 --- a/Shared/Views/VideoContextMenuView.swift +++ b/Shared/Views/VideoContextMenuView.swift @@ -1,4 +1,5 @@ import CoreData +import CoreMedia import Defaults import SwiftUI @@ -53,6 +54,9 @@ struct VideoContextMenuView: View { Section { playNowButton + #if os(iOS) + playNowInPictureInPictureButton + #endif } Section { @@ -133,6 +137,26 @@ struct VideoContextMenuView: View { } } + private var playNowInPictureInPictureButton: some View { + Button { + player.controls.startPiP(startImmediately: false) + + var time: CMTime? + if saveHistory, + let stoppedAt = watch?.stoppedAt, + !watch!.finished + { + time = .secondsInDefaultTimescale(stoppedAt) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + player.play(video, at: time, showingPlayer: false) + } + } label: { + Label("Play in PiP", systemImage: "pip") + } + } + private var playNextButton: some View { Button { player.playNext(video)