mirror of
				https://github.com/yattee/yattee.git
				synced 2025-11-04 06:32:03 +00:00 
			
		
		
		
	Add PiP for iOS
This commit is contained in:
		@@ -36,8 +36,9 @@ final class AVPlayerBackend: PlayerBackend {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private(set) var avPlayer = AVPlayer()
 | 
					    private(set) var avPlayer = AVPlayer()
 | 
				
			||||||
 | 
					 | 
				
			||||||
    var controller: AppleAVPlayerViewController?
 | 
					    var controller: AppleAVPlayerViewController?
 | 
				
			||||||
 | 
					    var enterPiPOnPlay = false
 | 
				
			||||||
 | 
					    var switchToMPVOnPipClose = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var asset: AVURLAsset?
 | 
					    private var asset: AVURLAsset?
 | 
				
			||||||
    private var composition = AVMutableComposition()
 | 
					    private var composition = AVMutableComposition()
 | 
				
			||||||
@@ -535,14 +536,27 @@ final class AVPlayerBackend: PlayerBackend {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if player.timeControlStatus != .waitingToPlayAtSpecifiedRate {
 | 
					            if player.timeControlStatus != .waitingToPlayAtSpecifiedRate {
 | 
				
			||||||
 | 
					                if let controller = self.model.pipController {
 | 
				
			||||||
 | 
					                    if controller.isPictureInPicturePossible {
 | 
				
			||||||
 | 
					                        if self.enterPiPOnPlay {
 | 
				
			||||||
 | 
					                            self.enterPiPOnPlay = false
 | 
				
			||||||
 | 
					                            DispatchQueue.main.async { [weak self] in
 | 
				
			||||||
 | 
					                                self?.model.pipController?.startPictureInPicture()
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                DispatchQueue.main.async { [weak self] in
 | 
					                DispatchQueue.main.async { [weak self] in
 | 
				
			||||||
                    self?.model.objectWillChange.send()
 | 
					                    self?.model.objectWillChange.send()
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if player.timeControlStatus == .playing, player.rate != self.model.currentRate {
 | 
					            if player.timeControlStatus == .playing {
 | 
				
			||||||
 | 
					                if player.rate != self.model.currentRate {
 | 
				
			||||||
                    player.rate = self.model.currentRate
 | 
					                    player.rate = self.model.currentRate
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #if os(macOS)
 | 
					            #if os(macOS)
 | 
				
			||||||
                if player.timeControlStatus == .playing {
 | 
					                if player.timeControlStatus == .playing {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,9 @@ final class MPVBackend: PlayerBackend {
 | 
				
			|||||||
        updateControlsIsPlaying()
 | 
					        updateControlsIsPlaying()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #if !os(macOS)
 | 
					        #if !os(macOS)
 | 
				
			||||||
            UIApplication.shared.isIdleTimerDisabled = model.presentingPlayer && isPlaying
 | 
					            DispatchQueue.main.async {
 | 
				
			||||||
 | 
					                UIApplication.shared.isIdleTimerDisabled = self.model.presentingPlayer && self.isPlaying
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        #endif
 | 
					        #endif
 | 
				
			||||||
    }}
 | 
					    }}
 | 
				
			||||||
    var playerItemDuration: CMTime?
 | 
					    var playerItemDuration: CMTime?
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								Model/Player/PiPDelegate.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Model/Player/PiPDelegate.swift
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import AVKit
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final class PiPDelegate: NSObject, AVPictureInPictureControllerDelegate {
 | 
				
			||||||
 | 
					    var player: PlayerModel!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func pictureInPictureController(
 | 
				
			||||||
 | 
					        _: AVPictureInPictureController,
 | 
				
			||||||
 | 
					        failedToStartPictureInPictureWithError error: Error
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        print(error.localizedDescription)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func pictureInPictureControllerWillStartPictureInPicture(_: AVPictureInPictureController) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func pictureInPictureControllerDidStartPictureInPicture(_: AVPictureInPictureController) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func pictureInPictureControllerDidStopPictureInPicture(_: AVPictureInPictureController) {
 | 
				
			||||||
 | 
					        if player?.avPlayerBackend.switchToMPVOnPipClose ?? false {
 | 
				
			||||||
 | 
					            DispatchQueue.main.async { [weak player] in
 | 
				
			||||||
 | 
					                player?.avPlayerBackend.switchToMPVOnPipClose = false
 | 
				
			||||||
 | 
					                player?.saveTime { [weak player] in
 | 
				
			||||||
 | 
					                    player?.changeActiveBackend(from: .appleAVPlayer, to: .mpv)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func pictureInPictureControllerWillStopPictureInPicture(_: AVPictureInPictureController) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    func pictureInPictureController(
 | 
				
			||||||
 | 
					        _: AVPictureInPictureController,
 | 
				
			||||||
 | 
					        restoreUserInterfaceForPictureInPictureStopWithCompletionHandler _: @escaping (Bool) -> Void
 | 
				
			||||||
 | 
					    ) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -83,6 +83,8 @@ final class PlayerModel: ObservableObject {
 | 
				
			|||||||
    var context: NSManagedObjectContext = PersistenceController.shared.container.viewContext
 | 
					    var context: NSManagedObjectContext = PersistenceController.shared.container.viewContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Published var playingInPictureInPicture = false
 | 
					    @Published var playingInPictureInPicture = false
 | 
				
			||||||
 | 
					    var pipController: AVPictureInPictureController?
 | 
				
			||||||
 | 
					    var pipDelegate = PiPDelegate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Published var presentingErrorDetails = false
 | 
					    @Published var presentingErrorDetails = false
 | 
				
			||||||
    var playerError: Error? { didSet {
 | 
					    var playerError: Error? { didSet {
 | 
				
			||||||
@@ -102,6 +104,9 @@ final class PlayerModel: ObservableObject {
 | 
				
			|||||||
    #endif
 | 
					    #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var currentArtwork: MPMediaItemArtwork?
 | 
					    private var currentArtwork: MPMediaItemArtwork?
 | 
				
			||||||
 | 
					    #if !os(macOS)
 | 
				
			||||||
 | 
					        var playerLayerView: PlayerLayerView!
 | 
				
			||||||
 | 
					    #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init(accounts: AccountsModel? = nil, comments: CommentsModel? = nil, controls: PlayerControlsModel? = nil) {
 | 
					    init(accounts: AccountsModel? = nil, comments: CommentsModel? = nil, controls: PlayerControlsModel? = nil) {
 | 
				
			||||||
        self.accounts = accounts ?? AccountsModel()
 | 
					        self.accounts = accounts ?? AccountsModel()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,14 @@
 | 
				
			|||||||
 | 
					import AVKit
 | 
				
			||||||
import Defaults
 | 
					import Defaults
 | 
				
			||||||
import SwiftUI
 | 
					import SwiftUI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct AppleAVPlayerView: UIViewControllerRepresentable {
 | 
					struct AppleAVPlayerView: UIViewRepresentable {
 | 
				
			||||||
    @EnvironmentObject<CommentsModel> private var comments
 | 
					 | 
				
			||||||
    @EnvironmentObject<NavigationModel> private var navigation
 | 
					 | 
				
			||||||
    @EnvironmentObject<PlayerModel> private var player
 | 
					    @EnvironmentObject<PlayerModel> private var player
 | 
				
			||||||
    @EnvironmentObject<SubscriptionsModel> private var subscriptions
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func makeUIViewController(context _: Context) -> UIViewController {
 | 
					    func makeUIView(context _: Context) -> some UIView {
 | 
				
			||||||
        let controller = AppleAVPlayerViewController()
 | 
					        player.playerLayerView = PlayerLayerView(frame: .zero)
 | 
				
			||||||
 | 
					        return player.playerLayerView
 | 
				
			||||||
        controller.commentsModel = comments
 | 
					 | 
				
			||||||
        controller.navigationModel = navigation
 | 
					 | 
				
			||||||
        controller.playerModel = player
 | 
					 | 
				
			||||||
        controller.subscriptionsModel = subscriptions
 | 
					 | 
				
			||||||
        player.avPlayerBackend.controller = controller
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return controller
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    func updateUIViewController(_: UIViewController, context _: Context) {
 | 
					    func updateUIView(_: UIViewType, context _: Context) {}
 | 
				
			||||||
        player.rebuildTVMenu()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -173,6 +173,9 @@ struct PlayerControls: View {
 | 
				
			|||||||
        HStack {
 | 
					        HStack {
 | 
				
			||||||
            #if !os(tvOS)
 | 
					            #if !os(tvOS)
 | 
				
			||||||
                fullscreenButton
 | 
					                fullscreenButton
 | 
				
			||||||
 | 
					                #if os(iOS)
 | 
				
			||||||
 | 
					                    pipButton
 | 
				
			||||||
 | 
					                #endif
 | 
				
			||||||
                rateButton
 | 
					                rateButton
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Spacer()
 | 
					                Spacer()
 | 
				
			||||||
@@ -235,6 +238,26 @@ struct PlayerControls: View {
 | 
				
			|||||||
        .init(get: { player.currentRate }, set: { rate in player.currentRate = rate })
 | 
					        .init(get: { player.currentRate }, set: { rate in player.currentRate = rate })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var pipButton: some View {
 | 
				
			||||||
 | 
					        button("PiP", systemImage: "pip") {
 | 
				
			||||||
 | 
					            if player.activeBackend == .mpv {
 | 
				
			||||||
 | 
					                player.avPlayerBackend.switchToMPVOnPipClose = true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            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.enterPiPOnPlay = true
 | 
				
			||||||
 | 
					                player.pipController?.startPictureInPicture()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var mediumButtonsBar: some View {
 | 
					    var mediumButtonsBar: some View {
 | 
				
			||||||
        HStack {
 | 
					        HStack {
 | 
				
			||||||
            #if !os(tvOS)
 | 
					            #if !os(tvOS)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								Shared/Player/PlayerLayerView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Shared/Player/PlayerLayerView.swift
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import AVFoundation
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					import UIKit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final class PlayerLayerView: UIView {
 | 
				
			||||||
 | 
					    var playerLayer = AVPlayerLayer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override init(frame: CGRect) {
 | 
				
			||||||
 | 
					        super.init(frame: frame)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        layer.addSublayer(playerLayer)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @available(*, unavailable)
 | 
				
			||||||
 | 
					    required init?(coder _: NSCoder) {
 | 
				
			||||||
 | 
					        fatalError("init(coder:) has not been implemented")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override func layoutSubviews() {
 | 
				
			||||||
 | 
					        super.layoutSubviews()
 | 
				
			||||||
 | 
					        playerLayer.frame = bounds
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -226,6 +226,17 @@ struct VideoPlayerView: View {
 | 
				
			|||||||
                    })
 | 
					                    })
 | 
				
			||||||
            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
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #if !os(tvOS)
 | 
					            #if !os(tvOS)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -190,6 +190,11 @@
 | 
				
			|||||||
		372915E62687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
 | 
							372915E62687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
 | 
				
			||||||
		372915E72687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
 | 
							372915E72687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
 | 
				
			||||||
		372915E82687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
 | 
							372915E82687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
 | 
				
			||||||
 | 
							372D85DE283841B800FF3C7D /* PiPDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373031F428383A89000CFD59 /* PiPDelegate.swift */; };
 | 
				
			||||||
 | 
							372D85DF283842EC00FF3C7D /* PiPDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373031F428383A89000CFD59 /* PiPDelegate.swift */; };
 | 
				
			||||||
 | 
							372D85E0283842EE00FF3C7D /* PlayerLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373031F22838388A000CFD59 /* PlayerLayerView.swift */; };
 | 
				
			||||||
 | 
							373031F32838388A000CFD59 /* PlayerLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373031F22838388A000CFD59 /* PlayerLayerView.swift */; };
 | 
				
			||||||
 | 
							373031F528383A89000CFD59 /* PiPDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373031F428383A89000CFD59 /* PiPDelegate.swift */; };
 | 
				
			||||||
		3730D8A02712E2B70020ED53 /* NowPlayingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3730D89F2712E2B70020ED53 /* NowPlayingView.swift */; };
 | 
							3730D8A02712E2B70020ED53 /* NowPlayingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3730D89F2712E2B70020ED53 /* NowPlayingView.swift */; };
 | 
				
			||||||
		3730F75A2733481E00F385FC /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; };
 | 
							3730F75A2733481E00F385FC /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; };
 | 
				
			||||||
		373197D92732015300EF734F /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; };
 | 
							373197D92732015300EF734F /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; };
 | 
				
			||||||
@@ -864,6 +869,8 @@
 | 
				
			|||||||
		3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-iOS.swift"; sourceTree = "<group>"; };
 | 
							3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisualEffectBlur-iOS.swift"; sourceTree = "<group>"; };
 | 
				
			||||||
		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>"; };
 | 
				
			||||||
 | 
							373031F22838388A000CFD59 /* PlayerLayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerLayerView.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>"; };
 | 
				
			||||||
		37319F0427103F94004ECCD0 /* PlayerQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerQueue.swift; sourceTree = "<group>"; };
 | 
							37319F0427103F94004ECCD0 /* PlayerQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerQueue.swift; sourceTree = "<group>"; };
 | 
				
			||||||
@@ -1351,6 +1358,7 @@
 | 
				
			|||||||
				37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
 | 
									37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
 | 
				
			||||||
				37E8B0EB27B326C00024006F /* TimelineView.swift */,
 | 
									37E8B0EB27B326C00024006F /* TimelineView.swift */,
 | 
				
			||||||
				37F9619A27BD89E000058149 /* TapRecognizerViewModifier.swift */,
 | 
									37F9619A27BD89E000058149 /* TapRecognizerViewModifier.swift */,
 | 
				
			||||||
 | 
									373031F22838388A000CFD59 /* PlayerLayerView.swift */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			path = Player;
 | 
								path = Player;
 | 
				
			||||||
			sourceTree = "<group>";
 | 
								sourceTree = "<group>";
 | 
				
			||||||
@@ -1439,6 +1447,7 @@
 | 
				
			|||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
				37EBD8C227AF0D7C00F1C24B /* Backends */,
 | 
									37EBD8C227AF0D7C00F1C24B /* Backends */,
 | 
				
			||||||
 | 
									373031F428383A89000CFD59 /* PiPDelegate.swift */,
 | 
				
			||||||
				37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */,
 | 
									37B767DA2677C3CA0098BAA8 /* PlayerModel.swift */,
 | 
				
			||||||
				37319F0427103F94004ECCD0 /* PlayerQueue.swift */,
 | 
									37319F0427103F94004ECCD0 /* PlayerQueue.swift */,
 | 
				
			||||||
				37CC3F44270CE30600608308 /* PlayerQueueItem.swift */,
 | 
									37CC3F44270CE30600608308 /* PlayerQueueItem.swift */,
 | 
				
			||||||
@@ -2548,6 +2557,7 @@
 | 
				
			|||||||
				37EF9A76275BEB8E0043B585 /* CommentView.swift in Sources */,
 | 
									37EF9A76275BEB8E0043B585 /* CommentView.swift in Sources */,
 | 
				
			||||||
				373C8FE4275B955100CB5936 /* CommentsPage.swift in Sources */,
 | 
									373C8FE4275B955100CB5936 /* CommentsPage.swift in Sources */,
 | 
				
			||||||
				3700155B271B0D4D0049C794 /* PipedAPI.swift in Sources */,
 | 
									3700155B271B0D4D0049C794 /* PipedAPI.swift in Sources */,
 | 
				
			||||||
 | 
									373031F32838388A000CFD59 /* PlayerLayerView.swift in Sources */,
 | 
				
			||||||
				37B044B726F7AB9000E1419D /* SettingsView.swift in Sources */,
 | 
									37B044B726F7AB9000E1419D /* SettingsView.swift in Sources */,
 | 
				
			||||||
				377FC7E3267A084A00A6BBAF /* VideoCell.swift in Sources */,
 | 
									377FC7E3267A084A00A6BBAF /* VideoCell.swift in Sources */,
 | 
				
			||||||
				37C3A251272366440087A57A /* ChannelPlaylistView.swift in Sources */,
 | 
									37C3A251272366440087A57A /* ChannelPlaylistView.swift in Sources */,
 | 
				
			||||||
@@ -2600,6 +2610,7 @@
 | 
				
			|||||||
				3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
 | 
									3788AC2726F6840700F6BAA9 /* FavoriteItemView.swift in Sources */,
 | 
				
			||||||
				375DFB5826F9DA010013F468 /* InstancesModel.swift in Sources */,
 | 
									375DFB5826F9DA010013F468 /* InstancesModel.swift in Sources */,
 | 
				
			||||||
				3751BA8327E6914F007B1A60 /* ReturnYouTubeDislikeAPI.swift in Sources */,
 | 
									3751BA8327E6914F007B1A60 /* ReturnYouTubeDislikeAPI.swift in Sources */,
 | 
				
			||||||
 | 
									373031F528383A89000CFD59 /* PiPDelegate.swift in Sources */,
 | 
				
			||||||
				37DD9DC62785D63A00539416 /* UIResponder+Extensions.swift in Sources */,
 | 
									37DD9DC62785D63A00539416 /* UIResponder+Extensions.swift in Sources */,
 | 
				
			||||||
				37C3A24927235FAA0087A57A /* ChannelPlaylistCell.swift in Sources */,
 | 
									37C3A24927235FAA0087A57A /* ChannelPlaylistCell.swift in Sources */,
 | 
				
			||||||
				373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
 | 
									373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */,
 | 
				
			||||||
@@ -2758,6 +2769,7 @@
 | 
				
			|||||||
				37A9965F26D6F9B9006E3224 /* FavoritesView.swift in Sources */,
 | 
									37A9965F26D6F9B9006E3224 /* FavoritesView.swift in Sources */,
 | 
				
			||||||
				37F4AE7326828F0900BD60EA /* VerticalCells.swift in Sources */,
 | 
									37F4AE7326828F0900BD60EA /* VerticalCells.swift in Sources */,
 | 
				
			||||||
				37001560271B12DD0049C794 /* SiestaConfiguration.swift in Sources */,
 | 
									37001560271B12DD0049C794 /* SiestaConfiguration.swift in Sources */,
 | 
				
			||||||
 | 
									372D85DE283841B800FF3C7D /* PiPDelegate.swift in Sources */,
 | 
				
			||||||
				37B81AFD26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
 | 
									37B81AFD26D2C9C900675966 /* VideoDetailsPaddingModifier.swift in Sources */,
 | 
				
			||||||
				37C0697F2725C8D400F7F6CB /* CMTime+DefaultTimescale.swift in Sources */,
 | 
									37C0697F2725C8D400F7F6CB /* CMTime+DefaultTimescale.swift in Sources */,
 | 
				
			||||||
				37A9965B26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
 | 
									37A9965B26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
 | 
				
			||||||
@@ -3000,6 +3012,8 @@
 | 
				
			|||||||
				37B17DA0268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */,
 | 
									37B17DA0268A1F89006AEE9B /* VideoContextMenuView.swift in Sources */,
 | 
				
			||||||
				37BE0BD726A1D4A90092E2DB /* AppleAVPlayerViewController.swift in Sources */,
 | 
									37BE0BD726A1D4A90092E2DB /* AppleAVPlayerViewController.swift in Sources */,
 | 
				
			||||||
				37484C3326FCB8F900287258 /* AccountValidator.swift in Sources */,
 | 
									37484C3326FCB8F900287258 /* AccountValidator.swift in Sources */,
 | 
				
			||||||
 | 
									372D85DF283842EC00FF3C7D /* PiPDelegate.swift in Sources */,
 | 
				
			||||||
 | 
									372D85E0283842EE00FF3C7D /* PlayerLayerView.swift in Sources */,
 | 
				
			||||||
				37CEE4C32677B697005A1EFE /* Stream.swift in Sources */,
 | 
									37CEE4C32677B697005A1EFE /* Stream.swift in Sources */,
 | 
				
			||||||
				37F64FE626FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
 | 
									37F64FE626FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
 | 
				
			||||||
				37B2631C2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */,
 | 
									37B2631C2735EAAB00FE0D40 /* FavoriteResourceObserver.swift in Sources */,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user