mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
PiP improvements
This commit is contained in:
parent
ace8c6e3ff
commit
6c6ba19df4
@ -34,9 +34,9 @@ final class NetworkStateModel: ObservableObject {
|
||||
|
||||
var needsUpdates: Bool {
|
||||
if let player = player {
|
||||
return pausedForCache || player.isSeeking || player.isLoadingVideo || player.controls.presentingControlsOverlay
|
||||
return !player.currentItem.isNil && (pausedForCache || player.isSeeking || player.isLoadingVideo || player.controls.presentingControlsOverlay)
|
||||
}
|
||||
|
||||
return pausedForCache
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,7 @@ final class AVPlayerBackend: PlayerBackend {
|
||||
|
||||
var aspectRatio: Double {
|
||||
#if os(iOS)
|
||||
guard let view = model?.playerLayerView else { return VideoPlayerView.defaultAspectRatio }
|
||||
|
||||
let videoRect = view.playerLayer.videoRect
|
||||
return videoRect.width / videoRect.height
|
||||
playerLayer.videoRect.width / playerLayer.videoRect.height
|
||||
#else
|
||||
VideoPlayerView.defaultAspectRatio
|
||||
#endif
|
||||
@ -54,7 +51,10 @@ final class AVPlayerBackend: PlayerBackend {
|
||||
}
|
||||
|
||||
private(set) var avPlayer = AVPlayer()
|
||||
private(set) var playerLayer = AVPlayerLayer()
|
||||
#if os(tvOS)
|
||||
var controller: AppleAVPlayerViewController?
|
||||
#endif
|
||||
var startPictureInPictureOnPlay = false
|
||||
|
||||
private var asset: AVURLAsset?
|
||||
@ -79,6 +79,8 @@ final class AVPlayerBackend: PlayerBackend {
|
||||
addFrequentTimeObserver()
|
||||
addInfrequentTimeObserver()
|
||||
addPlayerTimeControlStatusObserver()
|
||||
|
||||
playerLayer.player = avPlayer
|
||||
}
|
||||
|
||||
func bestPlayable(_ streams: [Stream], maxResolution _: ResolutionSetting) -> Stream? {
|
||||
@ -157,40 +159,10 @@ final class AVPlayerBackend: PlayerBackend {
|
||||
avPlayer.replaceCurrentItem(with: nil)
|
||||
}
|
||||
|
||||
#if os(tvOS)
|
||||
func closePiP(wasPlaying: Bool) {
|
||||
let item = avPlayer.currentItem
|
||||
let time = avPlayer.currentTime()
|
||||
|
||||
avPlayer.replaceCurrentItem(with: nil)
|
||||
|
||||
guard !item.isNil else {
|
||||
return
|
||||
}
|
||||
|
||||
avPlayer.seek(to: time)
|
||||
avPlayer.replaceCurrentItem(with: item)
|
||||
|
||||
guard wasPlaying else {
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
|
||||
self?.play()
|
||||
}
|
||||
}
|
||||
#else
|
||||
func closePiP(wasPlaying: Bool) {
|
||||
func closePiP() {
|
||||
model.pipController?.stopPictureInPicture()
|
||||
|
||||
guard wasPlaying else {
|
||||
return
|
||||
}
|
||||
|
||||
play()
|
||||
}
|
||||
#endif
|
||||
|
||||
private func loadSingleAsset(
|
||||
_ url: URL,
|
||||
stream: Stream,
|
||||
|
@ -324,7 +324,7 @@ final class MPVBackend: PlayerBackend {
|
||||
client?.stop()
|
||||
}
|
||||
|
||||
func closePiP(wasPlaying _: Bool) {}
|
||||
func closePiP() {}
|
||||
|
||||
func updateControls() {
|
||||
self.logger.info("updating controls")
|
||||
|
@ -45,7 +45,7 @@ protocol PlayerBackend {
|
||||
|
||||
func closeItem()
|
||||
|
||||
func closePiP(wasPlaying: Bool)
|
||||
func closePiP()
|
||||
|
||||
func updateControls()
|
||||
func startControlsUpdates()
|
||||
|
@ -67,6 +67,8 @@ final class PlayerModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
var playerBackendView = PlayerBackendView()
|
||||
|
||||
@Published var playerSize: CGSize = .zero { didSet {
|
||||
#if !os(tvOS)
|
||||
backend.setSize(playerSize.width, playerSize.height)
|
||||
@ -167,9 +169,6 @@ final class PlayerModel: ObservableObject {
|
||||
#endif
|
||||
|
||||
private var currentArtwork: MPMediaItemArtwork?
|
||||
#if !os(macOS)
|
||||
var playerLayerView: PlayerLayerView!
|
||||
#endif
|
||||
|
||||
var onPresentPlayer: (() -> Void)?
|
||||
private var remoteCommandCenterConfigured = false
|
||||
@ -207,6 +206,14 @@ final class PlayerModel: ObservableObject {
|
||||
|
||||
Defaults[.activeBackend] = .mpv
|
||||
playbackMode = Defaults[.playbackMode]
|
||||
|
||||
guard pipController.isNil else { return }
|
||||
pipController = .init(playerLayer: avPlayerBackend.playerLayer)
|
||||
let pipDelegate = PiPDelegate()
|
||||
pipDelegate.player = self
|
||||
|
||||
self.pipDelegate = pipDelegate
|
||||
pipController?.delegate = pipDelegate
|
||||
}
|
||||
|
||||
func show() {
|
||||
@ -421,7 +428,9 @@ final class PlayerModel: ObservableObject {
|
||||
return
|
||||
}
|
||||
|
||||
if let qualityProfileBackend = qualityProfile?.backend, qualityProfileBackend != activeBackend {
|
||||
if let qualityProfileBackend = qualityProfile?.backend, qualityProfileBackend != activeBackend,
|
||||
qualityProfileBackend == .appleAVPlayer || !(avPlayerBackend.startPictureInPictureOnPlay || playingInPictureInPicture)
|
||||
{
|
||||
changeActiveBackend(from: activeBackend, to: qualityProfileBackend)
|
||||
}
|
||||
|
||||
@ -464,16 +473,10 @@ final class PlayerModel: ObservableObject {
|
||||
}
|
||||
|
||||
if !presentingPlayer, pauseOnHidingPlayer, !playingInPictureInPicture {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.pause()
|
||||
}
|
||||
}
|
||||
|
||||
if !presentingPlayer, !pauseOnHidingPlayer, backend.isPlaying {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
|
||||
self?.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func changeActiveBackend(from: PlayerBackendType, to: PlayerBackendType) {
|
||||
@ -483,6 +486,10 @@ final class PlayerModel: ObservableObject {
|
||||
|
||||
pause()
|
||||
|
||||
if to == .mpv {
|
||||
closePiP()
|
||||
}
|
||||
|
||||
Defaults[.activeBackend] = to
|
||||
self.activeBackend = to
|
||||
|
||||
@ -553,6 +560,7 @@ final class PlayerModel: ObservableObject {
|
||||
|
||||
func closeCurrentItem(finished: Bool = false) {
|
||||
pause()
|
||||
closePiP()
|
||||
|
||||
prepareCurrentItemForHistory(finished: finished)
|
||||
currentItem = nil
|
||||
@ -562,7 +570,6 @@ final class PlayerModel: ObservableObject {
|
||||
aspectRatio = VideoPlayerView.defaultAspectRatio
|
||||
resetAutoplay()
|
||||
|
||||
closePiP()
|
||||
exitFullScreen()
|
||||
|
||||
#if !os(macOS)
|
||||
@ -577,14 +584,11 @@ final class PlayerModel: ObservableObject {
|
||||
return
|
||||
}
|
||||
|
||||
let wasPlaying = isPlaying
|
||||
pause()
|
||||
|
||||
#if os(tvOS)
|
||||
show()
|
||||
#endif
|
||||
|
||||
backend.closePiP(wasPlaying: wasPlaying)
|
||||
backend.closePiP()
|
||||
}
|
||||
|
||||
func handleQueueChange() {
|
||||
|
@ -132,6 +132,16 @@ struct ContentView: View {
|
||||
|
||||
@ViewBuilder var videoPlayer: some View {
|
||||
if player.presentingPlayer {
|
||||
playerView
|
||||
.transition(.move(edge: .bottom))
|
||||
} else if player.activeBackend == .appleAVPlayer {
|
||||
#if os(iOS)
|
||||
playerView.offset(y: UIScreen.main.bounds.height)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
var playerView: some View {
|
||||
VideoPlayerView()
|
||||
.environmentObject(accounts)
|
||||
.environmentObject(comments)
|
||||
@ -144,8 +154,6 @@ struct ContentView: View {
|
||||
.environmentObject(subscriptions)
|
||||
.environmentObject(thumbnailsModel)
|
||||
.environment(\.navigationStyle, navigationStyle)
|
||||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,9 @@ struct AppleAVPlayerView: UIViewRepresentable {
|
||||
@EnvironmentObject<PlayerModel> private var player
|
||||
|
||||
func makeUIView(context _: Context) -> some UIView {
|
||||
player.playerLayerView = PlayerLayerView(frame: .zero)
|
||||
return player.playerLayerView
|
||||
let playerLayerView = PlayerLayerView(frame: .zero)
|
||||
playerLayerView.player = player
|
||||
return playerLayerView
|
||||
}
|
||||
|
||||
func updateUIView(_: UIViewType, context _: Context) {}
|
||||
|
@ -227,8 +227,8 @@ struct PlayerControls: View {
|
||||
HStack(spacing: 20) {
|
||||
fullscreenButton
|
||||
|
||||
#if os(iOS)
|
||||
pipButton
|
||||
#if os(iOS)
|
||||
lockOrientationButton
|
||||
#endif
|
||||
|
||||
|
@ -15,17 +15,6 @@ struct PlayerBackendView: View {
|
||||
player.mpvPlayerView
|
||||
case .appleAVPlayer:
|
||||
player.avPlayerView
|
||||
#if os(iOS)
|
||||
.onAppear {
|
||||
player.pipController = .init(playerLayer: player.playerLayerView.playerLayer)
|
||||
let pipDelegate = PiPDelegate()
|
||||
pipDelegate.player = player
|
||||
|
||||
player.pipDelegate = pipDelegate
|
||||
player.pipController?.delegate = pipDelegate
|
||||
player.playerLayerView.playerLayer.player = player.avPlayerBackend.avPlayer
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.overlay(GeometryReader { proxy in
|
||||
|
@ -1,23 +1,51 @@
|
||||
import AVFoundation
|
||||
import Foundation
|
||||
import UIKit
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
#else
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
final class PlayerLayerView: UIView {
|
||||
var playerLayer = AVPlayerLayer()
|
||||
#if os(macOS)
|
||||
final class PlayerLayerView: NSView {
|
||||
var player: PlayerModel! { didSet {
|
||||
wantsLayer = true
|
||||
}}
|
||||
|
||||
override init(frame frameRect: NSRect) {
|
||||
super.init(frame: frameRect)
|
||||
}
|
||||
|
||||
override func makeBackingLayer() -> CALayer {
|
||||
player.avPlayerBackend.playerLayer
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
}
|
||||
#else
|
||||
final class PlayerLayerView: UIView {
|
||||
var player: PlayerModel!
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
layer.addSublayer(playerLayer)
|
||||
}
|
||||
|
||||
private var layerAdded = false
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder _: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
playerLayer.frame = bounds
|
||||
if !layerAdded {
|
||||
layerAdded = true
|
||||
layer.addSublayer(player.avPlayerBackend.playerLayer)
|
||||
}
|
||||
}
|
||||
player.avPlayerBackend.playerLayer.frame = bounds
|
||||
super.layoutSubviews()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -33,7 +33,9 @@ struct VideoDetails: View {
|
||||
@StateObject private var page: Page = .first()
|
||||
|
||||
@Environment(\.navigationStyle) private var navigationStyle
|
||||
#if os(iOS)
|
||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||
#endif
|
||||
|
||||
@EnvironmentObject<AccountsModel> private var accounts
|
||||
@EnvironmentObject<CommentsModel> private var comments
|
||||
@ -227,7 +229,9 @@ struct VideoDetails: View {
|
||||
.redacted(reason: .placeholder)
|
||||
} else if video.description != nil, !video.description!.isEmpty {
|
||||
VideoDescription(video: video, detailsSize: detailsSize)
|
||||
#if os(iOS)
|
||||
.padding(.bottom, fullScreenLayout ? 10 : SafeArea.insets.bottom)
|
||||
#endif
|
||||
} else {
|
||||
Text("No description")
|
||||
.foregroundColor(.secondary)
|
||||
|
@ -245,14 +245,14 @@ struct VideoPlayerView: View {
|
||||
ZStack(alignment: .bottomLeading) {
|
||||
#if os(tvOS)
|
||||
ZStack {
|
||||
PlayerBackendView()
|
||||
player.playerBackendView
|
||||
|
||||
tvControls
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
#else
|
||||
GeometryReader { geometry in
|
||||
PlayerBackendView()
|
||||
player.playerBackendView
|
||||
#if !os(tvOS)
|
||||
.modifier(
|
||||
VideoPlayerSizeModifier(
|
||||
|
@ -59,10 +59,8 @@ struct VideoContextMenuView: View {
|
||||
|
||||
Section {
|
||||
playNowButton
|
||||
#if os(iOS)
|
||||
playNowInPictureInPictureButton
|
||||
#endif
|
||||
#if !os(tvOS)
|
||||
playNowInPictureInPictureButton
|
||||
playNowInMusicMode
|
||||
#endif
|
||||
}
|
||||
@ -169,7 +167,8 @@ struct VideoContextMenuView: View {
|
||||
|
||||
private var playNowInPictureInPictureButton: some View {
|
||||
Button {
|
||||
player.controls.startPiP(startImmediately: false)
|
||||
player.controls.startPiP(startImmediately: player.presentingPlayer && player.activeBackend == .appleAVPlayer)
|
||||
player.hide()
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
player.play(video, at: watch?.timeToRestart, showingPlayer: false)
|
||||
|
@ -161,6 +161,7 @@
|
||||
37169AA62729E2CC0011DE61 /* AccountsBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37169AA52729E2CC0011DE61 /* AccountsBridge.swift */; };
|
||||
37169AA72729E2CC0011DE61 /* AccountsBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37169AA52729E2CC0011DE61 /* AccountsBridge.swift */; };
|
||||
37169AA82729E2CC0011DE61 /* AccountsBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37169AA52729E2CC0011DE61 /* AccountsBridge.swift */; };
|
||||
37192D5528B0D5D60012EEDD /* PlayerLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373031F22838388A000CFD59 /* PlayerLayerView.swift */; };
|
||||
371B7E5C27596B8400D21217 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B7E5B27596B8400D21217 /* Comment.swift */; };
|
||||
371B7E5D27596B8400D21217 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B7E5B27596B8400D21217 /* Comment.swift */; };
|
||||
371B7E5E27596B8400D21217 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B7E5B27596B8400D21217 /* Comment.swift */; };
|
||||
@ -623,7 +624,6 @@
|
||||
37BE0BD426A1D47D0092E2DB /* AppleAVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BD226A1D4780092E2DB /* AppleAVPlayerView.swift */; };
|
||||
37BE0BD626A1D4A90092E2DB /* AppleAVPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BD526A1D4A90092E2DB /* AppleAVPlayerViewController.swift */; };
|
||||
37BE0BD726A1D4A90092E2DB /* AppleAVPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BD526A1D4A90092E2DB /* AppleAVPlayerViewController.swift */; };
|
||||
37BE0BDA26A214630092E2DB /* AppleAVPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BD926A214630092E2DB /* AppleAVPlayerViewController.swift */; };
|
||||
37BE0BDC26A2367F0092E2DB /* AppleAVPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE0BDB26A2367F0092E2DB /* AppleAVPlayerView.swift */; };
|
||||
37BF661C27308859008CCFB0 /* DropFavorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF661B27308859008CCFB0 /* DropFavorite.swift */; };
|
||||
37BF661D27308859008CCFB0 /* DropFavorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF661B27308859008CCFB0 /* DropFavorite.swift */; };
|
||||
@ -1000,7 +1000,7 @@
|
||||
3729037D2739E47400EA99F6 /* MenuCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuCommands.swift; sourceTree = "<group>"; };
|
||||
372915E52687E3B900F5A35B /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
|
||||
372CFD14285F2E2A00B0B54B /* ControlsBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlsBar.swift; sourceTree = "<group>"; };
|
||||
373031F22838388A000CFD59 /* PlayerLayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerLayerView.swift; sourceTree = "<group>"; };
|
||||
373031F22838388A000CFD59 /* PlayerLayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerLayerView.swift; sourceTree = "<group>"; tabWidth = 5; };
|
||||
373031F428383A89000CFD59 /* PiPDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPDelegate.swift; sourceTree = "<group>"; };
|
||||
3730D89F2712E2B70020ED53 /* NowPlayingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingView.swift; sourceTree = "<group>"; };
|
||||
373197D82732015300EF734F /* RelatedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelatedView.swift; sourceTree = "<group>"; };
|
||||
@ -1161,7 +1161,6 @@
|
||||
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerView.swift; sourceTree = "<group>"; };
|
||||
37BE0BD226A1D4780092E2DB /* AppleAVPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleAVPlayerView.swift; sourceTree = "<group>"; };
|
||||
37BE0BD526A1D4A90092E2DB /* AppleAVPlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleAVPlayerViewController.swift; sourceTree = "<group>"; };
|
||||
37BE0BD926A214630092E2DB /* AppleAVPlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleAVPlayerViewController.swift; sourceTree = "<group>"; };
|
||||
37BE0BDB26A2367F0092E2DB /* AppleAVPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleAVPlayerView.swift; sourceTree = "<group>"; };
|
||||
37BF661B27308859008CCFB0 /* DropFavorite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropFavorite.swift; sourceTree = "<group>"; };
|
||||
37BF661E27308884008CCFB0 /* DropFavoriteOutside.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropFavoriteOutside.swift; sourceTree = "<group>"; };
|
||||
@ -1889,7 +1888,6 @@
|
||||
children = (
|
||||
374C0542272496E4009BDDBE /* AppDelegate.swift */,
|
||||
37BE0BDB26A2367F0092E2DB /* AppleAVPlayerView.swift */,
|
||||
37BE0BD926A214630092E2DB /* AppleAVPlayerViewController.swift */,
|
||||
37FD43DB270470B70073EE42 /* InstancesSettings.swift */,
|
||||
3751BA7D27E63F1D007B1A60 /* MPVOGLView.swift */,
|
||||
374108D0272B11B2006C5CC8 /* PictureInPictureDelegate.swift */,
|
||||
@ -2972,6 +2970,7 @@
|
||||
377ABC4D286E6A78009C986F /* LocationsSettings.swift in Sources */,
|
||||
3782B95027553A6700990149 /* SearchSuggestions.swift in Sources */,
|
||||
371B7E6B2759791900D21217 /* CommentsModel.swift in Sources */,
|
||||
37192D5528B0D5D60012EEDD /* PlayerLayerView.swift in Sources */,
|
||||
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */,
|
||||
3756C2AB2861151C00E4B059 /* NetworkStateModel.swift in Sources */,
|
||||
375EC95A289EEB8200751258 /* QualityProfileForm.swift in Sources */,
|
||||
@ -3075,7 +3074,6 @@
|
||||
377ABC49286E5887009C986F /* Sequence+Unique.swift in Sources */,
|
||||
3748186726A7627F0084E870 /* Video+Fixtures.swift in Sources */,
|
||||
3784B23E2728B85300B09468 /* ShareButton.swift in Sources */,
|
||||
37BE0BDA26A214630092E2DB /* AppleAVPlayerViewController.swift in Sources */,
|
||||
375F7411289DC35A00747050 /* PlayerBackendView.swift in Sources */,
|
||||
37FEF11427EFD8580033912F /* PlaceholderCell.swift in Sources */,
|
||||
37E64DD226D597EB00C71877 /* SubscriptionsModel.swift in Sources */,
|
||||
|
@ -1,27 +1,16 @@
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
struct AppleAVPlayerView: NSViewControllerRepresentable {
|
||||
struct AppleAVPlayerView: NSViewRepresentable {
|
||||
@EnvironmentObject<PlayerModel> private var player
|
||||
|
||||
@State private var controller: AppleAVPlayerViewController?
|
||||
func makeNSView(context _: Context) -> some NSView {
|
||||
let playerLayerView = PlayerLayerView(frame: .zero)
|
||||
|
||||
init(controller: AppleAVPlayerViewController? = nil) {
|
||||
self.controller = controller
|
||||
playerLayerView.player = player
|
||||
|
||||
return playerLayerView
|
||||
}
|
||||
|
||||
func makeNSViewController(context _: Context) -> AppleAVPlayerViewController {
|
||||
if self.controller != nil {
|
||||
return self.controller!
|
||||
}
|
||||
|
||||
let controller = AppleAVPlayerViewController()
|
||||
|
||||
controller.playerModel = player
|
||||
player.avPlayerBackend.controller = controller
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
func updateNSViewController(_: AppleAVPlayerViewController, context _: Context) {}
|
||||
func updateNSView(_: NSViewType, context _: Context) {}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
import AVKit
|
||||
import SwiftUI
|
||||
|
||||
final class AppleAVPlayerViewController: NSViewController {
|
||||
var playerModel: PlayerModel!
|
||||
var playerView = AVPlayerView()
|
||||
var pictureInPictureDelegate = PictureInPictureDelegate()
|
||||
|
||||
var aspectRatio: Double? {
|
||||
let ratio = Double(playerView.videoBounds.width) / Double(playerView.videoBounds.height)
|
||||
|
||||
if !ratio.isFinite {
|
||||
return VideoPlayerView.defaultAspectRatio
|
||||
}
|
||||
|
||||
return [ratio, 1.0].max()!
|
||||
}
|
||||
|
||||
override func viewDidDisappear() {
|
||||
super.viewDidDisappear()
|
||||
}
|
||||
|
||||
override func loadView() {
|
||||
playerView.player = playerModel.avPlayerBackend.avPlayer
|
||||
pictureInPictureDelegate.playerModel = playerModel
|
||||
|
||||
playerView.controlsStyle = .none
|
||||
playerView.allowsPictureInPicturePlayback = true
|
||||
|
||||
playerView.pictureInPictureDelegate = pictureInPictureDelegate
|
||||
|
||||
view = playerView
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user