浏览代码

Merge pull request #2412 from nextcloud/VLC

Vlc
Marino Faggiana 1 年之前
父节点
当前提交
b9b21f0511

+ 0 - 0
iOSClient/Images.xcassets/play.fill.imageset/Contents.json → iOSClient/Images.xcassets/play.imageset/Contents.json


+ 0 - 0
iOSClient/Images.xcassets/play.fill.imageset/play.svg → iOSClient/Images.xcassets/play.imageset/play.svg


+ 1 - 1
iOSClient/Media/NCMedia.swift

@@ -108,7 +108,7 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
         collectionView.prefetchDataSource = self
 
         cacheImages.cellLivePhotoImage = NCUtility.shared.loadImage(named: "livephoto", color: .white)
-        cacheImages.cellPlayImage = NCUtility.shared.loadImage(named: "play.fill", color: .white)
+        cacheImages.cellPlayImage = NCUtility.shared.loadImage(named: "play", color: .white)
     }
 
     override func viewWillAppear(_ animated: Bool) {

+ 1 - 0
iOSClient/Utility/CCUtility.h

@@ -211,6 +211,7 @@
 + (NSString *)getDirectoryProviderStorageOcId:(NSString *)ocId fileNameView:(NSString *)fileNameView;
 + (NSString *)getDirectoryProviderStorageIconOcId:(NSString *)ocId etag:(NSString *)etag;
 + (NSString *)getDirectoryProviderStoragePreviewOcId:(NSString *)ocId etag:(NSString *)etag;
++ (NSString *)getDirectoryProviderStorageSnapshotOcId:(NSString *)ocId etag:(NSString *)etag;
 + (BOOL)fileProviderStorageExists:(tableMetadata *)metadata;
 + (int64_t)fileProviderStorageSize:(NSString *)ocId fileNameView:(NSString *)fileNameView;
 + (BOOL)fileProviderStoragePreviewIconExists:(NSString *)ocId etag:(NSString *)etag;

+ 5 - 0
iOSClient/Utility/CCUtility.m

@@ -1107,6 +1107,11 @@
     return [NSString stringWithFormat:@"%@/%@.preview.%@", [self getDirectoryProviderStorageOcId:ocId], etag, [NCGlobal shared].extensionPreview];
 }
 
++ (NSString *)getDirectoryProviderStorageSnapshotOcId:(NSString *)ocId etag:(NSString *)etag
+{
+    return [NSString stringWithFormat:@"%@/%@.snapshot.%@", [self getDirectoryProviderStorageOcId:ocId], etag, [NCGlobal shared].extensionPreview];
+}
+
 + (BOOL)fileProviderStorageExists:(tableMetadata *)metadata
 {
     NSString *fileNameViewPath = [self getDirectoryProviderStorageOcId:metadata.ocId fileNameView:metadata.fileNameView];

+ 40 - 27
iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift

@@ -36,8 +36,8 @@ class NCPlayer: NSObject {
     internal var width: Int?
     internal var height: Int?
     internal var length: Int?
-    internal let fileNamePreviewLocalPath: String
     internal let userAgent = CCUtility.getUserAgent()!
+    internal var pauseAfterPlay: Bool = false
 
     internal weak var playerToolBar: NCPlayerToolBar?
     internal weak var viewerMediaPage: NCViewerMediaPage?
@@ -55,8 +55,6 @@ class NCPlayer: NSObject {
         self.metadata = metadata
         self.viewerMediaPage = viewerMediaPage
 
-        fileNamePreviewLocalPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)!
-
         super.init()
     }
 
@@ -82,7 +80,6 @@ class NCPlayer: NSObject {
         if let result = NCManageDatabase.shared.getVideo(metadata: metadata),
             let resultPosition = result.position {
             position = resultPosition
-            player.position = position
         }
 
         player.drawable = imageVideoContainer
@@ -91,19 +88,32 @@ class NCPlayer: NSObject {
             view.addGestureRecognizer(singleTapGestureRecognizer)
         }
 
-        playerToolBar?.setBarPlayer(position: position, ncplayer: self, metadata: metadata, viewerMediaPage: viewerMediaPage)
+        player.play()
+        player.position = position
 
-        self.player.play()
-        if !autoplay {
-            self.player.pause()
-            if position == 0 {
-                self.player.position = 0
-            }
+        if autoplay {
+            pauseAfterPlay = false
+        } else {
+            pauseAfterPlay = true
         }
 
+        playerToolBar?.setBarPlayer(position: position, ncplayer: self, metadata: metadata, viewerMediaPage: viewerMediaPage)
+
         NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidEnterBackground), object: nil)
     }
 
