Browse Source

start PiP

marinofaggiana 3 years ago
parent
commit
42f13af2d2

+ 12 - 0
iOSClient/Images.xcassets/pip.enter.imageset/Contents.json

@@ -0,0 +1,12 @@
+{
+  "images" : [
+    {
+      "filename" : "pip.enter.svg",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 1 - 0
iOSClient/Images.xcassets/pip.enter.imageset/pip.enter.svg

@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,11H11V17H19V11M23,19V5C23,3.88 22.1,3 21,3H3A2,2 0 0,0 1,5V19A2,2 0 0,0 3,21H21A2,2 0 0,0 23,19M21,19H3V4.97H21V19Z" /></svg>

+ 26 - 4
iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift

@@ -25,6 +25,10 @@ import Foundation
 import NCCommunication
 import UIKit
 import AVFoundation
+import AVKit
+
+/// The Set of custom player controllers currently using or transitioning out of PiP
+private var activeNCPlayer = Set<NCPlayer>()
 
 class NCPlayer: NSObject {
    
@@ -36,6 +40,7 @@ class NCPlayer: NSObject {
     
     public var metadata: tableMetadata?
     public var videoLayer: AVPlayerLayer?
+    public var pictureInPictureController: AVPictureInPictureController?
 
     init(url: URL, imageVideoContainer: imageVideoContainerView?, playerToolBar: NCPlayerToolBar?, metadata: tableMetadata, detailView: NCViewerMediaDetailView?) {
         super.init()
@@ -94,6 +99,11 @@ class NCPlayer: NSObject {
                                 imageVideoContainer.layer.addSublayer(self.videoLayer!)
                                 imageVideoContainer.playerLayer = self.videoLayer
                                 imageVideoContainer.metadata = self.metadata
+                                // PiP
+                                if let playerLayer = self.videoLayer {
+                                    self.pictureInPictureController = AVPictureInPictureController(playerLayer: playerLayer)
+                                    self.pictureInPictureController?.delegate = self
+                                }
                             }
                         }
                         NCManageDatabase.shared.addVideoTime(metadata: metadata, time: nil, durationTime: durationTime)
@@ -138,7 +148,8 @@ class NCPlayer: NSObject {
     @objc func applicationDidEnterBackground(_ notification: NSNotification) {
         
         if metadata?.classFile == NCCommunicationCommon.typeClassFile.video.rawValue {
-            appDelegate.player?.pause()
+            if let pictureInPictureController = pictureInPictureController, pictureInPictureController.isPictureInPictureActive { return }
+            playerPause()
         }
     }
     
@@ -149,12 +160,12 @@ class NCPlayer: NSObject {
     
     //MARK: -
     
-    func videoPlay() {
+    func playerPlay() {
                 
         appDelegate.player?.play()
     }
     
-    func videoPause() {
+    func playerPause() {
         
         appDelegate.player?.pause()
     }
@@ -175,7 +186,7 @@ class NCPlayer: NSObject {
     
     func videoRemoved() {
 
-        videoPause()
+        playerPause()
 
         if let observerAVPlayerItemDidPlayToEndTime = self.observerAVPlayerItemDidPlayToEndTime {
             NotificationCenter.default.removeObserver(observerAVPlayerItemDidPlayToEndTime)
@@ -224,3 +235,14 @@ class NCPlayer: NSObject {
     }
 }
 
+extension NCPlayer: AVPictureInPictureControllerDelegate {
+    
+    func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
+        activeNCPlayer.insert(self)
+    }
+    
+    func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
+        
+    }
+}
+

+ 28 - 13
iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift

@@ -29,8 +29,9 @@ import UIKit
 class NCPlayerToolBar: UIView {
     
     @IBOutlet weak var playerTopToolBarView: UIView!
-    @IBOutlet weak var playButton: UIButton!
+    @IBOutlet weak var pipButton: UIButton!
     @IBOutlet weak var muteButton: UIButton!
+    @IBOutlet weak var playButton: UIButton!
     @IBOutlet weak var forwardButton: UIButton!
     @IBOutlet weak var backButton: UIButton!
     @IBOutlet weak var playbackSlider: UISlider!
@@ -84,6 +85,8 @@ class NCPlayerToolBar: UIView {
         blurEffectTopToolBarView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
         playerTopToolBarView.insertSubview(blurEffectTopToolBarView, at:0)
         
+        pipButton.setImage(NCUtility.shared.loadImage(named: "pip.enter", color: .lightGray), for: .normal)
+        muteButton.setImage(NCUtility.shared.loadImage(named: "audioOff", color: .lightGray), for: .normal)
         
         playbackSlider.value = 0
         playbackSlider.minimumValue = 0
@@ -99,7 +102,6 @@ class NCPlayerToolBar: UIView {
         backButton.setImage(NCUtility.shared.loadImage(named: "gobackward.15", color: .lightGray), for: .normal)
         playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .lightGray), for: .normal)
         forwardButton.setImage(NCUtility.shared.loadImage(named: "goforward.15", color: .lightGray), for: .normal)
-        muteButton.setImage(NCUtility.shared.loadImage(named: "audioOff", color: .lightGray), for: .normal)
     }
     
     deinit {
@@ -199,6 +201,21 @@ class NCPlayerToolBar: UIView {
         var currentTime = appDelegate.player?.currentTime() ?? .zero
         currentTime = currentTime.convertScale(1000, method: .default)
         
+        if CCUtility.getAudioMute() {
+            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOff", color: .white), for: .normal)
+        } else {
+            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOn", color: .white), for: .normal)
+        }
+        muteButton.isEnabled = true
+        
+        if ncplayer?.pictureInPictureController != nil {
+            pipButton.setImage(NCUtility.shared.loadImage(named: "pip.enter", color: .white), for: .normal)
+            pipButton.isEnabled = true
+        } else {
+            pipButton.setImage(NCUtility.shared.loadImage(named: "pip.enter", color: .gray), for: .normal)
+            pipButton.isEnabled = false
+        }
+        
         if appDelegate.player?.rate == 1 { namedPlay = "pause.fill"}
         
         if timeSeek != nil {
@@ -229,13 +246,6 @@ class NCPlayerToolBar: UIView {
         }
         forwardButton.isEnabled = true
         
-        if CCUtility.getAudioMute() {
-            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOff", color: .white), for: .normal)
-        } else {
-            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOn", color: .white), for: .normal)
-        }
-        muteButton.isEnabled = true
-        
         labelCurrentTime.text = NCUtility.shared.stringFromTime(currentTime)
         labelOverallDuration.text = "-" + NCUtility.shared.stringFromTime(self.durationTime - currentTime)
     }
@@ -252,7 +262,7 @@ class NCPlayerToolBar: UIView {
             switch touchEvent.phase {
             case .began:
                 wasInPlay = appDelegate.player?.rate == 1 ? true : false
-                ncplayer?.videoPause()
+                ncplayer?.playerPause()
                 playbackSliderEvent = .began
             case .moved:
                 ncplayer?.videoSeek(time: targetTime)
@@ -260,7 +270,7 @@ class NCPlayerToolBar: UIView {
             case .ended:
                 ncplayer?.videoSeek(time: targetTime)
                 if wasInPlay {
-                    ncplayer?.videoPlay()
+                    ncplayer?.playerPlay()
                 }
                 playbackSliderEvent = .ended
             default:
@@ -282,13 +292,13 @@ class NCPlayerToolBar: UIView {
     @IBAction func playerPause(_ sender: Any) {
         
         if appDelegate.player?.timeControlStatus == .playing {
-            ncplayer?.videoPause()
+            ncplayer?.playerPause()
             if let time = appDelegate.player?.currentTime() {
                 ncplayer?.saveTime(time)
             }
             timerAutoHide?.invalidate()
         } else if appDelegate.player?.timeControlStatus == .paused {
-            ncplayer?.videoPlay()
+            ncplayer?.playerPlay()
             startTimerAutoHide()
         } else if appDelegate.player?.timeControlStatus == .waitingToPlayAtSpecifiedRate {
             print("timeControlStatus.waitingToPlayAtSpecifiedRate")
@@ -316,6 +326,11 @@ class NCPlayerToolBar: UIView {
         updateToolBar()
     }
     
+    @IBAction func setPip(_ sender: Any) {
+        
+        ncplayer?.pictureInPictureController?.startPictureInPicture()
+    }
+    
     @IBAction func forwardButtonSec(_ sender: Any) {
         guard let ncplayer = ncplayer else { return }
         guard let player = appDelegate.player else { return }

+ 19 - 9
iOSClient/Viewer/NCViewerMedia/NCViewerMedia.storyboard

@@ -241,25 +241,37 @@
                                         </connections>
                                     </view>
                                     <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dgJ-dQ-lSp" userLabel="Player Top Tool Bar">
-                                        <rect key="frame" x="354" y="10" width="45" height="45"/>
+                                        <rect key="frame" x="319" y="10" width="80" height="45"/>
                                         <subviews>
                                             <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8AB-hx-yqN" userLabel="Mute Button">
-                                                <rect key="frame" x="10" y="10" width="25" height="25"/>
+                                                <rect key="frame" x="50" y="10" width="25" height="25"/>
                                                 <constraints>
                                                     <constraint firstAttribute="width" constant="25" id="6yU-23-dkA"/>
                                                     <constraint firstAttribute="height" constant="25" id="hBk-Ku-BAd"/>
                                                 </constraints>
-                                                <color key="tintColor" systemColor="labelColor"/>
                                                 <state key="normal" image="audioOn"/>
                                                 <connections>
                                                     <action selector="setMute:" destination="sBp-t2-eFh" eventType="touchUpInside" id="cVl-BA-mPJ"/>
                                                 </connections>
                                             </button>
+                                            <button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NwE-zQ-Y5D" userLabel="Mute Button">
+                                                <rect key="frame" x="5" y="10" width="25" height="25"/>
+                                                <constraints>
+                                                    <constraint firstAttribute="width" constant="25" id="CaQ-c0-MES"/>
+                                                    <constraint firstAttribute="height" constant="25" id="N06-qe-ZVY"/>
+                                                </constraints>
+                                                <state key="normal" image="pip.enter" catalog="system"/>
+                                                <connections>
+                                                    <action selector="setPip:" destination="sBp-t2-eFh" eventType="touchUpInside" id="svR-8R-DQY"/>
+                                                </connections>
+                                            </button>
                                         </subviews>
                                         <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                         <constraints>
-                                            <constraint firstItem="8AB-hx-yqN" firstAttribute="centerX" secondItem="dgJ-dQ-lSp" secondAttribute="centerX" id="AqQ-8Y-T0u"/>
-                                            <constraint firstAttribute="width" constant="45" id="LTs-QZ-nVw"/>
+                                            <constraint firstItem="NwE-zQ-Y5D" firstAttribute="centerY" secondItem="dgJ-dQ-lSp" secondAttribute="centerY" id="Ad6-Aj-hvc"/>
+                                            <constraint firstAttribute="width" constant="80" id="LTs-QZ-nVw"/>
+                                            <constraint firstAttribute="trailing" secondItem="8AB-hx-yqN" secondAttribute="trailing" constant="5" id="bQK-xA-Jyu"/>
+                                            <constraint firstItem="NwE-zQ-Y5D" firstAttribute="leading" secondItem="dgJ-dQ-lSp" secondAttribute="leading" constant="5" id="cZY-tl-BOh"/>
                                             <constraint firstItem="8AB-hx-yqN" firstAttribute="centerY" secondItem="dgJ-dQ-lSp" secondAttribute="centerY" id="uNT-D4-mK3"/>
                                             <constraint firstAttribute="height" constant="45" id="xf9-B5-HMs"/>
                                         </constraints>
@@ -293,7 +305,6 @@
                                                             <constraint firstAttribute="width" constant="40" id="Cmv-LX-Phg"/>
                                                             <constraint firstAttribute="height" constant="40" id="djE-Ml-YD0"/>
                                                         </constraints>
-                                                        <color key="tintColor" systemColor="labelColor"/>
                                                         <state key="normal">
                                                             <imageReference key="image" image="play.fill" catalog="system" symbolScale="default"/>
                                                             <preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="default"/>
@@ -365,6 +376,7 @@
                                             <outlet property="labelCurrentTime" destination="kVv-X4-6SK" id="vyf-Bb-TPL"/>
                                             <outlet property="labelOverallDuration" destination="OUD-HH-cXH" id="E0O-99-aeq"/>
                                             <outlet property="muteButton" destination="8AB-hx-yqN" id="9zQ-k7-auv"/>
+                                            <outlet property="pipButton" destination="NwE-zQ-Y5D" id="veJ-QD-fOd"/>
                                             <outlet property="playButton" destination="x3E-b2-obf" id="0Nw-L4-W7M"/>
                                             <outlet property="playbackSlider" destination="SR4-e8-1hC" id="Khx-Oe-NEQ"/>
                                             <outlet property="playerTopToolBarView" destination="dgJ-dQ-lSp" id="22g-Yn-k5r"/>
@@ -427,10 +439,8 @@
         <image name="gobackward.15" catalog="system" width="121" height="128"/>
         <image name="goforward.15" catalog="system" width="121" height="128"/>
         <image name="logo" width="256" height="128"/>
+        <image name="pip.enter" catalog="system" width="128" height="96"/>
         <image name="play.fill" catalog="system" width="116" height="128"/>
-        <systemColor name="labelColor">
-            <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-        </systemColor>
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
         </systemColor>

+ 2 - 2
iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift

@@ -528,7 +528,7 @@ extension NCViewerMedia: UIGestureRecognizerDelegate {
                     
                     if let url = NCKTVHTTPCache.shared.getVideoURL(metadata: metadata) {
                         self.ncplayerLivePhoto = NCPlayer.init(url: url, imageVideoContainer: self.currentViewController.imageVideoContainer, playerToolBar: nil, metadata: metadata, detailView: nil)
-                        self.ncplayerLivePhoto?.videoPlay()
+                        self.ncplayerLivePhoto?.playerPlay()
                     }
                     
                 } else {
@@ -557,7 +557,7 @@ extension NCViewerMedia: UIGestureRecognizerDelegate {
                                 
                                 if let url = NCKTVHTTPCache.shared.getVideoURL(metadata: metadata) {
                                     self.ncplayerLivePhoto = NCPlayer.init(url: url, imageVideoContainer: self.currentViewController.imageVideoContainer, playerToolBar: nil, metadata: metadata, detailView: nil)
-                                    self.ncplayerLivePhoto?.videoPlay()
+                                    self.ncplayerLivePhoto?.playerPlay()
                                 }
                             }
                         }