mirror of
https://github.com/yattee/yattee.git
synced 2025-10-10 17:38:15 +00:00
AVPlayer system controls on iOS
This commit is contained in:
@@ -2,15 +2,119 @@ import AVKit
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
#if !os(macOS)
|
||||
final class AppleAVPlayerViewControllerDelegate: NSObject, AVPlayerViewControllerDelegate {
|
||||
var player: PlayerModel { .shared }
|
||||
|
||||
func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_: AVPlayerViewController) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
func playerViewController(_: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator _: UIViewControllerTransitionCoordinator) {
|
||||
Delay.by(0.5) { [weak self] in
|
||||
self?.player.playingFullScreen = true
|
||||
}
|
||||
}
|
||||
|
||||
func playerViewController(_: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
|
||||
let wasPlaying = player.isPlaying
|
||||
coordinator.animate(alongsideTransition: nil) { context in
|
||||
#if os(iOS)
|
||||
if wasPlaying {
|
||||
self.player.play()
|
||||
}
|
||||
#endif
|
||||
if !context.isCancelled {
|
||||
#if os(iOS)
|
||||
self.player.lockedOrientation = nil
|
||||
|
||||
if Defaults[.rotateToPortraitOnExitFullScreen] {
|
||||
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: .portrait)
|
||||
}
|
||||
|
||||
if wasPlaying {
|
||||
self.player.play()
|
||||
}
|
||||
|
||||
self.player.playingFullScreen = false
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func playerViewController(_: AVPlayerViewController, restoreUserInterfaceForFullScreenExitWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
|
||||
withAnimation(nil) {
|
||||
player.presentingPlayer = true
|
||||
}
|
||||
|
||||
completionHandler(true)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
struct AppleAVPlayerView: UIViewRepresentable {
|
||||
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 {
|
||||
func makeUIView(context _: Context) -> some UIView {
|
||||
PlayerLayerView()
|
||||
PlayerLayerView(frame: .zero)
|
||||
}
|
||||
|
||||
func updateUIView(_: UIViewType, context _: Context) {}
|
||||
}
|
||||
#else
|
||||
|
||||
#elseif os(tvOS)
|
||||
struct AppleAVPlayerView: UIViewControllerRepresentable {
|
||||
func makeUIViewController(context _: Context) -> AppleAVPlayerViewController {
|
||||
let controller = AppleAVPlayerViewController()
|
||||
@@ -23,4 +127,27 @@ import SwiftUI
|
||||
PlayerModel.shared.rebuildTVMenu()
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct AppleAVPlayerView: NSViewRepresentable {
|
||||
@State private var pictureInPictureDelegate = MacOSPiPDelegate()
|
||||
|
||||
func makeNSView(context _: Context) -> some NSView {
|
||||
let view = AVPlayerView()
|
||||
view.player = PlayerModel.shared.avPlayerBackend.avPlayer
|
||||
view.showsFullScreenToggleButton = true
|
||||
view.allowsPictureInPicturePlayback = true
|
||||
view.pictureInPictureDelegate = pictureInPictureDelegate
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_: NSViewType, context _: Context) {}
|
||||
}
|
||||
|
||||
struct AppleAVPlayerLayerView: NSViewRepresentable {
|
||||
func makeNSView(context _: Context) -> some NSView {
|
||||
PlayerLayerView(frame: .zero)
|
||||
}
|
||||
|
||||
func updateNSView(_: NSViewType, context _: Context) {}
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user