+    func restartAVPlayer(position: Float) {
+
+        if let url = self.url {
+            player.media = VLCMedia(url: url)
+            player.position = position
+            playerToolBar?.setBarPlayer(position: position)
+            viewerMediaPage?.changeScreenMode(mode: .normal)
+            pauseAfterPlay = true
+            player.play()
+        }
+    }
+
     // MARK: - UIGestureRecognizerDelegate
 
     @objc func didSingleTapWith(gestureRecognizer: UITapGestureRecognizer) {
@@ -116,7 +126,7 @@ class NCPlayer: NSObject {
     @objc func applicationDidEnterBackground(_ notification: NSNotification) {
 
         if metadata.isVideo {
-            playerStop()
+            playerPause()
         }
     }
 
@@ -130,14 +140,14 @@ class NCPlayer: NSObject {
     func playerPlay() {
 
         playerToolBar?.playbackSliderEvent = .began
-        player.play()
-        playerToolBar?.playButtonPause()
 
         if let result = NCManageDatabase.shared.getVideo(metadata: metadata), let position = result.position {
             player.position = position
             playerToolBar?.playbackSliderEvent = .moved
         }
 
+        player.play()
+
         DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
             self.playerToolBar?.playbackSliderEvent = .ended
         }
@@ -145,16 +155,13 @@ class NCPlayer: NSObject {
 
     @objc func playerStop() {
 
-        savePosition()
         player.stop()
-        playerToolBar?.playButtonPlay()
     }
 
     @objc func playerPause() {
 
         savePosition()
         player.pause()
-        playerToolBar?.playButtonPlay()
     }
 
     func playerPosition(_ position: Float) {
@@ -171,11 +178,13 @@ class NCPlayer: NSObject {
 
     func jumpForward(_ seconds: Int32) {
 
+        player.play()
         player.jumpForward(seconds)
     }
 
     func jumpBackward(_ seconds: Int32) {
 
+        player.play()
         player.jumpBackward(seconds)
     }
 }
@@ -186,9 +195,11 @@ extension NCPlayer: VLCMediaPlayerDelegate {
 
         switch player.state {
         case .stopped:
+            playerToolBar?.playButtonPlay()
             print("Played mode: STOPPED")
             break
         case .opening:
+            playerToolBar?.playButtonPause()
             print("Played mode: OPENING")
             break
         case .buffering:
@@ -196,16 +207,12 @@ extension NCPlayer: VLCMediaPlayerDelegate {
             break
         case .ended:
             if let url = self.url {
-                NCManageDatabase.shared.addVideo(metadata: metadata, position: 0)
-                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
-                    self.player.media = VLCMedia(url: url)
-                    self.player.position = 0
-                    self.playerToolBar?.setBarPlayer(position: 0)
-                    self.player.play()
-                    self.player.pause()
-                    self.player.position = 0
+                NCManageDatabase.shared.addVideo(metadata: self.metadata, position: 0)
+                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                    self.restartAVPlayer(position: 0)
                 }
             }
+            playerToolBar?.playButtonPlay()
             print("Played mode: ENDED")
             break
         case .error:
@@ -215,6 +222,11 @@ extension NCPlayer: VLCMediaPlayerDelegate {
             print("Played mode: ERROR")
             break
         case .playing:
+            if pauseAfterPlay {
+                player.pause()
+                pauseAfterPlay = false
+                print(player.position)
+            }
             let size = player.videoSize
             if let mediaLength = player.media?.length.intValue {
                 self.length = Int(mediaLength)
@@ -223,9 +235,11 @@ extension NCPlayer: VLCMediaPlayerDelegate {
             self.height = Int(size.height)
             playerToolBar?.updateTopToolBar(videoSubTitlesIndexes: player.videoSubTitlesIndexes, audioTrackIndexes: player.audioTrackIndexes)
             NCManageDatabase.shared.addVideo(metadata: metadata, width: self.width, height: self.height, length: self.length)
+            playerToolBar?.playButtonPause()
             print("Played mode: PLAYING")
             break
         case .paused:
+            playerToolBar?.playButtonPlay()
             print("Played mode: PAUSED")
             break
         default: break
@@ -233,7 +247,6 @@ extension NCPlayer: VLCMediaPlayerDelegate {
     }
 
     func mediaPlayerTimeChanged(_ aNotification: Notification) {
-
         playerToolBar?.update()
     }
 
@@ -250,7 +263,7 @@ extension NCPlayer: VLCMediaPlayerDelegate {
     }
 
     func mediaPlayerSnapshot(_ aNotification: Notification) {
-        print("Snapshot saved")
+        // Handle other states...
     }
 
     func mediaPlayerStartedRecording(_ player: VLCMediaPlayer) {

+ 30 - 37
iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift

@@ -32,15 +32,16 @@ import FloatingPanel
 
 class NCPlayerToolBar: UIView {
 
-    @IBOutlet weak var playerTopToolBarView: UIStackView!
+    @IBOutlet weak var utilityView: UIStackView!
     @IBOutlet weak var subtitleButton: UIButton!
     @IBOutlet weak var audioButton: UIButton!
 
-    @IBOutlet weak var playerToolBarView: UIView!
+    @IBOutlet weak var playerButtonView: UIStackView!
+    @IBOutlet weak var backButton: UIButton!
     @IBOutlet weak var playButton: UIButton!
-
     @IBOutlet weak var forwardButton: UIButton!
-    @IBOutlet weak var backButton: UIButton!
+
+    @IBOutlet weak var playbackSliderView: UIView!
     @IBOutlet weak var playbackSlider: UISlider!
     @IBOutlet weak var labelLeftTime: UILabel!
     @IBOutlet weak var labelCurrentTime: UILabel!
@@ -57,6 +58,8 @@ class NCPlayerToolBar: UIView {
     private let audioSession = AVAudioSession.sharedInstance()
     private var subTitleIndex: Int32?
     private var audioIndex: Int32?
+
+    private var pointSize: CGFloat = 0
     
     private weak var viewerMediaPage: NCViewerMediaPage?
 
@@ -65,43 +68,35 @@ class NCPlayerToolBar: UIView {
     override func awakeFromNib() {
         super.awakeFromNib()
 
-        let blurEffectTopToolBarView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        blurEffectTopToolBarView.frame = playerTopToolBarView.bounds
-        blurEffectTopToolBarView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+        subtitleButton.setImage(NCUtility.shared.loadImage(named: "captions.bubble", color: .white), for: .normal)
+        subtitleButton.isEnabled = false
 
-        playerTopToolBarView.insertSubview(blurEffectTopToolBarView, at: 0)
-        playerTopToolBarView.layer.cornerRadius = 10
-        playerTopToolBarView.layer.masksToBounds = true
-        playerTopToolBarView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapTopToolBarWith(gestureRecognizer:))))
+        audioButton.setImage(NCUtility.shared.loadImage(named: "speaker.zzz", color: .white), for: .normal)
+        audioButton.isEnabled = false
 
-        let blurEffectToolBarView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        blurEffectToolBarView.frame = playerToolBarView.bounds
-        blurEffectToolBarView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+        if UIDevice.current.userInterfaceIdiom == .pad {
+            pointSize = 60
+        } else {
+            pointSize = 50
+        }
 
-        playerToolBarView.insertSubview(blurEffectToolBarView, at: 0)
-        playerToolBarView.layer.cornerRadius = 10
-        playerToolBarView.layer.masksToBounds = true
-        playerToolBarView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapToolBarWith(gestureRecognizer:))))
+        playerButtonView.spacing = pointSize
+        backButton.setImage(NCUtility.shared.loadImage(named: "gobackward.10", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: pointSize)), for: .normal)
+        playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: pointSize)), for: .normal)
+        forwardButton.setImage(NCUtility.shared.loadImage(named: "goforward.10", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: pointSize)), for: .normal)
 
+        playbackSlider.setThumbImage(UIImage(systemName: "circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 10)), for: .normal)
         playbackSlider.value = 0
-        playbackSlider.tintColor = .lightGray
+        playbackSlider.tintColor = .white
         playbackSlider.addTarget(self, action: #selector(playbackValChanged(slider:event:)), for: .valueChanged)
 
+        utilityView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap(gestureRecognizer:))))
+        playbackSliderView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap(gestureRecognizer:))))
+        playerButtonView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap(gestureRecognizer:))))
+
         labelCurrentTime.textColor = .white
         labelLeftTime.textColor = .white
 
