2022-05-20 21:23:14 +00:00
|
|
|
import AVKit
|
2021-09-25 08:18:22 +00:00
|
|
|
import Defaults
|
2021-07-18 22:32:46 +00:00
|
|
|
import SwiftUI
|
|
|
|
|
2023-05-20 20:49:10 +00:00
|
|
|
#if !os(macOS)
|
|
|
|
final class AppleAVPlayerViewControllerDelegate: NSObject, AVPlayerViewControllerDelegate {
|
|
|
|
var player: PlayerModel { .shared }
|
|
|
|
|
|
|
|
func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_: AVPlayerViewController) -> Bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2023-06-07 21:19:00 +00:00
|
|
|
#if os(iOS)
|
|
|
|
func playerViewController(_: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator) {
|
2024-09-06 15:05:20 +00:00
|
|
|
let lockOrientation = player.rotateToLandscapeOnEnterFullScreen.interfaceOrientation
|
|
|
|
if player.currentVideoIsLandscape {
|
|
|
|
if player.fullscreenInitiatedByButton {
|
|
|
|
Orientation.lockOrientation(player.isOrientationLocked
|
|
|
|
? (lockOrientation == .landscapeRight ? .landscapeRight : .landscapeLeft)
|
|
|
|
: .landscape)
|
2023-05-21 17:11:11 +00:00
|
|
|
}
|
2024-09-06 15:05:20 +00:00
|
|
|
let orientation = OrientationTracker.shared.currentDeviceOrientation.isLandscape
|
|
|
|
? OrientationTracker.shared.currentInterfaceOrientation
|
|
|
|
: player.rotateToLandscapeOnEnterFullScreen.interfaceOrientation
|
|
|
|
|
|
|
|
Orientation.lockOrientation(
|
|
|
|
player.isOrientationLocked
|
|
|
|
? (lockOrientation == .landscapeRight ? .landscapeRight : .landscapeLeft)
|
|
|
|
: .all,
|
|
|
|
andRotateTo: orientation
|
|
|
|
)
|
2023-05-21 17:11:11 +00:00
|
|
|
}
|
2023-06-07 21:19:00 +00:00
|
|
|
}
|
2023-05-20 20:49:10 +00:00
|
|
|
|
2023-06-07 21:19:00 +00:00
|
|
|
func playerViewController(_: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
|
|
|
let wasPlaying = player.isPlaying
|
|
|
|
coordinator.animate(alongsideTransition: nil) { context in
|
2023-05-20 20:49:10 +00:00
|
|
|
if wasPlaying {
|
|
|
|
self.player.play()
|
|
|
|
}
|
2023-06-07 21:19:00 +00:00
|
|
|
if !context.isCancelled {
|
|
|
|
#if os(iOS)
|
2024-09-06 15:05:20 +00:00
|
|
|
if self.player.lockPortraitWhenBrowsing {
|
|
|
|
self.player.lockedOrientation = UIInterfaceOrientationMask.portrait
|
2023-06-07 21:19:00 +00:00
|
|
|
}
|
2024-09-06 15:05:20 +00:00
|
|
|
let rotationOrientation = self.player.lockPortraitWhenBrowsing ? UIInterfaceOrientation.portrait : nil
|
|
|
|
Orientation.lockOrientation(self.player.lockPortraitWhenBrowsing ? .portrait : .all, andRotateTo: rotationOrientation)
|
2023-05-20 20:49:10 +00:00
|
|
|
|
2023-06-07 21:19:00 +00:00
|
|
|
if wasPlaying {
|
|
|
|
self.player.play()
|
|
|
|
}
|
2023-05-20 20:49:10 +00:00
|
|
|
|
2023-06-07 21:19:00 +00:00
|
|
|
self.player.playingFullScreen = false
|
|
|
|
#endif
|
|
|
|
}
|
2023-05-20 20:49:10 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-07 21:19:00 +00:00
|
|
|
|
|
|
|
func playerViewController(_: AVPlayerViewController, restoreUserInterfaceForFullScreenExitWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
|
|
|
|
withAnimation(nil) {
|
|
|
|
player.presentingPlayer = true
|
|
|
|
}
|
|
|
|
|
|
|
|
completionHandler(true)
|
|
|
|
}
|
|
|
|
#endif
|
2023-05-20 20:49:10 +00:00
|
|
|
|
|
|
|
func playerViewControllerWillStartPictureInPicture(_: AVPlayerViewController) {}
|
|
|
|
|
|
|
|
func playerViewControllerWillStopPictureInPicture(_: AVPlayerViewController) {}
|
|
|
|
|
|
|
|
func playerViewControllerDidStartPictureInPicture(_: AVPlayerViewController) {
|
|
|
|
player.playingInPictureInPicture = true
|
|
|
|
player.avPlayerBackend.startPictureInPictureOnPlay = false
|
|
|
|
player.avPlayerBackend.startPictureInPictureOnSwitch = false
|
|
|
|
player.controls.objectWillChange.send()
|
|
|
|
|
|
|
|
if Defaults[.closePlayerOnOpeningPiP] { Delay.by(0.1) { self.player.hide() } }
|
|
|
|
}
|
|
|
|
|
|
|
|
func playerViewControllerDidStopPictureInPicture(_: AVPlayerViewController) {
|
|
|
|
player.playingInPictureInPicture = false
|
|
|
|
player.controls.objectWillChange.send()
|
|
|
|
}
|
|
|
|
|
|
|
|
func playerViewController(_: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
|
|
|
|
player.presentingPlayer = true
|
|
|
|
withAnimation(.linear(duration: 0.3)) {
|
|
|
|
self.player.playingInPictureInPicture = false
|
|
|
|
Delay.by(0.5) {
|
|
|
|
completionHandler(true)
|
|
|
|
Delay.by(0.2) {
|
|
|
|
self.player.play()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-08-20 21:05:40 +00:00
|
|
|
#if os(iOS)
|
2023-05-20 20:49:10 +00:00
|
|
|
struct AppleAVPlayerView: UIViewControllerRepresentable {
|
|
|
|
@State private var controller = AVPlayerViewController()
|
|
|
|
|
|
|
|
func makeUIViewController(context _: Context) -> AVPlayerViewController {
|
|
|
|
setupController()
|
|
|
|
return controller
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateUIViewController(_: AVPlayerViewController, context _: Context) {
|
|
|
|
setupController()
|
|
|
|
}
|
|
|
|
|
|
|
|
func setupController() {
|
|
|
|
controller.delegate = PlayerModel.shared.appleAVPlayerViewControllerDelegate
|
|
|
|
controller.allowsPictureInPicturePlayback = true
|
|
|
|
if #available(iOS 14.2, *) {
|
|
|
|
controller.canStartPictureInPictureAutomaticallyFromInline = true
|
|
|
|
}
|
|
|
|
PlayerModel.shared.avPlayerBackend.controller = controller
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct AppleAVPlayerLayerView: UIViewRepresentable {
|
2022-08-20 21:05:40 +00:00
|
|
|
func makeUIView(context _: Context) -> some UIView {
|
2023-05-20 20:49:10 +00:00
|
|
|
PlayerLayerView(frame: .zero)
|
2022-08-20 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func updateUIView(_: UIViewType, context _: Context) {}
|
2021-07-18 22:32:46 +00:00
|
|
|
}
|
2023-05-20 20:49:10 +00:00
|
|
|
|
|
|
|
#elseif os(tvOS)
|
2022-08-20 21:05:40 +00:00
|
|
|
struct AppleAVPlayerView: UIViewControllerRepresentable {
|
|
|
|
func makeUIViewController(context _: Context) -> AppleAVPlayerViewController {
|
|
|
|
let controller = AppleAVPlayerViewController()
|
2022-11-24 20:36:05 +00:00
|
|
|
PlayerModel.shared.avPlayerBackend.controller = controller
|
2022-08-20 21:05:40 +00:00
|
|
|
|
|
|
|
return controller
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateUIViewController(_: AppleAVPlayerViewController, context _: Context) {
|
2022-11-24 20:36:05 +00:00
|
|
|
PlayerModel.shared.rebuildTVMenu()
|
2022-08-20 21:05:40 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-20 20:49:10 +00:00
|
|
|
#else
|
|
|
|
struct AppleAVPlayerView: NSViewRepresentable {
|
|
|
|
func makeNSView(context _: Context) -> some NSView {
|
|
|
|
let view = AVPlayerView()
|
|
|
|
view.player = PlayerModel.shared.avPlayerBackend.avPlayer
|
|
|
|
view.showsFullScreenToggleButton = true
|
|
|
|
view.allowsPictureInPicturePlayback = true
|
2023-05-22 20:48:11 +00:00
|
|
|
view.pictureInPictureDelegate = MacOSPiPDelegate.shared
|
2023-05-20 20:49:10 +00:00
|
|
|
return view
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateNSView(_: NSViewType, context _: Context) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct AppleAVPlayerLayerView: NSViewRepresentable {
|
|
|
|
func makeNSView(context _: Context) -> some NSView {
|
|
|
|
PlayerLayerView(frame: .zero)
|
|
|
|
}
|
|
|
|
|
|
|
|
func updateNSView(_: NSViewType, context _: Context) {}
|
|
|
|
}
|
2022-08-20 21:05:40 +00:00
|
|
|
#endif
|