Browse Source

Better media detail view (#2556)

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* oops

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Remove useless things

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Add button for opening detail

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Load location from metadata

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Fix crash + other things

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Refuce font size

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Reduce font size

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* WIP

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Update iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift

Co-authored-by: Aditya Tyagi <77538183+adityagi02@users.noreply.github.com>
Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Stop live photo from playing when detail view is open

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Fix ipad layout

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Handle live photo

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* FInishing touches

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Finishing touches 2

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Small spacing changes

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Refactor

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Fix for tips view

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Final

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

* Oopsie

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>

---------

Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>
Co-authored-by: Aditya Tyagi <77538183+adityagi02@users.noreply.github.com>
Milen Pivchev 1 year ago
parent
commit
9d9b4cac27

+ 5 - 0
.github/workflows/xcode.yml

@@ -44,6 +44,11 @@ jobs:
       run: wget "https://raw.githubusercontent.com/firebase/quickstart-ios/master/mock-GoogleService-Info.plist" -O GoogleService-Info.plist
       run: wget "https://raw.githubusercontent.com/firebase/quickstart-ios/master/mock-GoogleService-Info.plist" -O GoogleService-Info.plist
     - name: Install docker
     - name: Install docker
       run: |
       run: |
+        # Workaround for https://github.com/actions/runner-images/issues/8104
+        brew remove --ignore-dependencies qemu
+        curl -o ./qemu.rb https://raw.githubusercontent.com/Homebrew/homebrew-core/dc0669eca9479e9eeb495397ba3a7480aaa45c2e/Formula/qemu.rb
+        brew install ./qemu.rb
+
         brew install docker
         brew install docker
         colima start
         colima start
     - name: Create docker test server and export enviroment variables
     - name: Create docker test server and export enviroment variables

+ 1 - 1
Brand/Database.swift

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

+ 16 - 4
Nextcloud.xcodeproj/project.pbxproj

@@ -68,7 +68,6 @@
 		AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; };
 		AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; };
 		AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; };
 		AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; };
 		AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; };
 		AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; };
-		AFD33240276A02C100F5AE02 /* UIApplication+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD3323F276A02C000F5AE02 /* UIApplication+Extension.swift */; };
 		C0046CDD2A17B98400D87C9D /* LoginUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0046CDC2A17B98400D87C9D /* LoginUITests.swift */; };
 		C0046CDD2A17B98400D87C9D /* LoginUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0046CDC2A17B98400D87C9D /* LoginUITests.swift */; };
 		C03BA14A2A17BC57002C8BA3 /* XLForm in Frameworks */ = {isa = PBXBuildFile; productRef = C03BA1492A17BC57002C8BA3 /* XLForm */; };
 		C03BA14A2A17BC57002C8BA3 /* XLForm in Frameworks */ = {isa = PBXBuildFile; productRef = C03BA1492A17BC57002C8BA3 /* XLForm */; };
 		C03BA14C2A17BC60002C8BA3 /* UICKeyChainStore in Frameworks */ = {isa = PBXBuildFile; productRef = C03BA14B2A17BC60002C8BA3 /* UICKeyChainStore */; };
 		C03BA14C2A17BC60002C8BA3 /* UICKeyChainStore in Frameworks */ = {isa = PBXBuildFile; productRef = C03BA14B2A17BC60002C8BA3 /* UICKeyChainStore */; };
@@ -117,6 +116,13 @@
 		F343A4BF2A1E734600DDA874 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */; };
 		F343A4BF2A1E734600DDA874 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */; };
 		F343A4C02A1E734600DDA874 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */; };
 		F343A4C02A1E734600DDA874 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */; };
 		F343A4C12A1E734600DDA874 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */; };
 		F343A4C12A1E734600DDA874 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */; };
+		F359D8672A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; };
+		F359D8682A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; };
+		F359D8692A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; };
+		F359D86A2A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; };
+		F359D86B2A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; };
+		F359D86C2A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; };
+		F359D86D2A7D03420023F405 /* NCUtility+Exif.swift in Sources */ = {isa = PBXBuildFile; fileRef = F359D8662A7D03420023F405 /* NCUtility+Exif.swift */; };
 		F39298972A3B12CB00509762 /* BaseNCMoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39298962A3B12CB00509762 /* BaseNCMoreCell.swift */; };
 		F39298972A3B12CB00509762 /* BaseNCMoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39298962A3B12CB00509762 /* BaseNCMoreCell.swift */; };
 		F3953BD72A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3953BD62A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift */; };
 		F3953BD72A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3953BD62A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift */; };
 		F3A7AFC62A41AA82001FC89C /* BaseUIXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3A7AFC52A41AA82001FC89C /* BaseUIXCTestCase.swift */; };
 		F3A7AFC62A41AA82001FC89C /* BaseUIXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3A7AFC52A41AA82001FC89C /* BaseUIXCTestCase.swift */; };
@@ -818,7 +824,6 @@
 		AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = "<group>"; };
 		AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = "<group>"; };
 		AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = "<group>"; };
 		AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = "<group>"; };
 		AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = "<group>"; };
 		AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = "<group>"; };
-		AFD3323F276A02C000F5AE02 /* UIApplication+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Extension.swift"; sourceTree = "<group>"; };
 		C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		C0046CDC2A17B98400D87C9D /* LoginUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginUITests.swift; sourceTree = "<group>"; };
 		C0046CDC2A17B98400D87C9D /* LoginUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginUITests.swift; sourceTree = "<group>"; };
 		C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -834,6 +839,7 @@
 		F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCMoreUserCell.xib; sourceTree = "<group>"; };
 		F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCMoreUserCell.xib; sourceTree = "<group>"; };
 		F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAsset+Extension.swift"; sourceTree = "<group>"; };
 		F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAsset+Extension.swift"; sourceTree = "<group>"; };
 		F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = "<group>"; };
 		F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = "<group>"; };
+		F359D8662A7D03420023F405 /* NCUtility+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCUtility+Exif.swift"; sourceTree = "<group>"; };
 		F39298962A3B12CB00509762 /* BaseNCMoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNCMoreCell.swift; sourceTree = "<group>"; };
 		F39298962A3B12CB00509762 /* BaseNCMoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNCMoreCell.swift; sourceTree = "<group>"; };
 		F3953BD62A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseIntegrationXCTestCase.swift; sourceTree = "<group>"; };
 		F3953BD62A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseIntegrationXCTestCase.swift; sourceTree = "<group>"; };
 		F3A7AFC52A41AA82001FC89C /* BaseUIXCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUIXCTestCase.swift; sourceTree = "<group>"; };
 		F3A7AFC52A41AA82001FC89C /* BaseUIXCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUIXCTestCase.swift; sourceTree = "<group>"; };
@@ -2103,7 +2109,6 @@
 				F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */,
 				F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */,
 				F7A0D1342591FBC5008F8A13 /* String+Extension.swift */,
 				F7A0D1342591FBC5008F8A13 /* String+Extension.swift */,
 				AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */,
 				AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */,
-				AFD3323F276A02C000F5AE02 /* UIApplication+Extension.swift */,
 				AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */,
 				AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */,
 				F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */,
 				F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */,
 				F79B645F26CA661600838ACA /* UIControl+Extension.swift */,
 				F79B645F26CA661600838ACA /* UIControl+Extension.swift */,
@@ -2229,6 +2234,7 @@
 				F707C26421A2DC5200F6181E /* NCStoreReview.swift */,
 				F707C26421A2DC5200F6181E /* NCStoreReview.swift */,
 				AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */,
 				AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */,
 				F70BFC7320E0FA7C00C67599 /* NCUtility.swift */,
 				F70BFC7320E0FA7C00C67599 /* NCUtility.swift */,
+				F359D8662A7D03420023F405 /* NCUtility+Exif.swift */,
 				AF93474B27E34120002537EE /* NCUtility+Image.swift */,
 				AF93474B27E34120002537EE /* NCUtility+Image.swift */,
 				F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */,
 				F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */,
 				F702F2FC25EE5D2C008F8E80 /* NYMnemonic */,
 				F702F2FC25EE5D2C008F8E80 /* NYMnemonic */,
@@ -3324,6 +3330,7 @@
 				AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
 				AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
 				F7BF9D872934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F7BF9D872934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F749B64F297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F749B64F297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
+				F359D86D2A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				D575039F27146F93008DC9DC /* String+Extension.swift in Sources */,
 				D575039F27146F93008DC9DC /* String+Extension.swift in Sources */,
 				F769CA1A2966EA3C00039397 /* ComponentView.swift in Sources */,
 				F769CA1A2966EA3C00039397 /* ComponentView.swift in Sources */,
 				F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
@@ -3401,6 +3408,7 @@
 				F7490E8C29882D02009DCE94 /* CCUtility.m in Sources */,
 				F7490E8C29882D02009DCE94 /* CCUtility.m in Sources */,
 				F7490E7729882C10009DCE94 /* UIColor+Extension.swift in Sources */,
 				F7490E7729882C10009DCE94 /* UIColor+Extension.swift in Sources */,
 				F70716E62987F81500E72C1D /* DocumentActionViewController.swift in Sources */,
 				F70716E62987F81500E72C1D /* DocumentActionViewController.swift in Sources */,
+				F359D86C2A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				F7490E8429882C89009DCE94 /* NCManageDatabase+Share.swift in Sources */,
 				F7490E8429882C89009DCE94 /* NCManageDatabase+Share.swift in Sources */,
 				F7490E6F29882B67009DCE94 /* UIImage+Extension.swift in Sources */,
 				F7490E6F29882B67009DCE94 /* UIImage+Extension.swift in Sources */,
 				F7490E7E29882C6E009DCE94 /* NCManageDatabase+Account.swift in Sources */,
 				F7490E7E29882C6E009DCE94 /* NCManageDatabase+Account.swift in Sources */,
@@ -3438,6 +3446,7 @@
 				F70460532499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70460532499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70BFC7520E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				F70BFC7520E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				AF22B20C277C6F4D00DAB0CC /* NCShareCell.swift in Sources */,
 				AF22B20C277C6F4D00DAB0CC /* NCShareCell.swift in Sources */,
+				F359D86A2A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				F7E98C1727E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F7E98C1727E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F79B646126CA661600838ACA /* UIControl+Extension.swift in Sources */,
 				F79B646126CA661600838ACA /* UIControl+Extension.swift in Sources */,
 				F77C973A2953143A00FDDD09 /* NCCameraRoll.swift in Sources */,
 				F77C973A2953143A00FDDD09 /* NCCameraRoll.swift in Sources */,
@@ -3504,6 +3513,7 @@
 				F783030328B4C4DD00B84583 /* ThreadSafeDictionary.swift in Sources */,
 				F783030328B4C4DD00B84583 /* ThreadSafeDictionary.swift in Sources */,
 				F77ED59128C9CE9D00E24ED0 /* ToolbarData.swift in Sources */,
 				F77ED59128C9CE9D00E24ED0 /* ToolbarData.swift in Sources */,
 				F78302F728B4C3C900B84583 /* NCManageDatabase.swift in Sources */,
 				F78302F728B4C3C900B84583 /* NCManageDatabase.swift in Sources */,
+				F359D8682A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				F7346E1628B0EF5C006CE2D2 /* Widget.swift in Sources */,
 				F7346E1628B0EF5C006CE2D2 /* Widget.swift in Sources */,
 				F78302F828B4C3E100B84583 /* NCManageDatabase+Activity.swift in Sources */,
 				F78302F828B4C3E100B84583 /* NCManageDatabase+Activity.swift in Sources */,
 				F783030228B4C4B800B84583 /* NCUtility.swift in Sources */,
 				F783030228B4C4B800B84583 /* NCUtility.swift in Sources */,
@@ -3572,6 +3582,7 @@
 				F798F0E725880609000DAFFD /* UIColor+Extension.swift in Sources */,
 				F798F0E725880609000DAFFD /* UIColor+Extension.swift in Sources */,
 				F74B6D992A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F74B6D992A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F7D68FCF28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				F7D68FCF28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
+				F359D86B2A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				F7864AD02A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				F7864AD02A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
@@ -3719,6 +3730,7 @@
 				F7CA212D25F1333300826ABB /* NCAccountRequest.swift in Sources */,
 				F7CA212D25F1333300826ABB /* NCAccountRequest.swift in Sources */,
 				F765F73125237E3F00391DBE /* NCRecent.swift in Sources */,
 				F765F73125237E3F00391DBE /* NCRecent.swift in Sources */,
 				F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
 				F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
+				F359D8672A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				F7581D2425EFDDDF004DC699 /* NCMedia+Menu.swift in Sources */,
 				F7581D2425EFDDDF004DC699 /* NCMedia+Menu.swift in Sources */,
 				F738D4902756740100CD1D38 /* NCLoginNavigationController.swift in Sources */,
 				F738D4902756740100CD1D38 /* NCLoginNavigationController.swift in Sources */,
 				F77B0E981D118A16002130FE /* CCManageAccount.m in Sources */,
 				F77B0E981D118A16002130FE /* CCManageAccount.m in Sources */,
@@ -3732,7 +3744,6 @@
 				F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */,
 				F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */,
 				F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */,
 				F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */,
 				F7E8A391295DC5E0006CB2D0 /* View+Extension.swift in Sources */,
 				F7E8A391295DC5E0006CB2D0 /* View+Extension.swift in Sources */,
-				AFD33240276A02C100F5AE02 /* UIApplication+Extension.swift in Sources */,
 				F79B869B265E19D40085C0E0 /* NSMutableAttributedString+Extension.swift in Sources */,
 				F79B869B265E19D40085C0E0 /* NSMutableAttributedString+Extension.swift in Sources */,
 				F7B7504B2397D38F004E13EC /* UIImage+Extension.swift in Sources */,
 				F7B7504B2397D38F004E13EC /* UIImage+Extension.swift in Sources */,
 				F7EFC0CD256BF8DD00461AAD /* NCUserStatus.swift in Sources */,
 				F7EFC0CD256BF8DD00461AAD /* NCUserStatus.swift in Sources */,
@@ -3818,6 +3829,7 @@
 				F7A8D73F28F181EF008BBE1C /* NCGlobal.swift in Sources */,
 				F7A8D73F28F181EF008BBE1C /* NCGlobal.swift in Sources */,
 				F74B6D972A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F74B6D972A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F749B653297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F749B653297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
+				F359D8692A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
 				F763D29F2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F763D29F2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F7A8D74328F1826F008BBE1C /* String+Extension.swift in Sources */,
 				F7A8D74328F1826F008BBE1C /* String+Extension.swift in Sources */,
 				F7A8D73728F17E1E008BBE1C /* NCManageDatabase+Account.swift in Sources */,
 				F7A8D73728F17E1E008BBE1C /* NCManageDatabase+Account.swift in Sources */,

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

@@ -100,6 +100,10 @@ class tableMetadata: Object, NCUserBaseUrl {
     @objc dynamic var urlBase = ""
     @objc dynamic var urlBase = ""
     @objc dynamic var user = ""
     @objc dynamic var user = ""
     @objc dynamic var userId = ""
     @objc dynamic var userId = ""
+    @objc dynamic var latitude: Double = 0
+    @objc dynamic var longitude: Double = 0
+    @objc dynamic var height: Int = 0
+    @objc dynamic var width: Int = 0
 
 
     override static func primaryKey() -> String {
     override static func primaryKey() -> String {
         return "ocId"
         return "ocId"
@@ -332,6 +336,10 @@ extension NCManageDatabase {
         metadata.urlBase = file.urlBase
         metadata.urlBase = file.urlBase
         metadata.user = file.user
         metadata.user = file.user
         metadata.userId = file.userId
         metadata.userId = file.userId
+        metadata.latitude = file.latitude
+        metadata.longitude = file.longitude
+        metadata.height = file.height
+        metadata.width = file.width
 
 
         // E2EE find the fileName for fileNameView
         // E2EE find the fileName for fileNameView
         if isDirectoryE2EE || file.e2eEncrypted {
         if isDirectoryE2EE || file.e2eEncrypted {

+ 0 - 1
iOSClient/Data/NCManageDatabase.swift

@@ -473,7 +473,6 @@ class NCManageDatabase: NSObject {
         return nil
         return nil
     }
     }
 
 
-    // MARK: -
     // MARK: Table Photo Library
     // MARK: Table Photo Library
 
 
     @discardableResult
     @discardableResult

+ 0 - 34
iOSClient/Extensions/UIApplication+Extension.swift

@@ -1,34 +0,0 @@
-//
-//  UIApplication+Extension.swift
-//  Nextcloud
-//
-//  Created by Henrik Storch on 15.12.2021.
-//  Copyright (c) 2021 Henrik Storch. All rights reserved.
-//
-//  Author Henrik Storch <henrik.storch@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-import UIKit
-
-extension UIApplication {
-    // indicates if current device is in landscape orientation
-    var isLandscape: Bool {
-        if UIDevice.current.orientation.isValidInterfaceOrientation {
-            return UIDevice.current.orientation.isLandscape
-        } else {
-            return windows.first?.windowScene?.interfaceOrientation.isLandscape ?? false
-        }
-    }
-}

+ 14 - 0
iOSClient/Extensions/UIDevice+Extension.swift

@@ -36,3 +36,17 @@ extension UIDevice {
         }
         }
     }
     }
 }
 }
+
+extension UIDeviceOrientation {
+    /// According to Apple... if the device is laid flat the UI is neither portrait nor landscape, so this flag ignores that and checks if the UI is REALLY in landscape. Thanks Apple.
+    /// 
+    /// Unless you really need to use this, you can instead try `traitCollection.verticalSizeClass` and `traitCollection.horizontalSizeClass`.
+    var isLandscapeHardCheck: Bool {
+        if UIDevice.current.orientation.isValidInterfaceOrientation {
+            return UIDevice.current.orientation.isLandscape
+        } else {
+            return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape ?? false
+        }
+    }
+}
+

+ 1 - 1
iOSClient/Menu/NCMenu+FloatingPanel.swift

@@ -42,7 +42,7 @@ class NCMenuFloatingPanelLayout: FloatingPanelLayout {
         // sometimes UIScreen.main.bounds.size.height is not updated correctly
         // sometimes UIScreen.main.bounds.size.height is not updated correctly
         // this ensures we use the correct height value
         // this ensures we use the correct height value
         // can't use `layoutFor size` since menu is dieplayed on top of the whole screen not just the VC
         // can't use `layoutFor size` since menu is dieplayed on top of the whole screen not just the VC
-        let screenHeight = UIApplication.shared.isLandscape
+        let screenHeight = UIDevice.current.orientation.isLandscapeHardCheck
         ? min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
         ? min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
         : max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
         : max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
         let window = UIApplication.shared.connectedScenes.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }.first { $0.isKeyWindow }
         let window = UIApplication.shared.connectedScenes.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }.first { $0.isKeyWindow }

+ 0 - 1
iOSClient/Networking/NCNetworking.swift

@@ -385,7 +385,6 @@ class NCNetworking: NSObject, NKCommonDelegate {
                 if let result = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "fileNameIdentifier == %@ AND serverUrl == %@", metadata.fileName, metadata.serverUrl)) {
                 if let result = NCManageDatabase.shared.getE2eEncryption(predicate: NSPredicate(format: "fileNameIdentifier == %@ AND serverUrl == %@", metadata.fileName, metadata.serverUrl)) {
                     NCEndToEndEncryption.sharedManager()?.decryptFile(metadata.fileName, fileNameView: metadata.fileNameView, ocId: metadata.ocId, key: result.key, initializationVector: result.initializationVector, authenticationTag: result.authenticationTag)
                     NCEndToEndEncryption.sharedManager()?.decryptFile(metadata.fileName, fileNameView: metadata.fileNameView, ocId: metadata.ocId, key: result.key, initializationVector: result.initializationVector, authenticationTag: result.authenticationTag)
                 }
                 }
-                CCUtility.setExif(metadata) { _, _, _, _, _ in }
 #endif
 #endif
                 NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "selector": selector, "error": error])
                 NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account, "selector": selector, "error": error])
 
 

+ 5 - 2
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -442,7 +442,9 @@
 "_pull_down_"                               = "Pull down to refresh";
 "_pull_down_"                               = "Pull down to refresh";
 "_no_photo_load_"                           = "No photo or video";
 "_no_photo_load_"                           = "No photo or video";
 "_tutorial_autoupload_view_"                = "You can enable auto uploads from \"Settings\"";
 "_tutorial_autoupload_view_"                = "You can enable auto uploads from \"Settings\"";
-"_no_date_"                                 = "No date";
+"_no_date_information_"                     = "No date information";
+"_no_camera_information_"                   = "No camera information";
+"_no_lens_information_"                     = "No lens information";
 "_today_"                                   = "Today";
 "_today_"                                   = "Today";
 "_yesterday_"                               = "Yesterday";
 "_yesterday_"                               = "Yesterday";
 "_time_"                                    = "Time: %@\n\n%@";
 "_time_"                                    = "Time: %@\n\n%@";
@@ -863,7 +865,8 @@
 "_the_entered_page_number_does_not_exist_"   = "The entered page number does not exist";
 "_the_entered_page_number_does_not_exist_"   = "The entered page number does not exist";
 "_error_something_wrong_"   = "Something went wrong";
 "_error_something_wrong_"   = "Something went wrong";
 "_resolution_"              = "Resolution";
 "_resolution_"              = "Resolution";
-"_try_download_full_resolution_"            = "For more detail try to download the image in full resolution";
+"_try_download_full_resolution_"            = "Download full resolution image";
+"_full_resolution_image_info_"            = "This may reveal more information about the photo.";
 "_copied_path_"             = "Copied path";
 "_copied_path_"             = "Copied path";
 "_copy_path_"               = "Copy path";
 "_copy_path_"               = "Copy path";
 "_certificates_"            = "Certificates";
 "_certificates_"            = "Certificates";

+ 1 - 1
iOSClient/Transfers/NCTransfers.swift

@@ -242,7 +242,7 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
         if self.appDelegate.account != metadata.account {
         if self.appDelegate.account != metadata.account {
             cell.labelInfo.text = NSLocalizedString("_waiting_for_", comment: "") + " " + NSLocalizedString("_user_", comment: "").lowercased() + " \(metadata.userId) " + NSLocalizedString("_in_", comment: "") + " \(metadata.urlBase)"
             cell.labelInfo.text = NSLocalizedString("_waiting_for_", comment: "") + " " + NSLocalizedString("_user_", comment: "").lowercased() + " \(metadata.userId) " + NSLocalizedString("_in_", comment: "") + " \(metadata.urlBase)"
         }
         }
-        let isWiFi = NCNetworking.shared.networkReachability == NKCommon.TypeReachability.reachableEthernetOrWiFi
+        let isWiFi = NCNetworking.shared.networkReachability == .reachableEthernetOrWiFi
         if metadata.session == NCNetworking.shared.sessionIdentifierBackgroundWWan && !isWiFi {
         if metadata.session == NCNetworking.shared.sessionIdentifierBackgroundWWan && !isWiFi {
             cell.labelInfo.text = NSLocalizedString("_waiting_for_", comment: "") + " " + NSLocalizedString("_reachable_wifi_", comment: "")
             cell.labelInfo.text = NSLocalizedString("_waiting_for_", comment: "") + " " + NSLocalizedString("_reachable_wifi_", comment: "")
         }
         }

+ 0 - 4
iOSClient/Utility/CCUtility.h

@@ -244,10 +244,6 @@
 + (BOOL)isPermissionToRead:(NSInteger) permissionValue;
 + (BOOL)isPermissionToRead:(NSInteger) permissionValue;
 + (BOOL)isPermissionToReadCreateUpdate:(NSInteger) permissionValue;
 + (BOOL)isPermissionToReadCreateUpdate:(NSInteger) permissionValue;
 
 
-// ===== EXIF =====
-
-+ (void)setExif:(tableMetadata *)metadata withCompletionHandler:(void(^)(double latitude, double longitude, NSString *location, NSDate *date, NSString *lensModel))completition;
-
 // ===== Third parts =====
 // ===== Third parts =====
 
 
 + (NSString *)getExtension:(NSString*)fileName;
 + (NSString *)getExtension:(NSString*)fileName;

+ 115 - 291
iOSClient/Utility/CCUtility.m

