Explorar o código

Merge pull request #2408 from nextcloud/VLC

Vlc
Marino Faggiana hai 1 ano
pai
achega
e871fd5064
Modificáronse 34 ficheiros con 342 adicións e 217 borrados
  1. 1 1
      Brand/Database.swift
  2. 2 2
      Nextcloud.xcodeproj/project.pbxproj
  3. 1 1
      iOSClient/Data/NCElementsJSON.swift
  4. 16 0
      iOSClient/Data/NCManageDatabase+Metadata.swift
  5. 17 34
      iOSClient/Data/NCManageDatabase+Video.swift
  6. 2 1
      iOSClient/Data/NCManageDatabase.swift
  7. 0 1
      iOSClient/Images.xcassets/captions.bubble.imageset/subtitles-outline.svg
  8. 1 4
      iOSClient/Images.xcassets/speaker0.imageset/Contents.json
  9. 8 0
      iOSClient/Images.xcassets/speaker0.imageset/speaker0.svg
  10. 12 0
      iOSClient/Images.xcassets/speaker1.imageset/Contents.json
  11. 8 0
      iOSClient/Images.xcassets/speaker1.imageset/speaker1.svg
  12. 12 0
      iOSClient/Images.xcassets/speaker2.imageset/Contents.json
  13. 4 0
      iOSClient/Images.xcassets/speaker2.imageset/speaker2.svg
  14. 12 0
      iOSClient/Images.xcassets/speaker3.imageset/Contents.json
  15. 4 0
      iOSClient/Images.xcassets/speaker3.imageset/speaker3.svg
  16. 2 2
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  17. 3 3
      iOSClient/Main/NCActionCenter.swift
  18. 1 1
      iOSClient/Media/NCMedia.swift
  19. 10 1
      iOSClient/Menu/NCMenu.swift
  20. 1 1
      iOSClient/Menu/NCViewer+Menu.swift
  21. 2 2
      iOSClient/Menu/UIViewController+Menu.swift
  22. 0 3
      iOSClient/Utility/CCUtility.h
  23. 0 17
      iOSClient/Utility/CCUtility.m
  24. 4 4
      iOSClient/Utility/NCUtility+Image.swift
  25. 3 3
      iOSClient/Utility/NCUtility.swift
  26. 1 1
      iOSClient/Viewer/NCViewer.swift
  27. 13 38
      iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift
  28. 119 37
      iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift
  29. 24 10
      iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.xib
  30. 29 28
      iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift
  31. 1 1
      iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift
  32. 20 11
      iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift
  33. 7 8
      iOSClient/Viewer/NCViewerProviderContextMenu.swift
  34. 2 2
      iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLook.swift

+ 1 - 1
Brand/Database.swift

@@ -26,4 +26,4 @@ import Foundation
 // Database Realm
 //
 let databaseName                    = "nextcloud.realm"
-let databaseSchemaVersion: UInt64   = 292
+let databaseSchemaVersion: UInt64   = 295

+ 2 - 2
Nextcloud.xcodeproj/project.pbxproj

@@ -3958,7 +3958,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 1;
+				CURRENT_PROJECT_VERSION = 2;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -4021,7 +4021,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 1;
+				CURRENT_PROJECT_VERSION = 2;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;

+ 1 - 1
iOSClient/Data/NCElementsJSON.swift

@@ -71,5 +71,5 @@ import UIKit
     @objc public let capabilitiesUserStatusEnabled: Array = ["ocs", "data", "capabilities", "user_status", "enabled"]
     @objc public let capabilitiesUserStatusSupportsEmoji: Array = ["ocs", "data", "capabilities", "user_status", "supports_emoji"]
 
-    @objc public let capabilitiesGroupfoldersEnabled: Array = ["ocs", "data", "capabilities", "groupfolders", "hasAccessibleGroupFolders"]
+    @objc public let capabilitiesGroupfoldersEnabled: Array = ["ocs", "data", "capabilities", "groupfolders", "hasGroupFolders"]
 }

+ 16 - 0
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -144,6 +144,22 @@ extension tableMetadata {
         sharePermissionsCollaborationServices == NCGlobal.shared.permissionReadShare && classFile == NKCommon.TypeClassFile.document.rawValue
     }
 
+    var isMediaPlay: Bool {
+        return classFile == NKCommon.TypeClassFile.audio.rawValue || classFile == NKCommon.TypeClassFile.video.rawValue
+    }
+
+    var isVideo: Bool {
+        return classFile == NKCommon.TypeClassFile.video.rawValue
+    }
+
+    var isAudio: Bool {
+        return classFile == NKCommon.TypeClassFile.audio.rawValue
+    }
+
+    var isImage: Bool {
+        return classFile == NKCommon.TypeClassFile.image.rawValue
+    }
+
     var isSavebleAsImage: Bool {
         classFile == NKCommon.TypeClassFile.image.rawValue && contentType != "image/svg+xml"
     }

+ 17 - 34
iOSClient/Data/NCManageDatabase+Video.swift

@@ -25,25 +25,21 @@ import Foundation
 import RealmSwift
 import NextcloudKit
 