-        playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: 30)), for: .normal)
-
-        subtitleButton.setImage(NCUtility.shared.loadImage(named: "captions.bubble", color: .white), for: .normal)
-        subtitleButton.isEnabled = false
-        
-        audioButton.setImage(NCUtility.shared.loadImage(named: "speaker.zzz", color: .white), for: .normal)
-        audioButton.isEnabled = false
-
-        backButton.setImage(NCUtility.shared.loadImage(named: "gobackward.10", color: .white), for: .normal)
-
-        forwardButton.setImage(NCUtility.shared.loadImage(named: "goforward.10", color: .white), for: .normal)
-
         // Normally hide
         self.alpha = 0
         self.isHidden = true
@@ -130,7 +125,7 @@ class NCPlayerToolBar: UIView {
             self.viewerMediaPage = viewerMediaPage
         }
 
-        playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: 30)), for: .normal)
+        playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: pointSize)), for: .normal)
         MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = 0
 
         playbackSlider.value = position
@@ -192,13 +187,13 @@ class NCPlayerToolBar: UIView {
 
     func playButtonPause() {
 
-        playButton.setImage(NCUtility.shared.loadImage(named: "pause.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: 30)), for: .normal)
+        playButton.setImage(NCUtility.shared.loadImage(named: "pause.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: pointSize)), for: .normal)
         MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = 1
     }
 
     func playButtonPlay() {
 
-        playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: 30)), for: .normal)
+        playButton.setImage(NCUtility.shared.loadImage(named: "play.fill", color: .white, symbolConfiguration: UIImage.SymbolConfiguration(pointSize: pointSize)), for: .normal)
         MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = 0
     }
 
@@ -232,9 +227,7 @@ class NCPlayerToolBar: UIView {
 
     // MARK: - Action
 
-    @objc func tapTopToolBarWith(gestureRecognizer: UITapGestureRecognizer) { }
-
-    @objc func tapToolBarWith(gestureRecognizer: UITapGestureRecognizer) { }
+    @objc func tap(gestureRecognizer: UITapGestureRecognizer) { }
 
     @IBAction func tapPlayerPause(_ sender: Any) {
         guard let ncplayer = ncplayer else { return }

+ 58 - 87
iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.xib

@@ -1,10 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
-    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
-        <capability name="Image references" minToolsVersion="12.0"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -12,18 +11,14 @@
         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
         <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="NCPlayerToolBar" customModule="Nextcloud" customModuleProvider="target">
-            <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
             <subviews>
-                <stackView opaque="NO" contentMode="scaleToFill" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="XfW-XC-eMf" userLabel="Player Top Tool Bar">
-                    <rect key="frame" x="329" y="58" width="75" height="35"/>
+                <stackView opaque="NO" contentMode="scaleToFill" distribution="equalCentering" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="XfW-XC-eMf" userLabel="Player Top Tool Bar">
+                    <rect key="frame" x="297" y="0.0" width="78" height="52"/>
                     <subviews>
                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qqZ-QN-TsW">
-                            <rect key="frame" x="5" y="5" width="25" height="25"/>
-                            <constraints>
-                                <constraint firstAttribute="height" constant="25" id="S3q-Dj-i67"/>
-                                <constraint firstAttribute="width" constant="25" id="rg2-EW-KJX"/>
-                            </constraints>
+                            <rect key="frame" x="5" y="25" width="22.5" height="22"/>
                             <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                             <state key="normal" image="captions.bubble" catalog="system"/>
                             <connections>
@@ -31,11 +26,7 @@
                             </connections>
                         </button>
                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sMY-qo-4CE">
-                            <rect key="frame" x="45" y="5" width="25" height="25"/>
-                            <constraints>
-                                <constraint firstAttribute="height" constant="25" id="kui-Ih-KqM"/>
-                                <constraint firstAttribute="width" constant="25" id="zUF-5q-I6f"/>
-                            </constraints>
+                            <rect key="frame" x="47.5" y="25" width="25.5" height="22"/>
                             <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                             <state key="normal" image="speaker.zzz" catalog="system"/>
                             <connections>
@@ -45,70 +36,51 @@
                     </subviews>
                     <directionalEdgeInsets key="directionalLayoutMargins" top="5" leading="5" bottom="5" trailing="5"/>
                 </stackView>
+                <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="ncM-9U-phl" userLabel="Player Top Tool Bar">
+                    <rect key="frame" x="125" y="317.5" width="125" height="32.5"/>
+                    <subviews>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xja-nq-uD3">
+                            <rect key="frame" x="5" y="5" width="20" height="22.5"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" image="gobackward.10" catalog="system"/>
+                            <connections>
+                                <action selector="tapBack:" destination="iN0-l3-epB" eventType="touchUpInside" id="dam-FU-7fD"/>
+                            </connections>
+                        </button>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qo0-x8-OfL">
+                            <rect key="frame" x="55" y="5" width="15" height="22"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="18"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" image="play.fill" catalog="system"/>
+                            <connections>
+                                <action selector="tapPlayerPause:" destination="iN0-l3-epB" eventType="touchUpInside" id="XcN-Tk-ad8"/>
+                            </connections>
+                        </button>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Zd-By-Fko">
+                            <rect key="frame" x="100" y="5" width="20" height="22.5"/>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                            <state key="normal" image="goforward.10" catalog="system"/>
+                            <connections>
+                                <action selector="tapForward:" destination="iN0-l3-epB" eventType="touchUpInside" id="MAM-Kd-NXu"/>
+                            </connections>
+                        </button>
+                    </subviews>
+                    <directionalEdgeInsets key="directionalLayoutMargins" top="5" leading="5" bottom="5" trailing="5"/>
+                </stackView>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="85m-50-8yp">
-                    <rect key="frame" x="10" y="794" width="394" height="58"/>
+                    <rect key="frame" x="0.0" y="609" width="375" height="58"/>
                     <subviews>
-                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ixi-yR-HDH" userLabel="Container play">
-                            <rect key="frame" x="0.0" y="0.0" width="118" height="58"/>
-                            <subviews>
-                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uP7-aY-x4n">
-                                    <rect key="frame" x="3.5" y="9" width="40" height="40"/>
-                                    <constraints>
-                                        <constraint firstAttribute="width" constant="40" id="0jv-Tl-Nch"/>
-                                        <constraint firstAttribute="height" constant="40" id="jnZ-cX-iJY"/>
-                                    </constraints>
-                                    <state key="normal" image="gobackward.10" catalog="system"/>
-                                    <connections>
-                                        <action selector="tapBack:" destination="iN0-l3-epB" eventType="touchUpInside" id="q3g-BH-iUc"/>
-                                    </connections>
-                                </button>
-                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hx9-d5-yiD">
-                                    <rect key="frame" x="39" y="9" width="40" height="40"/>
-                                    <constraints>
-                                        <constraint firstAttribute="width" constant="40" id="Ime-ag-2Hm"/>
-                                        <constraint firstAttribute="height" constant="40" id="snM-fJ-0LV"/>
-                                    </constraints>
-                                    <state key="normal">
-                                        <imageReference key="image" image="play.fill" catalog="system" symbolScale="default"/>
-                                        <preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="default"/>
-                                    </state>
-                                    <connections>
-                                        <action selector="tapPlayerPause:" destination="iN0-l3-epB" eventType="touchUpInside" id="XHf-om-3g9"/>
-                                    </connections>
-                                </button>
-                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bGn-IC-3V1">
-                                    <rect key="frame" x="74.5" y="9" width="40" height="40"/>
-                                    <constraints>
-                                        <constraint firstAttribute="height" constant="40" id="VDT-no-B6f"/>
-                                        <constraint firstAttribute="width" constant="40" id="eA5-wy-Sqb"/>
-                                    </constraints>
-                                    <state key="normal" image="goforward.10" catalog="system"/>
-                                    <connections>
-                                        <action selector="tapForward:" destination="iN0-l3-epB" eventType="touchUpInside" id="45z-IH-Fyr"/>
-                                    </connections>
-                                </button>
-                            </subviews>
-                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                            <constraints>
-                                <constraint firstItem="hx9-d5-yiD" firstAttribute="centerY" secondItem="ixi-yR-HDH" secondAttribute="centerY" id="Brn-9w-mrJ"/>
-                                <constraint firstItem="bGn-IC-3V1" firstAttribute="centerY" secondItem="ixi-yR-HDH" secondAttribute="centerY" id="JBD-51-iYm"/>
-                                <constraint firstItem="uP7-aY-x4n" firstAttribute="centerY" secondItem="ixi-yR-HDH" secondAttribute="centerY" id="MPU-Hg-zQa"/>
-                                <constraint firstItem="hx9-d5-yiD" firstAttribute="centerX" secondItem="ixi-yR-HDH" secondAttribute="centerX" id="Vyv-jg-Cwu"/>
-                                <constraint firstItem="uP7-aY-x4n" firstAttribute="centerX" secondItem="ixi-yR-HDH" secondAttribute="centerX" multiplier="0.4" id="bwk-Bx-qVb"/>
-                                <constraint firstItem="bGn-IC-3V1" firstAttribute="centerX" secondItem="ixi-yR-HDH" secondAttribute="centerX" multiplier="1.6" id="wJP-ph-5c5"/>
-                            </constraints>
-                        </view>
                         <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="MY0-FC-j88">
-                            <rect key="frame" x="121" y="14" width="265" height="31"/>
+                            <rect key="frame" x="-2" y="14" width="379" height="31"/>
                         </slider>
                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="--:--" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="svM-TQ-AyQ">
-                            <rect key="frame" x="361.5" y="44" width="22.5" height="12"/>
+                            <rect key="frame" x="352.5" y="44" width="22.5" height="12"/>
                             <fontDescription key="fontDescription" type="system" pointSize="10"/>
                             <nil key="textColor"/>
                             <nil key="highlightedColor"/>
                         </label>
                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="--:--" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OHB-2J-Gqb">
-                            <rect key="frame" x="123" y="44" width="22.5" height="12"/>
+                            <rect key="frame" x="0.0" y="44" width="22.5" height="12"/>
                             <fontDescription key="fontDescription" type="system" pointSize="10"/>
                             <nil key="textColor"/>
                             <nil key="highlightedColor"/>
@@ -116,16 +88,12 @@
                     </subviews>
                     <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                     <constraints>
-                        <constraint firstItem="ixi-yR-HDH" firstAttribute="centerY" secondItem="85m-50-8yp" secondAttribute="centerY" id="5sz-fh-GbG"/>
                         <constraint firstItem="OHB-2J-Gqb" firstAttribute="leading" secondItem="MY0-FC-j88" secondAttribute="leading" id="6n7-If-xdS"/>
-                        <constraint firstItem="ixi-yR-HDH" firstAttribute="height" secondItem="85m-50-8yp" secondAttribute="height" id="8xM-7l-FXN"/>
                         <constraint firstAttribute="height" constant="58" id="9Uv-dV-to4"/>
                         <constraint firstItem="svM-TQ-AyQ" firstAttribute="top" secondItem="MY0-FC-j88" secondAttribute="bottom" id="Aan-ac-nr9"/>
-                        <constraint firstItem="MY0-FC-j88" firstAttribute="leading" secondItem="ixi-yR-HDH" secondAttribute="trailing" constant="5" id="BAz-4C-w3A"/>
-                        <constraint firstAttribute="trailing" secondItem="svM-TQ-AyQ" secondAttribute="trailing" constant="10" id="JXl-DO-x6b"/>
-                        <constraint firstItem="ixi-yR-HDH" firstAttribute="leading" secondItem="85m-50-8yp" secondAttribute="leading" id="Kh2-nU-bMU"/>
-                        <constraint firstItem="ixi-yR-HDH" firstAttribute="width" secondItem="85m-50-8yp" secondAttribute="width" multiplier="0.3" id="gXG-4n-Ee3"/>
-                        <constraint firstAttribute="trailing" secondItem="MY0-FC-j88" secondAttribute="trailing" constant="10" id="hBO-J2-Kdo"/>
+                        <constraint firstItem="MY0-FC-j88" firstAttribute="leading" secondItem="85m-50-8yp" secondAttribute="leading" id="Hjo-k0-bpn"/>
+                        <constraint firstAttribute="trailing" secondItem="svM-TQ-AyQ" secondAttribute="trailing" id="JXl-DO-x6b"/>
+                        <constraint firstAttribute="trailing" secondItem="MY0-FC-j88" secondAttribute="trailing" id="hBO-J2-Kdo"/>
                         <constraint firstItem="OHB-2J-Gqb" firstAttribute="top" secondItem="MY0-FC-j88" secondAttribute="bottom" id="jdb-Vq-WoF"/>
                         <constraint firstItem="MY0-FC-j88" firstAttribute="centerY" secondItem="85m-50-8yp" secondAttribute="centerY" id="lG8-DN-rTE"/>
                     </constraints>
@@ -134,25 +102,28 @@
             <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
             <constraints>
-                <constraint firstItem="85m-50-8yp" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="10" id="5H2-Gg-PEb"/>
-                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="85m-50-8yp" secondAttribute="trailing" constant="10" id="BXT-Qo-qFl"/>
-                <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="85m-50-8yp" secondAttribute="bottom" constant="10" id="N7Q-PF-7lb"/>
-                <constraint firstItem="XfW-XC-eMf" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="10" id="fq3-6h-kkx"/>
-                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="XfW-XC-eMf" secondAttribute="trailing" constant="10" id="uYG-Ai-CGv"/>
+                <constraint firstItem="85m-50-8yp" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="5H2-Gg-PEb"/>
+                <constraint firstAttribute="trailing" secondItem="85m-50-8yp" secondAttribute="trailing" id="BXT-Qo-qFl"/>
+                <constraint firstItem="ncM-9U-phl" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="DAA-xj-35k"/>
+                <constraint firstAttribute="bottom" secondItem="85m-50-8yp" secondAttribute="bottom" id="N7Q-PF-7lb"/>
+                <constraint firstItem="ncM-9U-phl" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="dPB-Kf-Ad7"/>
+                <constraint firstItem="XfW-XC-eMf" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="fq3-6h-kkx"/>
+                <constraint firstAttribute="trailing" secondItem="XfW-XC-eMf" secondAttribute="trailing" id="uYG-Ai-CGv"/>
             </constraints>
             <connections>
                 <outlet property="audioButton" destination="sMY-qo-4CE" id="R7Q-de-Dsv"/>
-                <outlet property="backButton" destination="uP7-aY-x4n" id="SyC-qV-IMq"/>
-                <outlet property="forwardButton" destination="bGn-IC-3V1" id="0OZ-f2-eWU"/>
+                <outlet property="backButton" destination="xja-nq-uD3" id="l3U-Mo-DEL"/>
+                <outlet property="forwardButton" destination="5Zd-By-Fko" id="ocQ-YT-Rwm"/>
                 <outlet property="labelCurrentTime" destination="OHB-2J-Gqb" id="pFy-CJ-x2A"/>
                 <outlet property="labelLeftTime" destination="svM-TQ-AyQ" id="UDV-Lh-12z"/>
-                <outlet property="playButton" destination="hx9-d5-yiD" id="Enk-Ge-2Yx"/>
+                <outlet property="playButton" destination="qo0-x8-OfL" id="m4a-gb-D0J"/>
                 <outlet property="playbackSlider" destination="MY0-FC-j88" id="bVe-Kc-80k"/>
-                <outlet property="playerToolBarView" destination="85m-50-8yp" id="eZK-p1-v65"/>
-                <outlet property="playerTopToolBarView" destination="XfW-XC-eMf" id="Qdp-IW-YhT"/>
+                <outlet property="playbackSliderView" destination="85m-50-8yp" id="SOs-XA-Mgh"/>
+                <outlet property="playerButtonView" destination="ncM-9U-phl" id="aTD-g1-xGg"/>
                 <outlet property="subtitleButton" destination="qqZ-QN-TsW" id="XCP-hb-eZB"/>
+                <outlet property="utilityView" destination="XfW-XC-eMf" id="QiB-so-jiU"/>
             </connections>
-            <point key="canvasLocation" x="137.68115942028987" y="152.67857142857142"/>
+            <point key="canvasLocation" x="136.80000000000001" y="152.47376311844079"/>
         </view>
     </objects>
     <resources>

+ 18 - 10
iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift

@@ -94,10 +94,10 @@ class NCViewerMedia: UIViewController {
             if let playerToolBar = playerToolBar {
                 view.addSubview(playerToolBar)
                 playerToolBar.translatesAutoresizingMaskIntoConstraints = false
-                playerToolBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
-                playerToolBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
-                playerToolBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
-                playerToolBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
+                playerToolBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
+                playerToolBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
+                playerToolBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10).isActive = true
+                playerToolBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10).isActive = true
             }
 
             self.ncplayer = NCPlayer(imageVideoContainer: self.imageVideoContainer, playerToolBar: self.playerToolBar, metadata: self.metadata, viewerMediaPage: self.viewerMediaPage)
@@ -174,9 +174,7 @@ class NCViewerMedia: UIViewController {
         super.viewDidAppear(animated)
 
         if metadata.isMovie {
-
             if let ncplayer = self.ncplayer {
-
                 if ncplayer.url == nil {
                     NCNetworking.shared.getVideoUrl(metadata: metadata) { url, autoplay in
                         if let url = url {
@@ -190,16 +188,18 @@ class NCViewerMedia: UIViewController {
                     } else {
                         playerToolBar?.hide()
                     }
+                    var position: Float = 0
+                    if let result = NCManageDatabase.shared.getVideo(metadata: metadata), let resultPosition = result.position {
+                        position = resultPosition
+                    }
+                    ncplayer.restartAVPlayer(position: position)
                 }
             }
-            
         } else if metadata.isImage {
-
             viewerMediaPage?.clearCommandCenter()
+            showTip()
         }
 
-        showTip()
-
         NotificationCenter.default.addObserver(self, selector: #selector(openDetail(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterOpenMediaDetail), object: nil)
     }
 
@@ -209,6 +209,14 @@ class NCViewerMedia: UIViewController {
         self.tipView?.dismiss()
     }
 
+    override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+
+        if let ncplayer = ncplayer, ncplayer.isPlay() {
+            ncplayer.playerPause()
+        }
+    }
+
     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
         super.viewWillTransition(to: size, with: coordinator)
 

+ 1 - 4
iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift

@@ -161,10 +161,6 @@ class NCViewerMediaPage: UIViewController {
     override func viewDidDisappear(_ animated: Bool) {
         super.viewDidDisappear(animated)
 
-        if let ncplayer = currentViewController.ncplayer, ncplayer.isPlay() {
-            ncplayer.playerPause()
-        }
-        clearCommandCenter()
         timerAutoHide?.invalidate()
     }
 
@@ -400,6 +396,7 @@ class NCViewerMediaPage: UIViewController {
     @objc func applicationDidBecomeActive(_ notification: NSNotification) {
 
         progressView.progress = 0
+        changeScreenMode(mode: .normal)
     }
 
     // MARK: - Command Center