@@ -51,11 +51,11 @@
 + (void)storeAllChainInService
 + (void)storeAllChainInService
 {
 {
     UICKeyChainStore *store = [UICKeyChainStore keyChainStore];
     UICKeyChainStore *store = [UICKeyChainStore keyChainStore];
-    
+
     NSArray *items = store.allItems;
     NSArray *items = store.allItems;
-    
+
     for (NSDictionary *item in items) {
     for (NSDictionary *item in items) {
-        
+
         [UICKeyChainStore setString:[item objectForKey:@"value"] forKey:[item objectForKey:@"key"] service:NCGlobal.shared.serviceShareKeyChain];
         [UICKeyChainStore setString:[item objectForKey:@"value"] forKey:[item objectForKey:@"key"] service:NCGlobal.shared.serviceShareKeyChain];
         [UICKeyChainStore removeItemForKey:[item objectForKey:@"key"]];
         [UICKeyChainStore removeItemForKey:[item objectForKey:@"key"]];
     }
     }
@@ -87,13 +87,13 @@
 + (BOOL)getEnableTouchFaceID
 + (BOOL)getEnableTouchFaceID
 {
 {
     NSString *valueString = [UICKeyChainStore stringForKey:@"enableTouchFaceID" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *valueString = [UICKeyChainStore stringForKey:@"enableTouchFaceID" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     // Default TRUE
     // Default TRUE
     if (valueString == nil) {
     if (valueString == nil) {
         [self setEnableTouchFaceID:YES];
         [self setEnableTouchFaceID:YES];
         return true;
         return true;
     }
     }
-    
+
     return [valueString boolValue];
     return [valueString boolValue];
 }
 }
 
 
@@ -112,15 +112,15 @@
 + (NSString *)getGroupBySettings
 + (NSString *)getGroupBySettings
 {
 {
     NSString *groupby = [UICKeyChainStore stringForKey:@"groupby" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *groupby = [UICKeyChainStore stringForKey:@"groupby" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     if (groupby == nil) {
     if (groupby == nil) {
-        
+
         [self setGroupBySettings:@"none"];
         [self setGroupBySettings:@"none"];
         return @"none";
         return @"none";
     }
     }
-    
+
     return @"none";
     return @"none";
-    
+
     //return groupby;
     //return groupby;
 }
 }
 
 
@@ -136,14 +136,14 @@
         [CCUtility setIntro:YES];
         [CCUtility setIntro:YES];
         return YES;
         return YES;
     }
     }
-    
+
     return [[UICKeyChainStore stringForKey:@"intro" service:NCGlobal.shared.serviceShareKeyChain] boolValue];
     return [[UICKeyChainStore stringForKey:@"intro" service:NCGlobal.shared.serviceShareKeyChain] boolValue];
 }
 }
 
 
 + (BOOL)getIntroMessageOldVersion
 + (BOOL)getIntroMessageOldVersion
 {
 {
     NSString *key = [INTRO_MessageType stringByAppendingString:@"Intro"];
     NSString *key = [INTRO_MessageType stringByAppendingString:@"Intro"];
-    
+
     return [[UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain] boolValue];
     return [[UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain] boolValue];
 }
 }
 
 
@@ -157,12 +157,12 @@
 + (NSString *)getIncrementalNumber
 + (NSString *)getIncrementalNumber
 {
 {
     long number = [[UICKeyChainStore stringForKey:@"incrementalnumber" service:NCGlobal.shared.serviceShareKeyChain] intValue];
     long number = [[UICKeyChainStore stringForKey:@"incrementalnumber" service:NCGlobal.shared.serviceShareKeyChain] intValue];
-    
+
     number++;
     number++;
     if (number >= 9999) number = 1;
     if (number >= 9999) number = 1;
-    
+
     [UICKeyChainStore setString:[NSString stringWithFormat:@"%ld", number] forKey:@"incrementalnumber" service:NCGlobal.shared.serviceShareKeyChain];
     [UICKeyChainStore setString:[NSString stringWithFormat:@"%ld", number] forKey:@"incrementalnumber" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     return [NSString stringWithFormat:@"%04ld", number];
     return [NSString stringWithFormat:@"%04ld", number];
 }
 }
 
 
@@ -240,10 +240,10 @@
 + (NSString *)getFileNameMask:(NSString *)key
 + (NSString *)getFileNameMask:(NSString *)key
 {
 {
     NSString *mask = [UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain];
     NSString *mask = [UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     if (mask == nil)
     if (mask == nil)
         mask = @"";
         mask = @"";
-    
+
     return mask;
     return mask;
 }
 }
 
 
@@ -288,13 +288,13 @@
 + (BOOL)getFormatCompatibility
 + (BOOL)getFormatCompatibility
 {
 {
     NSString *valueString = [UICKeyChainStore stringForKey:@"formatCompatibility" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *valueString = [UICKeyChainStore stringForKey:@"formatCompatibility" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     // Default TRUE
     // Default TRUE
     if (valueString == nil) {
     if (valueString == nil) {
         [self setFormatCompatibility:YES];
         [self setFormatCompatibility:YES];
         return true;
         return true;
     }
     }
-    
+
     return [valueString boolValue];
     return [valueString boolValue];
 }
 }
 
 
@@ -307,7 +307,7 @@
 + (NSString *)getEndToEndCertificate:(NSString *)account
 + (NSString *)getEndToEndCertificate:(NSString *)account
 {
 {
     NSString *key, *certificate;
     NSString *key, *certificate;
-    
+
     key = [E2E_certificate stringByAppendingString:account];
     key = [E2E_certificate stringByAppendingString:account];
     certificate = [UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain];
     certificate = [UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain];
 
 
@@ -316,7 +316,7 @@
         key = [@"EndToEndPublicKey_" stringByAppendingString:account];
         key = [@"EndToEndPublicKey_" stringByAppendingString:account];
         certificate = [UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain];
         certificate = [UICKeyChainStore stringForKey:key service:NCGlobal.shared.serviceShareKeyChain];
     }
     }
-    
+
     return certificate;
     return certificate;
 }
 }
 
 
@@ -366,7 +366,7 @@
 {
 {
     BOOL isE2EEEnabled = [[NCGlobal shared] capabilityE2EEEnabled];
     BOOL isE2EEEnabled = [[NCGlobal shared] capabilityE2EEEnabled];
     NSString* versionE2EE = [[NCGlobal shared] capabilityE2EEApiVersion];
     NSString* versionE2EE = [[NCGlobal shared] capabilityE2EEApiVersion];
-    
+
     NSString *certificate = [self getEndToEndCertificate:account];
     NSString *certificate = [self getEndToEndCertificate:account];
     NSString *publicKey = [self getEndToEndPublicKey:account];
     NSString *publicKey = [self getEndToEndPublicKey:account];
     NSString *privateKey = [self getEndToEndPrivateKey:account];
     NSString *privateKey = [self getEndToEndPrivateKey:account];
@@ -385,7 +385,7 @@
     [self setEndToEndPrivateKey:account privateKey:nil];
     [self setEndToEndPrivateKey:account privateKey:nil];
     [self setEndToEndPublicKey:account publicKey:nil];
     [self setEndToEndPublicKey:account publicKey:nil];
     [self setEndToEndPassphrase:account passphrase:nil];
     [self setEndToEndPassphrase:account passphrase:nil];
-    
+
     // OLD
     // OLD
     [UICKeyChainStore setString:nil forKey:[@"EndToEndPublicKey_" stringByAppendingString:account] service:NCGlobal.shared.serviceShareKeyChain];
     [UICKeyChainStore setString:nil forKey:[@"EndToEndPublicKey_" stringByAppendingString:account] service:NCGlobal.shared.serviceShareKeyChain];
 }
 }
@@ -486,7 +486,7 @@
 + (NSInteger)getMediaWidthImage
 + (NSInteger)getMediaWidthImage
 {
 {
     NSString *width = [UICKeyChainStore stringForKey:@"mediaWidthImage" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *width = [UICKeyChainStore stringForKey:@"mediaWidthImage" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     if (width == nil) {
     if (width == nil) {
         return 80;
         return 80;
     } else {
     } else {
@@ -556,13 +556,13 @@
 + (BOOL)getLivePhoto
 + (BOOL)getLivePhoto
 {
 {
     NSString *valueString = [UICKeyChainStore stringForKey:@"livePhoto" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *valueString = [UICKeyChainStore stringForKey:@"livePhoto" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     // Default TRUE
     // Default TRUE
     if (valueString == nil) {
     if (valueString == nil) {
         [self setLivePhoto:YES];
         [self setLivePhoto:YES];
         return true;
         return true;
     }
     }
-    
+
     return [valueString boolValue];
     return [valueString boolValue];
 }
 }
 
 
@@ -575,13 +575,13 @@
 + (NSString *)getMediaSortDate
 + (NSString *)getMediaSortDate
 {
 {
     NSString *valueString = [UICKeyChainStore stringForKey:@"mediaSortDate" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *valueString = [UICKeyChainStore stringForKey:@"mediaSortDate" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     // Default TRUE
     // Default TRUE
     if (valueString == nil) {
     if (valueString == nil) {
         [self setMediaSortDate:@"date"];
         [self setMediaSortDate:@"date"];
         return @"date";
         return @"date";
     }
     }
-    
+
     return valueString;
     return valueString;
 }
 }
 
 
@@ -642,7 +642,7 @@
 + (NSInteger)getLogLevel
 + (NSInteger)getLogLevel
 {
 {
     NSString *value = [UICKeyChainStore stringForKey:@"logLevel" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *value = [UICKeyChainStore stringForKey:@"logLevel" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     if (value == nil) {
     if (value == nil) {
         return 1;
         return 1;
     } else {
     } else {
@@ -670,7 +670,7 @@
 + (NSInteger)getCleanUpDay
 + (NSInteger)getCleanUpDay
 {
 {
     NSString *size = [UICKeyChainStore stringForKey:@"cleanUpDay" service:NCGlobal.shared.serviceShareKeyChain];
     NSString *size = [UICKeyChainStore stringForKey:@"cleanUpDay" service:NCGlobal.shared.serviceShareKeyChain];
-    
+
     if (size == nil) {
     if (size == nil) {
         NSInteger days = [[NCBrandOptions shared] cleanUpDay];
         NSInteger days = [[NCBrandOptions shared] cleanUpDay];
         return days;
         return days;
@@ -712,7 +712,7 @@
 #pragma --------------------------------------------------------------------------------------------
 #pragma --------------------------------------------------------------------------------------------
 
 
 + (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
 + (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
-{    
+{
     NSError *error = nil;
     NSError *error = nil;
     BOOL success = [URL setResourceValue:[NSNumber numberWithBool: YES] forKey: NSURLIsExcludedFromBackupKey error: &error];
     BOOL success = [URL setResourceValue:[NSNumber numberWithBool: YES] forKey: NSURLIsExcludedFromBackupKey error: &error];
     if(success) {
     if(success) {
@@ -720,7 +720,7 @@
     } else {
     } else {
         NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
         NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
     }
     }
-    
+
     return success;
     return success;
 }
 }
 
 
@@ -728,7 +728,7 @@
 {
 {
     NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
     NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
     NSString *userAgent = [[NCBrandOptions shared] userAgent];
     NSString *userAgent = [[NCBrandOptions shared] userAgent];
-    
+
     return [NSString stringWithFormat:@"Mozilla/5.0 (iOS) %@/%@", userAgent, appVersion];
     return [NSString stringWithFormat:@"Mozilla/5.0 (iOS) %@/%@", userAgent, appVersion];
 }
 }
 
 
@@ -779,11 +779,11 @@
 + (NSString *)removeForbiddenCharactersServer:(NSString *)fileName
 + (NSString *)removeForbiddenCharactersServer:(NSString *)fileName
 {
 {
     NSArray *arrayForbiddenCharacters = [NSArray arrayWithObjects:@"/", nil];
     NSArray *arrayForbiddenCharacters = [NSArray arrayWithObjects:@"/", nil];
-    
+
     for (NSString *currentCharacter in arrayForbiddenCharacters) {
     for (NSString *currentCharacter in arrayForbiddenCharacters) {
         fileName = [fileName stringByReplacingOccurrencesOfString:currentCharacter withString:@""];
         fileName = [fileName stringByReplacingOccurrencesOfString:currentCharacter withString:@""];
     }
     }
-    
+
     return fileName;
     return fileName;
 }
 }
 
 
@@ -791,24 +791,24 @@
 + (NSString *)removeForbiddenCharactersFileSystem:(NSString *)fileName
 + (NSString *)removeForbiddenCharactersFileSystem:(NSString *)fileName
 {
 {
     NSArray *arrayForbiddenCharacters = [NSArray arrayWithObjects:@"\\",@"<",@">",@":",@"\"",@"|",@"?",@"*",@"/", nil];
     NSArray *arrayForbiddenCharacters = [NSArray arrayWithObjects:@"\\",@"<",@">",@":",@"\"",@"|",@"?",@"*",@"/", nil];
-    
+
     for (NSString *currentCharacter in arrayForbiddenCharacters) {
     for (NSString *currentCharacter in arrayForbiddenCharacters) {
         fileName = [fileName stringByReplacingOccurrencesOfString:currentCharacter withString:@""];
         fileName = [fileName stringByReplacingOccurrencesOfString:currentCharacter withString:@""];
     }
     }
-    
+
     return fileName;
     return fileName;
 }
 }
 
 
 + (NSString*)stringAppendServerUrl:(NSString *)serverUrl addFileName:(NSString *)addFileName
 + (NSString*)stringAppendServerUrl:(NSString *)serverUrl addFileName:(NSString *)addFileName
 {
 {
     NSString *result;
     NSString *result;
-    
+
     if (serverUrl == nil || addFileName == nil) return nil;
     if (serverUrl == nil || addFileName == nil) return nil;
     if ([addFileName isEqualToString:@""]) return serverUrl;
     if ([addFileName isEqualToString:@""]) return serverUrl;
-    
+
     if ([serverUrl isEqualToString:@"/"]) result = [serverUrl stringByAppendingString:addFileName];
     if ([serverUrl isEqualToString:@"/"]) result = [serverUrl stringByAppendingString:addFileName];
     else result = [NSString stringWithFormat:@"%@/%@", serverUrl, addFileName];
     else result = [NSString stringWithFormat:@"%@/%@", serverUrl, addFileName];
-    
+
     return result;
     return result;
 }
 }
 
 
@@ -818,44 +818,44 @@
     [formatter setDateFormat:@"yy-MM-dd HH-mm-ss"];
     [formatter setDateFormat:@"yy-MM-dd HH-mm-ss"];
     NSString *fileNameDate = [formatter stringFromDate:[NSDate date]];
     NSString *fileNameDate = [formatter stringFromDate:[NSDate date]];
     NSString *returnFileName;
     NSString *returnFileName;
-    
+
     if ([fileName isEqualToString:@""] && ![extension isEqualToString:@""]) {
     if ([fileName isEqualToString:@""] && ![extension isEqualToString:@""]) {
         returnFileName = [NSString stringWithFormat:@"%@.%@", fileNameDate, extension];
         returnFileName = [NSString stringWithFormat:@"%@.%@", fileNameDate, extension];
     }
     }
-    
+
     if (![fileName isEqualToString:@""] && [extension isEqualToString:@""]) {
     if (![fileName isEqualToString:@""] && [extension isEqualToString:@""]) {
         returnFileName = [NSString stringWithFormat:@"%@ %@", fileName, fileNameDate];
         returnFileName = [NSString stringWithFormat:@"%@ %@", fileName, fileNameDate];
     }
     }
-    
+
     if ([fileName isEqualToString:@""] && [extension isEqualToString:@""]) {
     if ([fileName isEqualToString:@""] && [extension isEqualToString:@""]) {
         returnFileName = fileNameDate;
         returnFileName = fileNameDate;
     }
     }
-    
+
     if (![fileName isEqualToString:@""] && ![extension isEqualToString:@""]) {
     if (![fileName isEqualToString:@""] && ![extension isEqualToString:@""]) {
         returnFileName = [NSString stringWithFormat:@"%@ %@.%@", fileName, fileNameDate, extension];
         returnFileName = [NSString stringWithFormat:@"%@ %@.%@", fileName, fileNameDate, extension];
     }
     }
-    
+
     return returnFileName;
     return returnFileName;
 }
 }
 
 
 + (NSString *)createFileName:(NSString *)fileName fileDate:(NSDate *)fileDate fileType:(PHAssetMediaType)fileType keyFileName:(NSString *)keyFileName keyFileNameType:(NSString *)keyFileNameType keyFileNameOriginal:(NSString *)keyFileNameOriginal forcedNewFileName:(BOOL)forcedNewFileName
 + (NSString *)createFileName:(NSString *)fileName fileDate:(NSDate *)fileDate fileType:(PHAssetMediaType)fileType keyFileName:(NSString *)keyFileName keyFileNameType:(NSString *)keyFileNameType keyFileNameOriginal:(NSString *)keyFileNameOriginal forcedNewFileName:(BOOL)forcedNewFileName
 {
 {
     BOOL addFileNameType = NO;
     BOOL addFileNameType = NO;
-    
+
     // Original FileName ?
     // Original FileName ?
     if ([self getOriginalFileName:keyFileNameOriginal] && !forcedNewFileName) {
     if ([self getOriginalFileName:keyFileNameOriginal] && !forcedNewFileName) {
         return fileName;
         return fileName;
     }
     }
-    
+
     NSString *numberFileName;
     NSString *numberFileName;
     if ([fileName length] > 8) numberFileName = [fileName substringWithRange:NSMakeRange(04, 04)];
     if ([fileName length] > 8) numberFileName = [fileName substringWithRange:NSMakeRange(04, 04)];
     else numberFileName = [CCUtility getIncrementalNumber];
     else numberFileName = [CCUtility getIncrementalNumber];
-    
+
     NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
     NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
     [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
     [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
     [formatter setDateFormat:@"yy-MM-dd HH-mm-ss"];
     [formatter setDateFormat:@"yy-MM-dd HH-mm-ss"];
     NSString *fileNameDate = [formatter stringFromDate:fileDate];
     NSString *fileNameDate = [formatter stringFromDate:fileDate];
-    
+
     NSString *fileNameType = @"";
     NSString *fileNameType = @"";
     if (fileType == PHAssetMediaTypeImage)
     if (fileType == PHAssetMediaTypeImage)
         fileNameType = NSLocalizedString(@"_photo_", nil);
         fileNameType = NSLocalizedString(@"_photo_", nil);
@@ -869,15 +869,15 @@
     // Use File Name Type
     // Use File Name Type
     if (keyFileNameType)
     if (keyFileNameType)
         addFileNameType = [CCUtility getFileNameType:keyFileNameType];
         addFileNameType = [CCUtility getFileNameType:keyFileNameType];
-    
+
     NSString *fileNameExt = [[fileName pathExtension] lowercaseString];
     NSString *fileNameExt = [[fileName pathExtension] lowercaseString];
-    
+
     if (keyFileName) {
     if (keyFileName) {
-        
+
         fileName = [CCUtility getFileNameMask:keyFileName];
         fileName = [CCUtility getFileNameMask:keyFileName];
-        
+
         if ([fileName length] > 0) {
         if ([fileName length] > 0) {
-            
+
             [formatter setDateFormat:@"dd"];
             [formatter setDateFormat:@"dd"];
             NSString *dayNumber = [formatter stringFromDate:fileDate];
             NSString *dayNumber = [formatter stringFromDate:fileDate];
             [formatter setDateFormat:@"MMM"];
             [formatter setDateFormat:@"MMM"];
@@ -898,7 +898,7 @@
             NSString *second = [formatter stringFromDate:fileDate];
             NSString *second = [formatter stringFromDate:fileDate];
             [formatter setDateFormat:@"a"];
             [formatter setDateFormat:@"a"];
             NSString *ampm = [formatter stringFromDate:fileDate];
             NSString *ampm = [formatter stringFromDate:fileDate];
-            
+
             // Replace string with date
             // Replace string with date
 
 
             fileName = [fileName stringByReplacingOccurrencesOfString:@"DD" withString:dayNumber];
             fileName = [fileName stringByReplacingOccurrencesOfString:@"DD" withString:dayNumber];
@@ -917,26 +917,26 @@
                 fileName = [NSString stringWithFormat:@"%@%@%@.%@", fileNameType, fileName, numberFileName, fileNameExt];
                 fileName = [NSString stringWithFormat:@"%@%@%@.%@", fileNameType, fileName, numberFileName, fileNameExt];
             else
             else
                 fileName = [NSString stringWithFormat:@"%@%@.%@", fileName, numberFileName, fileNameExt];
                 fileName = [NSString stringWithFormat:@"%@%@.%@", fileName, numberFileName, fileNameExt];
-            
+
             fileName = [fileName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
             fileName = [fileName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
-            
+
         } else {
         } else {
-            
+
             if (addFileNameType)
             if (addFileNameType)
                 fileName = [NSString stringWithFormat:@"%@ %@ %@.%@", fileNameType, fileNameDate, numberFileName, fileNameExt];
                 fileName = [NSString stringWithFormat:@"%@ %@ %@.%@", fileNameType, fileNameDate, numberFileName, fileNameExt];
             else
             else
                 fileName = [NSString stringWithFormat:@"%@ %@.%@", fileNameDate, numberFileName, fileNameExt];
                 fileName = [NSString stringWithFormat:@"%@ %@.%@", fileNameDate, numberFileName, fileNameExt];
         }
         }
-        
+
     } else {
     } else {
-        
+
         if (addFileNameType)
         if (addFileNameType)
             fileName = [NSString stringWithFormat:@"%@ %@ %@.%@", fileNameType, fileNameDate, numberFileName, fileNameExt];
             fileName = [NSString stringWithFormat:@"%@ %@ %@.%@", fileNameType, fileNameDate, numberFileName, fileNameExt];
         else
         else
             fileName = [NSString stringWithFormat:@"%@ %@.%@", fileNameDate, numberFileName, fileNameExt];
             fileName = [NSString stringWithFormat:@"%@ %@.%@", fileNameDate, numberFileName, fileNameExt];
 
 
     }
     }
-    
+
     return fileName;
     return fileName;
 }
 }
 
 
@@ -944,42 +944,42 @@
 {
 {
     NSString *path;
     NSString *path;
     NSURL *dirGroup = [CCUtility getDirectoryGroup];
     NSURL *dirGroup = [CCUtility getDirectoryGroup];
-    
+
     NSLog(@"[LOG] Dir Group");
     NSLog(@"[LOG] Dir Group");
     NSLog(@"%@", [dirGroup path]);
     NSLog(@"%@", [dirGroup path]);
     NSLog(@"[LOG] Program application ");
     NSLog(@"[LOG] Program application ");
     NSLog(@"%@", [[CCUtility getDirectoryDocuments] stringByDeletingLastPathComponent]);
     NSLog(@"%@", [[CCUtility getDirectoryDocuments] stringByDeletingLastPathComponent]);
-    
+
     // create Directory Documents
     // create Directory Documents
     path = [CCUtility getDirectoryDocuments];
     path = [CCUtility getDirectoryDocuments];
     if (![[NSFileManager defaultManager] fileExistsAtPath: path])
     if (![[NSFileManager defaultManager] fileExistsAtPath: path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     // create Directory audio => Library, Application Support, audio
     // create Directory audio => Library, Application Support, audio
     path = [CCUtility getDirectoryAudio];
     path = [CCUtility getDirectoryAudio];
     if (![[NSFileManager defaultManager] fileExistsAtPath: path])
     if (![[NSFileManager defaultManager] fileExistsAtPath: path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     // create Directory database Nextcloud
     // create Directory database Nextcloud
     path = [[dirGroup URLByAppendingPathComponent:[[NCGlobal shared] appDatabaseNextcloud]] path];
     path = [[dirGroup URLByAppendingPathComponent:[[NCGlobal shared] appDatabaseNextcloud]] path];
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     // create Directory User Data
     // create Directory User Data
     path = [[dirGroup URLByAppendingPathComponent:NCGlobal.shared.appUserData] path];
     path = [[dirGroup URLByAppendingPathComponent:NCGlobal.shared.appUserData] path];
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     // create Directory Provider Storage
     // create Directory Provider Storage
     path = [CCUtility getDirectoryProviderStorage];
     path = [CCUtility getDirectoryProviderStorage];
     if (![[NSFileManager defaultManager] fileExistsAtPath: path])
     if (![[NSFileManager defaultManager] fileExistsAtPath: path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     // create Directory Scan
     // create Directory Scan
     path = [[dirGroup URLByAppendingPathComponent:NCGlobal.shared.appScan] path];
     path = [[dirGroup URLByAppendingPathComponent:NCGlobal.shared.appScan] path];
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     // create Directory Temp
     // create Directory Temp
     path = NSTemporaryDirectory();
     path = NSTemporaryDirectory();
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
@@ -1006,14 +1006,14 @@
 + (NSString *)getDirectoryDocuments
 + (NSString *)getDirectoryDocuments
 {
 {
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-    
+
     return [paths objectAtIndex:0];
     return [paths objectAtIndex:0];
 }
 }
 
 
 + (NSString *)getDirectoryReaderMetadata
 + (NSString *)getDirectoryReaderMetadata
 {
 {
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
-    
+
     return [NSString stringWithFormat:@"%@/Reader Metadata", [paths objectAtIndex:0]];
     return [NSString stringWithFormat:@"%@/Reader Metadata", [paths objectAtIndex:0]];
 }
 }
 
 
@@ -1021,7 +1021,7 @@
 + (NSString *)getDirectoryAudio
 + (NSString *)getDirectoryAudio
 {
 {
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
-    
+
     return [NSString stringWithFormat:@"%@/%@", [paths objectAtIndex:0], @"audio"];
     return [NSString stringWithFormat:@"%@/%@", [paths objectAtIndex:0], @"audio"];
 }
 }
 
 
@@ -1029,27 +1029,27 @@
 + (NSString *)getDirectoryCerificates
 + (NSString *)getDirectoryCerificates
 {
 {
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.appCertificates] path];
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.appCertificates] path];
-    
+
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     return path;
     return path;
 }
 }
 
 
 + (NSString *)getDirectoryUserData
 + (NSString *)getDirectoryUserData
 {
 {
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.appUserData] path];
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.appUserData] path];
-    
+
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     return path;
     return path;
 }
 }
 
 
 + (NSString *)getDirectoryProviderStorage
 + (NSString *)getDirectoryProviderStorage
 {
 {
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.directoryProviderStorage] path];
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.directoryProviderStorage] path];
-    
+
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
 
 
@@ -1059,7 +1059,7 @@
 + (NSString *)getDirectoryProviderStorageOcId:(NSString *)ocId
 + (NSString *)getDirectoryProviderStorageOcId:(NSString *)ocId
 {
 {
     NSString *path = [NSString stringWithFormat:@"%@/%@", [self getDirectoryProviderStorage], ocId];
     NSString *path = [NSString stringWithFormat:@"%@/%@", [self getDirectoryProviderStorage], ocId];
-    
+
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
 
 
@@ -1069,14 +1069,14 @@
 + (NSString *)getDirectoryProviderStorageOcId:(NSString *)ocId fileNameView:(NSString *)fileNameView
 + (NSString *)getDirectoryProviderStorageOcId:(NSString *)ocId fileNameView:(NSString *)fileNameView
 {
 {
     NSString *fileNamePath = [NSString stringWithFormat:@"%@/%@", [self getDirectoryProviderStorageOcId:ocId], fileNameView];
     NSString *fileNamePath = [NSString stringWithFormat:@"%@/%@", [self getDirectoryProviderStorageOcId:ocId], fileNameView];
-    
+
     // if do not exists create file 0 length
     // if do not exists create file 0 length
     // causes files with lenth 0 to never be downloaded, because already exist
     // causes files with lenth 0 to never be downloaded, because already exist
     // also makes it impossible to delete any file with length 0 (from cache)
     // also makes it impossible to delete any file with length 0 (from cache)
     if ([[NSFileManager defaultManager] fileExistsAtPath:fileNamePath] == NO) {
     if ([[NSFileManager defaultManager] fileExistsAtPath:fileNamePath] == NO) {
         [[NSFileManager defaultManager] createFileAtPath:fileNamePath contents:nil attributes:nil];
         [[NSFileManager defaultManager] createFileAtPath:fileNamePath contents:nil attributes:nil];
     }
     }
-    
+
     return fileNamePath;
     return fileNamePath;
 }
 }
 
 
@@ -1112,9 +1112,9 @@
 + (int64_t)fileProviderStorageSize:(NSString *)ocId fileNameView:(NSString *)fileNameView
 + (int64_t)fileProviderStorageSize:(NSString *)ocId fileNameView:(NSString *)fileNameView
 {
 {
     NSString *fileNamePath = [self getDirectoryProviderStorageOcId:ocId fileNameView:fileNameView];
     NSString *fileNamePath = [self getDirectoryProviderStorageOcId:ocId fileNameView:fileNameView];
-    
+
     int64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:fileNamePath error:nil] fileSize];
     int64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:fileNamePath error:nil] fileSize];
-    
+
     return fileSize;
     return fileSize;
 }
 }
 
 
@@ -1122,10 +1122,10 @@
 {
 {
     NSString *fileNamePathPreview = [self getDirectoryProviderStoragePreviewOcId:ocId etag:etag];
     NSString *fileNamePathPreview = [self getDirectoryProviderStoragePreviewOcId:ocId etag:etag];
     NSString *fileNamePathIcon = [self getDirectoryProviderStorageIconOcId:ocId etag:etag];
     NSString *fileNamePathIcon = [self getDirectoryProviderStorageIconOcId:ocId etag:etag];
-    
+
     unsigned long long fileSizePreview = [[[NSFileManager defaultManager] attributesOfItemAtPath:fileNamePathPreview error:nil] fileSize];
     unsigned long long fileSizePreview = [[[NSFileManager defaultManager] attributesOfItemAtPath:fileNamePathPreview error:nil] fileSize];
     unsigned long long fileSizeIcon = [[[NSFileManager defaultManager] attributesOfItemAtPath:fileNamePathIcon error:nil] fileSize];
     unsigned long long fileSizeIcon = [[[NSFileManager defaultManager] attributesOfItemAtPath:fileNamePathIcon error:nil] fileSize];
-    
+
     if (fileSizePreview > 0 && fileSizeIcon > 0) return true;
     if (fileSizePreview > 0 && fileSizeIcon > 0) return true;
     else return false;
     else return false;
 }
 }
@@ -1134,7 +1134,7 @@
 {
 {
     NSURL *dirGroup = [CCUtility getDirectoryGroup];
     NSURL *dirGroup = [CCUtility getDirectoryGroup];
     NSString *path = [[dirGroup URLByAppendingPathComponent:NCGlobal.shared.appApplicationSupport] path];
     NSString *path = [[dirGroup URLByAppendingPathComponent:NCGlobal.shared.appApplicationSupport] path];
-    
+
     [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
     [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
 }
 }
 
 
@@ -1172,22 +1172,22 @@
     NSString *title;
     NSString *title;
     NSDate *today = [NSDate date];
     NSDate *today = [NSDate date];
     NSDate *yesterday = [today dateByAddingTimeInterval: -86400.0];
     NSDate *yesterday = [today dateByAddingTimeInterval: -86400.0];
-    
+
     if ([date isEqualToDate:[CCUtility datetimeWithOutTime:[NSDate distantPast]]]) {
     if ([date isEqualToDate:[CCUtility datetimeWithOutTime:[NSDate distantPast]]]) {
-        
+
         title =  NSLocalizedString(@"_no_date_", nil);
         title =  NSLocalizedString(@"_no_date_", nil);
-        
+
     } else {
     } else {
-        
+
         title = [NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterLongStyle timeStyle:0];
         title = [NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterLongStyle timeStyle:0];
-        
+
         if ([date isEqualToDate:[CCUtility datetimeWithOutTime:today]])
         if ([date isEqualToDate:[CCUtility datetimeWithOutTime:today]])
             title = [NSString stringWithFormat:NSLocalizedString(@"_today_", nil)];
             title = [NSString stringWithFormat:NSLocalizedString(@"_today_", nil)];
-        
+
         if ([date isEqualToDate:[CCUtility datetimeWithOutTime:yesterday]])
         if ([date isEqualToDate:[CCUtility datetimeWithOutTime:yesterday]])
             title = [NSString stringWithFormat:NSLocalizedString(@"_yesterday_", nil)];
             title = [NSString stringWithFormat:NSLocalizedString(@"_yesterday_", nil)];
     }
     }
-    
+
     return title;
     return title;
 }
 }
 
 
@@ -1220,18 +1220,18 @@
     NSString *path = [serverUrl stringByReplacingOccurrencesOfString:homeServer withString:@""];
     NSString *path = [serverUrl stringByReplacingOccurrencesOfString:homeServer withString:@""];
     return path;
     return path;
 }
 }
-                                       
+
 + (NSString *)returnFileNamePathFromFileName:(NSString *)metadataFileName serverUrl:(NSString *)serverUrl urlBase:(NSString *)urlBase userId:(NSString *)userId account:(NSString *)account
 + (NSString *)returnFileNamePathFromFileName:(NSString *)metadataFileName serverUrl:(NSString *)serverUrl urlBase:(NSString *)urlBase userId:(NSString *)userId account:(NSString *)account
 {
 {
     if (metadataFileName == nil || serverUrl == nil || urlBase == nil) {
     if (metadataFileName == nil || serverUrl == nil || urlBase == nil) {
         return @"";
         return @"";
     }
     }
-    
+
     NSString *homeServer = [[NCUtilityFileSystem shared] getHomeServerWithUrlBase:urlBase userId:userId];
     NSString *homeServer = [[NCUtilityFileSystem shared] getHomeServerWithUrlBase:urlBase userId:userId];
     NSString *fileName = [NSString stringWithFormat:@"%@/%@", [serverUrl stringByReplacingOccurrencesOfString:homeServer withString:@""], metadataFileName];
     NSString *fileName = [NSString stringWithFormat:@"%@/%@", [serverUrl stringByReplacingOccurrencesOfString:homeServer withString:@""], metadataFileName];
-    
+
     if ([fileName hasPrefix:@"/"]) fileName = [fileName substringFromIndex:1];
     if ([fileName hasPrefix:@"/"]) fileName = [fileName substringFromIndex:1];
-    
+
     return fileName;
     return fileName;
 }
 }
 
 
@@ -1239,33 +1239,33 @@
 {
 {
     CFStringRef fileUTI = nil;
     CFStringRef fileUTI = nil;
     NSString *returnFileUTI = nil;
     NSString *returnFileUTI = nil;
-    
+
     if ([fileNameView isEqualToString:@"."]) {
     if ([fileNameView isEqualToString:@"."]) {
-        
+
         return returnFileUTI;
         return returnFileUTI;
-        
+
     } else {
     } else {
         CFStringRef fileExtension = (__bridge CFStringRef)[fileNameView pathExtension];
         CFStringRef fileExtension = (__bridge CFStringRef)[fileNameView pathExtension];
         NSString *ext = (__bridge NSString *)fileExtension;
         NSString *ext = (__bridge NSString *)fileExtension;
         ext = ext.uppercaseString;
         ext = ext.uppercaseString;
         fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
         fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);
-        
+
         if (fileUTI != nil) {
         if (fileUTI != nil) {
             returnFileUTI = (__bridge NSString *)fileUTI;
             returnFileUTI = (__bridge NSString *)fileUTI;
             CFRelease(fileUTI);
             CFRelease(fileUTI);
         }
         }
     }
     }
-    
+
     return returnFileUTI;
     return returnFileUTI;
 }
 }
 
 
 + (NSString *)getDirectoryScan
 + (NSString *)getDirectoryScan
 {
 {
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.appScan] path];
     NSString *path = [[[CCUtility getDirectoryGroup] URLByAppendingPathComponent:NCGlobal.shared.appScan] path];
-    
+
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
     if (![[NSFileManager defaultManager] fileExistsAtPath:path])
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
         [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
-    
+
     return path;
     return path;
 }
 }
 
 
@@ -1274,9 +1274,9 @@
 #pragma --------------------------------------------------------------------------------------------
 #pragma --------------------------------------------------------------------------------------------
 
 
 + (NSInteger) getPermissionsValueByCanEdit:(BOOL)canEdit andCanCreate:(BOOL)canCreate andCanChange:(BOOL)canChange andCanDelete:(BOOL)canDelete andCanShare:(BOOL)canShare andIsFolder:(BOOL) isFolder
 + (NSInteger) getPermissionsValueByCanEdit:(BOOL)canEdit andCanCreate:(BOOL)canCreate andCanChange:(BOOL)canChange andCanDelete:(BOOL)canDelete andCanShare:(BOOL)canShare andIsFolder:(BOOL) isFolder
-{    
+{
     NSInteger permissionsValue = NCGlobal.shared.permissionReadShare;
     NSInteger permissionsValue = NCGlobal.shared.permissionReadShare;
-    
+
     if (canEdit && !isFolder) {
     if (canEdit && !isFolder) {
         permissionsValue = permissionsValue + NCGlobal.shared.permissionUpdateShare;
         permissionsValue = permissionsValue + NCGlobal.shared.permissionUpdateShare;
     }
     }
@@ -1292,7 +1292,7 @@
     if (canShare) {
     if (canShare) {
         permissionsValue = permissionsValue + NCGlobal.shared.permissionShareShare;
         permissionsValue = permissionsValue + NCGlobal.shared.permissionShareShare;
     }
     }
-    
+
     return permissionsValue;
     return permissionsValue;
 }
 }
 
 
@@ -1317,16 +1317,16 @@
 }
 }
 
 
 + (BOOL) isAnyPermissionToEdit:(NSInteger) permissionValue {
 + (BOOL) isAnyPermissionToEdit:(NSInteger) permissionValue {
-    
+
     BOOL canCreate = [self isPermissionToCanCreate:permissionValue];
     BOOL canCreate = [self isPermissionToCanCreate:permissionValue];
     BOOL canChange = [self isPermissionToCanChange:permissionValue];
     BOOL canChange = [self isPermissionToCanChange:permissionValue];
     BOOL canDelete = [self isPermissionToCanDelete:permissionValue];
     BOOL canDelete = [self isPermissionToCanDelete:permissionValue];
-    
-    
+
+
     BOOL canEdit = (canCreate || canChange || canDelete);
     BOOL canEdit = (canCreate || canChange || canDelete);
-    
+
     return canEdit;
     return canEdit;
-    
+
 }
 }
 
 
 + (BOOL) isPermissionToRead:(NSInteger) permissionValue {
 + (BOOL) isPermissionToRead:(NSInteger) permissionValue {
@@ -1335,192 +1335,16 @@
 }
 }
 
 
 + (BOOL) isPermissionToReadCreateUpdate:(NSInteger) permissionValue {
 + (BOOL) isPermissionToReadCreateUpdate:(NSInteger) permissionValue {
-    
+
     BOOL canRead   = [self isPermissionToRead:permissionValue];
     BOOL canRead   = [self isPermissionToRead:permissionValue];
     BOOL canCreate = [self isPermissionToCanCreate:permissionValue];
     BOOL canCreate = [self isPermissionToCanCreate:permissionValue];
     BOOL canChange = [self isPermissionToCanChange:permissionValue];
     BOOL canChange = [self isPermissionToCanChange:permissionValue];
-    
-    
-    BOOL canEdit = (canCreate && canChange && canRead);
-    
-    return canEdit;
-    
-}
 
 
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== EXIF =====
-#pragma --------------------------------------------------------------------------------------------
 
 
-+ (void)setExif:(tableMetadata *)metadata withCompletionHandler:(void(^)(double latitude, double longitude, NSString *location, NSDate *date, NSString *lensModel))completition
-{
-    NSString *dateTime;
-    NSString *latitudeRef;
-    NSString *longitudeRef;
-    NSString *stringLatitude = @"0";
-    NSString *stringLongitude = @"0";
-    __block NSString *location = @"";
-    
-    double latitude = 0;
-    double longitude = 0;
-    
-    NSDate *date = nil;
-    long fileSize = 0;
-    int pixelY = 0;
-    int pixelX = 0;
-    NSString *lensModel = @"";
-
-    if (![metadata.classFile isEqualToString:@"image"] || ![CCUtility fileProviderStorageExists:metadata]) {
-        completition(latitude, longitude, location, date, lensModel);
-        return;
-    }
-    
-    NSURL *url = [NSURL fileURLWithPath:[CCUtility getDirectoryProviderStorageOcId:metadata.ocId fileNameView:metadata.fileNameView]];
-    CGImageSourceRef originalSource =  CGImageSourceCreateWithURL((CFURLRef) url, NULL);
-    if (!originalSource) {
-        completition(latitude, longitude, location, date, lensModel);
-        return;
-    }
-    
-    CFDictionaryRef fileProperties = CGImageSourceCopyProperties(originalSource, nil);
-    if (!fileProperties) {
-        CFRelease(originalSource);
-        completition(latitude, longitude, location, date, lensModel);
-        return;
-    }
-    
-    // FILES PROPERTIES
-    NSNumber *fileSizeNumber = CFDictionaryGetValue(fileProperties, kCGImagePropertyFileSize);
-    fileSize = [fileSizeNumber longValue];
-    
-    CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(originalSource, 0, NULL);
-    if (!imageProperties) {
-        CFRelease(originalSource);
-        CFRelease(fileProperties);
-        completition(latitude, longitude, location, date, lensModel);
-        return;
-    }
+    BOOL canEdit = (canCreate && canChange && canRead);
 
 
-    CFDictionaryRef tiff = CFDictionaryGetValue(imageProperties, kCGImagePropertyTIFFDictionary);
-    CFDictionaryRef gps = CFDictionaryGetValue(imageProperties, kCGImagePropertyGPSDictionary);
-    CFDictionaryRef exif = CFDictionaryGetValue(imageProperties, kCGImagePropertyExifDictionary);
-    
-    if (exif) {
-        
-        NSString *sPixelX = (NSString *)CFDictionaryGetValue(exif, kCGImagePropertyExifPixelXDimension);
-        pixelX = [sPixelX intValue];
-        NSString *sPixelY = (NSString *)CFDictionaryGetValue(exif, kCGImagePropertyExifPixelYDimension);
-        pixelY = [sPixelY intValue];
-        lensModel = (NSString *)CFDictionaryGetValue(exif, kCGImagePropertyExifLensModel);
-        dateTime = (NSString *)CFDictionaryGetValue(exif, kCGImagePropertyExifDateTimeOriginal);
-        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
-        [dateFormatter setDateFormat:@"yyyy:MM:dd HH:mm:ss"];
-        date = [dateFormatter dateFromString:dateTime];
-    }
- 
-    if (tiff) {
-        
-        dateTime = (NSString *)CFDictionaryGetValue(tiff, kCGImagePropertyTIFFDateTime);
-        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
-        [dateFormatter setDateFormat:@"yyyy:MM:dd HH:mm:ss"];
-        date = [dateFormatter dateFromString:dateTime];
-    }
-    
-    if (gps) {
-        
-        latitude = [(NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLatitude) doubleValue];
-        longitude = [(NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLongitude) doubleValue];
-        
-        latitudeRef = (NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLatitudeRef);
-        longitudeRef = (NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLongitudeRef);
-        
-        // conversion 4 decimal +N -S
-        // The latitude in degrees. Positive values indicate latitudes north of the equator. Negative values indicate latitudes south of the equator.
-        if ([latitudeRef isEqualToString:@"N"]) {
-            stringLatitude = [NSString stringWithFormat:@"+%.4f", latitude];
-        } else {
-            stringLatitude = [NSString stringWithFormat:@"-%.4f", latitude];
-            latitude *= -1;
-        }
-        
-        // conversion 4 decimal +E -W
-        // The longitude in degrees. Measurements are relative to the zero meridian, with positive values extending east of the meridian
-        // and negative values extending west of the meridian.
-        if ([longitudeRef isEqualToString:@"E"]) {
-            stringLongitude = [NSString stringWithFormat:@"+%.4f", longitude];
-        } else {
-            stringLongitude = [NSString stringWithFormat:@"-%.4f", longitude];
-            longitude *= -1;
-        }
-        
-        if (latitude == 0 || longitude == 0) {
-            stringLatitude = @"0";
-            stringLongitude = @"0";
-        }
-    }
+    return canEdit;
 
 
-    // Wite data EXIF in DB
-    if (tiff || gps) {
-        [[NCManageDatabase shared] setLocalFileWithOcId:metadata.ocId exifDate:date exifLatitude:stringLatitude exifLongitude:stringLongitude exifLensModel:lensModel];
-        if ([stringLatitude doubleValue] != 0 || [stringLongitude doubleValue] != 0) {
-            
-            // If exists already geocoder data in TableGPS exit
-            location = [[NCManageDatabase shared] getLocationFromGeoLatitude:stringLatitude longitude:stringLongitude];
-            if (location != nil) {
-                CFRelease(originalSource);
-                CFRelease(imageProperties);
-                CFRelease(fileProperties);
-                completition(latitude, longitude, location, date, lensModel);
-                return;
-            }
-            
-            CLGeocoder *geocoder = [[CLGeocoder alloc] init];
-            CLLocation *llocation = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
-            
-            [geocoder reverseGeocodeLocation:llocation completionHandler:^(NSArray *placemarks, NSError *error) {
-                        
-                if (error == nil && [placemarks count] > 0) {
-                    
-                    CLPlacemark *placemark = [placemarks lastObject];
-                    
-                    NSString *thoroughfare = @"";
-                    NSString *postalCode = @"";
-                    NSString *locality = @"";
-                    NSString *administrativeArea = @"";
-                    NSString *country = @"";
-                    
-                    if (placemark.thoroughfare) thoroughfare = placemark.thoroughfare;
-                    if (placemark.postalCode) postalCode = placemark.postalCode;
-                    if (placemark.locality) locality = placemark.locality;
-                    if (placemark.administrativeArea) administrativeArea = placemark.administrativeArea;
-                    if (placemark.country) country = placemark.country;
-                    
-                    location = [NSString stringWithFormat:@"%@ %@ %@ %@ %@", thoroughfare, postalCode, locality, administrativeArea, country];
-                    location = [location stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
-                    
-                    // GPS
-                    if ([location length] > 0) {
-                        
-                        [[NCManageDatabase shared] addGeocoderLocation:location placemarkAdministrativeArea:placemark.administrativeArea placemarkCountry:placemark.country placemarkLocality:placemark.locality placemarkPostalCode:placemark.postalCode placemarkThoroughfare:placemark.thoroughfare latitude:stringLatitude longitude:stringLongitude];
-                    }
-                    
-                    CFRelease(originalSource);
-                    CFRelease(imageProperties);
-                    CFRelease(fileProperties);
-                    completition(latitude, longitude, location, date, lensModel);
-                }
-            }];
-        } else {
-            CFRelease(originalSource);
-            CFRelease(imageProperties);
-            CFRelease(fileProperties);
-            completition(latitude, longitude, location, date, lensModel);
-        }
-    } else {
-        CFRelease(originalSource);
-        CFRelease(imageProperties);
-        CFRelease(fileProperties);
-        completition(latitude, longitude, location, date, lensModel);
-    }
 }
 }
 
 
 #pragma --------------------------------------------------------------------------------------------
 #pragma --------------------------------------------------------------------------------------------
@@ -1548,10 +1372,10 @@
 + (NSDate *)datetimeWithOutTime:(NSDate *)datDate
 + (NSDate *)datetimeWithOutTime:(NSDate *)datDate
 {
 {
     if (datDate == nil) return nil;
     if (datDate == nil) return nil;
-    
+
     NSDateComponents* comps = [[NSCalendar currentCalendar] components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:datDate];
     NSDateComponents* comps = [[NSCalendar currentCalendar] components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:datDate];
     datDate = [[NSCalendar currentCalendar] dateFromComponents:comps];
     datDate = [[NSCalendar currentCalendar] dateFromComponents:comps];
-    
+
     return datDate;
     return datDate;
 }
 }
 
 

+ 149 - 0
iOSClient/Utility/NCUtility+Exif.swift

@@ -0,0 +1,149 @@
+//
+//  NCUtility+Exif.swift
+//  Nextcloud
+//
+//  Created by Milen on 04.08.23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+public struct ExifData {
+    var colorModel: String?
+    var width: Int?
+    var height: Int?
+    var dpiWidth: Int?
+    var dpiHeight: Int?
+    var depth: Int?
+    var orientation: Int?
+    var apertureValue: Double?
+    var exposureValue: Int?
+    var shutterSpeedApex: Double?
+    var iso: Int?
+    var lensLength: Int?
+    var brightnessValue: String?
+    var dateTimeDigitized: String?
+    var dateTimeOriginal: String?
+    var offsetTime: String?
+    var offsetTimeDigitized: String?
+    var offsetTimeOriginal: String?
+    var make: String?
+    var model: String?
+    var software: String?
+    var tileLength: Double?
+    var tileWidth: Double?
+    var xResolution: Double?
+    var yResolution: Double?
+    var altitude: String?
+    var destBearing: String?
+    var hPositioningError: String?
+    var imgDirection: String?
+    var latitude: Double?
+    var longitude: Double?
+    var speed: Double?
+    var location: String?
+    var lensModel: String?
+    var date: Date?
+}
+
+extension NCUtility {
+    func getExif(metadata: tableMetadata, completion: @escaping (ExifData) -> Void) {
+        var data = ExifData()
+
+        writeExifFromMetadata(metadata: metadata, data: &data)
+
+        if let latitude = data.latitude, let longitude = data.longitude {
+            getLocation(latitude: latitude, longitude: longitude) { location in
+                data.location = location
+                completion(data)
+            }
+        }
+
+        if metadata.classFile != "image" || !CCUtility.fileProviderStorageExists(metadata) {
+            print("Storage exists or file is not an image")
+        }
+
+        let url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
+
+        guard let originalSource = CGImageSourceCreateWithURL(url as CFURL, nil),
+              let imageProperties = CGImageSourceCopyPropertiesAtIndex(originalSource, 0, nil) as NSDictionary? else {
+            print("Could not get image properties")
+            completion(data)
+            return
+        }
+
+        data.colorModel = imageProperties[kCGImagePropertyColorModel] as? String
+        data.height = imageProperties[kCGImagePropertyPixelWidth] as? Int
+        data.width = imageProperties[kCGImagePropertyPixelHeight] as? Int
+        data.dpiWidth = imageProperties[kCGImagePropertyDPIWidth] as? Int
+        data.dpiHeight = imageProperties[kCGImagePropertyDPIHeight] as? Int
+        data.depth = imageProperties[kCGImagePropertyDepth] as? Int
+        data.orientation = imageProperties[kCGImagePropertyOrientation] as? Int
+
+        if let tiffData = imageProperties[kCGImagePropertyTIFFDictionary] as? NSDictionary {
+            data.make = tiffData[kCGImagePropertyTIFFMake] as? String
+            data.model = tiffData[kCGImagePropertyTIFFModel] as? String
+            data.software = tiffData[kCGImagePropertyTIFFSoftware] as? String
+            data.tileLength = tiffData[kCGImagePropertyTIFFTileLength] as? Double
+            data.tileWidth = tiffData[kCGImagePropertyTIFFTileWidth] as? Double
+            data.xResolution = tiffData[kCGImagePropertyTIFFXResolution] as? Double
+            data.yResolution = tiffData[kCGImagePropertyTIFFYResolution] as? Double
+
+            let dateTime = tiffData[kCGImagePropertyTIFFDateTime] as? String
+            let dateFormatter = DateFormatter()
+            dateFormatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
+            data.date = dateFormatter.date(from: dateTime ?? "")
+        }
+
+        if let exifData = imageProperties[kCGImagePropertyExifDictionary] as? NSDictionary {
+            data.apertureValue = exifData[kCGImagePropertyExifFNumber] as? Double
+            data.exposureValue = exifData[kCGImagePropertyExifExposureBiasValue] as? Int
+            data.shutterSpeedApex = exifData[kCGImagePropertyExifShutterSpeedValue] as? Double
+            data.iso = (exifData[kCGImagePropertyExifISOSpeedRatings] as? [Int])?[0]
+            data.lensLength = exifData[kCGImagePropertyExifFocalLenIn35mmFilm] as? Int
+            data.brightnessValue = exifData[kCGImagePropertyExifBrightnessValue] as? String
+            data.dateTimeDigitized = exifData[kCGImagePropertyExifDateTimeDigitized] as? String
+            data.dateTimeOriginal = exifData[kCGImagePropertyExifDateTimeOriginal] as? String
+            data.offsetTime = exifData[kCGImagePropertyExifOffsetTime] as? String
+            data.offsetTimeDigitized = exifData[kCGImagePropertyExifOffsetTimeDigitized] as? String
+            data.offsetTimeOriginal = exifData[kCGImagePropertyExifOffsetTimeOriginal] as? String
+            data.lensModel = exifData[kCGImagePropertyExifLensModel] as? String
+        }
+
+        if let gpsData = imageProperties[kCGImagePropertyGPSDictionary] as? NSDictionary {
+            data.altitude = gpsData[kCGImagePropertyGPSAltitude] as? String
+            data.destBearing = gpsData[kCGImagePropertyGPSDestBearing] as? String
+            data.hPositioningError = gpsData[kCGImagePropertyGPSHPositioningError] as? String
+            data.imgDirection = gpsData[kCGImagePropertyGPSImgDirection] as? String
+            data.latitude = gpsData[kCGImagePropertyGPSLatitude] as? Double
+            data.longitude = gpsData[kCGImagePropertyGPSLongitude] as? Double
+            data.speed = gpsData[kCGImagePropertyGPSSpeed] as? Double
+        }
+
+        writeExifFromMetadata(metadata: metadata, data: &data)
+
+        if let latitude = data.latitude, let longitude = data.longitude {
+            getLocation(latitude: latitude, longitude: longitude) { location in
+                data.location = location
+                completion(data)
+            }
+        }
+
+        completion(data)
+    }
+
+    /**
+     Since non-downloaded images are usually thumbnails, the server sends some exif metadata of the real image. This function writes that data to the local exif object, if that data doesn't exist already.
+     */
+    private func writeExifFromMetadata(metadata: tableMetadata, data: inout ExifData) {
+        if metadata.latitude != 0, metadata.longitude != 0 {
+            if data.latitude == nil { data.latitude = metadata.latitude }
+            if data.longitude == nil { data.longitude = metadata.longitude }
+        }
+
+        if metadata.height != 0, metadata.width != 0 {
+            if data.height == nil { data.height = metadata.height }
+            if data.width == nil { data.width = metadata.width }
+        }
+    }
+}

+ 162 - 147
iOSClient/Utility/NCUtility.swift

@@ -13,7 +13,7 @@
 //  (at your option) any later version.
 //  (at your option) any later version.
 //
 //
 //  This program is distributed in the hope that it will be useful,
 //  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  but WITHOUT ANY WARRANTY without even the implied warranty of
 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 //  GNU General Public License for more details.
 //  GNU General Public License for more details.
 //
 //
@@ -27,6 +27,7 @@ import PDFKit
 import Accelerate
 import Accelerate
 import CoreMedia
 import CoreMedia
 import Photos
 import Photos
+import Alamofire
 
 
 #if !EXTENSION
 #if !EXTENSION
 import SVGKit
 import SVGKit
@@ -40,37 +41,37 @@ class NCUtility: NSObject {
 
 
 #if !EXTENSION
 #if !EXTENSION
     func convertSVGtoPNGWriteToUserData(svgUrlString: String, fileName: String? = nil, width: CGFloat? = nil, rewrite: Bool, account: String, id: Int? = nil, completion: @escaping (_ imageNamePath: String?, _ id: Int?) -> Void) {
     func convertSVGtoPNGWriteToUserData(svgUrlString: String, fileName: String? = nil, width: CGFloat? = nil, rewrite: Bool, account: String, id: Int? = nil, completion: @escaping (_ imageNamePath: String?, _ id: Int?) -> Void) {
-
+        
         var fileNamePNG = ""
         var fileNamePNG = ""
-
+        
         guard let svgUrlString = svgUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
         guard let svgUrlString = svgUrlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
               let iconURL = URL(string: svgUrlString) else {
               let iconURL = URL(string: svgUrlString) else {
             return completion(nil, id)
             return completion(nil, id)
         }
         }
-
+        
         if let fileName = fileName {
         if let fileName = fileName {
             fileNamePNG = fileName
             fileNamePNG = fileName
         } else {
         } else {
             fileNamePNG = iconURL.deletingPathExtension().lastPathComponent + ".png"
             fileNamePNG = iconURL.deletingPathExtension().lastPathComponent + ".png"
         }
         }
-
+        
         let imageNamePath = CCUtility.getDirectoryUserData() + "/" + fileNamePNG
         let imageNamePath = CCUtility.getDirectoryUserData() + "/" + fileNamePNG
-
+        
         if !FileManager.default.fileExists(atPath: imageNamePath) || rewrite == true {
         if !FileManager.default.fileExists(atPath: imageNamePath) || rewrite == true {
-
+            
             NextcloudKit.shared.downloadContent(serverUrl: iconURL.absoluteString) { _, data, error in
             NextcloudKit.shared.downloadContent(serverUrl: iconURL.absoluteString) { _, data, error in
-
+                
                 if error == .success && data != nil {
                 if error == .success && data != nil {
-
+                    
                     if let image = UIImage(data: data!) {
                     if let image = UIImage(data: data!) {
-
+                        
                         var newImage: UIImage = image
                         var newImage: UIImage = image
-
+                        
                         if width != nil {
                         if width != nil {
-
+                            
                             let ratio = image.size.height / image.size.width
                             let ratio = image.size.height / image.size.width
                             let newSize = CGSize(width: width!, height: width! * ratio)
                             let newSize = CGSize(width: width!, height: width! * ratio)
-
+                            
                             let renderFormat = UIGraphicsImageRendererFormat.default()
                             let renderFormat = UIGraphicsImageRendererFormat.default()
                             renderFormat.opaque = false
                             renderFormat.opaque = false
                             let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
                             let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
@@ -79,108 +80,108 @@ class NCUtility: NSObject {
                                 image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
                                 image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
                             }
                             }
                         }
                         }
-
+                        
                         guard let pngImageData = newImage.pngData() else {
                         guard let pngImageData = newImage.pngData() else {
                             return completion(nil, id)
                             return completion(nil, id)
                         }
                         }
-
+                        
                         try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
                         try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
-
+                        
                         return completion(imageNamePath, id)
                         return completion(imageNamePath, id)
-
+                        
                     } else {
                     } else {
-
+                        
                         guard let svgImage: SVGKImage = SVGKImage(data: data) else {
                         guard let svgImage: SVGKImage = SVGKImage(data: data) else {
                             return completion(nil, id)
                             return completion(nil, id)
                         }
                         }
-
+                        
                         if width != nil {
                         if width != nil {
                             let scale = svgImage.size.height / svgImage.size.width
                             let scale = svgImage.size.height / svgImage.size.width
                             svgImage.size = CGSize(width: width!, height: width! * scale)
                             svgImage.size = CGSize(width: width!, height: width! * scale)
                         }
                         }
-
+                        
                         guard let image: UIImage = svgImage.uiImage else {
                         guard let image: UIImage = svgImage.uiImage else {
                             return completion(nil, id)
                             return completion(nil, id)
                         }
                         }
                         guard let pngImageData = image.pngData() else {
                         guard let pngImageData = image.pngData() else {
                             return completion(nil, id)
                             return completion(nil, id)
                         }
                         }
-
+                        
                         try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
                         try? pngImageData.write(to: URL(fileURLWithPath: imageNamePath))
-
+                        
                         return completion(imageNamePath, id)
                         return completion(imageNamePath, id)
                     }
                     }
                 } else {
                 } else {
                     return completion(nil, id)
                     return completion(nil, id)
                 }
                 }
             }
             }
-
+            
         } else {
         } else {
             return completion(imageNamePath, id)
             return completion(imageNamePath, id)
         }
         }
     }
     }
 #endif
 #endif
-
+    
     @objc func isSimulatorOrTestFlight() -> Bool {
     @objc func isSimulatorOrTestFlight() -> Bool {
         guard let path = Bundle.main.appStoreReceiptURL?.path else {
         guard let path = Bundle.main.appStoreReceiptURL?.path else {
             return false
             return false
         }
         }
         return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
         return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
     }
     }
-
+    
     @objc func isSimulator() -> Bool {
     @objc func isSimulator() -> Bool {
         guard let path = Bundle.main.appStoreReceiptURL?.path else {
         guard let path = Bundle.main.appStoreReceiptURL?.path else {
             return false
             return false
         }
         }
         return path.contains("CoreSimulator")
         return path.contains("CoreSimulator")
     }
     }
-
+    
     @objc func isRichDocument(_ metadata: tableMetadata) -> Bool {
     @objc func isRichDocument(_ metadata: tableMetadata) -> Bool {
-
+        
         guard let mimeType = CCUtility.getMimeType(metadata.fileNameView) else {
         guard let mimeType = CCUtility.getMimeType(metadata.fileNameView) else {
             return false
             return false
         }
         }
-
+        
         // contentype
         // contentype
         for richdocumentMimetype: String in NCGlobal.shared.capabilityRichdocumentsMimetypes {
         for richdocumentMimetype: String in NCGlobal.shared.capabilityRichdocumentsMimetypes {
             if richdocumentMimetype.contains(metadata.contentType) || metadata.contentType == "text/plain" {
             if richdocumentMimetype.contains(metadata.contentType) || metadata.contentType == "text/plain" {
                 return true
                 return true
             }
             }
         }
         }
-
+        
         // mimetype
         // mimetype
         if NCGlobal.shared.capabilityRichdocumentsMimetypes.count > 0 && mimeType.components(separatedBy: ".").count > 2 {
         if NCGlobal.shared.capabilityRichdocumentsMimetypes.count > 0 && mimeType.components(separatedBy: ".").count > 2 {
-
+            
             let mimeTypeArray = mimeType.components(separatedBy: ".")
             let mimeTypeArray = mimeType.components(separatedBy: ".")
             let mimeType = mimeTypeArray[mimeTypeArray.count - 2] + "." + mimeTypeArray[mimeTypeArray.count - 1]
             let mimeType = mimeTypeArray[mimeTypeArray.count - 2] + "." + mimeTypeArray[mimeTypeArray.count - 1]
-
+            
             for richdocumentMimetype: String in NCGlobal.shared.capabilityRichdocumentsMimetypes {
             for richdocumentMimetype: String in NCGlobal.shared.capabilityRichdocumentsMimetypes {
                 if richdocumentMimetype.contains(mimeType) {
                 if richdocumentMimetype.contains(mimeType) {
                     return true
                     return true
                 }
                 }
             }
             }
         }
         }
-
+        
         return false
         return false
     }
     }
-
+    
     @objc func isDirectEditing(account: String, contentType: String) -> [String] {
     @objc func isDirectEditing(account: String, contentType: String) -> [String] {
-
+        
         var editor: [String] = []
         var editor: [String] = []
-
+        
         guard let results = NCManageDatabase.shared.getDirectEditingEditors(account: account) else {
         guard let results = NCManageDatabase.shared.getDirectEditingEditors(account: account) else {
             return editor
             return editor
         }
         }
-
+        
         for result: tableDirectEditingEditors in results {
         for result: tableDirectEditingEditors in results {
             for mimetype in result.mimetypes {
             for mimetype in result.mimetypes {
                 if mimetype == contentType {
                 if mimetype == contentType {
                     editor.append(result.editor)
                     editor.append(result.editor)
                 }
                 }
-
+                
                 // HARDCODE
                 // HARDCODE
                 // https://github.com/nextcloud/text/issues/913
                 // https://github.com/nextcloud/text/issues/913
-
+                
                 if mimetype == "text/markdown" && contentType == "text/x-markdown" {
                 if mimetype == "text/markdown" && contentType == "text/x-markdown" {
                     editor.append(result.editor)
                     editor.append(result.editor)
                 }
                 }
@@ -194,37 +195,37 @@ class NCUtility: NSObject {
                 }
                 }
             }
             }
         }
         }
-
+        
         // HARDCODE
         // HARDCODE
         // if editor.count == 0 {
         // if editor.count == 0 {
         //    editor.append(NCGlobal.shared.editorText)
         //    editor.append(NCGlobal.shared.editorText)
         // }
         // }
-
+        
         return Array(Set(editor))
         return Array(Set(editor))
     }
     }
-
+    
 #if !EXTENSION
 #if !EXTENSION
     @objc func removeAllSettings() {
     @objc func removeAllSettings() {
-
+        
         URLCache.shared.memoryCapacity = 0
         URLCache.shared.memoryCapacity = 0
         URLCache.shared.diskCapacity = 0
         URLCache.shared.diskCapacity = 0
-
+        
         NCManageDatabase.shared.clearDatabase(account: nil, removeAccount: true)
         NCManageDatabase.shared.clearDatabase(account: nil, removeAccount: true)
-
+        
         CCUtility.removeGroupDirectoryProviderStorage()
         CCUtility.removeGroupDirectoryProviderStorage()
         CCUtility.removeGroupLibraryDirectory()
         CCUtility.removeGroupLibraryDirectory()
-
+        
         CCUtility.removeDocumentsDirectory()
         CCUtility.removeDocumentsDirectory()
         CCUtility.removeTemporaryDirectory()
         CCUtility.removeTemporaryDirectory()
-
+        
         CCUtility.createDirectoryStandard()
         CCUtility.createDirectoryStandard()
-
+        
         CCUtility.deleteAllChainStore()
         CCUtility.deleteAllChainStore()
     }
     }
 #endif
 #endif
-
+    
     @objc func permissionsContainsString(_ metadataPermissions: String, permissions: String) -> Bool {
     @objc func permissionsContainsString(_ metadataPermissions: String, permissions: String) -> Bool {
-
+        
         for char in permissions {
         for char in permissions {
             if metadataPermissions.contains(char) == false {
             if metadataPermissions.contains(char) == false {
                 return false
                 return false
@@ -232,12 +233,12 @@ class NCUtility: NSObject {
         }
         }
         return true
         return true
     }
     }
-
+    
     @objc func getCustomUserAgentNCText() -> String {
     @objc func getCustomUserAgentNCText() -> String {
         let userAgent: String = CCUtility.getUserAgent()
         let userAgent: String = CCUtility.getUserAgent()
         if UIDevice.current.userInterfaceIdiom == .phone {
         if UIDevice.current.userInterfaceIdiom == .phone {
             // NOTE: Hardcoded (May 2022)
             // NOTE: Hardcoded (May 2022)
-            // Tested for iPhone SE (1st), iOS 12; iPhone Pro Max, iOS 15.4
+            // Tested for iPhone SE (1st), iOS 12 iPhone Pro Max, iOS 15.4
             // 605.1.15 = WebKit build version
             // 605.1.15 = WebKit build version
             // 15E148 = frozen iOS build number according to: https://chromestatus.com/feature/4558585463832576
             // 15E148 = frozen iOS build number according to: https://chromestatus.com/feature/4558585463832576
             return userAgent + " " + "AppleWebKit/605.1.15 Mobile/15E148"
             return userAgent + " " + "AppleWebKit/605.1.15 Mobile/15E148"
@@ -245,9 +246,9 @@ class NCUtility: NSObject {
             return userAgent
             return userAgent
         }
         }
     }
     }
-
+    
     @objc func getCustomUserAgentOnlyOffice() -> String {
     @objc func getCustomUserAgentOnlyOffice() -> String {
-
+        
         let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")!
         let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")!
         if UIDevice.current.userInterfaceIdiom == .pad {
         if UIDevice.current.userInterfaceIdiom == .pad {
             return "Mozilla/5.0 (iPad) Nextcloud-iOS/\(appVersion)"
             return "Mozilla/5.0 (iPad) Nextcloud-iOS/\(appVersion)"
@@ -255,44 +256,44 @@ class NCUtility: NSObject {
             return "Mozilla/5.0 (iPhone) Mobile Nextcloud-iOS/\(appVersion)"
             return "Mozilla/5.0 (iPhone) Mobile Nextcloud-iOS/\(appVersion)"
         }
         }
     }
     }
-
+    
     @objc func pdfThumbnail(url: URL, width: CGFloat = 240) -> UIImage? {
     @objc func pdfThumbnail(url: URL, width: CGFloat = 240) -> UIImage? {
-
+        
         guard let data = try? Data(contentsOf: url), let page = PDFDocument(data: data)?.page(at: 0) else {
         guard let data = try? Data(contentsOf: url), let page = PDFDocument(data: data)?.page(at: 0) else {
             return nil
             return nil
         }
         }
-
+        
         let pageSize = page.bounds(for: .mediaBox)
         let pageSize = page.bounds(for: .mediaBox)
         let pdfScale = width / pageSize.width
         let pdfScale = width / pageSize.width
-
+        
         // Apply if you're displaying the thumbnail on screen
         // Apply if you're displaying the thumbnail on screen
         let scale = UIScreen.main.scale * pdfScale
         let scale = UIScreen.main.scale * pdfScale
         let screenSize = CGSize(width: pageSize.width * scale, height: pageSize.height * scale)
         let screenSize = CGSize(width: pageSize.width * scale, height: pageSize.height * scale)
-
+        
         return page.thumbnail(of: screenSize, for: .mediaBox)
         return page.thumbnail(of: screenSize, for: .mediaBox)
     }
     }
-
+    
     @objc func isQuickLookDisplayable(metadata: tableMetadata) -> Bool {
     @objc func isQuickLookDisplayable(metadata: tableMetadata) -> Bool {
         return true
         return true
     }
     }
-
+    
     @objc func ocIdToFileId(ocId: String?) -> String? {
     @objc func ocIdToFileId(ocId: String?) -> String? {
-
+        
         guard let ocId = ocId else { return nil }
         guard let ocId = ocId else { return nil }
-
+        
         let items = ocId.components(separatedBy: "oc")
         let items = ocId.components(separatedBy: "oc")
         if items.count < 2 { return nil }
         if items.count < 2 { return nil }
         guard let intFileId = Int(items[0]) else { return nil }
         guard let intFileId = Int(items[0]) else { return nil }
         return String(intFileId)
         return String(intFileId)
     }
     }
-
+    
     func getUserStatus(userIcon: String?, userStatus: String?, userMessage: String?) -> (onlineStatus: UIImage?, statusMessage: String, descriptionMessage: String) {
     func getUserStatus(userIcon: String?, userStatus: String?, userMessage: String?) -> (onlineStatus: UIImage?, statusMessage: String, descriptionMessage: String) {
-
+        
         var onlineStatus: UIImage?
         var onlineStatus: UIImage?
         var statusMessage: String = ""
         var statusMessage: String = ""
         var descriptionMessage: String = ""
         var descriptionMessage: String = ""
         var messageUserDefined: String = ""
         var messageUserDefined: String = ""
-
+        
         if userStatus?.lowercased() == "online" {
         if userStatus?.lowercased() == "online" {
             onlineStatus = UIImage(named: "circle_fill")!.image(color: UIColor(red: 103.0/255.0, green: 176.0/255.0, blue: 134.0/255.0, alpha: 1.0), size: 50)
             onlineStatus = UIImage(named: "circle_fill")!.image(color: UIColor(red: 103.0/255.0, green: 176.0/255.0, blue: 134.0/255.0, alpha: 1.0), size: 50)
             messageUserDefined = NSLocalizedString("_online_", comment: "")
             messageUserDefined = NSLocalizedString("_online_", comment: "")
@@ -311,7 +312,7 @@ class NCUtility: NSObject {
             messageUserDefined = NSLocalizedString("_invisible_", comment: "")
             messageUserDefined = NSLocalizedString("_invisible_", comment: "")
             descriptionMessage = NSLocalizedString("_invisible_description_", comment: "")
             descriptionMessage = NSLocalizedString("_invisible_description_", comment: "")
         }
         }
-
+        
         if let userIcon = userIcon {
         if let userIcon = userIcon {
             statusMessage = userIcon + " "
             statusMessage = userIcon + " "
         }
         }
@@ -322,18 +323,18 @@ class NCUtility: NSObject {
         if statusMessage == "" {
         if statusMessage == "" {
             statusMessage = messageUserDefined
             statusMessage = messageUserDefined
         }
         }
-
+        
         return(onlineStatus, statusMessage, descriptionMessage)
         return(onlineStatus, statusMessage, descriptionMessage)
     }
     }
-
+    
     func imageFromVideo(url: URL, at time: TimeInterval) -> UIImage? {
     func imageFromVideo(url: URL, at time: TimeInterval) -> UIImage? {
-
+        
         let asset = AVURLAsset(url: url)
         let asset = AVURLAsset(url: url)
         let assetIG = AVAssetImageGenerator(asset: asset)
         let assetIG = AVAssetImageGenerator(asset: asset)
-
+        
         assetIG.appliesPreferredTrackTransform = true
         assetIG.appliesPreferredTrackTransform = true
         assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
         assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
-
+        
         let cmTime = CMTime(seconds: time, preferredTimescale: 60)
         let cmTime = CMTime(seconds: time, preferredTimescale: 60)
         let thumbnailImageRef: CGImage
         let thumbnailImageRef: CGImage
         do {
         do {
@@ -342,19 +343,19 @@ class NCUtility: NSObject {
             print("Error: \(error)")
             print("Error: \(error)")
             return nil
             return nil
         }
         }
-
+        
         return UIImage(cgImage: thumbnailImageRef)
         return UIImage(cgImage: thumbnailImageRef)
     }
     }
-
+    
     func imageFromVideo(url: URL, at time: TimeInterval, completion: @escaping (UIImage?) -> Void) {
     func imageFromVideo(url: URL, at time: TimeInterval, completion: @escaping (UIImage?) -> Void) {
         DispatchQueue.global().async {
         DispatchQueue.global().async {
-
+            
             let asset = AVURLAsset(url: url)
             let asset = AVURLAsset(url: url)
             let assetIG = AVAssetImageGenerator(asset: asset)
             let assetIG = AVAssetImageGenerator(asset: asset)
-
+            
             assetIG.appliesPreferredTrackTransform = true
             assetIG.appliesPreferredTrackTransform = true
             assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
             assetIG.apertureMode = AVAssetImageGenerator.ApertureMode.encodedPixels
-
+            
             let cmTime = CMTime(seconds: time, preferredTimescale: 60)
             let cmTime = CMTime(seconds: time, preferredTimescale: 60)
             let thumbnailImageRef: CGImage
             let thumbnailImageRef: CGImage
             do {
             do {
@@ -363,46 +364,46 @@ class NCUtility: NSObject {
                 print("Error: \(error)")
                 print("Error: \(error)")
                 return completion(nil)
                 return completion(nil)
             }
             }
-
+            
             DispatchQueue.main.async {
             DispatchQueue.main.async {
                 completion(UIImage(cgImage: thumbnailImageRef))
                 completion(UIImage(cgImage: thumbnailImageRef))
             }
             }
         }
         }
     }
     }
-
+    
     func createImageFrom(fileNameView: String, ocId: String, etag: String, classFile: String) {
     func createImageFrom(fileNameView: String, ocId: String, etag: String, classFile: String) {
-
+        
         var originalImage, scaleImagePreview, scaleImageIcon: UIImage?
         var originalImage, scaleImagePreview, scaleImageIcon: UIImage?
-
+        
         let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)!
         let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)!
         let fileNamePathPreview = CCUtility.getDirectoryProviderStoragePreviewOcId(ocId, etag: etag)!
         let fileNamePathPreview = CCUtility.getDirectoryProviderStoragePreviewOcId(ocId, etag: etag)!
         let fileNamePathIcon = CCUtility.getDirectoryProviderStorageIconOcId(ocId, etag: etag)!
         let fileNamePathIcon = CCUtility.getDirectoryProviderStorageIconOcId(ocId, etag: etag)!
-
+        
         if CCUtility.fileProviderStorageSize(ocId, fileNameView: fileNameView) > 0 && FileManager().fileExists(atPath: fileNamePathPreview) && FileManager().fileExists(atPath: fileNamePathIcon) { return }
         if CCUtility.fileProviderStorageSize(ocId, fileNameView: fileNameView) > 0 && FileManager().fileExists(atPath: fileNamePathPreview) && FileManager().fileExists(atPath: fileNamePathIcon) { return }
         if classFile != NKCommon.TypeClassFile.image.rawValue && classFile != NKCommon.TypeClassFile.video.rawValue { return }
         if classFile != NKCommon.TypeClassFile.image.rawValue && classFile != NKCommon.TypeClassFile.video.rawValue { return }
-
+        
         if classFile == NKCommon.TypeClassFile.image.rawValue {
         if classFile == NKCommon.TypeClassFile.image.rawValue {
-
+            
             originalImage = UIImage(contentsOfFile: fileNamePath)
             originalImage = UIImage(contentsOfFile: fileNamePath)
-
+            
             scaleImagePreview = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizePreview, height: NCGlobal.shared.sizePreview))
             scaleImagePreview = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizePreview, height: NCGlobal.shared.sizePreview))
             scaleImageIcon = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon))
             scaleImageIcon = originalImage?.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon))
-
+            
             try? scaleImagePreview?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
             try? scaleImagePreview?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
             try? scaleImageIcon?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
             try? scaleImageIcon?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
-
+            
         } else if classFile == NKCommon.TypeClassFile.video.rawValue {
         } else if classFile == NKCommon.TypeClassFile.video.rawValue {
-
+            
             let videoPath = NSTemporaryDirectory()+"tempvideo.mp4"
             let videoPath = NSTemporaryDirectory()+"tempvideo.mp4"
             NCUtilityFileSystem.shared.linkItem(atPath: fileNamePath, toPath: videoPath)
             NCUtilityFileSystem.shared.linkItem(atPath: fileNamePath, toPath: videoPath)
-
+            
             originalImage = imageFromVideo(url: URL(fileURLWithPath: videoPath), at: 0)
             originalImage = imageFromVideo(url: URL(fileURLWithPath: videoPath), at: 0)
-
+            
             try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
             try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathPreview))
             try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
             try? originalImage?.jpegData(compressionQuality: 0.7)?.write(to: URL(fileURLWithPath: fileNamePathIcon))
         }
         }
     }
     }
-
+    
     @objc func getVersionApp(withBuild: Bool = true) -> String {
     @objc func getVersionApp(withBuild: Bool = true) -> String {
         if let dictionary = Bundle.main.infoDictionary {
         if let dictionary = Bundle.main.infoDictionary {
             if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] {
             if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] {
@@ -415,11 +416,11 @@ class NCUtility: NSObject {
         }
         }
         return ""
         return ""
     }
     }
-
+    
     func loadImage(named imageName: String, color: UIColor = UIColor.systemGray, size: CGFloat = 50, symbolConfiguration: Any? = nil, renderingMode: UIImage.RenderingMode = .alwaysOriginal) -> UIImage {
     func loadImage(named imageName: String, color: UIColor = UIColor.systemGray, size: CGFloat = 50, symbolConfiguration: Any? = nil, renderingMode: UIImage.RenderingMode = .alwaysOriginal) -> UIImage {
-
+        
         var image: UIImage?
         var image: UIImage?
-
+        
         // see https://stackoverflow.com/questions/71764255
         // see https://stackoverflow.com/questions/71764255
         let sfSymbolName = imageName.replacingOccurrences(of: "_", with: ".")
         let sfSymbolName = imageName.replacingOccurrences(of: "_", with: ".")
         if let symbolConfiguration = symbolConfiguration {
         if let symbolConfiguration = symbolConfiguration {
@@ -433,15 +434,15 @@ class NCUtility: NSObject {
         if let image = image {
         if let image = image {
             return image
             return image
         }
         }
-
+        
         return  UIImage(named: "file")!.image(color: color, size: size)
         return  UIImage(named: "file")!.image(color: color, size: size)
     }
     }
-
+    
     @objc func loadUserImage(for user: String, displayName: String?, userBaseUrl: NCUserBaseUrl) -> UIImage {
     @objc func loadUserImage(for user: String, displayName: String?, userBaseUrl: NCUserBaseUrl) -> UIImage {
-
+        
         let fileName = userBaseUrl.userBaseUrl + "-" + user + ".png"
         let fileName = userBaseUrl.userBaseUrl + "-" + user + ".png"
         let localFilePath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
         let localFilePath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
-
+        
         if let localImage = UIImage(contentsOfFile: localFilePath) {
         if let localImage = UIImage(contentsOfFile: localFilePath) {
             return createAvatar(image: localImage, size: 30)
             return createAvatar(image: localImage, size: 30)
         } else if let loadedAvatar = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
         } else if let loadedAvatar = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
@@ -450,27 +451,27 @@ class NCUtility: NSObject {
             return avatarImg
             return avatarImg
         } else { return getDefaultUserIcon() }
         } else { return getDefaultUserIcon() }
     }
     }
-
+    
     func getDefaultUserIcon() -> UIImage {
     func getDefaultUserIcon() -> UIImage {
-            
+        
         let config = UIImage.SymbolConfiguration(pointSize: 30)
         let config = UIImage.SymbolConfiguration(pointSize: 30)
         return NCUtility.shared.loadImage(named: "person.crop.circle", symbolConfiguration: config)
         return NCUtility.shared.loadImage(named: "person.crop.circle", symbolConfiguration: config)
     }
     }
-
+    
     @objc func createAvatar(image: UIImage, size: CGFloat) -> UIImage {
     @objc func createAvatar(image: UIImage, size: CGFloat) -> UIImage {
-
+        
         var avatarImage = image
         var avatarImage = image
         let rect = CGRect(x: 0, y: 0, width: size, height: size)
         let rect = CGRect(x: 0, y: 0, width: size, height: size)
-
+        
         UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
         UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
         UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
         UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
         avatarImage.draw(in: rect)
         avatarImage.draw(in: rect)
         avatarImage = UIGraphicsGetImageFromCurrentImageContext() ?? image
         avatarImage = UIGraphicsGetImageFromCurrentImageContext() ?? image
         UIGraphicsEndImageContext()
         UIGraphicsEndImageContext()
-
+        
         return avatarImage
         return avatarImage
     }
     }
-
+    
     func createAvatar(displayName: String, size: CGFloat) -> UIImage? {
     func createAvatar(displayName: String, size: CGFloat) -> UIImage? {
         guard let initials = displayName.uppercaseInitials else {
         guard let initials = displayName.uppercaseInitials else {
             return nil
             return nil
@@ -478,7 +479,7 @@ class NCUtility: NSObject {
         let userColor = NCGlobal.shared.usernameToColor(displayName)
         let userColor = NCGlobal.shared.usernameToColor(displayName)
         let rect = CGRect(x: 0, y: 0, width: size, height: size)
         let rect = CGRect(x: 0, y: 0, width: size, height: size)
         var avatarImage: UIImage?
         var avatarImage: UIImage?
-
+        
         UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
         UIGraphicsBeginImageContextWithOptions(rect.size, false, 3.0)
         let context = UIGraphicsGetCurrentContext()
         let context = UIGraphicsGetCurrentContext()
         UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
         UIBezierPath(roundedRect: rect, cornerRadius: rect.size.height).addClip()
@@ -493,16 +494,16 @@ class NCUtility: NSObject {
                 withAttributes: [NSAttributedString.Key.paragraphStyle: textStyle])
                 withAttributes: [NSAttributedString.Key.paragraphStyle: textStyle])
         avatarImage = UIGraphicsGetImageFromCurrentImageContext()
         avatarImage = UIGraphicsGetImageFromCurrentImageContext()
         UIGraphicsEndImageContext()
         UIGraphicsEndImageContext()
-
+        
         return avatarImage
         return avatarImage
     }
     }
-
+    
     /*
     /*
-    Facebook's comparison algorithm:
-    */
-
+     Facebook's comparison algorithm:
+     */
+    
     func compare(tolerance: Float, expected: Data, observed: Data) throws -> Bool {
     func compare(tolerance: Float, expected: Data, observed: Data) throws -> Bool {
-
+        
         enum customError: Error {
         enum customError: Error {
             case unableToGetUIImageFromData
             case unableToGetUIImageFromData
             case unableToGetCGImageFromData
             case unableToGetCGImageFromData
@@ -510,7 +511,7 @@ class NCUtility: NSObject {
             case imagesHasDifferentSizes
             case imagesHasDifferentSizes
             case unableToInitializeContext
             case unableToInitializeContext
         }
         }
-
+        
         guard let expectedUIImage = UIImage(data: expected), let observedUIImage = UIImage(data: observed) else {
         guard let expectedUIImage = UIImage(data: expected), let observedUIImage = UIImage(data: observed) else {
             throw customError.unableToGetUIImageFromData
             throw customError.unableToGetUIImageFromData
         }
         }
@@ -525,17 +526,17 @@ class NCUtility: NSObject {
         }
         }
         let imageSize = CGSize(width: expectedCGImage.width, height: expectedCGImage.height)
         let imageSize = CGSize(width: expectedCGImage.width, height: expectedCGImage.height)
         let numberOfPixels = Int(imageSize.width * imageSize.height)
         let numberOfPixels = Int(imageSize.width * imageSize.height)
-
+        
         // Checking that our `UInt32` buffer has same number of bytes as image has.
         // Checking that our `UInt32` buffer has same number of bytes as image has.
         let bytesPerRow = min(expectedCGImage.bytesPerRow, observedCGImage.bytesPerRow)
         let bytesPerRow = min(expectedCGImage.bytesPerRow, observedCGImage.bytesPerRow)
         assert(MemoryLayout<UInt32>.stride == bytesPerRow / Int(imageSize.width))
         assert(MemoryLayout<UInt32>.stride == bytesPerRow / Int(imageSize.width))
-
+        
         let expectedPixels = UnsafeMutablePointer<UInt32>.allocate(capacity: numberOfPixels)
         let expectedPixels = UnsafeMutablePointer<UInt32>.allocate(capacity: numberOfPixels)
         let observedPixels = UnsafeMutablePointer<UInt32>.allocate(capacity: numberOfPixels)
         let observedPixels = UnsafeMutablePointer<UInt32>.allocate(capacity: numberOfPixels)
-
+        
         let expectedPixelsRaw = UnsafeMutableRawPointer(expectedPixels)
         let expectedPixelsRaw = UnsafeMutableRawPointer(expectedPixels)
         let observedPixelsRaw = UnsafeMutableRawPointer(observedPixels)
         let observedPixelsRaw = UnsafeMutableRawPointer(observedPixels)
-
+        
         let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
         let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
         guard let expectedContext = CGContext(data: expectedPixelsRaw, width: Int(imageSize.width), height: Int(imageSize.height),
         guard let expectedContext = CGContext(data: expectedPixelsRaw, width: Int(imageSize.width), height: Int(imageSize.height),
                                               bitsPerComponent: expectedCGImage.bitsPerComponent, bytesPerRow: bytesPerRow,
                                               bitsPerComponent: expectedCGImage.bitsPerComponent, bytesPerRow: bytesPerRow,
@@ -551,13 +552,13 @@ class NCUtility: NSObject {
             observedPixels.deallocate()
             observedPixels.deallocate()
             throw customError.unableToInitializeContext
             throw customError.unableToInitializeContext
         }
         }
-
+        
         expectedContext.draw(expectedCGImage, in: CGRect(origin: .zero, size: imageSize))
         expectedContext.draw(expectedCGImage, in: CGRect(origin: .zero, size: imageSize))
         observedContext.draw(observedCGImage, in: CGRect(origin: .zero, size: imageSize))
         observedContext.draw(observedCGImage, in: CGRect(origin: .zero, size: imageSize))
-
+        
         let expectedBuffer = UnsafeBufferPointer(start: expectedPixels, count: numberOfPixels)
         let expectedBuffer = UnsafeBufferPointer(start: expectedPixels, count: numberOfPixels)
         let observedBuffer = UnsafeBufferPointer(start: observedPixels, count: numberOfPixels)
         let observedBuffer = UnsafeBufferPointer(start: observedPixels, count: numberOfPixels)
-
+        
         var isEqual = true
         var isEqual = true
         if tolerance == 0 {
         if tolerance == 0 {
             isEqual = expectedBuffer.elementsEqual(observedBuffer)
             isEqual = expectedBuffer.elementsEqual(observedBuffer)
@@ -574,50 +575,50 @@ class NCUtility: NSObject {
                 }
                 }
             }
             }
         }
         }
-
+        
         expectedPixels.deallocate()
         expectedPixels.deallocate()
         observedPixels.deallocate()
         observedPixels.deallocate()
-
+        
         return isEqual
         return isEqual
     }
     }
-
+    
     func stringFromTime(_ time: CMTime) -> String {
     func stringFromTime(_ time: CMTime) -> String {
-
+        
         let interval = Int(CMTimeGetSeconds(time))
         let interval = Int(CMTimeGetSeconds(time))
-
+        
         let seconds = interval % 60
         let seconds = interval % 60
         let minutes = (interval / 60) % 60
         let minutes = (interval / 60) % 60
         let hours = (interval / 3600)
         let hours = (interval / 3600)
-
+        
         if hours > 0 {
         if hours > 0 {
             return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
             return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
         } else {
         } else {
             return String(format: "%02d:%02d", minutes, seconds)
             return String(format: "%02d:%02d", minutes, seconds)
         }
         }
     }
     }
-
+    
     func colorNavigationController(_ navigationController: UINavigationController?, backgroundColor: UIColor, titleColor: UIColor, tintColor: UIColor?, withoutShadow: Bool) {
     func colorNavigationController(_ navigationController: UINavigationController?, backgroundColor: UIColor, titleColor: UIColor, tintColor: UIColor?, withoutShadow: Bool) {
-
+        
         let appearance = UINavigationBarAppearance()
         let appearance = UINavigationBarAppearance()
         appearance.titleTextAttributes = [.foregroundColor: titleColor]
         appearance.titleTextAttributes = [.foregroundColor: titleColor]
         appearance.largeTitleTextAttributes = [.foregroundColor: titleColor]
         appearance.largeTitleTextAttributes = [.foregroundColor: titleColor]
-
+        
         if withoutShadow {
         if withoutShadow {
             appearance.shadowColor = .clear
             appearance.shadowColor = .clear
             appearance.shadowImage = UIImage()
             appearance.shadowImage = UIImage()
         }
         }
-
+        
         if let tintColor = tintColor {
         if let tintColor = tintColor {
             navigationController?.navigationBar.tintColor = tintColor
             navigationController?.navigationBar.tintColor = tintColor
         }
         }
-
+        
         navigationController?.view.backgroundColor = backgroundColor
         navigationController?.view.backgroundColor = backgroundColor
         navigationController?.navigationBar.barTintColor = titleColor
         navigationController?.navigationBar.barTintColor = titleColor
         navigationController?.navigationBar.standardAppearance = appearance
         navigationController?.navigationBar.standardAppearance = appearance
         navigationController?.navigationBar.compactAppearance = appearance
         navigationController?.navigationBar.compactAppearance = appearance
         navigationController?.navigationBar.scrollEdgeAppearance = appearance
         navigationController?.navigationBar.scrollEdgeAppearance = appearance
     }
     }
-
+    
     func getEncondingDataType(data: Data) -> String.Encoding? {
     func getEncondingDataType(data: Data) -> String.Encoding? {
         if let _ = String(data: data, encoding: .utf8) {
         if let _ = String(data: data, encoding: .utf8) {
             return .utf8
             return .utf8
@@ -687,14 +688,14 @@ class NCUtility: NSObject {
         }
         }
         return nil
         return nil
     }
     }
-
+    
     func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
     func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
         return UIDevice.current.systemVersion.compare(version,
         return UIDevice.current.systemVersion.compare(version,
-         options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending
+                                                      options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending
     }
     }
-
+    
     func getAvatarFromIconUrl(metadata: tableMetadata) -> String? {
     func getAvatarFromIconUrl(metadata: tableMetadata) -> String? {
-
+        
         var ownerId: String?
         var ownerId: String?
         if metadata.iconUrl.contains("http") && metadata.iconUrl.contains("avatar") {
         if metadata.iconUrl.contains("http") && metadata.iconUrl.contains("avatar") {
             let splitIconUrl = metadata.iconUrl.components(separatedBy: "/")
             let splitIconUrl = metadata.iconUrl.components(separatedBy: "/")
@@ -709,7 +710,7 @@ class NCUtility: NSObject {
         }
         }
         return ownerId
         return ownerId
     }
     }
-
+    
     // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
     // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
     func isValidEmail(_ email: String) -> Bool {
     func isValidEmail(_ email: String) -> Bool {
         
         
@@ -719,11 +720,11 @@ class NCUtility: NSObject {
     }
     }
     
     
     func createFilePreviewImage(ocId: String, etag: String, fileNameView: String, classFile: String, status: Int, createPreviewMedia: Bool) -> UIImage? {
     func createFilePreviewImage(ocId: String, etag: String, fileNameView: String, classFile: String, status: Int, createPreviewMedia: Bool) -> UIImage? {
-
+        
         var imagePreview: UIImage?
         var imagePreview: UIImage?
         let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)!
         let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)!
         let iconImagePath = CCUtility.getDirectoryProviderStorageIconOcId(ocId, etag: etag)!
         let iconImagePath = CCUtility.getDirectoryProviderStorageIconOcId(ocId, etag: etag)!
-
+        
         if FileManager().fileExists(atPath: iconImagePath) {
         if FileManager().fileExists(atPath: iconImagePath) {
             imagePreview = UIImage(contentsOfFile: iconImagePath)
             imagePreview = UIImage(contentsOfFile: iconImagePath)
         } else if !createPreviewMedia {
         } else if !createPreviewMedia {
@@ -743,10 +744,10 @@ class NCUtility: NSObject {
                 } catch { }
                 } catch { }
             }
             }
         }
         }
-
+        
         return imagePreview
         return imagePreview
     }
     }
-
+    
     func isDirectoryE2EE(serverUrl: String, userBase: NCUserBaseUrl) -> Bool {
     func isDirectoryE2EE(serverUrl: String, userBase: NCUserBaseUrl) -> Bool {
         return isDirectoryE2EE(account: userBase.account, urlBase: userBase.urlBase, userId: userBase.userId, serverUrl: serverUrl)
         return isDirectoryE2EE(account: userBase.account, urlBase: userBase.urlBase, userId: userBase.userId, serverUrl: serverUrl)
     }
     }
@@ -794,11 +795,11 @@ class NCUtility: NSObject {
     }
     }
 
 
     func createViewImageAndText(image: UIImage, title: String? = nil) -> UIView {
     func createViewImageAndText(image: UIImage, title: String? = nil) -> UIView {
-
+        
         let imageView = UIImageView()
         let imageView = UIImageView()
         let titleView = UIView()
         let titleView = UIView()
         let label = UILabel()
         let label = UILabel()
-
+        
         if let title = title {
         if let title = title {
             label.text = title + " "
             label.text = title + " "
         } else {
         } else {
@@ -807,15 +808,15 @@ class NCUtility: NSObject {
         label.sizeToFit()
         label.sizeToFit()
         label.center = titleView.center
         label.center = titleView.center
         label.textAlignment = NSTextAlignment.center
         label.textAlignment = NSTextAlignment.center
-
+        
         imageView.image = image
         imageView.image = image
-
+        
         let imageAspect = (imageView.image?.size.width ?? 0) / (imageView.image?.size.height ?? 0)
         let imageAspect = (imageView.image?.size.width ?? 0) / (imageView.image?.size.height ?? 0)
         let imageX = label.frame.origin.x - label.frame.size.height * imageAspect
         let imageX = label.frame.origin.x - label.frame.size.height * imageAspect
         let imageY = label.frame.origin.y
         let imageY = label.frame.origin.y
         let imageWidth = label.frame.size.height * imageAspect
         let imageWidth = label.frame.size.height * imageAspect
         let imageHeight = label.frame.size.height
         let imageHeight = label.frame.size.height
-
+        
         if title != nil {
         if title != nil {
             imageView.frame = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
             imageView.frame = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
             titleView.addSubview(label)
             titleView.addSubview(label)
@@ -823,12 +824,26 @@ class NCUtility: NSObject {
             imageView.frame = CGRect(x: imageX / 2, y: imageY, width: imageWidth, height: imageHeight)
             imageView.frame = CGRect(x: imageX / 2, y: imageY, width: imageWidth, height: imageHeight)
         }
         }
         imageView.contentMode = UIView.ContentMode.scaleAspectFit
         imageView.contentMode = UIView.ContentMode.scaleAspectFit
-
+        
         titleView.addSubview(imageView)
         titleView.addSubview(imageView)
         titleView.sizeToFit()
         titleView.sizeToFit()
-
+        
         return titleView
         return titleView
     }
     }
+
+    func getLocation(latitude: Double, longitude: Double, completion: @escaping (String?) -> Void) {
+        let geocoder = CLGeocoder()
+        let llocation = CLLocation(latitude: latitude, longitude: longitude)
+
+        geocoder.reverseGeocodeLocation(llocation) { placemarks, error in
+            if error == nil, let placemark = placemarks?.first {
+                let locationComponents: [String] = [placemark.name, placemark.locality, placemark.country]
+                    .compactMap{$0}
+
+                completion(locationComponents.joined(separator: ", "))
+            }
+        }
+    }
 }
 }
 
 
 
 

+ 0 - 1
iOSClient/Viewer/NCViewer.swift

@@ -42,7 +42,6 @@ class NCViewer: NSObject {
         self.metadatas = metadatas
         self.metadatas = metadatas
 
 
         var editor = editor
         var editor = editor
-        var xxxxxxx = NextcloudKit.shared.nkCommonInstance.getInternalTypeIdentifier(typeIdentifier: metadata.contentType)
 
 
         // URL
         // URL
         if metadata.classFile == NKCommon.TypeClassFile.url.rawValue {
         if metadata.classFile == NKCommon.TypeClassFile.url.rawValue {

+ 60 - 77
iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift

@@ -30,10 +30,13 @@ import MobileVLCKit
 import JGProgressHUD
 import JGProgressHUD
 import Alamofire
 import Alamofire
 
 
-class NCViewerMedia: UIViewController {
+public protocol NCViewerMediaViewDelegate: AnyObject {
+    func didOpenDetail()
+    func didCloseDetail()
+}
 
 
+class NCViewerMedia: UIViewController {
     @IBOutlet weak var detailViewTopConstraint: NSLayoutConstraint!
     @IBOutlet weak var detailViewTopConstraint: NSLayoutConstraint!
-    @IBOutlet weak var detailViewHeighConstraint: NSLayoutConstraint!
     @IBOutlet weak var imageViewTopConstraint: NSLayoutConstraint!
     @IBOutlet weak var imageViewTopConstraint: NSLayoutConstraint!
     @IBOutlet weak var imageViewBottomConstraint: NSLayoutConstraint!
     @IBOutlet weak var imageViewBottomConstraint: NSLayoutConstraint!
     @IBOutlet weak var scrollView: UIScrollView!
     @IBOutlet weak var scrollView: UIScrollView!
@@ -55,6 +58,7 @@ class NCViewerMedia: UIViewController {
     var doubleTapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer()
     var doubleTapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer()
     var imageViewConstraint: CGFloat = 0
     var imageViewConstraint: CGFloat = 0
     var isDetailViewInitializze: Bool = false
     var isDetailViewInitializze: Bool = false
+    weak var delegate: NCViewerMediaViewDelegate?
 
 
     // MARK: - View Life Cycle
     // MARK: - View Life Cycle
 
 
@@ -88,7 +92,7 @@ class NCViewerMedia: UIViewController {
             statusViewImage.image = nil
             statusViewImage.image = nil
             statusLabel.text = ""
             statusLabel.text = ""
         }
         }
-        
+
         if metadata.isAudioOrVideo {
         if metadata.isAudioOrVideo {
 
 
             playerToolBar = Bundle.main.loadNibNamed("NCPlayerToolBar", owner: self, options: nil)?.first as? NCPlayerToolBar
             playerToolBar = Bundle.main.loadNibNamed("NCPlayerToolBar", owner: self, options: nil)?.first as? NCPlayerToolBar
@@ -109,11 +113,11 @@ class NCViewerMedia: UIViewController {
         preferences.drawing.foregroundColor = .white
         preferences.drawing.foregroundColor = .white
         preferences.drawing.backgroundColor = NCBrandColor.shared.nextcloud
         preferences.drawing.backgroundColor = NCBrandColor.shared.nextcloud
         preferences.drawing.textAlignment = .left
         preferences.drawing.textAlignment = .left
-        preferences.drawing.arrowPosition = .top
+        preferences.drawing.arrowPosition = .bottom
         preferences.drawing.cornerRadius = 10
         preferences.drawing.cornerRadius = 10
 
 
-        preferences.animating.dismissTransform = CGAffineTransform(translationX: 0, y: 100)
-        preferences.animating.showInitialTransform = CGAffineTransform(translationX: 0, y: -100)
+        preferences.animating.dismissTransform = CGAffineTransform(translationX: 0, y: -15)
+        preferences.animating.showInitialTransform = CGAffineTransform(translationX: 0, y: -15)
         preferences.animating.showInitialAlpha = 0
         preferences.animating.showInitialAlpha = 0
         preferences.animating.showDuration = 0.5
         preferences.animating.showDuration = 0.5
         preferences.animating.dismissDuration = 0
         preferences.animating.dismissDuration = 0
@@ -133,7 +137,7 @@ class NCViewerMedia: UIViewController {
         super.viewWillAppear(animated)
         super.viewWillAppear(animated)
 
 
         viewerMediaPage?.navigationController?.navigationBar.prefersLargeTitles = false
         viewerMediaPage?.navigationController?.navigationBar.prefersLargeTitles = false
-        viewerMediaPage?.navigationItem.title = metadata.fileNameView
+        viewerMediaPage?.navigationItem.title = (metadata.fileNameView as NSString).deletingPathExtension
 
 
         if metadata.isImage, let viewerMediaPage = self.viewerMediaPage {
         if metadata.isImage, let viewerMediaPage = self.viewerMediaPage {
             if viewerMediaPage.modifiedOcId.contains(metadata.ocId) {
             if viewerMediaPage.modifiedOcId.contains(metadata.ocId) {
@@ -147,7 +151,7 @@ class NCViewerMedia: UIViewController {
         super.viewDidAppear(animated)
         super.viewDidAppear(animated)
 
 
         viewerMediaPage?.clearCommandCenter()
         viewerMediaPage?.clearCommandCenter()
-        
+
         if metadata.isAudioOrVideo {
         if metadata.isAudioOrVideo {
             if let ncplayer = self.ncplayer {
             if let ncplayer = self.ncplayer {
                 if ncplayer.url == nil {
                 if ncplayer.url == nil {
@@ -207,6 +211,7 @@ class NCViewerMedia: UIViewController {
         }
         }
 
 
         NotificationCenter.default.addObserver(self, selector: #selector(openDetail(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterOpenMediaDetail), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(openDetail(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterOpenMediaDetail), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(closeDetail(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadStartFile), object: nil)
     }
     }
 
 
     override func viewWillDisappear(_ animated: Bool) {
     override func viewWillDisappear(_ animated: Bool) {
@@ -225,6 +230,10 @@ class NCViewerMedia: UIViewController {
 
 
     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
 
 
+        if UIDevice.current.orientation.isValidInterfaceOrientation {
+            closeDetail()
+        }
+
         self.tipView?.dismiss()
         self.tipView?.dismiss()
         if metadata.isVideo {
         if metadata.isVideo {
             self.imageVideoContainer.isHidden = true
             self.imageVideoContainer.isHidden = true
@@ -237,7 +246,7 @@ class NCViewerMedia: UIViewController {
             self.scrollView.zoom(to: CGRect(x: 0, y: 0, width: self.scrollView.bounds.width, height: self.scrollView.bounds.height), animated: false)
             self.scrollView.zoom(to: CGRect(x: 0, y: 0, width: self.scrollView.bounds.width, height: self.scrollView.bounds.height), animated: false)
             self.view.layoutIfNeeded()
             self.view.layoutIfNeeded()
             UIView.animate(withDuration: context.transitionDuration) {
             UIView.animate(withDuration: context.transitionDuration) {
-                if self.detailView.isShow() {
+                if self.detailView.isShown {
                     self.openDetail()
                     self.openDetail()
                 }
                 }
             }
             }
@@ -252,9 +261,8 @@ class NCViewerMedia: UIViewController {
     // MARK: - Tip
     // MARK: - Tip
 
 
     func showTip() {
     func showTip() {
-
-        if !NCManageDatabase.shared.tipExists(NCGlobal.shared.tipNCViewerMediaDetailView), let view = self.navigationController?.navigationBar {
-            self.tipView?.show(forView: view)
+        if !NCManageDatabase.shared.tipExists(NCGlobal.shared.tipNCViewerMediaDetailView) {
+            self.tipView?.show(forView: detailView)
         }
         }
     }
     }
 
 
@@ -274,14 +282,6 @@ class NCViewerMedia: UIViewController {
                     NCNetworking.shared.download(metadata: metadata, selector: "") { _, _ in }
                     NCNetworking.shared.download(metadata: metadata, selector: "") { _, _ in }
                 }
                 }
             }
             }
-
-            NCNetworking.shared.download(metadata: metadata, selector: "") { _, _ in
-                let image = getImageMetadata(metadata)
-                if self.metadata.ocId == metadata.ocId {
-                    self.image = image
-                    self.imageVideoContainer.image = image
-                }
-            }
         }
         }
 
 
         // Get image
         // Get image
@@ -382,7 +382,7 @@ class NCViewerMedia: UIViewController {
 
 
     @objc func didDoubleTapWith(gestureRecognizer: UITapGestureRecognizer) {
     @objc func didDoubleTapWith(gestureRecognizer: UITapGestureRecognizer) {
 
 
-        guard metadata.isImage, !detailView.isShow()  else { return }
+        guard metadata.isImage, !detailView.isShown else { return }
 
 
         let pointInView = gestureRecognizer.location(in: self.imageVideoContainer)
         let pointInView = gestureRecognizer.location(in: self.imageVideoContainer)
         var newZoomScale = self.scrollView.maximumZoomScale
         var newZoomScale = self.scrollView.maximumZoomScale
@@ -406,20 +406,8 @@ class NCViewerMedia: UIViewController {
         let currentLocation = gestureRecognizer.translation(in: self.view)
         let currentLocation = gestureRecognizer.translation(in: self.view)
 
 
         switch gestureRecognizer.state {
         switch gestureRecognizer.state {
-
-        case .began:
-
-//        let velocity = gestureRecognizer.velocity(in: self.view)
-
-//            gesture moving Up
-//            if velocity.y < 0 {
-
-//            }
-            break
-
         case .ended:
         case .ended:
-
-            if detailView.isShow() {
+            if detailView.isShown {
                 self.imageViewTopConstraint.constant = -imageViewConstraint
                 self.imageViewTopConstraint.constant = -imageViewConstraint
                 self.imageViewBottomConstraint.constant = imageViewConstraint
                 self.imageViewBottomConstraint.constant = imageViewConstraint
             } else {
             } else {
@@ -428,7 +416,6 @@ class NCViewerMedia: UIViewController {
             }
             }
 
 
         case .changed:
         case .changed:
-
             imageViewTopConstraint.constant = (currentLocation.y - imageViewConstraint)
             imageViewTopConstraint.constant = (currentLocation.y - imageViewConstraint)
             imageViewBottomConstraint.constant = -(currentLocation.y - imageViewConstraint)
             imageViewBottomConstraint.constant = -(currentLocation.y - imageViewConstraint)
 
 
@@ -459,44 +446,39 @@ class NCViewerMedia: UIViewController {
     }
     }
 }
 }
 
 
-// MARK: -
-
 extension NCViewerMedia {
 extension NCViewerMedia {
-
     @objc func openDetail(_ notification: NSNotification) {
     @objc func openDetail(_ notification: NSNotification) {
-
         if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, ocId == metadata.ocId {
         if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, ocId == metadata.ocId {
             openDetail()
             openDetail()
         }
         }
     }
     }
 
 
-    private func openDetail() {
+    @objc func closeDetail(_ notification: NSNotification) {
+        closeDetail()
+    }
 
 
+    func toggleDetail () {
+        detailView.isShown ? closeDetail() : openDetail()
+    }
+
+    private func openDetail() {
+        delegate?.didOpenDetail()
         self.dismissTip()
         self.dismissTip()
-        
-        CCUtility.setExif(metadata) { latitude, longitude, location, date, lensModel in
 
 
-            if latitude != -1 && latitude != 0 && longitude != -1 && longitude != 0 {
-                self.detailViewHeighConstraint.constant = self.view.bounds.height / 2
-            } else {
-                self.detailViewHeighConstraint.constant = 170
-            }
+        statusLabel.isHidden = true
+        statusViewImage.isHidden = true
+
+        NCUtility.shared.getExif(metadata: metadata) { exif in
             self.view.layoutIfNeeded()
             self.view.layoutIfNeeded()
-            self.detailView.show(
-                metadata: self.metadata,
-                image: self.image,
-                textColor: self.viewerMediaPage?.textColor,
-                mediaMetadata: (latitude: latitude, longitude: longitude, location: location, date: date, lensModel: lensModel),
-                ncplayer: self.ncplayer,
-                delegate: self)
-                
+            self.showDetailView(exif: exif)
+
             if let image = self.imageVideoContainer.image {
             if let image = self.imageVideoContainer.image {
                 let ratioW = self.imageVideoContainer.frame.width / image.size.width
                 let ratioW = self.imageVideoContainer.frame.width / image.size.width
                 let ratioH = self.imageVideoContainer.frame.height / image.size.height
                 let ratioH = self.imageVideoContainer.frame.height / image.size.height
-                let ratio = ratioW < ratioH ? ratioW : ratioH
+                let ratio = min(ratioW, ratioH)
                 let imageHeight = image.size.height * ratio
                 let imageHeight = image.size.height * ratio
-                let VideoContainerHeight = self.imageVideoContainer.frame.height * ratio
-                let height = max(imageHeight, VideoContainerHeight)
+                let imageContainerHeight = self.imageVideoContainer.frame.height * ratio
+                let height = max(imageHeight, imageContainerHeight)
                 self.imageViewConstraint = self.detailView.frame.height - ((self.view.frame.height - height) / 2) + self.view.safeAreaInsets.bottom
                 self.imageViewConstraint = self.detailView.frame.height - ((self.view.frame.height - height) / 2) + self.view.safeAreaInsets.bottom
                 if self.imageViewConstraint < 0 { self.imageViewConstraint = 0 }
                 if self.imageViewConstraint < 0 { self.imageViewConstraint = 0 }
             }
             }
@@ -504,9 +486,8 @@ extension NCViewerMedia {
             UIView.animate(withDuration: 0.3) {
             UIView.animate(withDuration: 0.3) {
                 self.imageViewTopConstraint.constant = -self.imageViewConstraint
                 self.imageViewTopConstraint.constant = -self.imageViewConstraint
                 self.imageViewBottomConstraint.constant = self.imageViewConstraint
                 self.imageViewBottomConstraint.constant = self.imageViewConstraint
-                self.detailViewTopConstraint.constant = self.detailViewHeighConstraint.constant
+                self.detailViewTopConstraint.constant = self.detailView.frame.height
                 self.view.layoutIfNeeded()
                 self.view.layoutIfNeeded()
-            } completion: { _ in
             }
             }
 
 
             self.scrollView.pinchGestureRecognizer?.isEnabled = false
             self.scrollView.pinchGestureRecognizer?.isEnabled = false
@@ -514,39 +495,42 @@ extension NCViewerMedia {
     }
     }
 
 
     private func closeDetail() {
     private func closeDetail() {
-
+        delegate?.didCloseDetail()
         self.detailView.hide()
         self.detailView.hide()
         imageViewConstraint = 0
         imageViewConstraint = 0
 
 
+        statusLabel.isHidden = false
+        statusViewImage.isHidden = false
+
         UIView.animate(withDuration: 0.3) {
         UIView.animate(withDuration: 0.3) {
             self.imageViewTopConstraint.constant = 0
             self.imageViewTopConstraint.constant = 0
             self.imageViewBottomConstraint.constant = 0
             self.imageViewBottomConstraint.constant = 0
             self.detailViewTopConstraint.constant = 0
             self.detailViewTopConstraint.constant = 0
             self.view.layoutIfNeeded()
             self.view.layoutIfNeeded()
-        } completion: { _ in
         }
         }
 
 
         scrollView.pinchGestureRecognizer?.isEnabled = true
         scrollView.pinchGestureRecognizer?.isEnabled = true
     }
     }
 
 
-    func reloadDetail() {
+    private func showDetailView(exif: ExifData) {
+        self.detailView.show(
+            metadata: self.metadata,
+            image: self.image,
+            textColor: self.viewerMediaPage?.textColor,
+            exif: exif,
+            ncplayer: self.ncplayer,
+            delegate: self)
+    }
 
 
-        if self.detailView.isShow() {
-            CCUtility.setExif(metadata) { (latitude, longitude, location, date, lensModel) in
-                self.detailView.show(
-                    metadata: self.metadata,
-                    image: self.image,
-                    textColor: self.viewerMediaPage?.textColor,
-                    mediaMetadata: (latitude: latitude, longitude: longitude, location: location, date: date, lensModel: lensModel),
-                    ncplayer: self.ncplayer,
-                    delegate: self)
+    func reloadDetail() {
+        if self.detailView.isShown {
+            NCUtility.shared.getExif(metadata: metadata) { exif in
+                self.showDetailView(exif: exif)
             }
             }
         }
         }
     }
     }
 }
 }
 
 
-// MARK: -
-
 extension NCViewerMedia: UIScrollViewDelegate {
 extension NCViewerMedia: UIScrollViewDelegate {
 
 
     func viewForZooming(in scrollView: UIScrollView) -> UIView? {
     func viewForZooming(in scrollView: UIScrollView) -> UIView? {
@@ -563,9 +547,9 @@ extension NCViewerMedia: UIScrollViewDelegate {
                 let ratio = ratioW < ratioH ? ratioW : ratioH
                 let ratio = ratioW < ratioH ? ratioW : ratioH
                 let newWidth = image.size.width * ratio
                 let newWidth = image.size.width * ratio
                 let newHeight = image.size.height * ratio
                 let newHeight = image.size.height * ratio
-                let conditionLeft = newWidth*scrollView.zoomScale > imageVideoContainer.frame.width
+                let conditionLeft = newWidth * scrollView.zoomScale > imageVideoContainer.frame.width
                 let left = 0.5 * (conditionLeft ? newWidth - imageVideoContainer.frame.width : (scrollView.frame.width - scrollView.contentSize.width))
                 let left = 0.5 * (conditionLeft ? newWidth - imageVideoContainer.frame.width : (scrollView.frame.width - scrollView.contentSize.width))
-                let conditioTop = newHeight*scrollView.zoomScale > imageVideoContainer.frame.height
+                let conditioTop = newHeight * scrollView.zoomScale > imageVideoContainer.frame.height
 
 
                 let top = 0.5 * (conditioTop ? newHeight - imageVideoContainer.frame.height : (scrollView.frame.height - scrollView.contentSize.height))
                 let top = 0.5 * (conditioTop ? newHeight - imageVideoContainer.frame.height : (scrollView.frame.height - scrollView.contentSize.height))
 
 
@@ -583,7 +567,6 @@ extension NCViewerMedia: UIScrollViewDelegate {
 extension NCViewerMedia: NCViewerMediaDetailViewDelegate {
 extension NCViewerMedia: NCViewerMediaDetailViewDelegate {
 
 
     func downloadFullResolution() {
     func downloadFullResolution() {
-        closeDetail()
         NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorOpenDetail) { _, _ in }
         NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorOpenDetail) { _, _ in }
     }
     }
 }
 }

+ 155 - 117
iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift

@@ -24,52 +24,55 @@
 import UIKit
 import UIKit
 import MapKit
 import MapKit
 import NextcloudKit
 import NextcloudKit
-
-typealias NCImageMetadata = (latitude: Double, longitude: Double, location: String?, date: Date?, lensModel: String?)
+import Alamofire
 
 
 public protocol NCViewerMediaDetailViewDelegate: AnyObject {
 public protocol NCViewerMediaDetailViewDelegate: AnyObject {
     func downloadFullResolution()
     func downloadFullResolution()
 }
 }
 
 
 class NCViewerMediaDetailView: UIView {
 class NCViewerMediaDetailView: UIView {
-
-    @IBOutlet weak var separator: UIView!
-    @IBOutlet weak var sizeLabel: UILabel!
-    @IBOutlet weak var sizeValue: UILabel!
-    @IBOutlet weak var dateLabel: UILabel!
-    @IBOutlet weak var dateValue: UILabel!
-    @IBOutlet weak var dimLabel: UILabel!
-    @IBOutlet weak var dimValue: UILabel!
-    @IBOutlet weak var lensModelLabel: UILabel!
-    @IBOutlet weak var lensModelValue: UILabel!
-    @IBOutlet weak var messageButton: UIButton!
     @IBOutlet weak var mapContainer: UIView!
     @IBOutlet weak var mapContainer: UIView!
-    @IBOutlet weak var locationButton: UIButton!
-
-    var latitude: Double = 0
-    var longitude: Double = 0
-    var location: String?
-    var date: Date?
-    var lensModel: String?
-    var metadata: tableMetadata?
-    var mapView: MKMapView?
-    var ncplayer: NCPlayer?
+    @IBOutlet weak var outerMapContainer: UIView!
+    @IBOutlet weak var dayLabel: UILabel!
+    @IBOutlet weak var dateLabel: UILabel!
+    @IBOutlet weak var noDateLabel: UILabel!
+    @IBOutlet weak var timeLabel: UILabel!
+    @IBOutlet weak var nameLabel: UILabel!
+    @IBOutlet weak var modelLabel: UILabel!
+    @IBOutlet weak var deviceContainer: UIView!
+    @IBOutlet weak var outerContainer: UIView!
+    @IBOutlet weak var lensLabel: UILabel!
+    @IBOutlet weak var megaPixelLabel: UILabel!
+    @IBOutlet weak var megaPixelLabelDivider: UILabel!
+    @IBOutlet weak var resolutionLabel: UILabel!
+    @IBOutlet weak var resolutionLabelDivider: UILabel!
+    @IBOutlet weak var sizeLabel: UILabel!
+    @IBOutlet weak var extensionLabel: UILabel!
+    @IBOutlet weak var livePhotoImageView: UIImageView!
+    @IBOutlet weak var isoLabel: UILabel!
+    @IBOutlet weak var lensSizeLabel: UILabel!
+    @IBOutlet weak var exposureValueLabel: UILabel!
+    @IBOutlet weak var apertureLabel: UILabel!
+    @IBOutlet weak var shutterSpeedLabel: UILabel!
+    @IBOutlet weak var locationLabel: UILabel!
+    @IBOutlet weak var downloadImageButton: UIButton!
+    @IBOutlet weak var downloadImageLabel: UILabel!
+    @IBOutlet weak var downloadImageButtonContainer: UIStackView!
+    @IBOutlet weak var dateContainer: UIView!
+    @IBOutlet weak var lensInfoStackViewLeadingConstraint: NSLayoutConstraint!
+    @IBOutlet weak var lensInfoStackViewTrailingConstraint: NSLayoutConstraint!
+    @IBOutlet weak var lensInfoLeadingFakePadding: UILabel!
+    @IBOutlet weak var lensInfoTrailingFakePadding: UILabel!
+
+    private var metadata: tableMetadata?
+    private var mapView: MKMapView?
+    private var ncplayer: NCPlayer?
     weak var delegate: NCViewerMediaDetailViewDelegate?
     weak var delegate: NCViewerMediaDetailViewDelegate?
 
 
-    override func awakeFromNib() {
-        super.awakeFromNib()
-
-        separator.backgroundColor = .separator
-        sizeLabel.text = ""
-        sizeValue.text = ""
-        dateLabel.text = ""
-        dateValue.text = ""
-        dimLabel.text = ""
-        dimValue.text = ""
-        lensModelLabel.text = ""
-        lensModelValue.text = ""
-        messageButton.setTitle("", for: .normal)
-        locationButton.setTitle("", for: .normal)
+    private var exif: ExifData?
+
+    var isShown: Bool {
+        return !self.isHidden
     }
     }
 
 
     deinit {
     deinit {
@@ -82,134 +85,169 @@ class NCViewerMediaDetailView: UIView {
     func show(metadata: tableMetadata,
     func show(metadata: tableMetadata,
               image: UIImage?,
               image: UIImage?,
               textColor: UIColor?,
               textColor: UIColor?,
-              mediaMetadata: NCImageMetadata,
+              exif: ExifData,
               ncplayer: NCPlayer?,
               ncplayer: NCPlayer?,
               delegate: NCViewerMediaDetailViewDelegate?) {
               delegate: NCViewerMediaDetailViewDelegate?) {
 
 
         self.metadata = metadata
         self.metadata = metadata
-        self.latitude = mediaMetadata.latitude
-        self.longitude = mediaMetadata.longitude
-        self.location = mediaMetadata.location
-        self.date = mediaMetadata.date
-        self.lensModel = mediaMetadata.lensModel
+        self.exif = exif
         self.ncplayer = ncplayer
         self.ncplayer = ncplayer
         self.delegate = delegate
         self.delegate = delegate
 
 
-        if mapView == nil && (latitude != -1 && latitude != 0 && longitude != -1 && longitude != 0) {
+        outerMapContainer.isHidden = true
+        downloadImageButtonContainer.isHidden = true
+
+        if let latitude = exif.latitude, let longitude = exif.longitude, NCNetworking.shared.networkReachability != .notReachable {
+            // We hide the map view on phones in landscape (aka compact height), since there is too little space to fit all of it.
+            mapContainer.isHidden = traitCollection.verticalSizeClass == .compact
 
 
+            outerMapContainer.isHidden = false
             let annotation = MKPointAnnotation()
             let annotation = MKPointAnnotation()
             annotation.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
             annotation.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
+            let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 500, longitudinalMeters: 500)
+
+            if mapView == nil, mapView?.region.center.latitude != latitude, mapView?.region.center.longitude != longitude {
+                let mapView = MKMapView()
+                self.mapView = mapView
+                mapContainer.subviews.forEach { $0.removeFromSuperview() }
+                self.mapContainer.addSubview(mapView)
+                mapView.translatesAutoresizingMaskIntoConstraints = false
+                NSLayoutConstraint.activate([
+                    mapView.topAnchor.constraint(equalTo: self.mapContainer.topAnchor),
+                    mapView.bottomAnchor.constraint(equalTo: self.mapContainer.bottomAnchor),
+                    mapView.leadingAnchor.constraint(equalTo: self.mapContainer.leadingAnchor),
+                    mapView.trailingAnchor.constraint(equalTo: self.mapContainer.trailingAnchor)
+                ])
+
+                mapView.isZoomEnabled = true
+                mapView.isScrollEnabled = false
+                mapView.isUserInteractionEnabled = false
+                mapView.addAnnotation(annotation)
+
+                mapView.setRegion(region, animated: false)
+            }
+        }
 
 
-            let mapView = MKMapView()
-            self.mapView = mapView
-            self.mapContainer.addSubview(mapView)
-
-            mapView.translatesAutoresizingMaskIntoConstraints = false
-            NSLayoutConstraint.activate([
-                mapView.topAnchor.constraint(equalTo: self.mapContainer.topAnchor),
-                mapView.bottomAnchor.constraint(equalTo: self.mapContainer.bottomAnchor),
-                mapView.leadingAnchor.constraint(equalTo: self.mapContainer.leadingAnchor),
-                mapView.trailingAnchor.constraint(equalTo: self.mapContainer.trailingAnchor)
-            ])
-
-            mapView.layer.cornerRadius = 6
-            mapView.isZoomEnabled = true
-            mapView.isScrollEnabled = false
-            mapView.isUserInteractionEnabled = false
-            mapView.addAnnotation(annotation)
-            mapView.setRegion(MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 500, longitudinalMeters: 500), animated: false)
+        if let make = exif.make, let model = exif.model, let lensModel = exif.lensModel {
+            modelLabel.text = "\(make) \(model)"
+            lensLabel.text = lensModel
+                .replacingOccurrences(of: make, with: "")
+                .replacingOccurrences(of: model, with: "")
+                .replacingOccurrences(of: "f/", with: "ƒ").trimmingCharacters(in: .whitespacesAndNewlines).firstUppercased
+        } else {
+            modelLabel.text = NSLocalizedString("_no_camera_information_", comment: "")
+            lensLabel.text = NSLocalizedString("_no_lens_information_", comment: "")
         }
         }
 
 
-        // Size
-        sizeLabel.text = NSLocalizedString("_size_", comment: "")
-        sizeValue.text = CCUtility.transformedSize(metadata.size)
-        sizeValue.textColor = textColor
+        nameLabel.text = (metadata.fileNameView as NSString).deletingPathExtension
+        sizeLabel.text = CCUtility.transformedSize(metadata.size)
+
+        if let shutterSpeedApex = exif.shutterSpeedApex {
+            prepareLensInfoViewsForData()
+            shutterSpeedLabel.text = "1/\(Int(pow(2, shutterSpeedApex))) s"
+        }
+
+        if let iso = exif.iso {
+            prepareLensInfoViewsForData()
+            isoLabel.text = "ISO \(iso)"
+        }
+
+        if let apertureValue = exif.apertureValue {
+            apertureLabel.text = "ƒ\(apertureValue)"
+        }
+
+        if let exposureValue = exif.exposureValue {
+            exposureValueLabel.text = "\(exposureValue) ev"
+        }
+
+        if let lensLength = exif.lensLength {
+            lensSizeLabel.text = "\(lensLength) mm"
+        }
+
+        if let date = exif.date {
+            dateContainer.isHidden = false
+            noDateLabel.isHidden = true
 
 
-        // Date
-        if let date = date {
             let formatter = DateFormatter()
             let formatter = DateFormatter()
-            formatter.dateStyle = .full
-            formatter.timeStyle = .medium
+
+            formatter.dateFormat = "EEEE"
+            let dayString = formatter.string(from: date as Date)
+            dayLabel.text = dayString
+
+            formatter.dateFormat = "d MMM yyyy"
             let dateString = formatter.string(from: date as Date)
             let dateString = formatter.string(from: date as Date)
+            dateLabel.text = dateString
 
 
-            dateLabel.text = NSLocalizedString("_date_", comment: "")
-            dateValue.text = dateString
+            formatter.dateFormat = "HH:mm"
+            let timeString = formatter.string(from: date as Date)
+            timeLabel.text = timeString
         } else {
         } else {
-            dateLabel.text = NSLocalizedString("_date_", comment: "")
-            dateValue.text = NSLocalizedString("_not_available_", comment: "")
+            noDateLabel.text = NSLocalizedString("_no_date_information_", comment: "")
         }
         }
-        dateValue.textColor = textColor
 
 
-        // Dimension
-        if let image = image {
-            dimLabel.text = NSLocalizedString("_resolution_", comment: "")
-            dimValue.text = "\(Int(image.size.width)) x \(Int(image.size.height))"
+        if let height = exif.height, let width = exif.width {
+            megaPixelLabel.isHidden = false
+            megaPixelLabelDivider.isHidden = false
+            resolutionLabel.isHidden = false
+            resolutionLabelDivider.isHidden = false
+
+            resolutionLabel.text = "\(width) x \(height)"
+
+            let megaPixels: Double = Double(width * height) / 1000000
+            megaPixelLabel.text = megaPixels < 1 ? String(format: "%.1f MP", megaPixels) : "\(Int(megaPixels)) MP"
         }
         }
-        dimValue.textColor = textColor
 
 
-        // Model
-        if let lensModel = lensModel {
-            lensModelLabel.text = NSLocalizedString("_model_", comment: "")
-            lensModelValue.text = lensModel
-            lensModelValue.textColor = textColor
+        extensionLabel.text = metadata.fileExtension.uppercased()
+
+        if exif.location?.isEmpty == false {
+            locationLabel.text = exif.location
         }
         }
 
 
-        // Message
-        if metadata.isImage && !CCUtility.fileProviderStorageExists(metadata) && metadata.session.isEmpty {
-            messageButton.setTitle(NSLocalizedString("_try_download_full_resolution_", comment: ""), for: .normal)
-            messageButton.isHidden = false
-        } else {
-            messageButton.setTitle("", for: .normal)
-            messageButton.isHidden = true
+        if metadata.livePhoto {
+            livePhotoImageView.isHidden = false
         }
         }
 
 
-        // Location
-        if let location = location {
-            locationButton.setTitle(location, for: .normal)
-            locationButton.isHidden = false
-        } else {
-            locationButton.setTitle("", for: .normal)
-            locationButton.isHidden = true
+        if metadata.isImage && !CCUtility.fileProviderStorageExists(metadata) && metadata.session.isEmpty {
+            downloadImageButton.setTitle(NSLocalizedString("_try_download_full_resolution_", comment: ""), for: .normal)
+            downloadImageLabel.text = NSLocalizedString("_full_resolution_image_info_", comment: "")
+            downloadImageButtonContainer.isHidden = false
         }
         }
 
 
         self.isHidden = false
         self.isHidden = false
+        layoutIfNeeded()
     }
     }
 
 
     func hide() {
     func hide() {
         self.isHidden = true
         self.isHidden = true
     }
     }
 
 
-    func isShow() -> Bool {
-        return !self.isHidden
+    private func prepareLensInfoViewsForData() {
+        lensInfoLeadingFakePadding.isHidden = true
+        lensInfoTrailingFakePadding.isHidden = true
+        lensInfoStackViewLeadingConstraint.constant = 5
+        lensInfoStackViewTrailingConstraint.constant = 5
     }
     }
 
 
     // MARK: - Action
     // MARK: - Action
 
 
     @IBAction func touchLocation(_ sender: Any) {
     @IBAction func touchLocation(_ sender: Any) {
+        guard let latitude = exif?.latitude, let longitude = exif?.longitude else { return }
 
 
-        guard latitude != -1, latitude != 0, longitude != -1, longitude != 0 else { return }
-
-        let latitude: CLLocationDegrees = self.latitude
-        let longitude: CLLocationDegrees = self.longitude
+        let latitudeDeg: CLLocationDegrees = latitude
+        let longitudeDeg: CLLocationDegrees = longitude
 
 
-        let regionDistance: CLLocationDistance = 10000
-        let coordinates = CLLocationCoordinate2DMake(latitude, longitude)
-        let regionSpan = MKCoordinateRegion(center: coordinates, latitudinalMeters: regionDistance, longitudinalMeters: regionDistance)
-        let options = [
-            MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: regionSpan.center),
-            MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: regionSpan.span)
-        ]
+        let coordinates = CLLocationCoordinate2DMake(latitudeDeg, longitudeDeg)
         let placemark = MKPlacemark(coordinate: coordinates, addressDictionary: nil)
         let placemark = MKPlacemark(coordinate: coordinates, addressDictionary: nil)
         let mapItem = MKMapItem(placemark: placemark)
         let mapItem = MKMapItem(placemark: placemark)
-        mapItem.name = location
-        mapItem.openInMaps(launchOptions: options)
-    }
 
 
-    @IBAction func touchFavorite(_ sender: Any) {
+        if let location = exif?.location {
+            mapItem.name = location
+        }
 
 
+        mapItem.openInMaps()
     }
     }
 
 
-    @IBAction func touchMessage(_ sender: Any) {
+    @IBAction func touchDownload(_ sender: Any) {
         delegate?.downloadFullResolution()
         delegate?.downloadFullResolution()
     }
     }
 }
 }

+ 454 - 160
iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="ne8-hS-cp3">
-    <device id="retina5_5" orientation="portrait" appearance="light"/>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22113.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="ne8-hS-cp3">
+    <device id="retina6_72" orientation="portrait" appearance="light"/>
     <dependencies>
     <dependencies>
         <deployment identifier="iOS"/>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22089.1"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -18,17 +18,17 @@
                         <viewControllerLayoutGuide type="bottom" id="baP-ZX-MR4"/>
                         <viewControllerLayoutGuide type="bottom" id="baP-ZX-MR4"/>
                     </layoutGuides>
                     </layoutGuides>
                     <view key="view" opaque="NO" contentMode="scaleToFill" id="wvY-tB-6ZK">
                     <view key="view" opaque="NO" contentMode="scaleToFill" id="wvY-tB-6ZK">
-                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                        <rect key="frame" x="0.0" y="0.0" width="430" height="932"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                         <subviews>
                             <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fpt-Rz-5fT">
                             <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fpt-Rz-5fT">
-                                <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                                <rect key="frame" x="0.0" y="0.0" width="430" height="932"/>
                                 <connections>
                                 <connections>
                                     <segue destination="A4d-OP-AMT" kind="embed" id="sDx-bX-1Jt"/>
                                     <segue destination="A4d-OP-AMT" kind="embed" id="sDx-bX-1Jt"/>
                                 </connections>
                                 </connections>
                             </containerView>
                             </containerView>
                             <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="sD9-1i-ZdY">
                             <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="sD9-1i-ZdY">
-                                <rect key="frame" x="0.0" y="20" width="414" height="1"/>
+                                <rect key="frame" x="0.0" y="59" width="430" height="1"/>
                                 <constraints>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="1" id="F4E-lI-3jZ"/>
                                     <constraint firstAttribute="height" constant="1" id="F4E-lI-3jZ"/>
                                 </constraints>
                                 </constraints>
@@ -73,181 +73,439 @@
                         <viewControllerLayoutGuide type="bottom" id="zwn-Sc-mqc"/>
                         <viewControllerLayoutGuide type="bottom" id="zwn-Sc-mqc"/>
                     </layoutGuides>
                     </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="fIE-H6-KKc">
                     <view key="view" contentMode="scaleToFill" id="fIE-H6-KKc">
-                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                        <rect key="frame" x="0.0" y="0.0" width="430" height="932"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                         <subviews>
                             <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" maximumZoomScale="4" translatesAutoresizingMaskIntoConstraints="NO" id="CdQ-LC-Trx">
                             <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" maximumZoomScale="4" translatesAutoresizingMaskIntoConstraints="NO" id="CdQ-LC-Trx">
-                                <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                                <rect key="frame" x="0.0" y="0.0" width="430" height="932"/>
                                 <subviews>
                                 <subviews>
                                     <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="networkInProgress" translatesAutoresizingMaskIntoConstraints="NO" id="kPV-JM-UnM">
                                     <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="networkInProgress" translatesAutoresizingMaskIntoConstraints="NO" id="kPV-JM-UnM">
-                                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                                        <rect key="frame" x="0.0" y="0.0" width="430" height="932"/>
                                     </imageView>
                                     </imageView>
                                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2AU-85-K8y">
                                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="2AU-85-K8y">
-                                        <rect key="frame" x="10" y="30" width="30" height="30"/>
+                                        <rect key="frame" x="10" y="69" width="30" height="30"/>
                                         <constraints>
                                         <constraints>
                                             <constraint firstAttribute="height" constant="30" id="l1v-vA-4gG"/>
                                             <constraint firstAttribute="height" constant="30" id="l1v-vA-4gG"/>
                                             <constraint firstAttribute="width" constant="30" id="mSt-o6-S1g"/>
                                             <constraint firstAttribute="width" constant="30" id="mSt-o6-S1g"/>
                                         </constraints>
                                         </constraints>
                                     </imageView>
                                     </imageView>
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DAi-gz-qGP">
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DAi-gz-qGP">
-                                        <rect key="frame" x="50" y="36.666666666666664" width="344" height="17"/>
+                                        <rect key="frame" x="50" y="75.666666666666671" width="360" height="17"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                         <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                         <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                         <nil key="highlightedColor"/>
                                         <nil key="highlightedColor"/>
                                     </label>
                                     </label>
-                                    <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="P8R-4f-zAl" customClass="NCViewerMediaDetailView" customModule="Nextcloud" customModuleProvider="target">
-                                        <rect key="frame" x="0.0" y="336" width="414" height="400"/>
+                                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="P8R-4f-zAl" customClass="NCViewerMediaDetailView" customModule="Nextcloud" customModuleProvider="target">
+                                        <rect key="frame" x="0.0" y="398" width="430" height="455.33333333333326"/>
                                         <subviews>
                                         <subviews>
-                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HRq-3M-yeb">
-                                                <rect key="frame" x="15" y="20" width="384" height="1"/>
-                                                <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <constraints>
-                                                    <constraint firstAttribute="height" constant="1" id="X4S-cr-F2P"/>
-                                                </constraints>
-                                            </view>
-                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dJP-ZX-iug">
-                                                <rect key="frame" x="15" y="150" width="384" height="222"/>
-                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <gestureRecognizers/>
-                                                <connections>
-                                                    <outletCollection property="gestureRecognizers" destination="fvW-pC-4g1" appends="YES" id="gVL-xL-CmY"/>
-                                                </connections>
-                                            </view>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="size" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WXS-Lw-DkI">
-                                                <rect key="frame" x="15" y="36" width="80" height="16"/>
-                                                <constraints>
-                                                    <constraint firstAttribute="width" constant="80" id="DLa-7b-rDS"/>
-                                                </constraints>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="size value" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XLb-0a-du9">
-                                                <rect key="frame" x="105" y="36" width="294" height="16"/>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="date" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Son-CZ-zFa">
-                                                <rect key="frame" x="15" y="62" width="80" height="16"/>
-                                                <constraints>
-                                                    <constraint firstAttribute="width" constant="80" id="e83-SZ-3FA"/>
-                                                </constraints>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="date value" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hBd-KD-Jq5">
-                                                <rect key="frame" x="105" y="62" width="294" height="16"/>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="dim" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uaE-Lv-t0Q">
-                                                <rect key="frame" x="15" y="88" width="80" height="16"/>
-                                                <constraints>
-                                                    <constraint firstAttribute="width" constant="80" id="iwq-Fq-8U0"/>
-                                                </constraints>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="dim value" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="n1C-OB-gq2">
-                                                <rect key="frame" x="105" y="88" width="294" height="16"/>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="lens" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uYI-ic-d8g">
-                                                <rect key="frame" x="15" y="114" width="80" height="16"/>
-                                                <constraints>
-                                                    <constraint firstAttribute="width" constant="80" id="egy-z4-Im6"/>
-                                                </constraints>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="lens value" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ix8-uQ-chU">
-                                                <rect key="frame" x="105" y="114" width="294" height="16"/>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                                <nil key="highlightedColor"/>
-                                            </label>
-                                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GWF-lf-c8t">
-                                                <rect key="frame" x="15" y="140" width="384" height="30"/>
-                                                <constraints>
-                                                    <constraint firstAttribute="height" constant="30" id="ehZ-sm-6Om"/>
-                                                </constraints>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <state key="normal" title="message"/>
-                                                <connections>
-                                                    <action selector="touchMessage:" destination="P8R-4f-zAl" eventType="touchUpInside" id="pa6-KU-ig2"/>
-                                                </connections>
-                                            </button>
-                                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oov-9f-Oeu">
-                                                <rect key="frame" x="15" y="372" width="384" height="28"/>
-                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                                <state key="normal" title="location"/>
-                                                <connections>
-                                                    <action selector="touchLocation:" destination="P8R-4f-zAl" eventType="touchUpInside" id="Z9s-pM-WsS"/>
-                                                </connections>
-                                            </button>
+                                            <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="Z0h-yS-myv">
+                                                <rect key="frame" x="15" y="10" width="400" height="435.33333333333331"/>
+                                                <subviews>
+                                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="2" translatesAutoresizingMaskIntoConstraints="NO" id="IBY-Wf-Fqo">
+                                                        <rect key="frame" x="0.0" y="0.0" width="400" height="40.666666666666664"/>
+                                                        <subviews>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No date information" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Mb-ss-cAE" userLabel="Day">
+                                                                <rect key="frame" x="0.0" y="0.0" width="400" height="19.333333333333332"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                                <nil key="textColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                            <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="v7L-HF-dAc">
+                                                                <rect key="frame" x="0.0" y="20.333333333333314" width="400" height="20"/>
+                                                                <subviews>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Friday" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f9E-HN-L3Y" userLabel="Day">
+                                                                        <rect key="frame" x="0.0" y="0.0" width="46.666666666666664" height="20"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                                        <nil key="textColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="·" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ANo-uV-FWJ">
+                                                                        <rect key="frame" x="51.666666666666671" y="0.0" width="6.6666666666666643" height="20"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="black" pointSize="17"/>
+                                                                        <nil key="textColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="13 July 2023" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4LY-PI-0gT" userLabel="Date">
+                                                                        <rect key="frame" x="63.333333333333321" y="0.0" width="97.666666666666686" height="20"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                                        <nil key="textColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="·" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YkY-Ae-DWl">
+                                                                        <rect key="frame" x="166" y="0.0" width="6.6666666666666572" height="20"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="black" pointSize="17"/>
+                                                                        <nil key="textColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="20:04" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="POq-uU-ask" userLabel="Time">
+                                                                        <rect key="frame" x="177.66666666666666" y="0.0" width="45.666666666666657" height="20"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                                                        <nil key="textColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                </subviews>
+                                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                                                <constraints>
+                                                                    <constraint firstItem="4LY-PI-0gT" firstAttribute="top" secondItem="v7L-HF-dAc" secondAttribute="top" id="0Nj-od-jgr"/>
+                                                                    <constraint firstAttribute="height" constant="20" id="5Y4-56-xQm"/>
+                                                                    <constraint firstAttribute="bottom" secondItem="f9E-HN-L3Y" secondAttribute="bottom" id="683-b3-OWL"/>
+                                                                    <constraint firstItem="4LY-PI-0gT" firstAttribute="leading" secondItem="ANo-uV-FWJ" secondAttribute="trailing" constant="5" id="8NU-Iw-MKs"/>
+                                                                    <constraint firstItem="f9E-HN-L3Y" firstAttribute="top" secondItem="v7L-HF-dAc" secondAttribute="top" id="C6J-KV-6Rt"/>
+                                                                    <constraint firstAttribute="bottom" secondItem="YkY-Ae-DWl" secondAttribute="bottom" id="OfB-zH-kmh"/>
+                                                                    <constraint firstItem="YkY-Ae-DWl" firstAttribute="leading" secondItem="4LY-PI-0gT" secondAttribute="trailing" constant="5" id="TPG-Ft-gS9"/>
+                                                                    <constraint firstItem="ANo-uV-FWJ" firstAttribute="leading" secondItem="f9E-HN-L3Y" secondAttribute="trailing" constant="5" id="UfF-b1-NXC"/>
+                                                                    <constraint firstItem="POq-uU-ask" firstAttribute="leading" secondItem="YkY-Ae-DWl" secondAttribute="trailing" constant="5" id="UhC-VA-9kZ"/>
+                                                                    <constraint firstAttribute="bottom" secondItem="ANo-uV-FWJ" secondAttribute="bottom" id="acf-iK-YWp"/>
+                                                                    <constraint firstAttribute="bottom" secondItem="4LY-PI-0gT" secondAttribute="bottom" id="bNV-o6-ntx"/>
+                                                                    <constraint firstItem="POq-uU-ask" firstAttribute="top" secondItem="v7L-HF-dAc" secondAttribute="top" id="cgF-AS-UnZ"/>
+                                                                    <constraint firstAttribute="bottom" secondItem="POq-uU-ask" secondAttribute="bottom" id="e8Y-HT-Oq1"/>
+                                                                    <constraint firstItem="YkY-Ae-DWl" firstAttribute="top" secondItem="v7L-HF-dAc" secondAttribute="top" id="snm-cE-GUd"/>
+                                                                    <constraint firstItem="f9E-HN-L3Y" firstAttribute="leading" secondItem="v7L-HF-dAc" secondAttribute="leading" id="w48-hI-Njc"/>
+                                                                    <constraint firstItem="ANo-uV-FWJ" firstAttribute="top" secondItem="v7L-HF-dAc" secondAttribute="top" id="zkd-LW-elc"/>
+                                                                </constraints>
+                                                            </view>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="IMG_003" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PVW-g9-z43" userLabel="Title">
+                                                                <rect key="frame" x="0.0" y="21.333333333333314" width="400" height="19.333333333333329"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                                <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                        </subviews>
+                                                    </stackView>
+                                                    <view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="YSP-f2-T7B">
+                                                        <rect key="frame" x="0.0" y="52.666666666666693" width="400" height="117.66666666666669"/>
+                                                        <subviews>
+                                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ucG-To-acr">
+                                                                <rect key="frame" x="0.0" y="0.0" width="400" height="35"/>
+                                                                <subviews>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Apple iPhone 12 Pro" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cA8-2k-F4N" userLabel="Device">
+                                                                        <rect key="frame" x="5" y="7.9999999999999982" width="145.33333333333334" height="19.333333333333329"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                                        <nil key="textColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="RMk-ip-NjG">
+                                                                        <rect key="frame" x="345" y="7.6666666666666288" width="50" height="20"/>
+                                                                        <subviews>
+                                                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Zh3-hb-yoa">
+                                                                                <rect key="frame" x="0.0" y="0.0" width="50" height="20"/>
+                                                                                <subviews>
+                                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" text="HEIF" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ux8-XJ-hpJ">
+                                                                                        <rect key="frame" x="4" y="2" width="42" height="16"/>
+                                                                                        <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                                                                        <nil key="highlightedColor"/>
+                                                                                    </label>
+                                                                                </subviews>
+                                                                                <color key="backgroundColor" systemColor="systemGray2Color"/>
+                                                                                <constraints>
+                                                                                    <constraint firstAttribute="trailing" secondItem="Ux8-XJ-hpJ" secondAttribute="trailing" constant="4" id="ILq-QM-ZRq"/>
+                                                                                    <constraint firstItem="Ux8-XJ-hpJ" firstAttribute="leading" secondItem="Zh3-hb-yoa" secondAttribute="leading" constant="4" id="MXv-aT-9Pp"/>
+                                                                                    <constraint firstAttribute="bottom" secondItem="Ux8-XJ-hpJ" secondAttribute="bottom" constant="2" id="dxJ-k4-SDG"/>
+                                                                                    <constraint firstItem="Ux8-XJ-hpJ" firstAttribute="top" secondItem="Zh3-hb-yoa" secondAttribute="top" constant="2" id="vKd-Kp-jlU"/>
+                                                                                </constraints>
+                                                                                <userDefinedRuntimeAttributes>
+                                                                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                                                                        <integer key="value" value="3"/>
+                                                                                    </userDefinedRuntimeAttribute>
+                                                                                </userDefinedRuntimeAttributes>
+                                                                            </view>
+                                                                            <imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="livephoto" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="Pix-ui-Onk">
+                                                                                <rect key="frame" x="0.0" y="-3.5527136788005009e-15" width="20" height="20.333333333333336"/>
+                                                                                <color key="tintColor" systemColor="systemGrayColor"/>
+                                                                                <constraints>
+                                                                                    <constraint firstAttribute="width" constant="20" id="f4P-jF-ymT"/>
+                                                                                </constraints>
+                                                                            </imageView>
+                                                                        </subviews>
+                                                                        <constraints>
+                                                                            <constraint firstAttribute="height" constant="20" id="HZ6-y7-FsB"/>
+                                                                        </constraints>
+                                                                    </stackView>
+                                                                </subviews>
+                                                                <color key="backgroundColor" systemColor="systemGray4Color"/>
+                                                                <constraints>
+                                                                    <constraint firstItem="RMk-ip-NjG" firstAttribute="centerY" secondItem="ucG-To-acr" secondAttribute="centerY" id="5eG-3c-FkU"/>
+                                                                    <constraint firstAttribute="trailing" secondItem="RMk-ip-NjG" secondAttribute="trailing" constant="5" id="A8u-lU-5wY"/>
+                                                                    <constraint firstItem="cA8-2k-F4N" firstAttribute="leading" secondItem="ucG-To-acr" secondAttribute="leading" constant="5" id="SUB-is-irh"/>
+                                                                    <constraint firstAttribute="height" constant="35" id="rKP-vs-CL4"/>
+                                                                    <constraint firstItem="cA8-2k-F4N" firstAttribute="centerY" secondItem="ucG-To-acr" secondAttribute="centerY" id="yG7-dQ-2xn"/>
+                                                                </constraints>
+                                                            </view>
+                                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PAH-Zm-6f7" userLabel="Separator">
+                                                                <rect key="frame" x="0.0" y="35" width="400" height="1"/>
+                                                                <color key="backgroundColor" systemColor="systemGray3Color"/>
+                                                                <constraints>
+                                                                    <constraint firstAttribute="height" constant="1" id="oDS-NK-8Fh"/>
+                                                                </constraints>
+                                                            </view>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Ultra Wide Camera - 13 mm " textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d4R-Eg-BEV">
+                                                                <rect key="frame" x="5" y="43" width="388" height="19.333333333333329"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                                <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                            <stackView opaque="NO" contentMode="scaleToFill" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="6cz-nf-75X">
+                                                                <rect key="frame" x="5" y="64.333333333333314" width="390" height="19.333333333333329"/>
+                                                                <subviews>
+                                                                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="12 MP" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sxI-vc-KfJ" userLabel="Megapixel">
+                                                                        <rect key="frame" x="0.0" y="0.0" width="0.0" height="19.333333333333332"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="·" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EKQ-RW-a5p">
+                                                                        <rect key="frame" x="0.0" y="0.0" width="0.0" height="19.333333333333332"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="black" pointSize="16"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3024 x 4032 " textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6A5-qu-7x1" userLabel="Resolution">
+                                                                        <rect key="frame" x="0.0" y="0.0" width="0.0" height="19.333333333333332"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="·" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PVg-lD-V6e">
+                                                                        <rect key="frame" x="0.0" y="0.0" width="0.0" height="19.333333333333332"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="black" pointSize="16"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3,1 MB" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yOh-G2-fPm" userLabel="Size">
+                                                                        <rect key="frame" x="0.0" y="0.0" width="390" height="19.333333333333332"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="16"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                </subviews>
+                                                            </stackView>
+                                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EkY-Gj-aPB" userLabel="Separator">
+                                                                <rect key="frame" x="0.0" y="90.666666666666686" width="400" height="1"/>
+                                                                <color key="backgroundColor" systemColor="systemGray3Color"/>
+                                                                <constraints>
+                                                                    <constraint firstAttribute="height" constant="1" id="r0C-1B-Hav"/>
+                                                                </constraints>
+                                                            </view>
+                                                            <stackView opaque="NO" contentMode="scaleToFill" distribution="equalCentering" translatesAutoresizingMaskIntoConstraints="NO" id="IFA-TY-kPl">
+                                                                <rect key="frame" x="0.0" y="95.666666666666686" width="400" height="18"/>
+                                                                <subviews>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="|" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TJr-Hv-2Gl">
+                                                                        <rect key="frame" x="0.0" y="0.0" width="3.3333333333333335" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="15"/>
+                                                                        <color key="textColor" systemColor="systemGray5Color"/>
+                                                                        <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="6Cs-pM-Ful" userLabel="ISO">
+                                                                        <rect key="frame" x="38" y="0.0" width="6.6666666666666643" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="|" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kVB-Rd-ORU">
+                                                                        <rect key="frame" x="79.333333333333329" y="0.0" width="3.3333333333333286" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="15"/>
+                                                                        <color key="textColor" systemColor="tertiaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="crU-0D-RI9" userLabel="Lens size">
+                                                                        <rect key="frame" x="117.33333333333334" y="0.0" width="6.6666666666666714" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="|" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Nx-B1-R1C">
+                                                                        <rect key="frame" x="158.66666666666666" y="0.0" width="3.3333333333333428" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="15"/>
+                                                                        <color key="textColor" systemColor="tertiaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CDk-Yx-uJI" userLabel="Exposure value">
+                                                                        <rect key="frame" x="196.66666666666666" y="0.0" width="6.6666666666666572" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="|" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PGe-rH-CVF">
+                                                                        <rect key="frame" x="238" y="0.0" width="3.3333333333333428" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="15"/>
+                                                                        <color key="textColor" systemColor="tertiaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dyh-MY-ZPm" userLabel="Aperture">
+                                                                        <rect key="frame" x="276" y="0.0" width="6.6666666666666856" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="|" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="t3F-Mb-moo">
+                                                                        <rect key="frame" x="317.33333333333331" y="0.0" width="3.3333333333333144" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="15"/>
+                                                                        <color key="textColor" systemColor="tertiaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="-" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LOe-Mx-JH3" userLabel="Shutter speed">
+                                                                        <rect key="frame" x="355.33333333333331" y="0.0" width="6.6666666666666856" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                                        <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="|" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tux-yK-e5c">
+                                                                        <rect key="frame" x="396.66666666666669" y="0.0" width="3.3333333333333144" height="18"/>
+                                                                        <fontDescription key="fontDescription" type="system" weight="thin" pointSize="15"/>
+                                                                        <color key="textColor" systemColor="systemGray5Color"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                </subviews>
+                                                            </stackView>
+                                                        </subviews>
+                                                        <color key="backgroundColor" systemColor="systemGray5Color"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="trailing" secondItem="d4R-Eg-BEV" secondAttribute="trailing" constant="7" id="0if-5h-4Hd"/>
+                                                            <constraint firstItem="EkY-Gj-aPB" firstAttribute="top" secondItem="6cz-nf-75X" secondAttribute="bottom" constant="7" id="1bM-RZ-yX0"/>
+                                                            <constraint firstAttribute="trailing" secondItem="IFA-TY-kPl" secondAttribute="trailing" id="9Cx-KD-RKx"/>
+                                                            <constraint firstAttribute="trailing" secondItem="EkY-Gj-aPB" secondAttribute="trailing" id="D88-MT-aJT"/>
+                                                            <constraint firstItem="ucG-To-acr" firstAttribute="top" secondItem="YSP-f2-T7B" secondAttribute="top" id="Dcv-Ag-2Q0"/>
+                                                            <constraint firstItem="d4R-Eg-BEV" firstAttribute="top" secondItem="PAH-Zm-6f7" secondAttribute="bottom" constant="7" id="Fzh-eW-7xS"/>
+                                                            <constraint firstItem="EkY-Gj-aPB" firstAttribute="leading" secondItem="YSP-f2-T7B" secondAttribute="leading" id="ItR-2I-zaS"/>
+                                                            <constraint firstItem="IFA-TY-kPl" firstAttribute="leading" secondItem="YSP-f2-T7B" secondAttribute="leading" id="Nhf-Tc-J12"/>
+                                                            <constraint firstItem="IFA-TY-kPl" firstAttribute="top" secondItem="EkY-Gj-aPB" secondAttribute="bottom" constant="4" id="Ris-Xd-8hF"/>
+                                                            <constraint firstItem="ucG-To-acr" firstAttribute="leading" secondItem="YSP-f2-T7B" secondAttribute="leading" id="RzN-xI-Nhl"/>
+                                                            <constraint firstItem="6cz-nf-75X" firstAttribute="top" secondItem="d4R-Eg-BEV" secondAttribute="bottom" constant="2" id="bI7-Xl-VUb"/>
+                                                            <constraint firstAttribute="trailing" secondItem="6cz-nf-75X" secondAttribute="trailing" constant="5" id="bqY-6X-bea"/>
+                                                            <constraint firstAttribute="trailing" secondItem="ucG-To-acr" secondAttribute="trailing" id="edf-ki-HLP"/>
+                                                            <constraint firstItem="6cz-nf-75X" firstAttribute="leading" secondItem="YSP-f2-T7B" secondAttribute="leading" constant="5" id="foV-h4-V7i"/>
+                                                            <constraint firstItem="PAH-Zm-6f7" firstAttribute="top" secondItem="ucG-To-acr" secondAttribute="bottom" id="jt5-Mj-0b5"/>
+                                                            <constraint firstAttribute="bottom" secondItem="IFA-TY-kPl" secondAttribute="bottom" constant="4" id="osF-4r-x4s"/>
+                                                            <constraint firstItem="PAH-Zm-6f7" firstAttribute="leading" secondItem="YSP-f2-T7B" secondAttribute="leading" id="tQZ-L6-6SM"/>
+                                                            <constraint firstAttribute="trailing" secondItem="PAH-Zm-6f7" secondAttribute="trailing" id="vQ3-9j-Ttg"/>
+                                                            <constraint firstItem="d4R-Eg-BEV" firstAttribute="leading" secondItem="YSP-f2-T7B" secondAttribute="leading" constant="5" id="zTL-0L-Yvq"/>
+                                                        </constraints>
+                                                        <userDefinedRuntimeAttributes>
+                                                            <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                                                <integer key="value" value="8"/>
+                                                            </userDefinedRuntimeAttribute>
+                                                        </userDefinedRuntimeAttributes>
+                                                    </view>
+                                                    <stackView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="kH6-LI-qFN">
+                                                        <rect key="frame" x="0.0" y="182.33333333333337" width="400" height="185"/>
+                                                        <subviews>
+                                                            <view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dJP-ZX-iug">
+                                                                <rect key="frame" x="0.0" y="0.0" width="400" height="150"/>
+                                                                <color key="backgroundColor" systemColor="systemGray6Color"/>
+                                                                <gestureRecognizers/>
+                                                                <constraints>
+                                                                    <constraint firstAttribute="height" constant="150" id="fJT-bf-c1B"/>
+                                                                </constraints>
+                                                            </view>
+                                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HcW-yY-GaX">
+                                                                <rect key="frame" x="0.0" y="150" width="400" height="35"/>
+                                                                <subviews>
+                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bOA-Hx-qza" userLabel="Location">
+                                                                        <rect key="frame" x="5" y="17.666666666666629" width="0.0" height="0.0"/>
+                                                                        <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                                        <color key="textColor" systemColor="linkColor"/>
+                                                                        <nil key="highlightedColor"/>
+                                                                    </label>
+                                                                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chevron.right" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="1yH-o3-9JB">
+                                                                        <rect key="frame" x="5" y="9.666666666666627" width="20" height="16.333333333333329"/>
+                                                                        <color key="tintColor" systemColor="secondaryLabelColor"/>
+                                                                        <constraints>
+                                                                            <constraint firstAttribute="width" constant="20" id="DXq-TZ-AgJ"/>
+                                                                            <constraint firstAttribute="height" constant="20" id="Qce-PW-4lw"/>
+                                                                        </constraints>
+                                                                    </imageView>
+                                                                </subviews>
+                                                                <color key="backgroundColor" systemColor="systemGray5Color"/>
+                                                                <constraints>
+                                                                    <constraint firstItem="1yH-o3-9JB" firstAttribute="centerY" secondItem="HcW-yY-GaX" secondAttribute="centerY" id="K0K-hv-VdN"/>
+                                                                    <constraint firstItem="bOA-Hx-qza" firstAttribute="leading" secondItem="HcW-yY-GaX" secondAttribute="leading" constant="5" id="KKt-Eb-NmT"/>
+                                                                    <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="1yH-o3-9JB" secondAttribute="trailing" id="iUk-3x-ojN"/>
+                                                                    <constraint firstItem="bOA-Hx-qza" firstAttribute="centerY" secondItem="HcW-yY-GaX" secondAttribute="centerY" id="quS-PT-b4t"/>
+                                                                    <constraint firstAttribute="height" constant="35" id="xGF-2V-n2g"/>
+                                                                    <constraint firstItem="1yH-o3-9JB" firstAttribute="leading" secondItem="bOA-Hx-qza" secondAttribute="trailing" id="xTF-7x-FMG"/>
+                                                                </constraints>
+                                                            </view>
+                                                        </subviews>
+                                                        <userDefinedRuntimeAttributes>
+                                                            <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                                                <integer key="value" value="8"/>
+                                                            </userDefinedRuntimeAttribute>
+                                                        </userDefinedRuntimeAttributes>
+                                                        <connections>
+                                                            <outletCollection property="gestureRecognizers" destination="fvW-pC-4g1" appends="YES" id="DUs-ga-raf"/>
+                                                        </connections>
+                                                    </stackView>
+                                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="swf-k6-4W6">
+                                                        <rect key="frame" x="0.0" y="379.33333333333337" width="400" height="56"/>
+                                                        <subviews>
+                                                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Umg-YQ-OqC">
+                                                                <rect key="frame" x="0.0" y="0.0" width="400" height="34.333333333333336"/>
+                                                                <state key="normal" title="Button"/>
+                                                                <buttonConfiguration key="configuration" style="gray" title="Button">
+                                                                    <color key="baseBackgroundColor" systemColor="systemGray5Color"/>
+                                                                </buttonConfiguration>
+                                                                <connections>
+                                                                    <outletCollection property="gestureRecognizers" destination="LMd-B2-U1g" appends="YES" id="Gap-7a-xBo"/>
+                                                                </connections>
+                                                            </button>
+                                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This may reveal more information about the photo." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZH0-dn-sQ5" userLabel="Info">
+                                                                <rect key="frame" x="0.0" y="40.333333333333258" width="400" height="15.666666666666664"/>
+                                                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                                                <color key="textColor" systemColor="secondaryLabelColor"/>
+                                                                <nil key="highlightedColor"/>
+                                                            </label>
+                                                        </subviews>
+                                                    </stackView>
+                                                </subviews>
+                                            </stackView>
                                         </subviews>
                                         </subviews>
-                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                         <constraints>
                                         <constraints>
-                                            <constraint firstItem="GWF-lf-c8t" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="0Ub-x3-dQs"/>
-                                            <constraint firstItem="WXS-Lw-DkI" firstAttribute="top" secondItem="HRq-3M-yeb" secondAttribute="bottom" constant="15" id="2RK-lk-nQe"/>
-                                            <constraint firstItem="uaE-Lv-t0Q" firstAttribute="top" secondItem="Son-CZ-zFa" secondAttribute="bottom" constant="10" id="3jD-4U-zwi"/>
-                                            <constraint firstItem="XLb-0a-du9" firstAttribute="centerY" secondItem="WXS-Lw-DkI" secondAttribute="centerY" id="6k5-Ur-AKZ"/>
-                                            <constraint firstAttribute="trailing" secondItem="n1C-OB-gq2" secondAttribute="trailing" constant="15" id="6o9-lb-LZc"/>
-                                            <constraint firstAttribute="trailing" secondItem="dJP-ZX-iug" secondAttribute="trailing" constant="15" id="AbM-Mc-iC7"/>
-                                            <constraint firstAttribute="trailing" secondItem="HRq-3M-yeb" secondAttribute="trailing" constant="15" id="DIq-e4-T4P"/>
-                                            <constraint firstAttribute="height" constant="400" id="HzF-N7-BQ8"/>
-                                            <constraint firstItem="XLb-0a-du9" firstAttribute="leading" secondItem="WXS-Lw-DkI" secondAttribute="trailing" constant="10" id="Iqg-lN-NpB"/>
-                                            <constraint firstItem="n1C-OB-gq2" firstAttribute="centerY" secondItem="uaE-Lv-t0Q" secondAttribute="centerY" id="KMX-7y-YXP"/>
-                                            <constraint firstItem="uYI-ic-d8g" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="MTM-eQ-CXC"/>
-                                            <constraint firstItem="dJP-ZX-iug" firstAttribute="top" secondItem="ix8-uQ-chU" secondAttribute="bottom" constant="20" id="Mxt-43-sew"/>
-                                            <constraint firstItem="ix8-uQ-chU" firstAttribute="centerY" secondItem="uYI-ic-d8g" secondAttribute="centerY" id="Oae-3R-C5Z"/>
-                                            <constraint firstAttribute="trailing" secondItem="GWF-lf-c8t" secondAttribute="trailing" constant="15" id="QJp-6z-62f"/>
-                                            <constraint firstItem="oov-9f-Oeu" firstAttribute="top" secondItem="dJP-ZX-iug" secondAttribute="bottom" id="SXt-nb-5Bf"/>
-                                            <constraint firstAttribute="trailing" secondItem="ix8-uQ-chU" secondAttribute="trailing" constant="15" id="TIp-le-wVn"/>
-                                            <constraint firstItem="hBd-KD-Jq5" firstAttribute="centerY" secondItem="Son-CZ-zFa" secondAttribute="centerY" id="Tez-na-gqC"/>
-                                            <constraint firstItem="HRq-3M-yeb" firstAttribute="top" secondItem="P8R-4f-zAl" secondAttribute="top" constant="20" id="UF1-fO-9hX"/>
-                                            <constraint firstAttribute="bottom" secondItem="oov-9f-Oeu" secondAttribute="bottom" id="YuK-2v-kzk"/>
-                                            <constraint firstItem="hBd-KD-Jq5" firstAttribute="leading" secondItem="Son-CZ-zFa" secondAttribute="trailing" constant="10" id="YuO-13-KTh"/>
-                                            <constraint firstItem="WXS-Lw-DkI" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="bRd-bi-Imh"/>
-                                            <constraint firstItem="uYI-ic-d8g" firstAttribute="top" secondItem="uaE-Lv-t0Q" secondAttribute="bottom" constant="10" id="bkM-Ic-ZoE"/>
-                                            <constraint firstItem="dJP-ZX-iug" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="ife-ps-Lx5"/>
-                                            <constraint firstItem="oov-9f-Oeu" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="lXY-IM-uQB"/>
-                                            <constraint firstItem="GWF-lf-c8t" firstAttribute="top" secondItem="ix8-uQ-chU" secondAttribute="bottom" constant="10" id="m7R-Xs-f01"/>
-                                            <constraint firstAttribute="trailing" secondItem="oov-9f-Oeu" secondAttribute="trailing" constant="15" id="mpQ-4V-Yfc"/>
-                                            <constraint firstItem="HRq-3M-yeb" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="oJB-7U-UpU"/>
-                                            <constraint firstAttribute="trailing" secondItem="XLb-0a-du9" secondAttribute="trailing" constant="15" id="p7C-ox-HFw"/>
-                                            <constraint firstAttribute="trailing" secondItem="hBd-KD-Jq5" secondAttribute="trailing" constant="15" id="sKA-YA-3Uc"/>
-                                            <constraint firstItem="uaE-Lv-t0Q" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="tnj-dz-2rk"/>
-                                            <constraint firstItem="ix8-uQ-chU" firstAttribute="leading" secondItem="uYI-ic-d8g" secondAttribute="trailing" constant="10" id="vPD-6e-zeT"/>
-                                            <constraint firstItem="Son-CZ-zFa" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="vsg-gX-rNv"/>
-                                            <constraint firstItem="n1C-OB-gq2" firstAttribute="leading" secondItem="uaE-Lv-t0Q" secondAttribute="trailing" constant="10" id="yAH-Dt-LC5"/>
-                                            <constraint firstItem="Son-CZ-zFa" firstAttribute="top" secondItem="WXS-Lw-DkI" secondAttribute="bottom" constant="10" id="z9W-ZR-cUN"/>
+                                            <constraint firstItem="Z0h-yS-myv" firstAttribute="leading" secondItem="P8R-4f-zAl" secondAttribute="leading" constant="15" id="Ian-z6-Edo"/>
+                                            <constraint firstItem="Z0h-yS-myv" firstAttribute="top" secondItem="P8R-4f-zAl" secondAttribute="top" constant="10" id="bVs-TI-kHP"/>
+                                            <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="814" id="cMZ-Da-ac2"/>
+                                            <constraint firstAttribute="trailing" secondItem="Z0h-yS-myv" secondAttribute="trailing" constant="15" id="hZn-el-dtj"/>
+                                            <constraint firstAttribute="bottom" secondItem="Z0h-yS-myv" secondAttribute="bottom" constant="10" id="qOC-jf-xdx"/>
                                         </constraints>
                                         </constraints>
                                         <connections>
                                         <connections>
-                                            <outlet property="dateLabel" destination="Son-CZ-zFa" id="0Wi-XW-0hw"/>
-                                            <outlet property="dateValue" destination="hBd-KD-Jq5" id="ple-nX-OpH"/>
-                                            <outlet property="dimLabel" destination="uaE-Lv-t0Q" id="MkZ-ko-UrJ"/>
-                                            <outlet property="dimValue" destination="n1C-OB-gq2" id="Ln4-gV-wXg"/>
-                                            <outlet property="lensModelLabel" destination="uYI-ic-d8g" id="DUn-uJ-sVj"/>
-                                            <outlet property="lensModelValue" destination="ix8-uQ-chU" id="GNF-8F-10P"/>
-                                            <outlet property="locationButton" destination="oov-9f-Oeu" id="cGg-Gb-m5S"/>
-                                            <outlet property="mapContainer" destination="dJP-ZX-iug" id="9xS-le-Hhe"/>
-                                            <outlet property="messageButton" destination="GWF-lf-c8t" id="cls-X9-Urf"/>
-                                            <outlet property="separator" destination="HRq-3M-yeb" id="ENP-xc-AWZ"/>
-                                            <outlet property="sizeLabel" destination="WXS-Lw-DkI" id="JG0-G0-oHg"/>
-                                            <outlet property="sizeValue" destination="XLb-0a-du9" id="9jm-Ku-sgt"/>
+                                            <outlet property="apertureLabel" destination="Dyh-MY-ZPm" id="cME-5C-3wz"/>
+                                            <outlet property="dateContainer" destination="v7L-HF-dAc" id="InI-Sl-2kQ"/>
+                                            <outlet property="dateLabel" destination="4LY-PI-0gT" id="dpX-Q9-Aaw"/>
+                                            <outlet property="dayLabel" destination="f9E-HN-L3Y" id="yks-Cu-1pt"/>
+                                            <outlet property="deviceContainer" destination="ucG-To-acr" id="B2F-qe-NwF"/>
+                                            <outlet property="downloadImageButton" destination="Umg-YQ-OqC" id="lFI-g5-fCc"/>
+                                            <outlet property="downloadImageButtonContainer" destination="swf-k6-4W6" id="atX-Zc-tax"/>
+                                            <outlet property="downloadImageLabel" destination="ZH0-dn-sQ5" id="4jd-7p-REW"/>
+                                            <outlet property="exposureValueLabel" destination="CDk-Yx-uJI" id="oZK-rh-iJI"/>
+                                            <outlet property="extensionLabel" destination="Ux8-XJ-hpJ" id="zPk-z9-QBK"/>
+                                            <outlet property="isoLabel" destination="6Cs-pM-Ful" id="lGL-oS-88h"/>
+                                            <outlet property="lensInfoLeadingFakePadding" destination="TJr-Hv-2Gl" id="uDd-r6-1XW"/>
+                                            <outlet property="lensInfoStackViewLeadingConstraint" destination="Nhf-Tc-J12" id="G0O-8L-Yp5"/>
+                                            <outlet property="lensInfoStackViewTrailingConstraint" destination="9Cx-KD-RKx" id="WMF-xt-feG"/>
+                                            <outlet property="lensInfoTrailingFakePadding" destination="Tux-yK-e5c" id="6mU-T2-gMI"/>
+                                            <outlet property="lensLabel" destination="d4R-Eg-BEV" id="ZaX-do-ccU"/>
+                                            <outlet property="lensSizeLabel" destination="crU-0D-RI9" id="ERb-7F-G0b"/>
+                                            <outlet property="livePhotoImageView" destination="Pix-ui-Onk" id="PyP-ld-K3T"/>
+                                            <outlet property="locationLabel" destination="bOA-Hx-qza" id="O8Y-V8-Xzp"/>
+                                            <outlet property="mapContainer" destination="dJP-ZX-iug" id="xqo-Mi-GOO"/>
+                                            <outlet property="megaPixelLabel" destination="sxI-vc-KfJ" id="Uz6-l8-4aI"/>
+                                            <outlet property="megaPixelLabelDivider" destination="EKQ-RW-a5p" id="Rjp-Id-djL"/>
+                                            <outlet property="modelLabel" destination="cA8-2k-F4N" id="Lwb-L5-0Hs"/>
+                                            <outlet property="nameLabel" destination="PVW-g9-z43" id="CC5-mu-Ftr"/>
+                                            <outlet property="noDateLabel" destination="0Mb-ss-cAE" id="dH8-pr-6Jp"/>
+                                            <outlet property="outerContainer" destination="YSP-f2-T7B" id="hxB-u3-8vl"/>
+                                            <outlet property="outerMapContainer" destination="kH6-LI-qFN" id="5I3-oe-jgb"/>
+                                            <outlet property="resolutionLabel" destination="6A5-qu-7x1" id="5Ei-Rx-Q4s"/>
+                                            <outlet property="resolutionLabelDivider" destination="PVg-lD-V6e" id="p6g-6E-XM6"/>
+                                            <outlet property="shutterSpeedLabel" destination="LOe-Mx-JH3" id="Qhq-jN-nXV"/>
+                                            <outlet property="sizeLabel" destination="yOh-G2-fPm" id="4ZL-ki-KhM"/>
+                                            <outlet property="timeLabel" destination="POq-uU-ask" id="ue5-U7-Ub1"/>
                                         </connections>
                                         </connections>
                                     </view>
                                     </view>
                                 </subviews>
                                 </subviews>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <constraints>
                                 <constraints>
+                                    <constraint firstItem="P8R-4f-zAl" firstAttribute="centerX" secondItem="CdQ-LC-Trx" secondAttribute="centerX" id="IFp-cD-s1W"/>
                                     <constraint firstItem="DAi-gz-qGP" firstAttribute="centerY" secondItem="2AU-85-K8y" secondAttribute="centerY" id="Lls-5R-JBM"/>
                                     <constraint firstItem="DAi-gz-qGP" firstAttribute="centerY" secondItem="2AU-85-K8y" secondAttribute="centerY" id="Lls-5R-JBM"/>
                                     <constraint firstAttribute="trailing" secondItem="DAi-gz-qGP" secondAttribute="trailing" constant="20" id="QWE-Iy-fcM"/>
                                     <constraint firstAttribute="trailing" secondItem="DAi-gz-qGP" secondAttribute="trailing" constant="20" id="QWE-Iy-fcM"/>
                                     <constraint firstItem="kPV-JM-UnM" firstAttribute="leading" secondItem="CdQ-LC-Trx" secondAttribute="leading" id="asL-Ft-Lmc"/>
                                     <constraint firstItem="kPV-JM-UnM" firstAttribute="leading" secondItem="CdQ-LC-Trx" secondAttribute="leading" id="asL-Ft-Lmc"/>
@@ -261,22 +519,24 @@
                             </scrollView>
                             </scrollView>
                         </subviews>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="Yo6-7W-moG"/>
                         <viewLayoutGuide key="safeArea" id="Yo6-7W-moG"/>
-                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <constraints>
                         <constraints>
                             <constraint firstAttribute="bottom" secondItem="CdQ-LC-Trx" secondAttribute="bottom" id="4qB-8y-OcG"/>
                             <constraint firstAttribute="bottom" secondItem="CdQ-LC-Trx" secondAttribute="bottom" id="4qB-8y-OcG"/>
                             <constraint firstAttribute="trailing" secondItem="CdQ-LC-Trx" secondAttribute="trailing" id="IwE-oE-d3Y"/>
                             <constraint firstAttribute="trailing" secondItem="CdQ-LC-Trx" secondAttribute="trailing" id="IwE-oE-d3Y"/>
                             <constraint firstItem="2AU-85-K8y" firstAttribute="leading" secondItem="Yo6-7W-moG" secondAttribute="leading" constant="10" id="X10-OG-EKg"/>
                             <constraint firstItem="2AU-85-K8y" firstAttribute="leading" secondItem="Yo6-7W-moG" secondAttribute="leading" constant="10" id="X10-OG-EKg"/>
                             <constraint firstItem="Yo6-7W-moG" firstAttribute="top" secondItem="2AU-85-K8y" secondAttribute="top" constant="-10" id="avO-83-uMQ"/>
                             <constraint firstItem="Yo6-7W-moG" firstAttribute="top" secondItem="2AU-85-K8y" secondAttribute="top" constant="-10" id="avO-83-uMQ"/>
-                            <constraint firstItem="Yo6-7W-moG" firstAttribute="bottom" secondItem="P8R-4f-zAl" secondAttribute="top" constant="400" id="bor-cg-Alz"/>
+                            <constraint firstItem="Yo6-7W-moG" firstAttribute="bottom" secondItem="P8R-4f-zAl" secondAttribute="top" constant="500" id="bor-cg-Alz"/>
                             <constraint firstItem="P8R-4f-zAl" firstAttribute="leading" secondItem="Yo6-7W-moG" secondAttribute="leading" id="dly-i5-fPW"/>
                             <constraint firstItem="P8R-4f-zAl" firstAttribute="leading" secondItem="Yo6-7W-moG" secondAttribute="leading" id="dly-i5-fPW"/>
                             <constraint firstItem="CdQ-LC-Trx" firstAttribute="leading" secondItem="fIE-H6-KKc" secondAttribute="leading" id="g8C-2m-KkX"/>
                             <constraint firstItem="CdQ-LC-Trx" firstAttribute="leading" secondItem="fIE-H6-KKc" secondAttribute="leading" id="g8C-2m-KkX"/>
                             <constraint firstItem="CdQ-LC-Trx" firstAttribute="top" secondItem="fIE-H6-KKc" secondAttribute="top" id="hcQ-lB-JwU"/>
                             <constraint firstItem="CdQ-LC-Trx" firstAttribute="top" secondItem="fIE-H6-KKc" secondAttribute="top" id="hcQ-lB-JwU"/>
-                            <constraint firstItem="Yo6-7W-moG" firstAttribute="trailing" secondItem="P8R-4f-zAl" secondAttribute="trailing" id="jf2-Nv-gFi"/>
                         </constraints>
                         </constraints>
+                        <variation key="heightClass=regular-widthClass=regular">
+                            <mask key="constraints">
+                                <exclude reference="dly-i5-fPW"/>
+                            </mask>
+                        </variation>
                     </view>
                     </view>
                     <connections>
                     <connections>
                         <outlet property="detailView" destination="P8R-4f-zAl" id="xFW-qq-Cdi"/>
                         <outlet property="detailView" destination="P8R-4f-zAl" id="xFW-qq-Cdi"/>
-                        <outlet property="detailViewHeighConstraint" destination="HzF-N7-BQ8" id="KE0-MF-H7w"/>
                         <outlet property="detailViewTopConstraint" destination="bor-cg-Alz" id="xcM-bF-u7e"/>
                         <outlet property="detailViewTopConstraint" destination="bor-cg-Alz" id="xcM-bF-u7e"/>
                         <outlet property="imageVideoContainer" destination="kPV-JM-UnM" id="2pA-VW-FuK"/>
                         <outlet property="imageVideoContainer" destination="kPV-JM-UnM" id="2pA-VW-FuK"/>
                         <outlet property="imageViewBottomConstraint" destination="vEd-X2-yGs" id="wp3-67-aZ2"/>
                         <outlet property="imageViewBottomConstraint" destination="vEd-X2-yGs" id="wp3-67-aZ2"/>
@@ -287,19 +547,53 @@
                     </connections>
                     </connections>
                 </viewController>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="fbE-Jv-mLH" userLabel="First Responder" sceneMemberID="firstResponder"/>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="fbE-Jv-mLH" userLabel="First Responder" sceneMemberID="firstResponder"/>
-                <tapGestureRecognizer id="fvW-pC-4g1">
+                <tapGestureRecognizer id="fvW-pC-4g1" userLabel="Open location Gesture Recognizer">
                     <connections>
                     <connections>
                         <action selector="touchLocation:" destination="P8R-4f-zAl" id="qyd-d2-RyB"/>
                         <action selector="touchLocation:" destination="P8R-4f-zAl" id="qyd-d2-RyB"/>
                     </connections>
                     </connections>
                 </tapGestureRecognizer>
                 </tapGestureRecognizer>
+                <tapGestureRecognizer id="LMd-B2-U1g" userLabel="Download Gesture Recognizer">
+                    <connections>
+                        <action selector="touchDownload:" destination="P8R-4f-zAl" id="f13-sg-aRk"/>
+                    </connections>
+                </tapGestureRecognizer>
             </objects>
             </objects>
-            <point key="canvasLocation" x="4547.826086956522" y="776.9021739130435"/>
+            <point key="canvasLocation" x="4547.4418604651164" y="776.39484978540781"/>
         </scene>
         </scene>
     </scenes>
     </scenes>
     <resources>
     <resources>
+        <image name="chevron.right" catalog="system" width="97" height="128"/>
+        <image name="livephoto" catalog="system" width="128" height="124"/>
         <image name="networkInProgress" width="300" height="300"/>
         <image name="networkInProgress" width="300" height="300"/>
+        <systemColor name="linkColor">
+            <color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="secondaryLabelColor">
+            <color red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
         <systemColor name="systemBackgroundColor">
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
         </systemColor>
         </systemColor>
+        <systemColor name="systemGray2Color">
+            <color red="0.68235294120000001" green="0.68235294120000001" blue="0.69803921570000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="systemGray3Color">
+            <color red="0.78039215689999997" green="0.78039215689999997" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="systemGray4Color">
+            <color red="0.81960784310000001" green="0.81960784310000001" blue="0.83921568629999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="systemGray5Color">
+            <color red="0.8980392157" green="0.8980392157" blue="0.91764705879999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="systemGray6Color">
+            <color red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="systemGrayColor">
+            <color red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="tertiaryLabelColor">
+            <color red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.29803921570000003" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
     </resources>
     </resources>
 </document>
 </document>

+ 47 - 31
iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift

@@ -24,8 +24,8 @@
 import UIKit
 import UIKit
 import NextcloudKit
 import NextcloudKit
 import MediaPlayer
 import MediaPlayer
-import JGProgressHUD
 import Alamofire
 import Alamofire
+import JGProgressHUD
 
 
 enum ScreenMode {
 enum ScreenMode {
     case full, normal
     case full, normal
@@ -66,15 +66,10 @@ class NCViewerMediaPage: UIViewController {
     var previousTrackCommand: Any?
     var previousTrackCommand: Any?
 
 
     var timerAutoHide: Timer?
     var timerAutoHide: Timer?
-    var timerAutoHideSeconds: Double {
-        get {
-            if NCUtility.shared.isSimulator() {
-                return 4
-            } else {
-                return 4
-            }
-        }
-    }
+    private var timerAutoHideSeconds: Double = 4
+
+    private lazy var moreNavigationItem = UIBarButtonItem(image: UIImage(named: "more")!.image(color: .label, size: 25), style: .plain, target: self, action: #selector(openMenuMore))
+    private lazy var imageDetailNavigationItem = UIBarButtonItem(image: UIImage(systemName: "info.circle")!.image(color: .label, size: 22), style: .plain, target: self, action: #selector(toggleDetail))
 
 
     // MARK: - View Life Cycle
     // MARK: - View Life Cycle
 
 
@@ -86,19 +81,13 @@ class NCViewerMediaPage: UIViewController {
 
 
     required init?(coder: NSCoder) {
     required init?(coder: NSCoder) {
         super.init(coder: coder)
         super.init(coder: coder)
-        
+
         viewerMediaScreenMode = .normal
         viewerMediaScreenMode = .normal
     }
     }
 
 
     override func viewDidLoad() {
     override func viewDidLoad() {
         super.viewDidLoad()
         super.viewDidLoad()
 
 
-        if metadatas.count == 1, let metadata = metadatas.first, !metadata.url.isEmpty {
-            // it's a video from URL
-        } else {
-            navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "more")!.image(color: .label, size: 25), style: .plain, target: self, action: #selector(self.openMenuMore))
-        }
-
         singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didSingleTapWith(gestureRecognizer:)))
         singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didSingleTapWith(gestureRecognizer:)))
         panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didPanWith(gestureRecognizer:)))
         panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didPanWith(gestureRecognizer:)))
         longtapGestureRecognizer = UILongPressGestureRecognizer()
         longtapGestureRecognizer = UILongPressGestureRecognizer()
@@ -117,7 +106,6 @@ class NCViewerMediaPage: UIViewController {
         progressView.trackTintColor = .clear
         progressView.trackTintColor = .clear
         progressView.progress = 0
         progressView.progress = 0
 
 
-
         let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex])
         let viewerMedia = getViewerMedia(index: currentIndex, metadata: metadatas[currentIndex])
         pageViewController.setViewControllers([viewerMedia], direction: .forward, animated: true, completion: nil)
         pageViewController.setViewControllers([viewerMedia], direction: .forward, animated: true, completion: nil)
         changeScreenMode(mode: viewerMediaScreenMode)
         changeScreenMode(mode: viewerMediaScreenMode)
@@ -138,6 +126,12 @@ class NCViewerMediaPage: UIViewController {
         NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
 
 
         NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil)
+
+        if currentViewController.metadata.isImage {
+            navigationItem.rightBarButtonItems = [moreNavigationItem, imageDetailNavigationItem]
+        } else {
+            navigationItem.rightBarButtonItems = [moreNavigationItem]
+        }
     }
     }
 
 
     deinit {
     deinit {
@@ -191,14 +185,13 @@ class NCViewerMediaPage: UIViewController {
         return hideStatusBar
         return hideStatusBar
     }
     }
 
 
-    // MARK: -
-    
     func getViewerMedia(index: Int, metadata: tableMetadata) -> NCViewerMedia {
     func getViewerMedia(index: Int, metadata: tableMetadata) -> NCViewerMedia {
-        
+    
         let viewerMedia = UIStoryboard(name: "NCViewerMediaPage", bundle: nil).instantiateViewController(withIdentifier: "NCViewerMedia") as! NCViewerMedia
         let viewerMedia = UIStoryboard(name: "NCViewerMediaPage", bundle: nil).instantiateViewController(withIdentifier: "NCViewerMedia") as! NCViewerMedia
         viewerMedia.index = index
         viewerMedia.index = index
         viewerMedia.metadata = metadata
         viewerMedia.metadata = metadata
         viewerMedia.viewerMediaPage = self
         viewerMedia.viewerMediaPage = self
+        viewerMedia.delegate = self
 
 
         singleTapGestureRecognizer.require(toFail: viewerMedia.doubleTapGestureRecognizer)
         singleTapGestureRecognizer.require(toFail: viewerMedia.doubleTapGestureRecognizer)
 
 
@@ -206,16 +199,19 @@ class NCViewerMediaPage: UIViewController {
     }
     }
 
 
     @objc func viewUnload() {
     @objc func viewUnload() {
-
         navigationController?.popViewController(animated: true)
         navigationController?.popViewController(animated: true)
     }
     }
 
 
-    @objc func openMenuMore() {
+    @objc private func openMenuMore() {
 
 
         let imageIcon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(currentViewController.metadata.ocId, etag: currentViewController.metadata.etag))
         let imageIcon = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(currentViewController.metadata.ocId, etag: currentViewController.metadata.etag))
         NCViewer.shared.toggleMenu(viewController: self, metadata: currentViewController.metadata, webView: false, imageIcon: imageIcon)
         NCViewer.shared.toggleMenu(viewController: self, metadata: currentViewController.metadata, webView: false, imageIcon: imageIcon)
     }
     }
 
 
+    @objc private func toggleDetail() {
+        currentViewController.toggleDetail()
+    }
+
     func changeScreenMode(mode: ScreenMode) {
     func changeScreenMode(mode: ScreenMode) {
 
 
         let metadata = currentViewController.metadata
         let metadata = currentViewController.metadata
@@ -240,11 +236,11 @@ class NCViewerMediaPage: UIViewController {
                 textColor = .white
                 textColor = .white
             } else {
             } else {
                 NCUtility.shared.colorNavigationController(navigationController, backgroundColor: .systemBackground, titleColor: .label, tintColor: nil, withoutShadow: false)
                 NCUtility.shared.colorNavigationController(navigationController, backgroundColor: .systemBackground, titleColor: .label, tintColor: nil, withoutShadow: false)
-                view.backgroundColor = .systemBackground
+                view.backgroundColor = .systemGray6
                 textColor = .label
                 textColor = .label
             }
             }
 
 
-        } else {
+        } else if !currentViewController.detailView.isShown {
 
 
             navigationController?.setNavigationBarHidden(true, animated: true)
             navigationController?.setNavigationBarHidden(true, animated: true)
             hideStatusBar = true
             hideStatusBar = true
@@ -274,13 +270,11 @@ class NCViewerMediaPage: UIViewController {
     }
     }
 
 
     @objc func startTimerAutoHide() {
     @objc func startTimerAutoHide() {
-
         timerAutoHide?.invalidate()
         timerAutoHide?.invalidate()
         timerAutoHide = Timer.scheduledTimer(timeInterval: timerAutoHideSeconds, target: self, selector: #selector(autoHide), userInfo: nil, repeats: true)
         timerAutoHide = Timer.scheduledTimer(timeInterval: timerAutoHideSeconds, target: self, selector: #selector(autoHide), userInfo: nil, repeats: true)
     }
     }
 
 
     @objc func autoHide() {
     @objc func autoHide() {
-
         let metadata = currentViewController.metadata
         let metadata = currentViewController.metadata
         if metadata.isVideo, viewerMediaScreenMode == .normal {
         if metadata.isVideo, viewerMediaScreenMode == .normal {
             changeScreenMode(mode: .full)
             changeScreenMode(mode: .full)
@@ -558,6 +552,16 @@ extension NCViewerMediaPage: UIPageViewControllerDelegate, UIPageViewControllerD
 
 
         guard let nextViewController = pendingViewControllers.first as? NCViewerMedia else { return }
         guard let nextViewController = pendingViewControllers.first as? NCViewerMedia else { return }
         nextIndex = nextViewController.index
         nextIndex = nextViewController.index
+
+        if nextViewController.metadata.isImage {
+            navigationItem.rightBarButtonItems = [moreNavigationItem, imageDetailNavigationItem]
+        } else {
+            navigationItem.rightBarButtonItems = [moreNavigationItem]
+        }
+
+        if nextViewController.detailView.isShown {
+            changeScreenMode(mode: .normal)
+        }
     }
     }
 
 
     // END TRANSITION
     // END TRANSITION
@@ -619,6 +623,7 @@ extension NCViewerMediaPage: UIGestureRecognizerDelegate {
     }
     }
 
 
     @objc func didSingleTapWith(gestureRecognizer: UITapGestureRecognizer) {
     @objc func didSingleTapWith(gestureRecognizer: UITapGestureRecognizer) {
+        if currentViewController.detailView.isShown { return }
 
 
         if viewerMediaScreenMode == .full {
         if viewerMediaScreenMode == .full {
             changeScreenMode(mode: .normal)
             changeScreenMode(mode: .normal)
@@ -627,12 +632,10 @@ extension NCViewerMediaPage: UIGestureRecognizerDelegate {
         }
         }
     }
     }
 
 
-    //
-    // LIVE PHOTO
-    //
+    // MARK: - Live Photo
     @objc func didLongpressGestureEvent(gestureRecognizer: UITapGestureRecognizer) {
     @objc func didLongpressGestureEvent(gestureRecognizer: UITapGestureRecognizer) {
 
 
-        if !currentViewController.metadata.livePhoto { return }
+        if !currentViewController.metadata.livePhoto || currentViewController.detailView.isShown { return }
 
 
         if gestureRecognizer.state == .began {
         if gestureRecognizer.state == .began {
             let fileName = (currentViewController.metadata.fileNameView as NSString).deletingPathExtension + ".mov"
             let fileName = (currentViewController.metadata.fileNameView as NSString).deletingPathExtension + ".mov"
@@ -664,3 +667,16 @@ extension UIPageViewController {
         }
         }
     }
     }
 }
 }
+
+extension NCViewerMediaPage: NCViewerMediaViewDelegate {
+    func didOpenDetail() {
+        changeScreenMode(mode: .normal)
+        imageDetailNavigationItem.image = UIImage(systemName: "info.circle.fill")
+    }
+
+    func didCloseDetail() {
+        imageDetailNavigationItem.image = UIImage(systemName: "info.circle")
+    }
+}
+
+