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