-typealias tableVideo = tableVideoV2
-class tableVideoV2: Object {
-
-    @objc dynamic var account = ""
-    @objc dynamic var ocId = ""
-    @objc dynamic var position: Float = 0
-    @objc dynamic var width: Int = 0
-    @objc dynamic var height: Int = 0
-    @objc dynamic var length: Int = 0
-    @objc dynamic var codecNameVideo: String?
-    @objc dynamic var codecNameAudio: String?
-    @objc dynamic var codecAudioChannelLayout: String?
-    @objc dynamic var codecAudioLanguage: String?
-    @objc dynamic var codecMaxCompatibility: Bool = false
-    @objc dynamic var codecQuality: String?
-
-    override static func primaryKey() -> String {
-        return "ocId"
-    }
+typealias tableVideo = tableVideoV3
+class tableVideoV3: Object {
+
+    @Persisted var account = ""
+    @Persisted(primaryKey: true) var ocId = ""
+    @Persisted var position: Float?
+    @Persisted var width: Int?
+    @Persisted var height: Int?
+    @Persisted var length: Int?
+    @Persisted var codecNameVideo: String?
+    @Persisted var codecNameAudio: String?
+    @Persisted var codecAudioChannelLayout: String?
+    @Persisted var codecAudioLanguage: String?
+    @Persisted var codecMaxCompatibility: Bool = false
+    @Persisted var codecQuality: String?
 }
 
 extension NCManageDatabase {
@@ -91,7 +87,7 @@ extension NCManageDatabase {
                     if let length = length {
                         result.length = length
                     }
-
+                    
                     realm.add(result, update: .all)
                 }
             }
@@ -142,20 +138,7 @@ extension NCManageDatabase {
 
         return tableVideo.init(value: result)
     }
-
-    func getVideoPosition(metadata: tableMetadata) -> Float? {
-
-        if metadata.livePhoto { return nil }
-        let realm = try! Realm()
-
-        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
-            return nil
-        }
-
-        if result.position == 0 { return nil }
-        return result.position
-    }
-
+    
     func deleteVideo(metadata: tableMetadata) {
 
         let realm = try! Realm()

+ 2 - 1
iOSClient/Data/NCManageDatabase.swift

@@ -70,7 +70,7 @@ class NCManageDatabase: NSObject {
             let config = Realm.Configuration(
                 fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName),
                 schemaVersion: databaseSchemaVersion,
-                objectTypes: [tableMetadata.self, tableLocalFile.self, tableDirectory.self, tableTag.self, tableAccount.self, tableCapabilities.self, tablePhotoLibrary.self, tableE2eEncryption.self, tableE2eEncryptionLock.self, tableShare.self, tableChunk.self, tableAvatar.self, tableDashboardWidget.self, tableDashboardWidgetButton.self, NCDBLayoutForView.self]
+                objectTypes: [tableMetadata.self, tableLocalFile.self, tableDirectory.self, tableTag.self, tableAccount.self, tableCapabilities.self, tablePhotoLibrary.self, tableE2eEncryption.self, tableE2eEncryptionLock.self, tableE2eMetadata.self, tableShare.self, tableChunk.self, tableAvatar.self, tableDashboardWidget.self, tableDashboardWidgetButton.self, NCDBLayoutForView.self]
             )
 
             Realm.Configuration.defaultConfiguration = config
@@ -194,6 +194,7 @@ class NCManageDatabase: NSObject {
         self.clearTable(tableDirectory.self, account: account)
         self.clearTable(tableE2eEncryption.self, account: account)
         self.clearTable(tableE2eEncryptionLock.self, account: account)
+        self.clearTable(tableE2eMetadata.self, account: account)
         self.clearTable(tableExternalSites.self, account: account)
         self.clearTable(tableGPS.self, account: nil)
         self.clearTable(TableGroupfolders.self, account: account)

+ 0 - 1
iOSClient/Images.xcassets/captions.bubble.imageset/subtitles-outline.svg

@@ -1 +0,0 @@
-<?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="M20,4A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4H20M20,18V6H4V18H20M6,10H8V12H6V10M6,14H14V16H6V14M16,14H18V16H16V14M10,10H18V12H10V10Z" /></svg>

+ 1 - 4
iOSClient/Images.xcassets/captions.bubble.imageset/Contents.json → iOSClient/Images.xcassets/speaker0.imageset/Contents.json

@@ -1,15 +1,12 @@
 {
   "images" : [
     {
-      "filename" : "subtitles-outline.svg",
+      "filename" : "speaker0.svg",
       "idiom" : "universal"
     }
   ],
   "info" : {
     "author" : "xcode",
     "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
   }
 }

+ 8 - 0
iOSClient/Images.xcassets/speaker0.imageset/speaker0.svg

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="0,0,256,256" width="50px" height="50px" fill-rule="nonzero" xmlns="http://www.w3.org/2000/svg">
+  <g fill="#000000" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal" transform="matrix(1, 0, 0, 1, 16.912527, 1.101919)">
+    <g transform="translate(239.02716,16.80287) rotate(90) scale(5.12,5.12)">
+      <path d="M24.15625,3c-0.30469,0 -0.60547,0.0625 -0.90625,0.15625c-0.60547,0.19141 -1.18359,0.55078 -1.6875,1.0625l-11.75,11.75h-6.8125c-1.66797,0 -3.03125,1.36328 -3.03125,3.03125v12c0,1.66797 1.36328,3.03125 3.03125,3.03125h6.8125l11.71875,11.65625c1.11719,1.12109 2.55078,1.61328 3.71875,1.0625c1.17578,-0.55469 1.75,-1.89062 1.75,-3.4375v-37c0,-1.5 -0.76562,-2.74609 -1.9375,-3.15625c-0.29297,-0.10156 -0.60156,-0.15625 -0.90625,-0.15625zM24.1875,5c0.10156,0 0.17969,0.00781 0.25,0.03125c0.28516,0.09766 0.5625,0.35156 0.5625,1.28125v37c0,1.06641 -0.35156,1.54297 -0.59375,1.65625c-0.24219,0.11328 -0.73047,0.125 -1.5,-0.65625l-12.59375,-12.59375c-0.01953,-0.01172 -0.04297,-0.02344 -0.0625,-0.03125c0.07422,0.06641 -0.25,-0.56641 -0.25,-0.9375v-11.5c0,-0.37109 0.33594,-1.01172 0.25,-0.9375c0.02344,-0.01953 0.04297,-0.03906 0.0625,-0.0625l12.65625,-12.625c0.46875,-0.47266 0.91016,-0.62109 1.21875,-0.625zM3,18.03125h5.1875c-0.12891,0.38281 -0.1875,0.80078 -0.1875,1.21875v11.5c0,0.41797 0.0625,0.83203 0.1875,1.21875h-5.1875c-0.53906,0 -0.96875,-0.42969 -0.96875,-0.96875v-12c0,-0.53906 0.42969,-0.96875 0.96875,-0.96875zM31.90625,18.96875c-0.04297,0.00781 -0.08594,0.01953 -0.125,0.03125c-0.375,0.06641 -0.67578,0.33984 -0.78125,0.70313c-0.10547,0.36719 0.00391,0.75781 0.28125,1.01563l4.28125,4.28125l-4.28125,4.28125c-0.39844,0.39844 -0.39844,1.03906 0,1.4375c0.39844,0.39844 1.03906,0.39844 1.4375,0l4.28125,-4.28125l4.28125,4.28125c0.39844,0.39844 1.03906,0.39844 1.4375,0c0.39844,-0.39844 0.39844,-1.03906 0,-1.4375l-4.28125,-4.28125l4.28125,-4.28125c0.32422,-0.30078 0.41016,-0.77734 0.21484,-1.17187c-0.19141,-0.39844 -0.625,-0.61719 -1.05859,-0.54687c-0.22266,0.02344 -0.43359,0.125 -0.59375,0.28125l-4.28125,4.28125l-4.28125,-4.28125c-0.20703,-0.22266 -0.50781,-0.33594 -0.8125,-0.3125z"/>
+    </g>
+  </g>
+</svg>

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

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

+ 8 - 0
iOSClient/Images.xcassets/speaker1.imageset/speaker1.svg

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="0,0,256,256" width="50px" height="50px" fill-rule="nonzero" xmlns="http://www.w3.org/2000/svg">
+  <g fill="#000000" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal" transform="matrix(1, 0, 0, 1, 29.158455, 5.359102)">
+    <g transform="translate(226.78124,30.5609) rotate(90) scale(5.12,5.12)">
+      <path d="M24.15625,3c-0.30469,0 -0.60547,0.0625 -0.90625,0.15625c-0.60547,0.19141 -1.18359,0.55078 -1.6875,1.0625l-11.75,11.75h-6.8125c-1.66797,0 -3.03125,1.36328 -3.03125,3.03125v12c0,1.66797 1.36328,3.03125 3.03125,3.03125h6.8125l11.71875,11.65625c1.11719,1.12109 2.55078,1.61328 3.71875,1.0625c1.17578,-0.55469 1.75,-1.89062 1.75,-3.4375v-37c0,-1.5 -0.76562,-2.74609 -1.9375,-3.15625c-0.29297,-0.10156 -0.60156,-0.15625 -0.90625,-0.15625zM24.1875,5c0.10156,0 0.17969,0.00781 0.25,0.03125c0.28516,0.09766 0.5625,0.35156 0.5625,1.28125v37c0,1.06641 -0.35156,1.54297 -0.59375,1.65625c-0.24219,0.11328 -0.73047,0.125 -1.5,-0.65625l-12.59375,-12.59375c-0.01953,-0.01172 -0.04297,-0.02344 -0.0625,-0.03125c0.07422,0.06641 -0.25,-0.56641 -0.25,-0.9375v-11.5c0,-0.37109 0.33594,-1.01172 0.25,-0.9375c0.02344,-0.01953 0.04297,-0.03906 0.0625,-0.0625l12.65625,-12.625c0.46875,-0.47266 0.91016,-0.62109 1.21875,-0.625zM3,18.03125h5.1875c-0.12891,0.38281 -0.1875,0.80078 -0.1875,1.21875v11.5c0,0.41797 0.0625,0.83203 0.1875,1.21875h-5.1875c-0.53906,0 -0.96875,-0.42969 -0.96875,-0.96875v-12c0,-0.53906 0.42969,-0.96875 0.96875,-0.96875zM30.53125,18.40625c-0.48437,0.05859 -0.85156,0.45703 -0.875,0.94531c-0.02344,0.48438 0.30469,0.91797 0.78125,1.02344c2.04688,0.53516 3.5625,2.40234 3.5625,4.625c0,2.22266 -1.51562,4.08984 -3.5625,4.625c-0.53516,0.13672 -0.85547,0.68359 -0.71875,1.21875c0.13672,0.53516 0.68359,0.85547 1.21875,0.71875c2.91016,-0.76172 5.0625,-3.42578 5.0625,-6.5625c0,-3.13672 -2.15234,-5.80078 -5.0625,-6.5625c-0.13281,-0.03906 -0.26953,-0.04687 -0.40625,-0.03125z"/>
+    </g>
+  </g>
+</svg>

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

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

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4 - 0
iOSClient/Images.xcassets/speaker2.imageset/speaker2.svg


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

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

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4 - 0
iOSClient/Images.xcassets/speaker3.imageset/speaker3.svg


+ 2 - 2
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -1342,10 +1342,10 @@ extension NCCollectionViewCommon: UICollectionViewDelegate {
             
             let imageIcon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag))
 
-            if metadata.classFile == NKCommon.TypeClassFile.image.rawValue || metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+            if metadata.isImage || metadata.isMediaPlay {
                 var metadatas: [tableMetadata] = []
                 for metadata in metadataSourceForAllSections {
-                    if metadata.classFile == NKCommon.TypeClassFile.image.rawValue || metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+                    if metadata.isImage || metadata.isMediaPlay {
                         metadatas.append(metadata)
                     }
                 }

+ 3 - 3
iOSClient/Main/NCActionCenter.swift

@@ -285,7 +285,7 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
         let printInfo = UIPrintInfo(dictionary: nil)
 
         printInfo.jobName = fileNameURL.lastPathComponent
-        printInfo.outputType = metadata.classFile == NKCommon.TypeClassFile.image.rawValue ? .photo : .general
+        printInfo.outputType = metadata.isImage ? .photo : .general
         printController.printInfo = printInfo
         printController.showsNumberOfCopies = true
 
@@ -330,7 +330,7 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
             let errorSave = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_file_not_saved_cameraroll_")
 
             do {
-                if metadata.classFile == NKCommon.TypeClassFile.image.rawValue {
+                if metadata.isImage {
                     let data = try Data(contentsOf: URL(fileURLWithPath: fileNamePath))
                     PHPhotoLibrary.shared().performChanges({
                         let assetRequest = PHAssetCreationRequest.forAsset()
@@ -340,7 +340,7 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
                             NCContentPresenter.shared.messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
                         }
                     }
-                } else if metadata.classFile == NKCommon.TypeClassFile.video.rawValue {
+                } else if metadata.isVideo {
                     PHPhotoLibrary.shared().performChanges({
                         PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: fileNamePath))
                     }) { success, _ in

+ 1 - 1
iOSClient/Media/NCMedia.swift

@@ -393,7 +393,7 @@ extension NCMedia: UICollectionViewDataSource {
             cell.fileObjectId = metadata.ocId
             cell.fileUser = metadata.ownerId
 
-            if metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+            if metadata.isMediaPlay {
                 cell.imageStatus.image = cacheImages.cellPlayImage
             } else if metadata.livePhoto && livePhoto {
                 cell.imageStatus.image = cacheImages.cellLivePhotoImage

+ 10 - 1
iOSClient/Menu/NCMenu.swift

@@ -35,10 +35,14 @@ extension Array where Element == NCMenuAction {
 class NCMenu: UITableViewController {
 
     var actions = [NCMenuAction]()
+    var menuColor = UIColor.systemBackground
+    var textColor = UIColor.label
 
-    static func makeNCMenu(with actions: [NCMenuAction]) -> NCMenu? {
+    static func makeNCMenu(with actions: [NCMenuAction], menuColor: UIColor, textColor: UIColor) -> NCMenu? {
         let menuViewController = UIStoryboard(name: "NCMenu", bundle: nil).instantiateInitialViewController() as? NCMenu
         menuViewController?.actions = actions
+        menuViewController?.menuColor = menuColor
+        menuViewController?.textColor = textColor
         return menuViewController
     }
 
@@ -48,6 +52,7 @@ class NCMenu: UITableViewController {
         super.viewDidLoad()
         tableView.estimatedRowHeight = 60
         tableView.rowHeight = UITableView.automaticDimension
+        self.view.backgroundColor = menuColor
     }
 
     override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
@@ -77,6 +82,7 @@ class NCMenu: UITableViewController {
         }
         let cell = tableView.dequeueReusableCell(withIdentifier: "menuActionCell", for: indexPath)
         cell.tintColor = NCBrandColor.shared.customer
+        cell.backgroundColor = menuColor
         let actionIconView = cell.viewWithTag(1) as? UIImageView
         let actionNameLabel = cell.viewWithTag(2) as? UILabel
         let actionDetailLabel = cell.viewWithTag(3) as? UILabel
@@ -86,15 +92,18 @@ class NCMenu: UITableViewController {
         }
         if let details = action.details {
             actionDetailLabel?.text = details
+            actionDetailLabel?.textColor = textColor
             actionNameLabel?.isHidden = false
         } else { actionDetailLabel?.isHidden = true }
 
         if action.isOn {
             actionIconView?.image = action.onIcon
             actionNameLabel?.text = action.onTitle
+            actionNameLabel?.textColor = textColor
         } else {
             actionIconView?.image = action.icon
             actionNameLabel?.text = action.title
+            actionNameLabel?.textColor = textColor
         }
 
         cell.accessoryType = action.selectable && action.selected ? .checkmark : .none

+ 1 - 1
iOSClient/Menu/NCViewer+Menu.swift

@@ -124,7 +124,7 @@ extension NCViewer {
         // CONVERSION VIDEO TO MPEG4 (MFFF Lib)
         //
 #if MFFFLIB
-        if metadata.classFile == NKCommon.TypeClassFile.video.rawValue {
+        if metadata.isVideo {
             
             actions.append(
                 NCMenuAction(

+ 2 - 2
iOSClient/Menu/UIViewController+Menu.swift

@@ -108,10 +108,10 @@ extension UIViewController {
         present(mail, animated: true)
     }
 
-    func presentMenu(with actions: [NCMenuAction]) {
+    func presentMenu(with actions: [NCMenuAction], menuColor: UIColor = .systemBackground, textColor: UIColor = .label) {
         guard !actions.isEmpty else { return }
         let actions = actions.sorted(by: { $0.order < $1.order })
-        guard let menuViewController = NCMenu.makeNCMenu(with: actions) else {
+        guard let menuViewController = NCMenu.makeNCMenu(with: actions, menuColor: menuColor, textColor: textColor) else {
             let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_internal_generic_error_")
             NCContentPresenter.shared.showError(error: error)
             return

+ 0 - 3
iOSClient/Utility/CCUtility.h

@@ -166,9 +166,6 @@
 + (NSInteger)getLogLevel;
 + (void)setLogLevel:(NSInteger)value;
 
-+ (NSInteger)getAudioVolume;
-+ (void)setAudioVolume:(NSInteger)volume;
-
 + (BOOL)getAccountRequest;
 + (void)setAccountRequest:(BOOL)set;
 

+ 0 - 17
iOSClient/Utility/CCUtility.m

@@ -656,23 +656,6 @@
     [UICKeyChainStore setString:valueString forKey:@"logLevel" service:NCGlobal.shared.serviceShareKeyChain];
 }
 
-+ (NSInteger)getAudioVolume
-{
-    NSString *volume = [UICKeyChainStore stringForKey:@"audioVolume" service:NCGlobal.shared.serviceShareKeyChain];
-
-    if (volume == nil) {
-        return 100;
-    } else {
-        return [volume integerValue];
-    }
-}
-
-+ (void)setAudioVolume:(NSInteger)volume
-{
-    NSString *volumeString = [@(volume) stringValue];
-    [UICKeyChainStore setString:volumeString forKey:@"audioVolume" service:NCGlobal.shared.serviceShareKeyChain];
-}
-
 + (BOOL)getAccountRequest
 {
     return [[UICKeyChainStore stringForKey:@"accountRequest" service:NCGlobal.shared.serviceShareKeyChain] boolValue];

+ 4 - 4
iOSClient/Utility/NCUtility+Image.swift

@@ -32,7 +32,7 @@ extension NCUtility {
             return image
         }
 
-        if metadata.classFile == NKCommon.TypeClassFile.video.rawValue && !metadata.hasPreview {
+        if metadata.isVideo && !metadata.hasPreview {
             NCUtility.shared.createImageFrom(fileNameView: metadata.fileNameView, ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile)
         }
 
@@ -42,9 +42,9 @@ extension NCUtility {
             }
         }
 
-        if metadata.classFile == NKCommon.TypeClassFile.video.rawValue {
+        if metadata.isVideo {
             return UIImage(named: "noPreviewVideo")?.image(color: .gray, size: size)
-        } else if metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+        } else if metadata.isAudio {
             return UIImage(named: "noPreviewAudio")?.image(color: .gray, size: size)
         } else {
             return UIImage(named: "noPreview")?.image(color: .gray, size: size)
@@ -55,7 +55,7 @@ extension NCUtility {
         let ext = CCUtility.getExtension(metadata.fileNameView)
         var image: UIImage?
 
-        if CCUtility.fileProviderStorageExists(metadata) && metadata.classFile == NKCommon.TypeClassFile.image.rawValue {
+        if CCUtility.fileProviderStorageExists(metadata) && metadata.isImage {
 
             let previewPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)!
             let imagePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!

+ 3 - 3
iOSClient/Utility/NCUtility.swift

@@ -420,16 +420,16 @@ class NCUtility: NSObject {
         return ""
     }
 
-    func loadImage(named imageName: String, color: UIColor = UIColor.systemGray, size: CGFloat = 50, symbolConfiguration: Any? = nil) -> UIImage {
+    func loadImage(named imageName: String, color: UIColor = UIColor.systemGray, size: CGFloat = 50, symbolConfiguration: Any? = nil, renderingMode: UIImage.RenderingMode = .alwaysOriginal) -> UIImage {
 
         var image: UIImage?
 
         // see https://stackoverflow.com/questions/71764255
         let sfSymbolName = imageName.replacingOccurrences(of: "_", with: ".")
         if let symbolConfiguration = symbolConfiguration {
-            image = UIImage(systemName: sfSymbolName, withConfiguration: symbolConfiguration as? UIImage.Configuration)?.withTintColor(color, renderingMode: .alwaysOriginal)
+            image = UIImage(systemName: sfSymbolName, withConfiguration: symbolConfiguration as? UIImage.Configuration)?.withTintColor(color, renderingMode: renderingMode)
         } else {
-            image = UIImage(systemName: sfSymbolName)?.withTintColor(color, renderingMode: .alwaysOriginal)
+            image = UIImage(systemName: sfSymbolName)?.withTintColor(color, renderingMode: renderingMode)
         }
         if image == nil {
             image = UIImage(named: imageName)?.image(color: color, size: size)

+ 1 - 1
iOSClient/Viewer/NCViewer.swift

@@ -69,7 +69,7 @@ class NCViewer: NSObject {
         }
 
         // IMAGE AUDIO VIDEO
-        if metadata.classFile == NKCommon.TypeClassFile.image.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue || metadata.classFile == NKCommon.TypeClassFile.video.rawValue {
+        if metadata.isImage || metadata.isMediaPlay {
 
             if let navigationController = viewController.navigationController {
 

+ 13 - 38
iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift

@@ -69,7 +69,7 @@ class NCPlayer: NSObject {
     func openAVPlayer(url: URL) {
 
         let userAgent = CCUtility.getUserAgent()!
-        var position: Float = 0
+        var positionSliderToolBar: Float = 0
 
         self.url = url
         self.singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didSingleTapWith(gestureRecognizer:)))
@@ -79,12 +79,14 @@ class NCPlayer: NSObject {
         player?.media = VLCMedia(url: url)
         player?.delegate = self
 
+        player?.audio?.passthrough = true
+
         // player?.media?.addOption("--network-caching=500")
         player?.media?.addOption(":http-user-agent=\(userAgent)")
 
-        if let result = NCManageDatabase.shared.getVideoPosition(metadata: metadata) {
-            position = result
-            player?.position = position
+        if let result = NCManageDatabase.shared.getVideo(metadata: metadata), let position = result.position {
+            positionSliderToolBar = position
+            player?.position = positionSliderToolBar
         }
 
         player?.drawable = imageVideoContainer
@@ -93,11 +95,7 @@ class NCPlayer: NSObject {
             view.addGestureRecognizer(singleTapGestureRecognizer)
         }
 
-        playerToolBar?.setBarPlayer(ncplayer: self, position: position, metadata: metadata, viewerMediaPage: viewerMediaPage)
-
-        if let media = player?.media {
-            thumbnailer = VLCMediaThumbnailer(media: media, andDelegate: self)
-        }
+        playerToolBar?.setBarPlayer(ncplayer: self, position: positionSliderToolBar, metadata: metadata, viewerMediaPage: viewerMediaPage)
 
         player?.play()
         player?.pause()
@@ -109,7 +107,6 @@ class NCPlayer: NSObject {
 
     @objc func didSingleTapWith(gestureRecognizer: UITapGestureRecognizer) {
 
-        playerToolBar?.show()
         viewerMediaPage?.didSingleTapWith(gestureRecognizer: gestureRecognizer)
     }
 
@@ -117,7 +114,7 @@ class NCPlayer: NSObject {
 
     @objc func applicationDidEnterBackground(_ notification: NSNotification) {
 
-        if metadata.classFile == NKCommon.TypeClassFile.video.rawValue {
+        if metadata.isVideo {
             playerStop()
         }
     }
@@ -134,8 +131,8 @@ class NCPlayer: NSObject {
         playerToolBar?.playbackSliderEvent = .began
         player?.play()
         playerToolBar?.playButtonPause()
-        
-        if let position = NCManageDatabase.shared.getVideoPosition(metadata: metadata) {
+
+        if let result = NCManageDatabase.shared.getVideo(metadata: metadata), let position = result.position {
             player?.position = position
             playerToolBar?.playbackSliderEvent = .moved
         }
@@ -167,20 +164,10 @@ class NCPlayer: NSObject {
 
     func savePosition() {
 
-        guard let position = player?.position, metadata.classFile == NKCommon.TypeClassFile.video.rawValue, isPlay() else { return }
-
-        if let width = width, let height = height {
-            player?.saveVideoSnapshot(at: fileNamePreviewLocalPath, withWidth: Int32(width), andHeight: Int32(height))
-        }
-
+        guard let position = player?.position, metadata.isVideo, isPlay() else { return }
         NCManageDatabase.shared.addVideo(metadata: metadata, position: position)
     }
 
-    func setVolumeAudio(_ volume: Int32) {
-
-        player?.audio?.volume = volume
-    }
-
     func jumpForward(_ seconds: Int32) {
 
         player?.jumpForward(seconds)
@@ -227,6 +214,7 @@ extension NCPlayer: VLCMediaPlayerDelegate {
             }
             self.width = Int(size.width)
             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)
             print("Played mode: PLAYING")
             break
@@ -271,18 +259,5 @@ extension NCPlayer: VLCMediaThumbnailerDelegate {
 
     func mediaThumbnailerDidTimeOut(_ mediaThumbnailer: VLCMediaThumbnailer) { }
 
-    func mediaThumbnailer(_ mediaThumbnailer: VLCMediaThumbnailer, didFinishThumbnail thumbnail: CGImage) {
-
-        var image: UIImage?
-
-        do {
-            image = UIImage(cgImage: thumbnail)
-            if let data = image?.jpegData(compressionQuality: 0.5) {
-                try data.write(to: URL(fileURLWithPath: fileNamePreviewLocalPath), options: .atomic)
-            }
-        } catch let error as NSError {
-            print("GeneratorImagePreview localized error:")
-            print(error.localizedDescription)
-        }
-    }
+    func mediaThumbnailer(_ mediaThumbnailer: VLCMediaThumbnailer, didFinishThumbnail thumbnail: CGImage) { }
 }

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

@@ -28,13 +28,17 @@ import UIKit
 import AVKit
 import MediaPlayer
 import MobileVLCKit
+import FloatingPanel
 
 class NCPlayerToolBar: UIView {
 
     @IBOutlet weak var playerTopToolBarView: UIStackView!
+    @IBOutlet weak var subtitleButton: UIButton!
+    @IBOutlet weak var audioButton: UIButton!
+
     @IBOutlet weak var playerToolBarView: UIView!
-    @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!
@@ -50,8 +54,10 @@ class NCPlayerToolBar: UIView {
 
     private var ncplayer: NCPlayer?
     private var metadata: tableMetadata?
-    private var wasInPlay: Bool = false
-
+    private let audioSession = AVAudioSession.sharedInstance()
+    private var subTitleIndex: Int32?
+    private var audioIndex: Int32?
+    
     private weak var viewerMediaPage: NCViewerMediaPage?
 
     // MARK: - View Life Cycle
@@ -59,35 +65,39 @@ class NCPlayerToolBar: UIView {
     override func awakeFromNib() {
         super.awakeFromNib()
 
-        let blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        blurEffectView.frame = self.bounds
-        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-        playerToolBarView.insertSubview(blurEffectView, at: 0)
-        playerTopToolBarView.layer.cornerRadius = 10
-        playerTopToolBarView.layer.masksToBounds = true
-        playerTopToolBarView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapTopToolBarWith(gestureRecognizer:))))
-
         let blurEffectTopToolBarView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
         blurEffectTopToolBarView.frame = playerTopToolBarView.bounds
         blurEffectTopToolBarView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+
         playerTopToolBarView.insertSubview(blurEffectTopToolBarView, at: 0)
+        playerTopToolBarView.layer.cornerRadius = 10
+        playerTopToolBarView.layer.masksToBounds = true
+        playerTopToolBarView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapTopToolBarWith(gestureRecognizer:))))
+
+        let blurEffectToolBarView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
+        blurEffectToolBarView.frame = playerToolBarView.bounds
+        blurEffectToolBarView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+
+        playerToolBarView.insertSubview(blurEffectToolBarView, at: 0)
         playerToolBarView.layer.cornerRadius = 10
         playerToolBarView.layer.masksToBounds = true
         playerToolBarView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapToolBarWith(gestureRecognizer:))))
 
         playbackSlider.value = 0
-        playbackSlider.minimumValue = 0
-        playbackSlider.maximumValue = 1
-        playbackSlider.isContinuous = true
         playbackSlider.tintColor = .lightGray
+        playbackSlider.addTarget(self, action: #selector(playbackValChanged(slider:event:)), for: .valueChanged)
 
         labelCurrentTime.textColor = .white
         labelLeftTime.textColor = .white
 
-        muteButton.setImage(NCUtility.shared.loadImage(named: "audioOn", color: .white), for: .normal)
-
         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)
@@ -102,6 +112,7 @@ class NCPlayerToolBar: UIView {
     }
 
     deinit {
+
         print("deinit NCPlayerToolBar")
     }
 
@@ -117,19 +128,10 @@ class NCPlayerToolBar: UIView {
         MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = 0
 
         playbackSlider.value = position
-        playbackSlider.addTarget(self, action: #selector(onSliderValChanged(slider:event:)), for: .valueChanged)
 
         labelCurrentTime.text = ncplayer.player?.time.stringValue
         labelLeftTime.text = ncplayer.player?.remainingTime?.stringValue
 
-        if CCUtility.getAudioVolume() == 0 {
-            ncplayer.setVolumeAudio(0)
-            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOff", color: .white), for: .normal)
-        } else {
-            ncplayer.setVolumeAudio(100)
-            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOn", color: .white), for: .normal)
-        }
-
         if viewerMediaScreenMode == .normal {
             show()
         } else {
@@ -155,6 +157,12 @@ class NCPlayerToolBar: UIView {
         MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = positionInSecond
     }
 
+    public func updateTopToolBar(videoSubTitlesIndexes: [Any], audioTrackIndexes: [Any]) {
+
+        self.subtitleButton.isEnabled = !videoSubTitlesIndexes.isEmpty
+        self.audioButton.isEnabled = !audioTrackIndexes.isEmpty
+    }
+
     // MARK: -
 
     public func show() {
@@ -189,7 +197,7 @@ class NCPlayerToolBar: UIView {
 
     // MARK: - Event / Gesture
 
-    @objc func onSliderValChanged(slider: UISlider, event: UIEvent) {
+    @objc func playbackValChanged(slider: UISlider, event: UIEvent) {
 
         guard let touchEvent = event.allTouches?.first,
               let ncplayer = ncplayer
@@ -233,21 +241,30 @@ class NCPlayerToolBar: UIView {
         self.viewerMediaPage?.startTimerAutoHide()
     }
 
-    @IBAction func tapMute(_ sender: Any) {
+    @IBAction func tapSubTitle(_ sender: Any) {
 
-        guard let ncplayer = ncplayer else { return }
+        guard let player = ncplayer?.player else { return }
 
-        if CCUtility.getAudioVolume() > 0 {
-            CCUtility.setAudioVolume(0)
-            ncplayer.setVolumeAudio(0)
-            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOff", color: .white), for: .normal)
-        } else {
-            CCUtility.setAudioVolume(100)
-            ncplayer.setVolumeAudio(100)
-            muteButton.setImage(NCUtility.shared.loadImage(named: "audioOn", color: .white), for: .normal)
+        let spuTracks = player.videoSubTitlesNames
+        let spuTrackIndexes = player.videoSubTitlesIndexes
+        let count = spuTracks.count
+
+        if count > 1 {
+            toggleMenuSubTitle(spuTracks: spuTracks, spuTrackIndexes: spuTrackIndexes)
         }
+    }
 
-        self.viewerMediaPage?.startTimerAutoHide()
+    @IBAction func tapAudio(_ sender: Any) {
+
+        guard let player = ncplayer?.player else { return }
+
+        let audioTracks = player.audioTrackNames
+        let audioTrackIndexes = player.audioTrackIndexes
+        let count = audioTracks.count
+
+        if count > 1 {
+            toggleMenuAudio(audioTracks: audioTracks, audioTrackIndexes: audioTrackIndexes)
+        }
     }
 
     @IBAction func tapForward(_ sender: Any) {
@@ -268,3 +285,68 @@ class NCPlayerToolBar: UIView {
         self.viewerMediaPage?.startTimerAutoHide()
     }
 }
+
+extension NCPlayerToolBar {
+
+    func toggleMenuSubTitle(spuTracks: [Any], spuTrackIndexes: [Any]) {
+
+        var actions = [NCMenuAction]()
+
+        if self.subTitleIndex == nil, let idx = ncplayer?.player?.currentVideoSubTitleIndex {
+            self.subTitleIndex = idx
+        }
+
+        for index in 0...spuTracks.count - 1 {
+
+            guard let title = spuTracks[index] as? String, let idx = spuTrackIndexes[index] as? Int32 else { return }
+
+            actions.append(
+                NCMenuAction(
+                    title: title,
+                    icon: UIImage(),
+                    onTitle: title,
+                    onIcon: UIImage(),
+                    selected: (self.subTitleIndex ?? -9999) == idx,
+                    on: (self.subTitleIndex ?? -9999) == idx,
+                    action: { _ in
+                        self.ncplayer?.player?.currentVideoSubTitleIndex = idx
+                        self.subTitleIndex = idx
+                    }
+                )
+            )
+        }
+
+        viewerMediaPage?.presentMenu(with: actions, menuColor: .darkGray, textColor: .white)
+    }
+
+    func toggleMenuAudio(audioTracks: [Any], audioTrackIndexes: [Any]) {
+
+        var actions = [NCMenuAction]()
+
+        if self.audioIndex == nil, let idx = ncplayer?.player?.currentAudioTrackIndex {
+            self.audioIndex = idx
+        }
+
+        for index in 0...audioTracks.count - 1 {
+
+            guard let title = audioTracks[index] as? String, let idx = audioTrackIndexes[index] as? Int32 else { return }
+
+            actions.append(
+                NCMenuAction(
+                    title: title,
+                    icon: UIImage(),
+                    onTitle: title,
+                    onIcon: UIImage(),
+                    selected: (self.audioIndex ?? -9999) == idx,
+                    on: (self.audioIndex ?? -9999) == idx,
+                    action: { _ in
+                        self.ncplayer?.player?.currentAudioTrackIndex = idx
+                        self.audioIndex = idx
+                    }
+                )
+            )
+        }
+
+        viewerMediaPage?.presentMenu(with: actions, menuColor: .darkGray, textColor: .white)
+    }
+}

+ 24 - 10
iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.xib

@@ -15,19 +15,31 @@
             <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
             <subviews>
-                <stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="XfW-XC-eMf" userLabel="Player Top Tool Bar">
-                    <rect key="frame" x="369" y="58" width="35" height="35"/>
+                <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"/>
                     <subviews>
-                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fml-c2-FMY">
+                        <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="width" constant="25" id="S8g-UR-4zh"/>
-                                <constraint firstAttribute="height" constant="25" id="zjo-O1-SI2"/>
+                                <constraint firstAttribute="height" constant="25" id="S3q-Dj-i67"/>
+                                <constraint firstAttribute="width" constant="25" id="rg2-EW-KJX"/>
                             </constraints>
                             <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
-                            <state key="normal" image="audioOn"/>
+                            <state key="normal" image="captions.bubble" catalog="system"/>
                             <connections>
-                                <action selector="tapMute:" destination="iN0-l3-epB" eventType="touchUpInside" id="FWr-cn-Pgw"/>
+                                <action selector="tapSubTitle:" destination="iN0-l3-epB" eventType="touchUpInside" id="ooC-tL-TBX"/>
+                            </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>
+                            <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>
+                                <action selector="tapAudio:" destination="iN0-l3-epB" eventType="touchUpInside" id="EVU-fE-n5T"/>
                             </connections>
                         </button>
                     </subviews>
@@ -86,7 +98,7 @@
                                 <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" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="MY0-FC-j88">
+                        <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"/>
                         </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">
@@ -129,23 +141,25 @@
                 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="XfW-XC-eMf" secondAttribute="trailing" constant="10" 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="labelCurrentTime" destination="OHB-2J-Gqb" id="pFy-CJ-x2A"/>
                 <outlet property="labelLeftTime" destination="svM-TQ-AyQ" id="UDV-Lh-12z"/>
-                <outlet property="muteButton" destination="Fml-c2-FMY" id="Fo1-Ep-ZPz"/>
                 <outlet property="playButton" destination="hx9-d5-yiD" id="Enk-Ge-2Yx"/>
                 <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="subtitleButton" destination="qqZ-QN-TsW" id="XCP-hb-eZB"/>
             </connections>
             <point key="canvasLocation" x="137.68115942028987" y="152.67857142857142"/>
         </view>
     </objects>
     <resources>
-        <image name="audioOn" width="28" height="28"/>
+        <image name="captions.bubble" catalog="system" width="128" height="110"/>
         <image name="gobackward.10" catalog="system" width="119" height="128"/>
         <image name="goforward.10" catalog="system" width="119" height="128"/>
         <image name="play.fill" catalog="system" width="117" height="128"/>
+        <image name="speaker.zzz" catalog="system" width="128" height="83"/>
     </resources>
 </document>

+ 29 - 28
iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift

@@ -88,7 +88,7 @@ class NCViewerMedia: UIViewController {
             statusLabel.text = ""
         }
         
-        if metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+        if metadata.isMediaPlay {
 
             playerToolBar = Bundle.main.loadNibNamed("NCPlayerToolBar", owner: self, options: nil)?.first as? NCPlayerToolBar
             if let playerToolBar = playerToolBar {
@@ -125,7 +125,7 @@ class NCViewerMedia: UIViewController {
         self.image = nil
         self.imageVideoContainer.image = nil
 
-        reloadImage()
+        loadImage()
     }
 
     override func viewWillAppear(_ animated: Bool) {
@@ -134,10 +134,10 @@ class NCViewerMedia: UIViewController {
         viewerMediaPage?.navigationController?.navigationBar.prefersLargeTitles = false
         viewerMediaPage?.navigationItem.title = metadata.fileNameView
 
-        if metadata.classFile == NKCommon.TypeClassFile.image.rawValue, let viewerMediaPage = self.viewerMediaPage {
+        if metadata.isImage, let viewerMediaPage = self.viewerMediaPage {
             if viewerMediaPage.modifiedOcId.contains(metadata.ocId) {
                 viewerMediaPage.modifiedOcId.removeAll(where: { $0 == metadata.ocId })
-                reloadImage()
+                loadImage()
             }
         }
 
@@ -145,28 +145,33 @@ class NCViewerMedia: UIViewController {
 
             viewerMediaPage?.navigationController?.setNavigationBarHidden(false, animated: true)
 
-            NCUtility.shared.colorNavigationController(viewerMediaPage?.navigationController, backgroundColor: .systemBackground, titleColor: .label, tintColor: nil, withoutShadow: false)
-
-            viewerMediaPage?.view.backgroundColor = .systemBackground
-            viewerMediaPage?.textColor = .label
+            if metadata.isMediaPlay {
+                viewerMediaPage?.view.backgroundColor = .black
+                viewerMediaPage?.textColor = .white
+            } else {
+                viewerMediaPage?.view.backgroundColor = .systemBackground
+                viewerMediaPage?.textColor = .label
+            }
             viewerMediaPage?.progressView.isHidden = false
 
+            NCUtility.shared.colorNavigationController(viewerMediaPage?.navigationController, backgroundColor: .systemBackground, titleColor: .label, tintColor: nil, withoutShadow: false)
+
         } else {
 
             viewerMediaPage?.navigationController?.setNavigationBarHidden(true, animated: true)
 
-            NCUtility.shared.colorNavigationController(viewerMediaPage?.navigationController, backgroundColor: .black, titleColor: .white, tintColor: nil, withoutShadow: false)
-
             viewerMediaPage?.view.backgroundColor = .black
             viewerMediaPage?.textColor = .white
             viewerMediaPage?.progressView.isHidden = true
+
+            NCUtility.shared.colorNavigationController(viewerMediaPage?.navigationController, backgroundColor: .black, titleColor: .white, tintColor: nil, withoutShadow: false)
         }
     }
 
     override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
 
-        if metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+        if metadata.isMediaPlay {
 
             if let ncplayer = self.ncplayer {
 
@@ -186,7 +191,7 @@ class NCViewerMedia: UIViewController {
                 }
             }
             
-        } else if metadata.classFile == NKCommon.TypeClassFile.image.rawValue {
+        } else if metadata.isImage {
 
             viewerMediaPage?.clearCommandCenter()
         }
@@ -231,17 +236,13 @@ class NCViewerMedia: UIViewController {
 
     // MARK: - Image
 
-    func reloadImage() {
-        if let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) {
-            self.metadata = metadata
-            loadImage(metadata: metadata)
-        }
-    }
+    func loadImage() {
 
-    func loadImage(metadata: tableMetadata) {
+        guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
+        self.metadata = metadata
 
         // Download image
-        if !CCUtility.fileProviderStorageExists(metadata) && metadata.classFile == NKCommon.TypeClassFile.image.rawValue && metadata.session == "" {
+        if !CCUtility.fileProviderStorageExists(metadata) && metadata.isImage && metadata.session == "" {
 
             if metadata.livePhoto {
                 let fileName = (metadata.fileNameView as NSString).deletingPathExtension + ".mov"
@@ -272,7 +273,7 @@ class NCViewerMedia: UIViewController {
                 return image
             }
 
-            if metadata.classFile == NKCommon.TypeClassFile.video.rawValue && !metadata.hasPreview {
+            if metadata.isVideo && !metadata.hasPreview {
                 NCUtility.shared.createImageFrom(fileNameView: metadata.fileNameView, ocId: metadata.ocId, etag: metadata.etag, classFile: metadata.classFile)
             }
 
@@ -282,12 +283,12 @@ class NCViewerMedia: UIViewController {
                 }
             }
 
-            if metadata.classFile == NKCommon.TypeClassFile.video.rawValue {
-                return UIImage(named: "noPreviewVideo")!.image(color: .gray, size: view.frame.width)
-            } else if metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+            if metadata.isAudio {
                 return UIImage(named: "noPreviewAudio")!.image(color: .gray, size: view.frame.width)
-            } else {
+            } else if metadata.isImage {
                 return UIImage(named: "noPreview")!.image(color: .gray, size: view.frame.width)
+            } else {
+                return nil
             }
         }
 
@@ -296,7 +297,7 @@ class NCViewerMedia: UIViewController {
             let ext = CCUtility.getExtension(metadata.fileNameView)
             var image: UIImage?
 
-            if CCUtility.fileProviderStorageExists(metadata) && metadata.classFile == NKCommon.TypeClassFile.image.rawValue {
+            if CCUtility.fileProviderStorageExists(metadata) && metadata.isImage {
 
                 let previewPath = CCUtility.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)!
                 let imagePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
@@ -365,7 +366,7 @@ class NCViewerMedia: UIViewController {
 
     @objc func didDoubleTapWith(gestureRecognizer: UITapGestureRecognizer) {
 
-        guard metadata.classFile == NKCommon.TypeClassFile.image.rawValue, !detailView.isShow()  else { return }
+        guard metadata.isImage, !detailView.isShow()  else { return }
 
         let pointInView = gestureRecognizer.location(in: self.imageVideoContainer)
         var newZoomScale = self.scrollView.maximumZoomScale
@@ -384,7 +385,7 @@ class NCViewerMedia: UIViewController {
 
     @objc func didPanWith(gestureRecognizer: UIPanGestureRecognizer) {
 
-        guard metadata.classFile == NKCommon.TypeClassFile.image.rawValue else { return }
+        guard metadata.isImage else { return }
 
         let currentLocation = gestureRecognizer.translation(in: self.view)
 

+ 1 - 1
iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift

@@ -155,7 +155,7 @@ class NCViewerMediaDetailView: UIView {
         }
 
         // Message
-        if metadata.classFile == NKCommon.TypeClassFile.image.rawValue && !CCUtility.fileProviderStorageExists(metadata) && metadata.session.isEmpty {
+        if metadata.isImage && !CCUtility.fileProviderStorageExists(metadata) && metadata.session.isEmpty {
             messageButton.setTitle(NSLocalizedString("_try_download_full_resolution_", comment: ""), for: .normal)
             messageButton.isHidden = false
         } else {

+ 20 - 11
iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift

@@ -69,7 +69,7 @@ class NCViewerMediaPage: UIViewController {
     var timerAutoHideSeconds: Double {
         get {
             if NCUtility.shared.isSimulator() {
-                return 5
+                return 4
             } else {
                 return 4
             }
@@ -118,8 +118,6 @@ class NCViewerMediaPage: UIViewController {
         progressView.trackTintColor = .clear
         progressView.progress = 0
 
-        startTimerAutoHide()
-
         NotificationCenter.default.addObserver(self, selector: #selector(deleteFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(renameFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(moveFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil)
@@ -150,6 +148,12 @@ class NCViewerMediaPage: UIViewController {
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil)
     }
 
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+
+        startTimerAutoHide()
+    }
+
     override func viewDidDisappear(_ animated: Bool) {
         super.viewDidDisappear(animated)
 
@@ -157,6 +161,7 @@ class NCViewerMediaPage: UIViewController {
             ncplayer.playerPause()
         }
         clearCommandCenter()
+        timerAutoHide?.invalidate()
     }
 
     override var preferredStatusBarStyle: UIStatusBarStyle {
@@ -209,13 +214,16 @@ class NCViewerMediaPage: UIViewController {
             hideStatusBar = false
             progressView.isHidden = false
 
-            if metadatas[currentIndex].classFile == NKCommon.TypeClassFile.video.rawValue || metadatas[currentIndex].classFile == NKCommon.TypeClassFile.audio.rawValue {
+            if metadatas[currentIndex].isMediaPlay {
                 currentViewController.playerToolBar?.show()
+                view.backgroundColor = .black
+                textColor = .white
+            } else {
+                view.backgroundColor = .systemBackground
+                textColor = .label
             }
 
             NCUtility.shared.colorNavigationController(navigationController, backgroundColor: .systemBackground, titleColor: .label, tintColor: nil, withoutShadow: false)
-            view.backgroundColor = .systemBackground
-            textColor = .label
 
         } else {
 
@@ -223,7 +231,7 @@ class NCViewerMediaPage: UIViewController {
             hideStatusBar = true
             progressView.isHidden = true
 
-            if metadatas[currentIndex].classFile == NKCommon.TypeClassFile.video.rawValue || metadatas[currentIndex].classFile == NKCommon.TypeClassFile.audio.rawValue {
+            if metadatas[currentIndex].isMediaPlay {
                 currentViewController.playerToolBar?.hide()
             }
 
@@ -232,6 +240,7 @@ class NCViewerMediaPage: UIViewController {
         }
 
         viewerMediaScreenMode = mode
+        print("Screen mode: \(viewerMediaScreenMode)")
 
         startTimerAutoHide()
         setNeedsStatusBarAppearanceUpdate()
@@ -247,7 +256,7 @@ class NCViewerMediaPage: UIViewController {
 
     @objc func autoHide() {
 
-        if metadatas[currentIndex].classFile == NKCommon.TypeClassFile.video.rawValue || metadatas[currentIndex].classFile == NKCommon.TypeClassFile.audio.rawValue, viewerMediaScreenMode == .normal {
+        if metadatas[currentIndex].isMediaPlay, viewerMediaScreenMode == .normal {
             changeScreenMode(mode: .full)
         }
     }
@@ -266,7 +275,7 @@ class NCViewerMediaPage: UIViewController {
         let metadata = metadatas[currentIndex]
 
         if metadata.ocId == ocId,
-           (metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue),
+           metadata.isMediaPlay,
            CCUtility.fileProviderStorageExists(metadata),
            let ncplayer = currentViewController.ncplayer {
             let url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!)
@@ -321,7 +330,7 @@ class NCViewerMediaPage: UIViewController {
 
         metadatas[index] = metadata
         if currentViewController.metadata.ocId == ocId {
-            currentViewController.reloadImage()
+            currentViewController.loadImage()
         } else {
             modifiedOcId.append(ocId)
         }
@@ -422,7 +431,7 @@ class NCViewerMediaPage: UIViewController {
         }
 
         // VIDEO / AUDIO () ()
-        if metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+        if metadata.isMediaPlay {
 
             MPRemoteCommandCenter.shared().skipForwardCommand.isEnabled = true
             skipForwardCommand = MPRemoteCommandCenter.shared().skipForwardCommand.addTarget { event in

+ 7 - 8
iOSClient/Viewer/NCViewerProviderContextMenu.swift

@@ -80,7 +80,7 @@ class NCViewerProviderContextMenu: UIViewController {
             }
 
             // VIEW IMAGE
-            if metadata.classFile == NKCommon.TypeClassFile.image.rawValue && CCUtility.fileProviderStorageExists(metadata) {
+            if metadata.isImage && CCUtility.fileProviderStorageExists(metadata) {
                 viewImage(metadata: metadata)
             }
 
@@ -90,18 +90,17 @@ class NCViewerProviderContextMenu: UIViewController {
             }
 
             // VIEW VIDEO
-            if metadata.classFile == NKCommon.TypeClassFile.video.rawValue && CCUtility.fileProviderStorageExists(metadata) {
+            if metadata.isVideo && CCUtility.fileProviderStorageExists(metadata) {
                 viewVideo(metadata: metadata)
             }
 
             // PLAY SOUND
-            if metadata.classFile == NKCommon.TypeClassFile.audio.rawValue && CCUtility.fileProviderStorageExists(metadata) {
+            if metadata.isAudio && CCUtility.fileProviderStorageExists(metadata) {
                 playSound(metadata: metadata)
             }
 
             // AUTO DOWNLOAD VIDEO / AUDIO
-            // if !CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) && (metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue || metadata.contentType == "application/pdf") {
-            if !CCUtility.fileProviderStorageExists(metadata) && (metadata.classFile == NKCommon.TypeClassFile.video.rawValue || metadata.classFile == NKCommon.TypeClassFile.audio.rawValue) {
+            if !CCUtility.fileProviderStorageExists(metadata) && metadata.isMediaPlay {
 
                 var maxDownload: UInt64 = 0
 
@@ -191,11 +190,11 @@ class NCViewerProviderContextMenu: UIViewController {
         else { return }
 
         if error == .success && metadata.ocId == self.metadata?.ocId {
-            if metadata.classFile == NKCommon.TypeClassFile.image.rawValue {
+            if metadata.isImage {
                 viewImage(metadata: metadata)
-            } else if metadata.classFile == NKCommon.TypeClassFile.video.rawValue {
+            } else if metadata.isVideo {
                 viewVideo(metadata: metadata)
-            } else if metadata.classFile == NKCommon.TypeClassFile.audio.rawValue {
+            } else if metadata.isAudio {
                 playSound(metadata: metadata)
             }
         }

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

@@ -75,7 +75,7 @@ private var hasChangesQuickLook: Bool = false
             NCContentPresenter.shared.showInfo(error: error)
         }
 
-        if let metadata = metadata, metadata.classFile == NKCommon.TypeClassFile.image.rawValue {
+        if let metadata = metadata, metadata.isImage {
             let buttonDone = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismission))
             let buttonCrop = UIBarButtonItem(image: UIImage(systemName: "crop"), style: .plain, target: self, action: #selector(crop))
             navigationItem.leftBarButtonItems = [buttonDone, buttonCrop]
@@ -145,7 +145,7 @@ private var hasChangesQuickLook: Bool = false
             self.dismiss(animated: true)
         })
 
-        if metadata.classFile == NKCommon.TypeClassFile.image.rawValue {
+        if metadata.isImage {
             present(alertController, animated: true)
         } else {
             parentVC?.present(alertController, animated: true)

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio