Эх сурвалжийг харах

Merge pull request #2623 from nextcloud/develop

Version 4.9.0
Marino Faggiana 1 жил өмнө
parent
commit
b99999adc3
100 өөрчлөгдсөн 3107 нэмэгдсэн , 2456 устгасан
  1. 5 0
      .github/workflows/xcode.yml
  2. 10 115
      .swiftlint.yml
  3. 1 1
      Brand/Database.swift
  4. 2 0
      Brand/Intro/NCIntroCollectionViewCell.swift
  5. 1 1
      Brand/Intro/NCIntroViewController.swift
  6. 39 35
      Brand/NCBrand.swift
  7. 3 3
      Brand/iOSClient.plist
  8. 4 3
      ExternalResources/NCApplicationHandle.swift
  9. 3 3
      File Provider Extension/FileProviderData.swift
  10. 2 2
      File Provider Extension/FileProviderDomain.swift
  11. 1 1
      File Provider Extension/FileProviderEnumerator.swift
  12. 3 5
      File Provider Extension/FileProviderExtension+Actions.swift
  13. 9 13
      File Provider Extension/FileProviderExtension.swift
  14. 155 28
      Nextcloud.xcodeproj/project.pbxproj
  15. 0 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme
  16. 2 2
      Notification Service Extension/NotificationService.swift
  17. 1 1
      README.md
  18. 1 0
      Share/NCShareExtension+DataSource.swift
  19. 2 1
      Share/NCShareExtension+NCDelegate.swift
  20. 12 4
      Share/NCShareExtension.swift
  21. 19 15
      Tests/NextcloudIntegrationTests/BaseIntegrationXCTestCase.swift
  22. 2 8
      Tests/NextcloudIntegrationTests/FilesIntegrationTests.swift
  23. 1 1
      Tests/NextcloudUITests/LoginUITests.swift
  24. 7 13
      Widget/Dashboard/DashboardData.swift
  25. 8 7
      Widget/Dashboard/DashboardWidgetView.swift
  26. 5 5
      Widget/Files/FilesData.swift
  27. 6 5
      Widget/Files/FilesWidgetView.swift
  28. 1 1
      Widget/Lockscreen/LockscreenData.swift
  29. 3 0
      Widget/Lockscreen/LockscreenWidgetView.swift
  30. 1 3
      Widget/Toolbar/ToolbarWidgetView.swift
  31. 16 0
      Widget/Widget.swift
  32. 16 23
      iOSClient/Activity/NCActivity.swift
  33. 14 5
      iOSClient/Activity/NCActivityTableViewCell.swift
  34. 161 204
      iOSClient/AppDelegate.swift
  35. 2 2
      iOSClient/BrowserWeb/NCBrowserWeb.swift
  36. 1 1
      iOSClient/Color/NCColorPicker.swift
  37. 7 96
      iOSClient/Data/NCDataSource.swift
  38. 2 40
      iOSClient/Data/NCDatabase.swift
  39. 20 20
      iOSClient/Data/NCManageDatabase+Account.swift
  40. 12 6
      iOSClient/Data/NCManageDatabase+Activity.swift
  41. 4 2
      iOSClient/Data/NCManageDatabase+Avatar.swift
  42. 7 1
      iOSClient/Data/NCManageDatabase+Capabilities.swift
  43. 127 0
      iOSClient/Data/NCManageDatabase+Chunk.swift
  44. 4 2
      iOSClient/Data/NCManageDatabase+DashboardWidget.swift
  45. 31 5
      iOSClient/Data/NCManageDatabase+Directory.swift
  46. 289 79
      iOSClient/Data/NCManageDatabase+E2EE.swift
  47. 2 1
      iOSClient/Data/NCManageDatabase+LayoutForView.swift
  48. 209 0
      iOSClient/Data/NCManageDatabase+LocalFile.swift
  49. 97 52
      iOSClient/Data/NCManageDatabase+Metadata.swift
  50. 23 8
      iOSClient/Data/NCManageDatabase+Share.swift
  51. 2 1
      iOSClient/Data/NCManageDatabase+Video.swift
  52. 54 260
      iOSClient/Data/NCManageDatabase.swift
  53. 0 1
      iOSClient/EmptyView/NCEmptyDataSet.swift
  54. 9 3
      iOSClient/Extensions/UIAlertController+Extension.swift
  55. 13 0
      iOSClient/Extensions/UIDevice+Extension.swift
  56. 1 1
      iOSClient/Extensions/UINavigationController+Extension.swift
  57. 2 2
      iOSClient/Extensions/UIToolbar+Extension.swift
  58. 34 51
      iOSClient/Favorites/NCFavorite.swift
  59. 70 44
      iOSClient/Files/NCFiles.swift
  60. 28 35
      iOSClient/Groupfolders/NCGroupfolders.swift
  61. 40 29
      iOSClient/Login/NCLogin.swift
  62. 47 58
      iOSClient/Login/NCLoginWeb.swift
  63. 1 1
      iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift
  64. 226 345
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  65. 15 14
      iOSClient/Main/Collection Common/NCGridCell.swift
  66. 19 18
      iOSClient/Main/Collection Common/NCListCell.swift
  67. 7 5
      iOSClient/Main/Collection Common/NCSelectableNavigationView.swift
  68. 18 19
      iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift
  69. 62 72
      iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift
  70. 27 27
      iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift
  71. 8 5
      iOSClient/Main/Create cloud/NCCreateMenuAdd.swift
  72. 70 97
      iOSClient/Main/NCActionCenter.swift
  73. 1 0
      iOSClient/Main/NCCellProtocol.swift
  74. 27 14
      iOSClient/Main/NCMainTabBar.swift
  75. 8 2
      iOSClient/Main/NCPickerViewController.swift
  76. 112 20
      iOSClient/Main/Section Header Footer/NCSectionHeaderMenu.swift
  77. 98 28
      iOSClient/Main/Section Header Footer/NCSectionHeaderMenu.xib
  78. 1 0
      iOSClient/Media/Cell/NCGridMediaCell.swift
  79. 97 87
      iOSClient/Media/NCMedia.swift
  80. 4 4
      iOSClient/Media/NCMediaCommandView.xib
  81. 72 65
      iOSClient/Menu/AppDelegate+Menu.swift
  82. 20 25
      iOSClient/Menu/NCCollectionViewCommon+Menu.swift
  83. 11 13
      iOSClient/Menu/NCContextMenu.swift
  84. 4 5
      iOSClient/Menu/NCLoginWeb+Menu.swift
  85. 14 11
      iOSClient/Menu/NCMedia+Menu.swift
  86. 1 1
      iOSClient/Menu/NCMenu+FloatingPanel.swift
  87. 15 13
      iOSClient/Menu/NCMenuAction.swift
  88. 15 1
      iOSClient/Menu/NCShare+Menu.swift
  89. 1 1
      iOSClient/Menu/NCSortMenu.swift
  90. 16 0
      iOSClient/Menu/NCTrash+Menu.swift
  91. 8 7
      iOSClient/Menu/NCViewer+Menu.swift
  92. 44 0
      iOSClient/More/Cells/BaseNCMoreCell.swift
  93. 18 0
      iOSClient/More/Cells/CCCellMore.swift
  94. 57 0
      iOSClient/More/Cells/NCMoreAppSuggestionsCell.swift
  95. 157 0
      iOSClient/More/Cells/NCMoreAppSuggestionsCell.xib
  96. 23 0
      iOSClient/More/Cells/NCMoreUserCell.swift
  97. 3 3
      iOSClient/More/Cells/NCMoreUserCell.xib
  98. 3 3
      iOSClient/More/NCMore.storyboard
  99. 102 190
      iOSClient/More/NCMore.swift
  100. 69 51
      iOSClient/NCGlobal.swift

+ 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

+ 10 - 115
.swiftlint.yml

@@ -10,24 +10,25 @@ empty_count:
   severity: warning
   severity: warning
 
 
 line_length:
 line_length:
-  warning: 400
+  warning: 1000
   error: 5000
   error: 5000
 
 
 function_body_length:
 function_body_length:
    warning: 400
    warning: 400
 
 
 type_body_length:
 type_body_length:
-  warning: 800
-  error: 1000
-  
+  warning: 1500
+  error: 2000
+
 file_length:
 file_length:
-  warning: 1000
-  error: 1500
+  warning: 2000
+  error: 2500
   ignore_comment_only_lines: true
   ignore_comment_only_lines: true
 
 
 identifier_name:
 identifier_name:
   min_length: 0
   min_length: 0
-  
+  max_length: 100
+
 disabled_rules:  
 disabled_rules:  
   - unused_setter_value
   - unused_setter_value
   - large_tuple
   - large_tuple
@@ -38,120 +39,14 @@ disabled_rules:
   - nesting
   - nesting
   - shorthand_operator
   - shorthand_operator
   - type_name
   - type_name
-    
+  - void_function_in_ternary
+
 excluded:
 excluded:
   - Carthage
   - Carthage
   - Pods
   - Pods
   - Tests
   - Tests
-
-  # iOS Files Quarantine
-
   - Brand/NCBrand.swift
   - Brand/NCBrand.swift
-  - File Provider Extension/FileProviderData.swift
-  - File Provider Extension/FileProviderDomain.swift
-  - File Provider Extension/FileProviderEnumerator.swift
-  - File Provider Extension/FileProviderExtension+Actions.swift
-  - File Provider Extension/FileProviderExtension+Thumbnail.swift
-  - File Provider Extension/FileProviderExtension.swift
-  - File Provider Extension/FileProviderUtility.swift
-  - Notification Service Extension/NotificationService.swift
-  - Widget/Widget.swift
-  - Widget/Dashboard/DashboardData.swift
-  - Widget/Dashboard/DashboardWidgetView.swift
-  - Widget/Files/FilesData.swift
-  - Widget/Files/FilesWidgetView.swift
-  - Widget/Lockscreen/LockscreenData.swift
-  - Widget/Lockscreen/LockscreenWidgetView.swift
-  - Widget/Lockscreen/LockscreenWidgetProvider.swift
-  - iOSClient/GUI
-  - iOSClient/ExternalResources
-  - iOSClient/Activity/NCActivity.swift
-  - iOSClient/Activity/NCActivityTableViewCell.swift
-  - iOSClient/AppDelegate.swift
-  - iOSClient/BackgroundImageColor/NCBackgroundImageColor.swift
-  - iOSClient/BrowserWeb/NCBrowserWeb.swift
-  - iOSClient/Diagnostics/NCCapabilitiesViewController.swift
-  - iOSClient/EmptyView/NCEmptyDataSet.swift
-  - iOSClient/Extensions/UIColor+Extensions.swift
-  - iOSClient/Extensions/UIImage+Extensions.swift
-  - iOSClient/FileViewInFolder/NCFileViewInFolder.swift
-  - iOSClient/Login/NCAppConfigView.swift
-  - iOSClient/Login/NCLogin.swift
-  - iOSClient/Login/NCLoginWeb.swift
-  - iOSClient/Main/Account Request/NCAccountRequest.swift
-  - iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift
-  - iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
-  - iOSClient/Main/Collection Common/NCGridCell.swift
-  - iOSClient/Main/Collection Common/NCListCell.swift
-  - iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift
-  - iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift
-  - iOSClient/Main/Create cloud/NCCreateFormUploadConflictCell.swift
-  - iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift
-  - iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift
-  - iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift
-  - iOSClient/Main/Create cloud/NCCreateMenuAdd.swift
-  - iOSClient/Main/NCFunctionCenter.swift
-  - iOSClient/Main/NCMainTabBar.swift
-  - iOSClient/Main/NCPickerViewController.swift
-  - iOSClient/Main/Section Header Footer/NCSectionHeaderFooter.swift
-  - iOSClient/Media/Cell/NCGridMediaCell.swift
-  - iOSClient/Media/NCMedia.swift
-  - iOSClient/Menu/AppDelegate+Menu.swift
-  - iOSClient/Menu/NCCollectionViewCommon+Menu.swift
-  - iOSClient/Menu/NCLoginWeb+Menu.swift
-  - iOSClient/Menu/NCMedia+Menu.swift
-  - iOSClient/Menu/NCSortMenu.swift
-  - iOSClient/Menu/NCViewer+Menu.swift
-  - iOSClient/More/NCMore.swift
   - iOSClient/NCGlobal.swift
   - iOSClient/NCGlobal.swift
-  - iOSClient/Networking/NCAutoUpload.swift
-  - iOSClient/Networking/NCNetworking.swift
-  - iOSClient/Networking/NCNetworkingCheckRemoteUser.swift
-  - iOSClient/Networking/NCNetworkingChunkedUpload.swift
-  - iOSClient/Networking/E2EE/NCNetworkingE2EE.swift
-  - iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift
-  - iOSClient/Networking/E2EE/NCNetworkingE2EEDelete.swift
-  - iOSClient/Networking/E2EE/NCNetworkingE2EERename.swift
-  - iOSClient/Networking/E2EE/NCNetworkingE2EECreateFolder.swift
-  - iOSClient/Networking/NCNetworkingProcessUpload.swift
-  - iOSClient/Networking/NCOperationQueue.swift
-  - iOSClient/Networking/NCService.swift
-  - iOSClient/Networking/NCConfigServer.swift
-  - iOSClient/Notification/NCNotification.swift
-  - iOSClient/Recent/NCRecent.swift
-  - iOSClient/Rename file/NCRenameFile.swift
-  - iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift
-  - iOSClient/RichWorkspace/NCViewerRichWorkspace.swift
-  - iOSClient/ScanDocument/ScanCollectionView.swift
-  - iOSClient/Security/NCEndToEndMetadata.swift
-  - iOSClient/Security/NCViewCertificateDetails.swift
-  - iOSClient/Select/NCSelect.swift
-  - iOSClient/Settings/NCEndToEndInitialize.swift
-  - iOSClient/Settings/NCManageAutoUploadFileName.swift
-  - iOSClient/Settings/NCManageE2EE.swift
-  - iOSClient/Share/NCShareCommon.swift
-  - iOSClient/Share/NCShareNetworking.swift
-  - iOSClient/Shares/NCShares.swift
-  - iOSClient/Transfers/NCTransferCell.swift
-  - iOSClient/Transfers/NCTransfers.swift
-  - iOSClient/UserStatus/NCUserStatus.swift
-  - iOSClient/Utility/NCAskAuthorization.swift
-  - iOSClient/Utility/NCContentPresenter.swift
   - iOSClient/Utility/NCLivePhoto.swift
   - iOSClient/Utility/NCLivePhoto.swift
-  - iOSClient/Utility/NCPopupViewController.swift
-  - iOSClient/Utility/NCStoreReview.swift
-  - iOSClient/Utility/NCUtility.swift
-  - iOSClient/Utility/NCUtilityFileSystem.swift
-  - iOSClient/Utility/NCUtilityGUI.swift
-  - iOSClient/Viewer/NCViewer.swift
-  - iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift
-  - iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift
-  - iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift
-  - iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift
-  - iOSClient/Viewer/NCViewerNextcloudText/NCViewerNextcloudText.swift
-  - iOSClient/Viewer/NCViewerPDF/NCViewerPDF.swift
-  - iOSClient/Viewer/NCViewerPDF/NCViewerPDFSearch.swift
-  - iOSClient/Viewer/NCViewerProviderContextMenu.swift
-  - iOSClient/Viewer/NCViewerRichdocument/NCViewerRichdocument.swift
 
 
 reporter: "xcode"
 reporter: "xcode"

+ 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   = 301
+let databaseSchemaVersion: UInt64   = 318

+ 2 - 0
Brand/Intro/NCIntroCollectionViewCell.swift

@@ -30,6 +30,8 @@ class NCIntroCollectionViewCell: UICollectionViewCell {
     @IBOutlet weak var titleLabel: UILabel!
     @IBOutlet weak var titleLabel: UILabel!
     @IBOutlet weak var imageView: UIImageView!
     @IBOutlet weak var imageView: UIImageView!
 
 
+    var indexPath = IndexPath()
+
     override func awakeFromNib() {
     override func awakeFromNib() {
         super.awakeFromNib()
         super.awakeFromNib()
     }
     }

+ 1 - 1
Brand/Intro/NCIntroViewController.swift

@@ -137,7 +137,7 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
         let cell = (collectionView.dequeueReusableCell(withReuseIdentifier: "introCell", for: indexPath) as? NCIntroCollectionViewCell)!
         let cell = (collectionView.dequeueReusableCell(withReuseIdentifier: "introCell", for: indexPath) as? NCIntroCollectionViewCell)!
         cell.backgroundColor = NCBrandColor.shared.customer
         cell.backgroundColor = NCBrandColor.shared.customer
-
+        cell.indexPath = indexPath
         cell.titleLabel.textColor = textColor
         cell.titleLabel.textColor = textColor
         cell.titleLabel.text = titles[indexPath.row]
         cell.titleLabel.text = titles[indexPath.row]
         cell.imageView.image = images[indexPath.row]
         cell.imageView.image = images[indexPath.row]

+ 39 - 35
Brand/NCBrand.swift

@@ -23,7 +23,11 @@
 
 
 import UIKit
 import UIKit
 
 
-// MARK: - Options
+let userAgent: String = {
+    let appVersion: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
+    // Original Nextcloud useragent "Mozilla/5.0 (iOS) Nextcloud-iOS/\(appVersion)"
+    return "Mozilla/5.0 (iOS) Nextcloud-iOS/\(appVersion)"
+}()
 
 
 @objc class NCBrandOptions: NSObject {
 @objc class NCBrandOptions: NSObject {
     @objc static let shared: NCBrandOptions = {
     @objc static let shared: NCBrandOptions = {
@@ -54,33 +58,31 @@ import UIKit
     @objc public var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud"
     @objc public var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud"
     @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps"
     @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps"
 
 
-    // User Agent
-    @objc public var userAgent: String = "Nextcloud-iOS"                                                            // Don't touch me !!
-
     // BRAND ONLY
     // BRAND ONLY
-    @objc public var use_login_web_personalized:        Bool = false                                                // Don't touch me !!
-    @objc public var use_AppConfig:                     Bool = false                                                // Don't touch me !!
-    @objc public var use_GroupApps:                     Bool = true                                                 // Don't touch me !!
+    @objc public var use_login_web_personalized: Bool = false                                   // Don't touch me !!
+    @objc public var use_AppConfig: Bool = false                                                // Don't touch me !!
+    @objc public var use_GroupApps: Bool = true                                                 // Don't touch me !!
 
 
     // Options
     // Options
-    @objc public var use_default_auto_upload:           Bool = false
-    @objc public var use_themingColor:                  Bool = true
-    @objc public var use_themingLogo:                   Bool = false
-    @objc public var use_storeLocalAutoUploadAll:       Bool = false
-    @objc public var use_loginflowv2:                   Bool = false                                                // Don't touch me !!
-
-    @objc public var disable_intro:                     Bool = false
-    @objc public var disable_request_login_url:         Bool = false
-    @objc public var disable_multiaccount:              Bool = false
-    @objc public var disable_manage_account:            Bool = false
-    @objc public var disable_more_external_site:        Bool = false
-    @objc public var disable_openin_file:               Bool = false                                                // Don't touch me !!
-    @objc public var disable_crash_service:             Bool = false
-    @objc public var disable_log:                       Bool = false
-    @objc public var disable_mobileconfig:              Bool = false
+    @objc public var use_default_auto_upload: Bool = false
+    @objc public var use_themingColor: Bool = true
+    @objc public var use_themingLogo: Bool = false
+    @objc public var use_storeLocalAutoUploadAll: Bool = false
+    @objc public var use_loginflowv2: Bool = false                                              // Don't touch me !!
+
+    @objc public var disable_intro: Bool = false
+    @objc public var disable_request_login_url: Bool = false
+    @objc public var disable_multiaccount: Bool = false
+    @objc public var disable_manage_account: Bool = false
+    @objc public var disable_more_external_site: Bool = false
+    @objc public var disable_openin_file: Bool = false                                          // Don't touch me !!
+    @objc public var disable_crash_service: Bool = false
+    @objc public var disable_log: Bool = false
+    @objc public var disable_mobileconfig: Bool = false
+    @objc public var disable_show_more_nextcloud_apps_in_settings: Bool = false
 
 
     // Internal option behaviour
     // Internal option behaviour
-    @objc public var cleanUpDay:                        Int = 0                                                     // Set default "Delete, in the cache, all files older than" possible days value are: 0, 1, 7, 30, 90, 180, 365
+    @objc public var cleanUpDay: Int = 0                                                        // Set default "Delete, in the cache, all files older than" possible days value are: 0, 1, 7, 30, 90, 180, 365
 
 
     // Info Paging
     // Info Paging
     enum NCInfoPagingTab: Int, CaseIterable {
     enum NCInfoPagingTab: Int, CaseIterable {
@@ -92,10 +94,10 @@ import UIKit
         if folderBrandAutoUpload != "" {
         if folderBrandAutoUpload != "" {
             folderDefaultAutoUpload = folderBrandAutoUpload
             folderDefaultAutoUpload = folderBrandAutoUpload
         }
         }
-        
+
         // wrapper AppConfig
         // wrapper AppConfig
         if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), use_AppConfig {
         if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), use_AppConfig {
-            
+
             if let str = configurationManaged[NCGlobal.shared.configuration_brand] as? String {
             if let str = configurationManaged[NCGlobal.shared.configuration_brand] as? String {
                 brand = str
                 brand = str
             }
             }
@@ -122,9 +124,11 @@ import UIKit
             }
             }
         }
         }
     }
     }
-}
 
 
-// MARK: - Color
+    @objc func getUserAgent() -> String {
+        return userAgent
+    }
+}
 
 
 class NCBrandColor: NSObject {
 class NCBrandColor: NSObject {
     @objc static let shared: NCBrandColor = {
     @objc static let shared: NCBrandColor = {
@@ -172,15 +176,15 @@ class NCBrandColor: NSObject {
     }
     }
 
 
     // Color
     // Color
-    @objc public let customer: UIColor = UIColor(red: 0.0/255.0, green: 130.0/255.0, blue: 201.0/255.0, alpha: 1.0)         // BLU NC : #0082c9
+    @objc public let customer: UIColor = UIColor(red: 0.0 / 255.0, green: 130.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0)         // BLU NC : #0082c9
     @objc public var customerText: UIColor = .white
     @objc public var customerText: UIColor = .white
 
 
     @objc public var brand: UIColor                                                                                         // don't touch me
     @objc public var brand: UIColor                                                                                         // don't touch me
     @objc public var brandElement: UIColor                                                                                  // don't touch me
     @objc public var brandElement: UIColor                                                                                  // don't touch me
     @objc public var brandText: UIColor                                                                                     // don't touch me
     @objc public var brandText: UIColor                                                                                     // don't touch me
 
 
-    @objc public let nextcloud: UIColor = UIColor(red: 0.0/255.0, green: 130.0/255.0, blue: 201.0/255.0, alpha: 1.0)
-    @objc public let yellowFavorite: UIColor = UIColor(red: 248.0/255.0, green: 205.0/255.0, blue: 70.0/255.0, alpha: 1.0)
+    @objc public let nextcloud: UIColor = UIColor(red: 0.0 / 255.0, green: 130.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0)
+    @objc public let yellowFavorite: UIColor = UIColor(red: 248.0 / 255.0, green: 205.0 / 255.0, blue: 70.0 / 255.0, alpha: 1.0)
 
 
     public var userColors: [CGColor] = []
     public var userColors: [CGColor] = []
     public var themingColor: String = ""
     public var themingColor: String = ""
@@ -224,7 +228,7 @@ class NCBrandColor: NSObject {
         cacheImages.folderGroup = UIImage(named: "folder_group")!.image(color: brandElement, size: folderWidth)
         cacheImages.folderGroup = UIImage(named: "folder_group")!.image(color: brandElement, size: folderWidth)
         cacheImages.folderExternal = UIImage(named: "folder_external")!.image(color: brandElement, size: folderWidth)
         cacheImages.folderExternal = UIImage(named: "folder_external")!.image(color: brandElement, size: folderWidth)
         cacheImages.folderAutomaticUpload = UIImage(named: "folderAutomaticUpload")!.image(color: brandElement, size: folderWidth)
         cacheImages.folderAutomaticUpload = UIImage(named: "folderAutomaticUpload")!.image(color: brandElement, size: folderWidth)
-        cacheImages.folder =  UIImage(named: "folder")!.image(color: brandElement, size: folderWidth)
+        cacheImages.folder = UIImage(named: "folder")!.image(color: brandElement, size: folderWidth)
 
 
         cacheImages.checkedYes = NCUtility.shared.loadImage(named: "checkmark.circle.fill", color: .systemBlue)
         cacheImages.checkedYes = NCUtility.shared.loadImage(named: "checkmark.circle.fill", color: .systemBlue)
         cacheImages.checkedNo = NCUtility.shared.loadImage(named: "circle", color: .systemGray)
         cacheImages.checkedNo = NCUtility.shared.loadImage(named: "circle", color: .systemGray)
@@ -315,7 +319,7 @@ class NCBrandColor: NSObject {
             brand = customer
             brand = customer
             brandText = customerText
             brandText = customerText
         }
         }
-        
+
         createImagesThemingColor()
         createImagesThemingColor()
 #if !EXTENSION
 #if !EXTENSION
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeTheming)
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeTheming)
@@ -352,9 +356,9 @@ class NCBrandColor: NSObject {
      3 colors \* 6 will result in 18 generated colors
      3 colors \* 6 will result in 18 generated colors
      */
      */
     func generateColors(steps: Int = 6) -> [CGColor] {
     func generateColors(steps: Int = 6) -> [CGColor] {
-        let red = UIColor(red: 182/255, green: 70/255, blue: 157/255, alpha: 1).cgColor
-        let yellow = UIColor(red: 221/255, green: 203/255, blue: 85/255, alpha: 1).cgColor
-        let blue = UIColor(red: 0/255, green: 130/255, blue: 201/255, alpha: 1).cgColor
+        let red = UIColor(red: 182 / 255, green: 70 / 255, blue: 157 / 255, alpha: 1).cgColor
+        let yellow = UIColor(red: 221 / 255, green: 203 / 255, blue: 85 / 255, alpha: 1).cgColor
+        let blue = UIColor(red: 0 / 255, green: 130 / 255, blue: 201 / 255, alpha: 1).cgColor
 
 
         let palette1 = mixPalette(steps: steps, color1: red, color2: yellow)
         let palette1 = mixPalette(steps: steps, color1: red, color2: yellow)
         let palette2 = mixPalette(steps: steps, color1: yellow, color2: blue)
         let palette2 = mixPalette(steps: steps, color1: yellow, color2: blue)

+ 3 - 3
Brand/iOSClient.plist

@@ -65,11 +65,11 @@
 	<key>NSFaceIDUsageDescription</key>
 	<key>NSFaceIDUsageDescription</key>
 	<string>Face ID is required to authenticate using face recognition.</string>
 	<string>Face ID is required to authenticate using face recognition.</string>
 	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
 	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
-	<string>GPS is used to detect new photos from camera roll. Continued use of GPS running in the background can dramatically decrease battery life.</string>
+	<string>The app will show your location on a map.</string>
 	<key>NSLocationAlwaysUsageDescription</key>
 	<key>NSLocationAlwaysUsageDescription</key>
-	<string>GPS is used to detect new photos from camera roll. Continued use of GPS running in the background can dramatically decrease battery life.</string>
+	<string>The app will show your location on a map.</string>
 	<key>NSLocationWhenInUseUsageDescription</key>
 	<key>NSLocationWhenInUseUsageDescription</key>
-	<string>GPS is used to detect new photos from camera roll on background. It is useless to use GPS only while using the app.</string>
+	<string>The app will show your location on a map.</string>
 	<key>NSMicrophoneUsageDescription</key>
 	<key>NSMicrophoneUsageDescription</key>
 	<string>Microphone access is required to create voice notes.</string>
 	<string>Microphone access is required to create voice notes.</string>
 	<key>NSPhotoLibraryAddUsageDescription</key>
 	<key>NSPhotoLibraryAddUsageDescription</key>

+ 4 - 3
ExternalResources/NCApplicationHandle.swift

@@ -32,8 +32,8 @@ class NCApplicationHandle: NSObject {
 
 
     // class: AppDelegate
     // class: AppDelegate
     // func nextcloudPushNotificationAction(data: [String: AnyObject])
     // func nextcloudPushNotificationAction(data: [String: AnyObject])
-    func nextcloudPushNotificationAction(data: [String: AnyObject], completion: @escaping () -> Void) {
-        completion()
+    func nextcloudPushNotificationAction(data: [String: AnyObject]) -> [String: AnyObject]? {
+        return data
     }
     }
 
 
     // class: AppDelegate
     // class: AppDelegate
@@ -86,6 +86,7 @@ class NCApplicationHandle: NSObject {
     }
     }
 
 
     // class: NCNotification
     // class: NCNotification
-    func didSelectNotification(_ notification: NKNotifications, viewController: UIViewController) {
+    func didSelectNotification(_ notification: NKNotifications, viewController: UIViewController) -> NKNotifications? {
+        return notification
     }
     }
 }
 }

+ 3 - 3
File Provider Extension/FileProviderData.swift

@@ -93,7 +93,7 @@ class fileProviderData: NSObject {
 
 
             NCManageDatabase.shared.setCapabilities(account: account)
             NCManageDatabase.shared.setCapabilities(account: account)
 
 
-            NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
+            NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: userAgent, nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
             NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
             NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
 
 
             return tableAccount.init(value: activeAccount)
             return tableAccount.init(value: activeAccount)
@@ -101,7 +101,7 @@ class fileProviderData: NSObject {
 
 
         // DOMAIN
         // DOMAIN
         let accounts = NCManageDatabase.shared.getAllAccount()
         let accounts = NCManageDatabase.shared.getAllAccount()
-        if accounts.count == 0 { return nil }
+        if accounts.isEmpty { return nil }
 
 
         for activeAccount in accounts {
         for activeAccount in accounts {
             guard let url = NSURL(string: activeAccount.urlBase) else { continue }
             guard let url = NSURL(string: activeAccount.urlBase) else { continue }
@@ -117,7 +117,7 @@ class fileProviderData: NSObject {
 
 
                 NCManageDatabase.shared.setCapabilities(account: account)
                 NCManageDatabase.shared.setCapabilities(account: account)
 
 
-                NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
+                NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: userAgent, nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
                 NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
                 NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
 
 
                 return tableAccount.init(value: activeAccount)
                 return tableAccount.init(value: activeAccount)

+ 2 - 2
File Provider Extension/FileProviderDomain.swift

@@ -43,7 +43,7 @@ class FileProviderDomain: NSObject {
                 for account in accounts {
                 for account in accounts {
                     guard let urlBase = NSURL(string: account.urlBase) else { continue }
                     guard let urlBase = NSURL(string: account.urlBase) else { continue }
                     guard let host = urlBase.host else { continue }
                     guard let host = urlBase.host else { continue }
-                    let accountDomain =  account.userId + " (" + host + ")"
+                    let accountDomain = account.userId + " (" + host + ")"
                     if domain == accountDomain {
                     if domain == accountDomain {
                         domainFound = true
                         domainFound = true
                         break
                         break
@@ -64,7 +64,7 @@ class FileProviderDomain: NSObject {
                 var domainFound = false
                 var domainFound = false
                 guard let urlBase = NSURL(string: account.urlBase) else { continue }
                 guard let urlBase = NSURL(string: account.urlBase) else { continue }
                 guard let host = urlBase.host else { continue }
                 guard let host = urlBase.host else { continue }
-                let accountDomain =  account.userId + " (" + host + ")"
+                let accountDomain = account.userId + " (" + host + ")"
                 for domain in domains {
                 for domain in domains {
                     if domain == accountDomain {
                     if domain == accountDomain {
                         domainFound = true
                         domainFound = true

+ 1 - 1
File Provider Extension/FileProviderEnumerator.swift

@@ -173,7 +173,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
 
 
             for metadata in metadatas! {
             for metadata in metadatas! {
 
 
-                if metadata.e2eEncrypted || (metadata.session != "" && metadata.session != NCNetworking.shared.sessionIdentifierBackgroundExtension) { continue }
+                if metadata.e2eEncrypted || (!metadata.session.isEmpty && metadata.session != NCNetworking.shared.sessionIdentifierBackgroundExtension) { continue }
 
 
                 fileProviderUtility.shared.createocIdentifierOnFileSystem(metadata: metadata)
                 fileProviderUtility.shared.createocIdentifierOnFileSystem(metadata: metadata)
 
 

+ 3 - 5
File Provider Extension/FileProviderExtension+Actions.swift

@@ -37,15 +37,13 @@ extension FileProviderExtension {
         let directoryName = NCUtilityFileSystem.shared.createFileName(directoryName, serverUrl: tableDirectory.serverUrl, account: fileProviderData.shared.account)
         let directoryName = NCUtilityFileSystem.shared.createFileName(directoryName, serverUrl: tableDirectory.serverUrl, account: fileProviderData.shared.account)
         let serverUrlFileName = tableDirectory.serverUrl + "/" + directoryName
         let serverUrlFileName = tableDirectory.serverUrl + "/" + directoryName
 
 
-        NextcloudKit.shared.createFolder(serverUrlFileName: serverUrlFileName) { account, ocId, _, error in
+        NextcloudKit.shared.createFolder(serverUrlFileName: serverUrlFileName) { _, ocId, _, error in
 
 
             if error == .success {
             if error == .success {
 
 
-                NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { account, files, _, error in
+                NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { _, files, _, error in
 
 
-                    if error == .success && files.count > 0 {
-
-                        let file = files.first!
+                    if error == .success, let file = files.first {
 
 
                         let isDirectoryEncrypted = NCUtility.shared.isDirectoryE2EE(file: file)
                         let isDirectoryEncrypted = NCUtility.shared.isDirectoryE2EE(file: file)
                         let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryEncrypted)
                         let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryEncrypted)

+ 9 - 13
File Provider Extension/FileProviderExtension.swift

@@ -79,9 +79,9 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate {
             if fileProviderData.shared.setupAccount(domain: domain, providerExtension: self) == nil {
             if fileProviderData.shared.setupAccount(domain: domain, providerExtension: self) == nil {
                 throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo: [:])
                 throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo: [:])
             } else if let passcode = CCUtility.getPasscode(), !passcode.isEmpty, CCUtility.isPasscodeAtStartEnabled() {
             } else if let passcode = CCUtility.getPasscode(), !passcode.isEmpty, CCUtility.isPasscodeAtStartEnabled() {
-                throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo: ["code" : NSNumber(value: NCGlobal.shared.errorUnauthorizedFilesPasscode)])
+                throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo: ["code": NSNumber(value: NCGlobal.shared.errorUnauthorizedFilesPasscode)])
             } else if CCUtility.getDisableFilesApp() || NCBrandOptions.shared.disable_openin_file {
             } else if CCUtility.getDisableFilesApp() || NCBrandOptions.shared.disable_openin_file {
-                throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo: ["code" : NSNumber(value: NCGlobal.shared.errorDisableFilesApp)])
+                throw NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.notAuthenticated.rawValue, userInfo: ["code": NSNumber(value: NCGlobal.shared.errorDisableFilesApp)])
             }
             }
         }
         }
 
 
@@ -190,26 +190,22 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate {
         let pathComponents = url.pathComponents
         let pathComponents = url.pathComponents
         let identifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
         let identifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
 
 
-        if let _ = outstandingSessionTasks[url] {
-            completionHandler(nil)
-            return
+        if outstandingSessionTasks[url] != nil {
+            return completionHandler(nil)
         }
         }
 
 
         guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(identifier) else {
         guard let metadata = fileProviderUtility.shared.getTableMetadataFromItemIdentifier(identifier) else {
-            completionHandler(NSFileProviderError(.noSuchItem))
-            return
+            return completionHandler(NSFileProviderError(.noSuchItem))
         }
         }
 
 
         // Document VIEW ONLY
         // Document VIEW ONLY
         if metadata.isDocumentViewableOnly {
         if metadata.isDocumentViewableOnly {
-            completionHandler(NSFileProviderError(.noSuchItem))
-            return
+            return completionHandler(NSFileProviderError(.noSuchItem))
         }
         }
 
 
         let tableLocalFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
         let tableLocalFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
         if tableLocalFile != nil && CCUtility.fileProviderStorageExists(metadata) && tableLocalFile?.etag == metadata.etag {
         if tableLocalFile != nil && CCUtility.fileProviderStorageExists(metadata) && tableLocalFile?.etag == metadata.etag {
-            completionHandler(nil)
-            return
+            return completionHandler(nil)
         }
         }
 
 
         let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
         let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
@@ -337,8 +333,8 @@ class FileProviderExtension: NSFileProviderExtension, NCNetworkingDelegate {
                 // typefile directory ? (NOT PERMITTED)
                 // typefile directory ? (NOT PERMITTED)
                 do {
                 do {
                     let attributes = try fileProviderUtility.shared.fileManager.attributesOfItem(atPath: fileURL.path)
                     let attributes = try fileProviderUtility.shared.fileManager.attributesOfItem(atPath: fileURL.path)
-                    size = attributes[FileAttributeKey.size] as! Int64
-                    let typeFile = attributes[FileAttributeKey.type] as! FileAttributeType
+                    size = attributes[FileAttributeKey.size] as? Int64 ?? 0
+                    let typeFile = attributes[FileAttributeKey.type] as? FileAttributeType
                     if typeFile == FileAttributeType.typeDirectory {
                     if typeFile == FileAttributeType.typeDirectory {
                         completionHandler(nil, NSFileProviderError(.noSuchItem))
                         completionHandler(nil, NSFileProviderError(.noSuchItem))
                         return
                         return

+ 155 - 28
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 */; };
@@ -102,6 +101,7 @@
 		F31F69662A2F929600162F76 /* PreviewSnapshotsTesting in Frameworks */ = {isa = PBXBuildFile; productRef = F31F69652A2F929600162F76 /* PreviewSnapshotsTesting */; };
 		F31F69662A2F929600162F76 /* PreviewSnapshotsTesting in Frameworks */ = {isa = PBXBuildFile; productRef = F31F69652A2F929600162F76 /* PreviewSnapshotsTesting */; };
 		F31F69692A2F92F000162F76 /* SnapshotTestingHEIC in Frameworks */ = {isa = PBXBuildFile; productRef = F31F69682A2F92F000162F76 /* SnapshotTestingHEIC */; };
 		F31F69692A2F92F000162F76 /* SnapshotTestingHEIC in Frameworks */ = {isa = PBXBuildFile; productRef = F31F69682A2F92F000162F76 /* SnapshotTestingHEIC */; };
 		F32ED5062A2F254400EABA81 /* EnvVars.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = F30A96302A27AEBF00D7BCFE /* EnvVars.generated.swift */; };
 		F32ED5062A2F254400EABA81 /* EnvVars.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = F30A96302A27AEBF00D7BCFE /* EnvVars.generated.swift */; };
+		F33AAF9A2A60394C006ECCBD /* NCMoreUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */; };
 		F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
 		F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
 		F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
 		F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
 		F343A4B52A1E084200DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
 		F343A4B52A1E084200DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
@@ -116,7 +116,20 @@
 		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 */; };
+		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 */; };
+		F3BB464D2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F3BB464C2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib */; };
+		F3BB464F2A39EBE500461F6E /* NCMoreUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */; };
+		F3BB46522A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */; };
+		F3BB46542A3A1E9D00461F6E /* CCCellMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */; };
 		F700222C1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
 		F700222C1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
 		F700222D1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
 		F700222D1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
 		F700510122DF63AC003A3356 /* NCShare.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F700510022DF63AC003A3356 /* NCShare.storyboard */; };
 		F700510122DF63AC003A3356 /* NCShare.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F700510022DF63AC003A3356 /* NCShare.storyboard */; };
@@ -177,7 +190,6 @@
 		F7148041262EBE4000693E51 /* NCShareExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7148040262EBE4000693E51 /* NCShareExtension.swift */; };
 		F7148041262EBE4000693E51 /* NCShareExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7148040262EBE4000693E51 /* NCShareExtension.swift */; };
 		F714804F262ED4F900693E51 /* NCGridCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4521903D010088454D /* NCGridCell.xib */; };
 		F714804F262ED4F900693E51 /* NCGridCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4521903D010088454D /* NCGridCell.xib */; };
 		F7148054262ED51000693E51 /* NCListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4321903CF20088454D /* NCListCell.xib */; };
 		F7148054262ED51000693E51 /* NCListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4321903CF20088454D /* NCListCell.xib */; };
-		F7148059262ED52200693E51 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD57219048040088454D /* NCSectionHeaderMenu.xib */; };
 		F714805E262ED52900693E51 /* NCSectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD53219047D40088454D /* NCSectionFooter.xib */; };
 		F714805E262ED52900693E51 /* NCSectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD53219047D40088454D /* NCSectionFooter.xib */; };
 		F7148063262ED66200693E51 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7239876253D86D300257F49 /* NCEmptyView.xib */; };
 		F7148063262ED66200693E51 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7239876253D86D300257F49 /* NCEmptyView.xib */; };
 		F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F717402B24F699A5000C87D5 /* NCFavorite.storyboard */; };
 		F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F717402B24F699A5000C87D5 /* NCFavorite.storyboard */; };
@@ -197,6 +209,10 @@
 		F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; };
 		F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; };
 		F72685E727C78E490019EF5E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F72685E927C78E490019EF5E /* InfoPlist.strings */; };
 		F72685E727C78E490019EF5E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F72685E927C78E490019EF5E /* InfoPlist.strings */; };
 		F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */; };
 		F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */; };
+		F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */; };
+		F72944F32A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */; };
+		F72944F52A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */; };
+		F72944F62A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */; };
 		F72A17D828B221E300F3F159 /* DashboardWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A17D728B221E300F3F159 /* DashboardWidgetView.swift */; };
 		F72A17D828B221E300F3F159 /* DashboardWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A17D728B221E300F3F159 /* DashboardWidgetView.swift */; };
 		F72A47EC2487B06B005AD489 /* NCOperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */; };
 		F72A47EC2487B06B005AD489 /* NCOperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */; };
 		F72AD70D28C24B93006CB92D /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F72AD70C28C24B93006CB92D /* NextcloudKit */; };
 		F72AD70D28C24B93006CB92D /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F72AD70C28C24B93006CB92D /* NextcloudKit */; };
@@ -294,6 +310,13 @@
 		F74AF3A4247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
 		F74AF3A4247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
 		F74AF3A5247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
 		F74AF3A5247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
 		F74AF3A6247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
 		F74AF3A6247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
+		F74B6D952A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */; };
+		F74B6D962A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */; };
+		F74B6D972A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */; };
+		F74B6D982A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */; };
+		F74B6D992A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */; };
+		F74B6D9A2A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */; };
+		F74B6D9B2A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */; };
 		F74C0436253F1CDC009762AB /* NCShares.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74C0434253F1CDC009762AB /* NCShares.swift */; };
 		F74C0436253F1CDC009762AB /* NCShares.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74C0434253F1CDC009762AB /* NCShares.swift */; };
 		F74C0437253F1CDC009762AB /* NCShares.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F74C0435253F1CDC009762AB /* NCShares.storyboard */; };
 		F74C0437253F1CDC009762AB /* NCShares.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F74C0435253F1CDC009762AB /* NCShares.storyboard */; };
 		F74DE14325135B6800917068 /* NCTransfers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74DE14125135B6800917068 /* NCTransfers.swift */; };
 		F74DE14325135B6800917068 /* NCTransfers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74DE14125135B6800917068 /* NCTransfers.swift */; };
@@ -415,6 +438,7 @@
 		F77BC3ED293E528A005F2B08 /* NCConfigServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77BC3EC293E528A005F2B08 /* NCConfigServer.swift */; };
 		F77BC3ED293E528A005F2B08 /* NCConfigServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77BC3EC293E528A005F2B08 /* NCConfigServer.swift */; };
 		F77C97392953131000FDDD09 /* NCCameraRoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77C97382953131000FDDD09 /* NCCameraRoll.swift */; };
 		F77C97392953131000FDDD09 /* NCCameraRoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77C97382953131000FDDD09 /* NCCameraRoll.swift */; };
 		F77C973A2953143A00FDDD09 /* NCCameraRoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77C97382953131000FDDD09 /* NCCameraRoll.swift */; };
 		F77C973A2953143A00FDDD09 /* NCCameraRoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77C97382953131000FDDD09 /* NCCameraRoll.swift */; };
+		F77CB6A92AA08053000C3CA4 /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F77CB6A82AA08053000C3CA4 /* OpenSSL */; };
 		F77ED59128C9CE9D00E24ED0 /* ToolbarData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59028C9CE9D00E24ED0 /* ToolbarData.swift */; };
 		F77ED59128C9CE9D00E24ED0 /* ToolbarData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59028C9CE9D00E24ED0 /* ToolbarData.swift */; };
 		F77ED59328C9CEA000E24ED0 /* ToolbarWidgetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59228C9CEA000E24ED0 /* ToolbarWidgetProvider.swift */; };
 		F77ED59328C9CEA000E24ED0 /* ToolbarWidgetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59228C9CEA000E24ED0 /* ToolbarWidgetProvider.swift */; };
 		F77ED59528C9CEA400E24ED0 /* ToolbarWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59428C9CEA300E24ED0 /* ToolbarWidgetView.swift */; };
 		F77ED59528C9CEA400E24ED0 /* ToolbarWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77ED59428C9CEA300E24ED0 /* ToolbarWidgetView.swift */; };
@@ -456,6 +480,13 @@
 		F785EEA42461A4A600B3F945 /* NCUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70BFC7320E0FA7C00C67599 /* NCUtility.swift */; };
 		F785EEA42461A4A600B3F945 /* NCUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70BFC7320E0FA7C00C67599 /* NCUtility.swift */; };
 		F785EEA52461A4CF00B3F945 /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; };
 		F785EEA52461A4CF00B3F945 /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; };
 		F785EEA62461A4FB00B3F945 /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; };
 		F785EEA62461A4FB00B3F945 /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; };
+		F7864ACC2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */; };
+		F7864ACD2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */; };
+		F7864ACE2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */; };
+		F7864ACF2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */; };
+		F7864AD02A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */; };
+		F7864AD12A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */; };
+		F7864AD22A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */; };
 		F787704F22E7019900F287A9 /* NCShareLinkCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F787704E22E7019900F287A9 /* NCShareLinkCell.xib */; };
 		F787704F22E7019900F287A9 /* NCShareLinkCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F787704E22E7019900F287A9 /* NCShareLinkCell.xib */; };
 		F787AC09298BCB4A0001BB00 /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F787AC08298BCB4A0001BB00 /* SVGKitSwift */; };
 		F787AC09298BCB4A0001BB00 /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F787AC08298BCB4A0001BB00 /* SVGKitSwift */; };
 		F787AC0B298BCB540001BB00 /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F787AC0A298BCB540001BB00 /* SVGKitSwift */; };
 		F787AC0B298BCB540001BB00 /* SVGKitSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F787AC0A298BCB540001BB00 /* SVGKitSwift */; };
@@ -476,7 +507,6 @@
 		F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4921903F850088454D /* NCTrashListCell.xib */; };
 		F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4921903F850088454D /* NCTrashListCell.xib */; };
 		F78ACD52219046DC0088454D /* NCSectionHeaderMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */; };
 		F78ACD52219046DC0088454D /* NCSectionHeaderMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */; };
 		F78ACD54219047D40088454D /* NCSectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD53219047D40088454D /* NCSectionFooter.xib */; };
 		F78ACD54219047D40088454D /* NCSectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD53219047D40088454D /* NCSectionFooter.xib */; };
-		F78ACD58219048040088454D /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD57219048040088454D /* NCSectionHeaderMenu.xib */; };
 		F78C6FDE296D677300C952C3 /* NCContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78C6FDD296D677300C952C3 /* NCContextMenu.swift */; };
 		F78C6FDE296D677300C952C3 /* NCContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78C6FDD296D677300C952C3 /* NCContextMenu.swift */; };
 		F78E2D6529AF02DB0024D4F3 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E2D6429AF02DB0024D4F3 /* Database.swift */; };
 		F78E2D6529AF02DB0024D4F3 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E2D6429AF02DB0024D4F3 /* Database.swift */; };
 		F78E2D6629AF02DB0024D4F3 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E2D6429AF02DB0024D4F3 /* Database.swift */; };
 		F78E2D6629AF02DB0024D4F3 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E2D6429AF02DB0024D4F3 /* Database.swift */; };
@@ -493,7 +523,6 @@
 		F793E59E28B763C2005E4B02 /* NCAskAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = F733598025C1C188002ABA72 /* NCAskAuthorization.swift */; };
 		F793E59E28B763C2005E4B02 /* NCAskAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = F733598025C1C188002ABA72 /* NCAskAuthorization.swift */; };
 		F793E59F28B764F6005E4B02 /* NCContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F765608E23BF813500765969 /* NCContentPresenter.swift */; };
 		F793E59F28B764F6005E4B02 /* NCContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F765608E23BF813500765969 /* NCContentPresenter.swift */; };
 		F793E5A128B76541005E4B02 /* NotificationCenter+MainThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70460512499061800BB98A7 /* NotificationCenter+MainThread.swift */; };
 		F793E5A128B76541005E4B02 /* NotificationCenter+MainThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70460512499061800BB98A7 /* NotificationCenter+MainThread.swift */; };
-		F793E5A228B76580005E4B02 /* NCNetworkingChunkedUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B8CD90261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift */; };
 		F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
 		F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
 		F798F0E725880609000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
 		F798F0E725880609000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
 		F798F0EC2588060A000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
 		F798F0EC2588060A000DAFFD /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
@@ -509,6 +538,8 @@
 		F79EC78926316AC4004E59D6 /* NCPopupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F702F30725EE5D47008F8E80 /* NCPopupViewController.swift */; };
 		F79EC78926316AC4004E59D6 /* NCPopupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F702F30725EE5D47008F8E80 /* NCPopupViewController.swift */; };
 		F79EDAA326B004980007D134 /* NCPlayerToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79EDA9F26B004980007D134 /* NCPlayerToolBar.swift */; };
 		F79EDAA326B004980007D134 /* NCPlayerToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79EDA9F26B004980007D134 /* NCPlayerToolBar.swift */; };
 		F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79EDAA126B004980007D134 /* NCPlayer.swift */; };
 		F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79EDAA126B004980007D134 /* NCPlayer.swift */; };
+		F79FFB262A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79FFB252A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift */; };
+		F79FFB272A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79FFB252A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift */; };
 		F7A0D1352591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; };
 		F7A0D1352591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; };
 		F7A0D1362591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; };
 		F7A0D1362591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; };
 		F7A0D1372591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; };
 		F7A0D1372591FBC5008F8A13 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; };
@@ -546,12 +577,11 @@
 		F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */; };
 		F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */; };
 		F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */; };
 		F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */; };
 		F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */; };
 		F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */; };
+		F7B398422A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */; };
+		F7B398432A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */; };
 		F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B6B70327C4E7FA00A7F6EB /* NCScan+CollectionView.swift */; };
 		F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B6B70327C4E7FA00A7F6EB /* NCScan+CollectionView.swift */; };
 		F7B7504B2397D38F004E13EC /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; };
 		F7B7504B2397D38F004E13EC /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; };
 		F7B8B83025681C3400967775 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F7B8B82F25681C3400967775 /* GoogleService-Info.plist */; };
 		F7B8B83025681C3400967775 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F7B8B82F25681C3400967775 /* GoogleService-Info.plist */; };
-		F7B8CD91261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B8CD90261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift */; };
-		F7B8CD96261AF401007C1359 /* NCNetworkingChunkedUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B8CD90261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift */; };
-		F7B8CD9B261AF401007C1359 /* NCNetworkingChunkedUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B8CD90261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift */; };
 		F7BAADC81ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */; };
 		F7BAADC81ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */; };
 		F7BAADC91ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */; };
 		F7BAADC91ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */; };
 		F7BAADCB1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */; };
 		F7BAADCB1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */; };
@@ -588,7 +618,6 @@
 		F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB68992541676B0050EC94 /* NCMore.storyboard */; };
 		F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB68992541676B0050EC94 /* NCMore.storyboard */; };
 		F7CB68A0254169530050EC94 /* NCSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB689F254169530050EC94 /* NCSettings.storyboard */; };
 		F7CB68A0254169530050EC94 /* NCSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB689F254169530050EC94 /* NCSettings.storyboard */; };
 		F7CBC31C24F78E79004D3812 /* NCSortMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */; };
 		F7CBC31C24F78E79004D3812 /* NCSortMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */; };
-		F7CF16A32A4D7C7A000FF107 /* NCMoreUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CF16A22A4D7C7A000FF107 /* NCMoreUserCell.xib */; };
 		F7D1612023CF19E30039EBBF /* NCViewerRichWorkspace.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7D1611F23CF19E30039EBBF /* NCViewerRichWorkspace.storyboard */; };
 		F7D1612023CF19E30039EBBF /* NCViewerRichWorkspace.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7D1611F23CF19E30039EBBF /* NCViewerRichWorkspace.storyboard */; };
 		F7D56B1A2972405500FA46C4 /* Mantis in Frameworks */ = {isa = PBXBuildFile; productRef = F7D56B192972405500FA46C4 /* Mantis */; };
 		F7D56B1A2972405500FA46C4 /* Mantis in Frameworks */ = {isa = PBXBuildFile; productRef = F7D56B192972405500FA46C4 /* Mantis */; };
 		F7D57C8626317BDA00DE301D /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */; };
 		F7D57C8626317BDA00DE301D /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */; };
@@ -635,6 +664,8 @@
 		F7F4F10C27ECDBDB008676F9 /* Inconsolata-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */; };
 		F7F4F10C27ECDBDB008676F9 /* Inconsolata-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */; };
 		F7F4F11027ECDC4A008676F9 /* UIDevice+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F10F27ECDC4A008676F9 /* UIDevice+Extension.swift */; };
 		F7F4F11027ECDC4A008676F9 /* UIDevice+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F10F27ECDC4A008676F9 /* UIDevice+Extension.swift */; };
 		F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */; };
 		F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */; };
+		F7F623B52A5EF4D30022D3D4 /* Gzip in Frameworks */ = {isa = PBXBuildFile; productRef = F7F623B42A5EF4D30022D3D4 /* Gzip */; };
+		F7F623B72A5EFA0C0022D3D4 /* Gzip in Frameworks */ = {isa = PBXBuildFile; productRef = F7F623B62A5EFA0C0022D3D4 /* Gzip */; };
 		F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */; };
 		F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */; };
@@ -796,7 +827,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; };
@@ -809,9 +839,17 @@
 		F31F69442A2F6D4600162F76 /* NextcloudSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudSnapshotTests.swift; sourceTree = "<group>"; };
 		F31F69442A2F6D4600162F76 /* NextcloudSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudSnapshotTests.swift; sourceTree = "<group>"; };
 		F31F694F2A2F707E00162F76 /* SwiftUIView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftUIView+Extensions.swift"; sourceTree = "<group>"; };
 		F31F694F2A2F707E00162F76 /* SwiftUIView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftUIView+Extensions.swift"; sourceTree = "<group>"; };
 		F31F69602A2F907800162F76 /* __Snapshots__ */ = {isa = PBXFileReference; lastKnownFileType = folder; path = __Snapshots__; sourceTree = "<group>"; };
 		F31F69602A2F907800162F76 /* __Snapshots__ */ = {isa = PBXFileReference; lastKnownFileType = folder; path = __Snapshots__; 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>"; };
+		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>"; };
+		F3BB464C2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCMoreAppSuggestionsCell.xib; sourceTree = "<group>"; };
+		F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreUserCell.swift; sourceTree = "<group>"; };
+		F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreAppSuggestionsCell.swift; sourceTree = "<group>"; };
+		F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCCellMore.swift; sourceTree = "<group>"; };
 		F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = "<group>"; };
 		F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = "<group>"; };
 		F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = "<group>"; };
 		F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = "<group>"; };
 		F700510222DF6897003A3356 /* Parchment.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Parchment.framework; path = Carthage/Build/iOS/Parchment.framework; sourceTree = "<group>"; };
 		F700510222DF6897003A3356 /* Parchment.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Parchment.framework; path = Carthage/Build/iOS/Parchment.framework; sourceTree = "<group>"; };
@@ -928,6 +966,8 @@
 		F7267A81225DFCE100D6DB7D /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/iOS/AFNetworking.framework; sourceTree = "<group>"; };
 		F7267A81225DFCE100D6DB7D /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/iOS/AFNetworking.framework; sourceTree = "<group>"; };
 		F72685E827C78E490019EF5E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		F72685E827C78E490019EF5E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCEndToEndInitialize.swift; sourceTree = "<group>"; };
 		F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCEndToEndInitialize.swift; sourceTree = "<group>"; };
+		F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadataV20.swift; sourceTree = "<group>"; };
+		F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadataV1.swift; sourceTree = "<group>"; };
 		F72A17D728B221E300F3F159 /* DashboardWidgetView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardWidgetView.swift; sourceTree = "<group>"; };
 		F72A17D728B221E300F3F159 /* DashboardWidgetView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardWidgetView.swift; sourceTree = "<group>"; };
 		F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCOperationQueue.swift; sourceTree = "<group>"; };
 		F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCOperationQueue.swift; sourceTree = "<group>"; };
 		F72CD63925C19EBF00F46F9A /* NCAutoUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAutoUpload.swift; sourceTree = "<group>"; };
 		F72CD63925C19EBF00F46F9A /* NCAutoUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAutoUpload.swift; sourceTree = "<group>"; };
@@ -970,6 +1010,7 @@
 		F749B650297B0F2400087535 /* NCManageDatabase+Avatar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Avatar.swift"; sourceTree = "<group>"; };
 		F749B650297B0F2400087535 /* NCManageDatabase+Avatar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Avatar.swift"; sourceTree = "<group>"; };
 		F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCUtilityFileSystem.swift; sourceTree = "<group>"; };
 		F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCUtilityFileSystem.swift; sourceTree = "<group>"; };
 		F74AFCE822E8B024003DE61F /* FSCalendar.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FSCalendar.framework; path = Carthage/Build/iOS/FSCalendar.framework; sourceTree = "<group>"; };
 		F74AFCE822E8B024003DE61F /* FSCalendar.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FSCalendar.framework; path = Carthage/Build/iOS/FSCalendar.framework; sourceTree = "<group>"; };
+		F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Chunk.swift"; sourceTree = "<group>"; };
 		F74C0434253F1CDC009762AB /* NCShares.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShares.swift; sourceTree = "<group>"; };
 		F74C0434253F1CDC009762AB /* NCShares.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShares.swift; sourceTree = "<group>"; };
 		F74C0435253F1CDC009762AB /* NCShares.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCShares.storyboard; sourceTree = "<group>"; };
 		F74C0435253F1CDC009762AB /* NCShares.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCShares.storyboard; sourceTree = "<group>"; };
 		F74C4FBA2328C3C100A23E25 /* OpenSSL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenSSL.framework; path = Carthage/Build/iOS/OpenSSL.framework; sourceTree = "<group>"; };
 		F74C4FBA2328C3C100A23E25 /* OpenSSL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenSSL.framework; path = Carthage/Build/iOS/OpenSSL.framework; sourceTree = "<group>"; };
@@ -1087,6 +1128,7 @@
 		F783031028B4C86200B84583 /* libc++.1.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.1.tbd"; path = "usr/lib/libc++.1.tbd"; sourceTree = SDKROOT; };
 		F783031028B4C86200B84583 /* libc++.1.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.1.tbd"; path = "usr/lib/libc++.1.tbd"; sourceTree = SDKROOT; };
 		F783031128B4C86200B84583 /* libc++abi.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++abi.tbd"; path = "usr/lib/libc++abi.tbd"; sourceTree = SDKROOT; };
 		F783031128B4C86200B84583 /* libc++abi.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++abi.tbd"; path = "usr/lib/libc++abi.tbd"; sourceTree = SDKROOT; };
 		F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingE2EE.swift; sourceTree = "<group>"; };
 		F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingE2EE.swift; sourceTree = "<group>"; };
+		F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+LocalFile.swift"; sourceTree = "<group>"; };
 		F787704E22E7019900F287A9 /* NCShareLinkCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareLinkCell.xib; sourceTree = "<group>"; };
 		F787704E22E7019900F287A9 /* NCShareLinkCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareLinkCell.xib; sourceTree = "<group>"; };
 		F78A10BE29322E8A008499B8 /* NCManageDatabase+Directory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Directory.swift"; sourceTree = "<group>"; };
 		F78A10BE29322E8A008499B8 /* NCManageDatabase+Directory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Directory.swift"; sourceTree = "<group>"; };
 		F78A18B523CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewerRichWorkspaceWebView.swift; sourceTree = "<group>"; };
 		F78A18B523CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewerRichWorkspaceWebView.swift; sourceTree = "<group>"; };
@@ -1100,7 +1142,6 @@
 		F78ACD4921903F850088454D /* NCTrashListCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCTrashListCell.xib; sourceTree = "<group>"; };
 		F78ACD4921903F850088454D /* NCTrashListCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCTrashListCell.xib; sourceTree = "<group>"; };
 		F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSectionHeaderMenu.swift; sourceTree = "<group>"; };
 		F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSectionHeaderMenu.swift; sourceTree = "<group>"; };
 		F78ACD53219047D40088454D /* NCSectionFooter.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCSectionFooter.xib; sourceTree = "<group>"; };
 		F78ACD53219047D40088454D /* NCSectionFooter.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCSectionFooter.xib; sourceTree = "<group>"; };
-		F78ACD57219048040088454D /* NCSectionHeaderMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCSectionHeaderMenu.xib; sourceTree = "<group>"; };
 		F78C6FDD296D677300C952C3 /* NCContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCContextMenu.swift; sourceTree = "<group>"; };
 		F78C6FDD296D677300C952C3 /* NCContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCContextMenu.swift; sourceTree = "<group>"; };
 		F78D6F461F0B7CB9002F9619 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		F78D6F461F0B7CB9002F9619 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		F78D6F4D1F0B7CE4002F9619 /* nb-NO */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "nb-NO"; path = "nb-NO.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		F78D6F4D1F0B7CE4002F9619 /* nb-NO */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "nb-NO"; path = "nb-NO.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -1121,6 +1162,7 @@
 		F79BCEEA270B49C800B5B71F /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
 		F79BCEEA270B49C800B5B71F /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
 		F79EDA9F26B004980007D134 /* NCPlayerToolBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPlayerToolBar.swift; sourceTree = "<group>"; };
 		F79EDA9F26B004980007D134 /* NCPlayerToolBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPlayerToolBar.swift; sourceTree = "<group>"; };
 		F79EDAA126B004980007D134 /* NCPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPlayer.swift; sourceTree = "<group>"; };
 		F79EDAA126B004980007D134 /* NCPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCPlayer.swift; sourceTree = "<group>"; };
+		F79FFB252A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingE2EEMarkFolder.swift; sourceTree = "<group>"; };
 		F7A0D1342591FBC5008F8A13 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
 		F7A0D1342591FBC5008F8A13 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
 		F7A321AB1E9E6AD50069AD1B /* CCAdvanced.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCAdvanced.h; sourceTree = "<group>"; };
 		F7A321AB1E9E6AD50069AD1B /* CCAdvanced.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCAdvanced.h; sourceTree = "<group>"; };
 		F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCAdvanced.m; sourceTree = "<group>"; };
 		F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCAdvanced.m; sourceTree = "<group>"; };
@@ -1189,10 +1231,10 @@
 		F7AF7632246BEDFE00B86E3C /* TOPasscodeViewController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TOPasscodeViewController.framework; path = Carthage/Build/iOS/TOPasscodeViewController.framework; sourceTree = "<group>"; };
 		F7AF7632246BEDFE00B86E3C /* TOPasscodeViewController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TOPasscodeViewController.framework; path = Carthage/Build/iOS/TOPasscodeViewController.framework; sourceTree = "<group>"; };
 		F7B1076C25D3CF2800E72DE2 /* BackgroundTasks.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BackgroundTasks.framework; path = System/Library/Frameworks/BackgroundTasks.framework; sourceTree = SDKROOT; };
 		F7B1076C25D3CF2800E72DE2 /* BackgroundTasks.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BackgroundTasks.framework; path = System/Library/Frameworks/BackgroundTasks.framework; sourceTree = SDKROOT; };
 		F7B1A7761EBB3C8000BFB6D1 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
 		F7B1A7761EBB3C8000BFB6D1 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
+		F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSectionHeaderMenu.xib; sourceTree = "<group>"; };
 		F7B6B70327C4E7FA00A7F6EB /* NCScan+CollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCScan+CollectionView.swift"; sourceTree = "<group>"; };
 		F7B6B70327C4E7FA00A7F6EB /* NCScan+CollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCScan+CollectionView.swift"; sourceTree = "<group>"; };
 		F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = "<group>"; };
 		F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = "<group>"; };
 		F7B8B82F25681C3400967775 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "GoogleService-Info.plist"; sourceTree = SOURCE_ROOT; };
 		F7B8B82F25681C3400967775 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "GoogleService-Info.plist"; sourceTree = SOURCE_ROOT; };
-		F7B8CD90261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingChunkedUpload.swift; sourceTree = "<group>"; };
 		F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCDatabase.swift; sourceTree = "<group>"; };
 		F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCDatabase.swift; sourceTree = "<group>"; };
 		F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCManageDatabase.swift; sourceTree = "<group>"; };
 		F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCManageDatabase.swift; sourceTree = "<group>"; };
 		F7BB04851FD58ACB00BBFD2A /* cs-CZ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "cs-CZ"; path = "cs-CZ.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		F7BB04851FD58ACB00BBFD2A /* cs-CZ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "cs-CZ"; path = "cs-CZ.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -1397,9 +1439,11 @@
 				F710FC80277B7D2700AA9FBF /* RealmSwift in Frameworks */,
 				F710FC80277B7D2700AA9FBF /* RealmSwift in Frameworks */,
 				F72AD70F28C24BA1006CB92D /* NextcloudKit in Frameworks */,
 				F72AD70F28C24BA1006CB92D /* NextcloudKit in Frameworks */,
 				F72CD01227A7E92400E59476 /* JGProgressHUD in Frameworks */,
 				F72CD01227A7E92400E59476 /* JGProgressHUD in Frameworks */,
+				F77CB6A92AA08053000C3CA4 /* OpenSSL in Frameworks */,
 				F73ADD2126554F8E0069EA0D /* SwiftEntryKit in Frameworks */,
 				F73ADD2126554F8E0069EA0D /* SwiftEntryKit in Frameworks */,
 				F7EBCDCF277B81FF00A4EF67 /* UICKeyChainStore in Frameworks */,
 				F7EBCDCF277B81FF00A4EF67 /* UICKeyChainStore in Frameworks */,
 				F70821D829E59E6D001CA2D7 /* TagListView in Frameworks */,
 				F70821D829E59E6D001CA2D7 /* TagListView in Frameworks */,
+				F7F623B72A5EFA0C0022D3D4 /* Gzip in Frameworks */,
 				F72D7EB7263B1207000B3DFC /* MarkdownKit in Frameworks */,
 				F72D7EB7263B1207000B3DFC /* MarkdownKit in Frameworks */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -1453,6 +1497,7 @@
 				F70B86752642CE3B00ED5349 /* FirebaseCrashlytics in Frameworks */,
 				F70B86752642CE3B00ED5349 /* FirebaseCrashlytics in Frameworks */,
 				F7A1050E29E587AF00FFD92B /* TagListView in Frameworks */,
 				F7A1050E29E587AF00FFD92B /* TagListView in Frameworks */,
 				F76DA969277B77EA0082465B /* DropDown in Frameworks */,
 				F76DA969277B77EA0082465B /* DropDown in Frameworks */,
+				F7F623B52A5EF4D30022D3D4 /* Gzip in Frameworks */,
 				F75EAED826D2552E00F4320E /* MarqueeLabel in Frameworks */,
 				F75EAED826D2552E00F4320E /* MarqueeLabel in Frameworks */,
 				F710FC7A277B7D0000AA9FBF /* Realm in Frameworks */,
 				F710FC7A277B7D0000AA9FBF /* Realm in Frameworks */,
 				F72DA9B425F53E4E00B87DB1 /* SwiftRichString in Frameworks */,
 				F72DA9B425F53E4E00B87DB1 /* SwiftRichString in Frameworks */,
@@ -1541,6 +1586,7 @@
 		C04E2F212A17BB4D001BAD85 /* NextcloudIntegrationTests */ = {
 		C04E2F212A17BB4D001BAD85 /* NextcloudIntegrationTests */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				F3953BD62A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift */,
 				C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */,
 				C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */,
 			);
 			);
 			path = NextcloudIntegrationTests;
 			path = NextcloudIntegrationTests;
@@ -1583,6 +1629,27 @@
 			path = Extensions;
 			path = Extensions;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		F33AAF982A601465006ECCBD /* Recovered References */ = {
+			isa = PBXGroup;
+			children = (
+				F7CF16A22A4D7C7A000FF107 /* NCMoreUserCell.xib */,
+			);
+			name = "Recovered References";
+			sourceTree = "<group>";
+		};
+		F3BB46502A39EC2D00461F6E /* Cells */ = {
+			isa = PBXGroup;
+			children = (
+				F3BB464C2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib */,
+				F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */,
+				F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */,
+				F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */,
+				F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */,
+				F39298962A3B12CB00509762 /* BaseNCMoreCell.swift */,
+			);
+			path = Cells;
+			sourceTree = "<group>";
+		};
 		F70211F31BAC56E9003FC03E /* Main */ = {
 		F70211F31BAC56E9003FC03E /* Main */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -1810,7 +1877,6 @@
 				F72CD63925C19EBF00F46F9A /* NCAutoUpload.swift */,
 				F72CD63925C19EBF00F46F9A /* NCAutoUpload.swift */,
 				F75A9EE523796C6F0044CFCE /* NCNetworking.swift */,
 				F75A9EE523796C6F0044CFCE /* NCNetworking.swift */,
 				F7D96FCB246ED7E100536D73 /* NCNetworkingCheckRemoteUser.swift */,
 				F7D96FCB246ED7E100536D73 /* NCNetworkingCheckRemoteUser.swift */,
-				F7B8CD90261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift */,
 				F70D8D8024A4A9BF000A5756 /* NCNetworkingProcessUpload.swift */,
 				F70D8D8024A4A9BF000A5756 /* NCNetworkingProcessUpload.swift */,
 				F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */,
 				F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */,
 				F755BD9A20594AC7008C5FBB /* NCService.swift */,
 				F755BD9A20594AC7008C5FBB /* NCService.swift */,
@@ -1961,7 +2027,7 @@
 			children = (
 			children = (
 				F78ACD53219047D40088454D /* NCSectionFooter.xib */,
 				F78ACD53219047D40088454D /* NCSectionFooter.xib */,
 				F7FF2CB02842159500EBB7A1 /* NCSectionHeader.xib */,
 				F7FF2CB02842159500EBB7A1 /* NCSectionHeader.xib */,
-				F78ACD57219048040088454D /* NCSectionHeaderMenu.xib */,
+				F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */,
 				F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */,
 				F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */,
 			);
 			);
 			path = "Section Header Footer";
 			path = "Section Header Footer";
@@ -2048,7 +2114,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 */,
@@ -2129,6 +2194,7 @@
 				F7C1EEA425053A9C00866ACC /* NCDataSource.swift */,
 				F7C1EEA425053A9C00866ACC /* NCDataSource.swift */,
 				F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */,
 				F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */,
 				AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */,
 				AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */,
+				F74B6D942A7E239A00F03C5F /* NCManageDatabase+Chunk.swift */,
 				AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */,
 				AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */,
 				F749B650297B0F2400087535 /* NCManageDatabase+Avatar.swift */,
 				F749B650297B0F2400087535 /* NCManageDatabase+Avatar.swift */,
 				F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */,
 				F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */,
@@ -2137,6 +2203,7 @@
 				F72FD3B4297ED49A00075D28 /* NCManageDatabase+E2EE.swift */,
 				F72FD3B4297ED49A00075D28 /* NCManageDatabase+E2EE.swift */,
 				F757CC8129E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift */,
 				F757CC8129E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift */,
 				F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */,
 				F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */,
+				F7864ACB2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift */,
 				AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */,
 				AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */,
 				F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */,
 				F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */,
 				F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */,
 				F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */,
@@ -2172,6 +2239,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 */,
@@ -2213,8 +2281,11 @@
 				F70CAE381F8CF31A008125FD /* NCEndToEndEncryption.h */,
 				F70CAE381F8CF31A008125FD /* NCEndToEndEncryption.h */,
 				F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */,
 				F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */,
 				F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */,
 				F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */,
+				F72944F12A84246400246839 /* NCEndToEndMetadataV20.swift */,
+				F72944F42A8424F800246839 /* NCEndToEndMetadataV1.swift */,
 				F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */,
 				F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */,
 				F7C30DF9291BCF790017149B /* NCNetworkingE2EECreateFolder.swift */,
 				F7C30DF9291BCF790017149B /* NCNetworkingE2EECreateFolder.swift */,
+				F79FFB252A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift */,
 				F7C30DFC291BD0B80017149B /* NCNetworkingE2EEDelete.swift */,
 				F7C30DFC291BD0B80017149B /* NCNetworkingE2EEDelete.swift */,
 				F7C30DFF291BD2610017149B /* NCNetworkingE2EERename.swift */,
 				F7C30DFF291BD2610017149B /* NCNetworkingE2EERename.swift */,
 				F7C30DF5291BC0CA0017149B /* NCNetworkingE2EEUpload.swift */,
 				F7C30DF5291BC0CA0017149B /* NCNetworkingE2EEUpload.swift */,
@@ -2265,7 +2336,7 @@
 		F7CB68942541670D0050EC94 /* More */ = {
 		F7CB68942541670D0050EC94 /* More */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				F7CF16A22A4D7C7A000FF107 /* NCMoreUserCell.xib */,
+				F3BB46502A39EC2D00461F6E /* Cells */,
 				F7CB68992541676B0050EC94 /* NCMore.storyboard */,
 				F7CB68992541676B0050EC94 /* NCMore.storyboard */,
 				F73F537E1E929C8500F8678D /* NCMore.swift */,
 				F73F537E1E929C8500F8678D /* NCMore.swift */,
 			);
 			);
@@ -2370,6 +2441,7 @@
 				C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */,
 				C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */,
 				C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */,
 				C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */,
 				F31F69422A2F6D4500162F76 /* NextcloudSnapshotTests.xctest */,
 				F31F69422A2F6D4500162F76 /* NextcloudSnapshotTests.xctest */,
+				F33AAF982A601465006ECCBD /* Recovered References */,
 			);
 			);
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
@@ -2714,6 +2786,8 @@
 				F72CD01127A7E92400E59476 /* JGProgressHUD */,
 				F72CD01127A7E92400E59476 /* JGProgressHUD */,
 				F72AD70E28C24BA1006CB92D /* NextcloudKit */,
 				F72AD70E28C24BA1006CB92D /* NextcloudKit */,
 				F70821D729E59E6D001CA2D7 /* TagListView */,
 				F70821D729E59E6D001CA2D7 /* TagListView */,
+				F7F623B62A5EFA0C0022D3D4 /* Gzip */,
+				F77CB6A82AA08053000C3CA4 /* OpenSSL */,
 			);
 			);
 			productName = "Share Ext";
 			productName = "Share Ext";
 			productReference = F7CE8AFB1DC1F8D8009CAE48 /* Share.appex */;
 			productReference = F7CE8AFB1DC1F8D8009CAE48 /* Share.appex */;
@@ -2814,6 +2888,7 @@
 				F787AC08298BCB4A0001BB00 /* SVGKitSwift */,
 				F787AC08298BCB4A0001BB00 /* SVGKitSwift */,
 				F7A1050D29E587AF00FFD92B /* TagListView */,
 				F7A1050D29E587AF00FFD92B /* TagListView */,
 				F31F69632A2F929600162F76 /* PreviewSnapshots */,
 				F31F69632A2F929600162F76 /* PreviewSnapshots */,
+				F7F623B42A5EF4D30022D3D4 /* Gzip */,
 			);
 			);
 			productName = "Crypto Cloud";
 			productName = "Crypto Cloud";
 			productReference = F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */;
 			productReference = F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */;
@@ -2988,6 +3063,7 @@
 				F31F694B2A2F6EFA00162F76 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
 				F31F694B2A2F6EFA00162F76 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
 				F31F69622A2F929600162F76 /* XCRemoteSwiftPackageReference "swiftui-preview-snapshots" */,
 				F31F69622A2F929600162F76 /* XCRemoteSwiftPackageReference "swiftui-preview-snapshots" */,
 				F31F69672A2F92F000162F76 /* XCRemoteSwiftPackageReference "SnapshotTestingHEIC" */,
 				F31F69672A2F92F000162F76 /* XCRemoteSwiftPackageReference "SnapshotTestingHEIC" */,
+				F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */,
 			);
 			);
 			productRefGroup = F7F67B9F1A24D27800EE80DA;
 			productRefGroup = F7F67B9F1A24D27800EE80DA;
 			projectDirPath = "";
 			projectDirPath = "";
@@ -3060,11 +3136,11 @@
 			isa = PBXResourcesBuildPhase;
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
-				F7148059262ED52200693E51 /* NCSectionHeaderMenu.xib in Resources */,
 				F714803B262EBE3900693E51 /* MainInterface.storyboard in Resources */,
 				F714803B262EBE3900693E51 /* MainInterface.storyboard in Resources */,
 				F7148054262ED51000693E51 /* NCListCell.xib in Resources */,
 				F7148054262ED51000693E51 /* NCListCell.xib in Resources */,
 				F7D57C8626317BDA00DE301D /* NCAccountRequest.storyboard in Resources */,
 				F7D57C8626317BDA00DE301D /* NCAccountRequest.storyboard in Resources */,
 				AF22B209277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.xib in Resources */,
 				AF22B209277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.xib in Resources */,
+				F7B398432A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */,
 				F7148063262ED66200693E51 /* NCEmptyView.xib in Resources */,
 				F7148063262ED66200693E51 /* NCEmptyView.xib in Resources */,
 				AF22B207277B4E4C00DAB0CC /* NCCreateFormUploadConflict.storyboard in Resources */,
 				AF22B207277B4E4C00DAB0CC /* NCCreateFormUploadConflict.storyboard in Resources */,
 				F7145A231D12E3B700CAFEEC /* Localizable.strings in Resources */,
 				F7145A231D12E3B700CAFEEC /* Localizable.strings in Resources */,
@@ -3102,6 +3178,7 @@
 				F7362A1F220C853A005101B5 /* LaunchScreen.storyboard in Resources */,
 				F7362A1F220C853A005101B5 /* LaunchScreen.storyboard in Resources */,
 				F77444F622281649000D5EB0 /* NCGridMediaCell.xib in Resources */,
 				F77444F622281649000D5EB0 /* NCGridMediaCell.xib in Resources */,
 				F78ACD4421903CF20088454D /* NCListCell.xib in Resources */,
 				F78ACD4421903CF20088454D /* NCListCell.xib in Resources */,
+				F3BB464D2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib in Resources */,
 				F7F4F10727ECDBDB008676F9 /* Inconsolata-Black.ttf in Resources */,
 				F7F4F10727ECDBDB008676F9 /* Inconsolata-Black.ttf in Resources */,
 				F761856D29E98543006EB3B0 /* NCIntroCollectionViewCell.xib in Resources */,
 				F761856D29E98543006EB3B0 /* NCIntroCollectionViewCell.xib in Resources */,
 				F78ACD4621903D010088454D /* NCGridCell.xib in Resources */,
 				F78ACD4621903D010088454D /* NCGridCell.xib in Resources */,
@@ -3115,6 +3192,7 @@
 				F723985C253C95CE00257F49 /* NCViewerRichdocument.storyboard in Resources */,
 				F723985C253C95CE00257F49 /* NCViewerRichdocument.storyboard in Resources */,
 				F758B45A212C564000515F55 /* NCScan.storyboard in Resources */,
 				F758B45A212C564000515F55 /* NCScan.storyboard in Resources */,
 				F70D87CF25EE6E58008CBBBD /* NCRenameFile.storyboard in Resources */,
 				F70D87CF25EE6E58008CBBBD /* NCRenameFile.storyboard in Resources */,
+				F33AAF9A2A60394C006ECCBD /* NCMoreUserCell.xib in Resources */,
 				F765F73225237E3F00391DBE /* NCRecent.storyboard in Resources */,
 				F765F73225237E3F00391DBE /* NCRecent.storyboard in Resources */,
 				F78F74342163757000C2ADAD /* NCTrash.storyboard in Resources */,
 				F78F74342163757000C2ADAD /* NCTrash.storyboard in Resources */,
 				F702F30225EE5D2C008F8E80 /* english.txt in Resources */,
 				F702F30225EE5D2C008F8E80 /* english.txt in Resources */,
@@ -3163,7 +3241,6 @@
 				F77B0F611D118A16002130FE /* Acknowledgements.rtf in Resources */,
 				F77B0F611D118A16002130FE /* Acknowledgements.rtf in Resources */,
 				F7EDE509262DA9D600414FE6 /* NCSelectCommandViewSelect.xib in Resources */,
 				F7EDE509262DA9D600414FE6 /* NCSelectCommandViewSelect.xib in Resources */,
 				F732D23327CF8AED000B0F1B /* NCPlayerToolBar.xib in Resources */,
 				F732D23327CF8AED000B0F1B /* NCPlayerToolBar.xib in Resources */,
-				F7CF16A32A4D7C7A000FF107 /* NCMoreUserCell.xib in Resources */,
 				F73D11FA253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard in Resources */,
 				F73D11FA253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard in Resources */,
 				F7EDE51B262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib in Resources */,
 				F7EDE51B262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib in Resources */,
 				F73B422B2476764F00A30FD3 /* NCNotification.storyboard in Resources */,
 				F73B422B2476764F00A30FD3 /* NCNotification.storyboard in Resources */,
@@ -3176,7 +3253,7 @@
 				F73CB3B222E072A000AD728E /* NCShareHeaderView.xib in Resources */,
 				F73CB3B222E072A000AD728E /* NCShareHeaderView.xib in Resources */,
 				F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */,
 				F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */,
 				F7EDE514262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib in Resources */,
 				F7EDE514262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib in Resources */,
-				F78ACD58219048040088454D /* NCSectionHeaderMenu.xib in Resources */,
+				F7B398422A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */,
 				F7501C322212E57500FB1415 /* NCMedia.storyboard in Resources */,
 				F7501C322212E57500FB1415 /* NCMedia.storyboard in Resources */,
 				F74DE14425135B6800917068 /* NCTransfers.storyboard in Resources */,
 				F74DE14425135B6800917068 /* NCTransfers.storyboard in Resources */,
 				F77910A525DD517B00CEDB9E /* Settings.bundle in Resources */,
 				F77910A525DD517B00CEDB9E /* Settings.bundle in Resources */,
@@ -3251,6 +3328,7 @@
 				F72FD3BA297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F72FD3BA297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F7E98C1927E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F7E98C1927E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				2C1D5D7623E2DE3300334ABB /* NCManageDatabase.swift in Sources */,
 				2C1D5D7623E2DE3300334ABB /* NCManageDatabase.swift in Sources */,
+				F7864AD22A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				F314F1142A30E2DE00BC7FAB /* View+Extension.swift in Sources */,
 				F314F1142A30E2DE00BC7FAB /* View+Extension.swift in Sources */,
 				F7D68FD028CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				F7D68FD028CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				F343A4C12A1E734600DDA874 /* Optional+Extension.swift in Sources */,
 				F343A4C12A1E734600DDA874 /* Optional+Extension.swift in Sources */,
@@ -3259,6 +3337,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 */,
@@ -3274,6 +3353,7 @@
 				F763D2A32A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F763D2A32A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F749B656297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F749B656297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F782FDC424E6933900666099 /* NCUtility.swift in Sources */,
 				F782FDC424E6933900666099 /* NCUtility.swift in Sources */,
+				F74B6D9B2A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -3301,6 +3381,7 @@
 			isa = PBXSourcesBuildPhase;
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
+				F3953BD72A6E87E000EE03F9 /* BaseIntegrationXCTestCase.swift in Sources */,
 				F30A96322A27AEDD00D7BCFE /* EnvVars.generated.swift in Sources */,
 				F30A96322A27AEDD00D7BCFE /* EnvVars.generated.swift in Sources */,
 				C04E2F232A17BB4D001BAD85 /* FilesIntegrationTests.swift in Sources */,
 				C04E2F232A17BB4D001BAD85 /* FilesIntegrationTests.swift in Sources */,
 			);
 			);
@@ -3318,6 +3399,7 @@
 			isa = PBXSourcesBuildPhase;
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
+				F74B6D9A2A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F7490E8329882C84009DCE94 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F7490E8329882C84009DCE94 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F7490E7629882BF3009DCE94 /* NCUserBaseUrl.swift in Sources */,
 				F7490E7629882BF3009DCE94 /* NCUserBaseUrl.swift in Sources */,
 				F7490E8029882C76009DCE94 /* NCManageDatabase+Avatar.swift in Sources */,
 				F7490E8029882C76009DCE94 /* NCManageDatabase+Avatar.swift in Sources */,
@@ -3333,6 +3415,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 */,
@@ -3341,6 +3424,7 @@
 				F7490E6C29882AEA009DCE94 /* String+Extension.swift in Sources */,
 				F7490E6C29882AEA009DCE94 /* String+Extension.swift in Sources */,
 				F7490E6B29882A92009DCE94 /* NCGlobal.swift in Sources */,
 				F7490E6B29882A92009DCE94 /* NCGlobal.swift in Sources */,
 				F7490E7529882BE2009DCE94 /* NCManageDatabase+Directory.swift in Sources */,
 				F7490E7529882BE2009DCE94 /* NCManageDatabase+Directory.swift in Sources */,
+				F7864AD12A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				F7490E8729882CA8009DCE94 /* ThreadSafeDictionary.swift in Sources */,
 				F7490E8729882CA8009DCE94 /* ThreadSafeDictionary.swift in Sources */,
 				F757CC8729E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F757CC8729E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F7490E8229882C80009DCE94 /* NCManageDatabase+E2EE.swift in Sources */,
 				F7490E8229882C80009DCE94 /* NCManageDatabase+E2EE.swift in Sources */,
@@ -3353,6 +3437,7 @@
 			isa = PBXSourcesBuildPhase;
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
+				F7864ACF2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				F7245925289BB59100474787 /* ThreadSafeDictionary.swift in Sources */,
 				F7245925289BB59100474787 /* ThreadSafeDictionary.swift in Sources */,
 				F7EDE4E5262D7BBE00414FE6 /* NCSectionHeaderMenu.swift in Sources */,
 				F7EDE4E5262D7BBE00414FE6 /* NCSectionHeaderMenu.swift in Sources */,
 				F7BF9D852934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F7BF9D852934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
@@ -3362,11 +3447,13 @@
 				AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */,
 				AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */,
 				F7A0D1362591FBC5008F8A13 /* String+Extension.swift in Sources */,
 				F7A0D1362591FBC5008F8A13 /* String+Extension.swift in Sources */,
 				F7EDE4D6262D7B9600414FE6 /* NCListCell.swift in Sources */,
 				F7EDE4D6262D7B9600414FE6 /* NCListCell.swift in Sources */,
+				F74B6D982A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F7707687263A853700A1BA94 /* NCContentPresenter.swift in Sources */,
 				F7707687263A853700A1BA94 /* NCContentPresenter.swift in Sources */,
 				F343A4B62A1E084200DDA874 /* PHAsset+Extension.swift in Sources */,
 				F343A4B62A1E084200DDA874 /* PHAsset+Extension.swift in Sources */,
 				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 */,
@@ -3390,6 +3477,7 @@
 				F702F2D025EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F702F2D025EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F343A4BE2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
 				F343A4BE2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
 				F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */,
 				F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */,
+				F72944F62A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */,
 				F7EDE4D1262D7B8400414FE6 /* NCDataSource.swift in Sources */,
 				F7EDE4D1262D7B8400414FE6 /* NCDataSource.swift in Sources */,
 				F71459D21D12E3B700CAFEEC /* CCUtility.m in Sources */,
 				F71459D21D12E3B700CAFEEC /* CCUtility.m in Sources */,
 				F75A9EE723796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				F75A9EE723796C6F0044CFCE /* NCNetworking.swift in Sources */,
@@ -3398,7 +3486,6 @@
 				F72FD3B8297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F72FD3B8297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F7EDE4E0262D7BAF00414FE6 /* NCGridCell.swift in Sources */,
 				F7EDE4E0262D7BAF00414FE6 /* NCGridCell.swift in Sources */,
 				F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */,
 				F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */,
-				F7B8CD96261AF401007C1359 /* NCNetworkingChunkedUpload.swift in Sources */,
 				F763D2A02A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F763D2A02A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F757CC8529E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F757CC8529E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F7BAADC91ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */,
 				F7BAADC91ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */,
@@ -3406,6 +3493,7 @@
 				F7D57C8B26317BDE00DE301D /* NCAccountRequest.swift in Sources */,
 				F7D57C8B26317BDE00DE301D /* NCAccountRequest.swift in Sources */,
 				F7C30DF7291BC0D30017149B /* NCNetworkingE2EEUpload.swift in Sources */,
 				F7C30DF7291BC0D30017149B /* NCNetworkingE2EEUpload.swift in Sources */,
 				F78A10C229322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
 				F78A10C229322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
+				F79FFB272A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift in Sources */,
 				F7D68FCE28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				F7D68FCE28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				AF22B217277D196700DAB0CC /* NCShareExtension+DataSource.swift in Sources */,
 				AF22B217277D196700DAB0CC /* NCShareExtension+DataSource.swift in Sources */,
 				F76D364728A4F8BF00214537 /* NCActivityIndicator.swift in Sources */,
 				F76D364728A4F8BF00214537 /* NCActivityIndicator.swift in Sources */,
@@ -3415,6 +3503,7 @@
 				AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */,
 				AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */,
 				F7148041262EBE4000693E51 /* NCShareExtension.swift in Sources */,
 				F7148041262EBE4000693E51 /* NCShareExtension.swift in Sources */,
 				F76B3CCF1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
 				F76B3CCF1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
+				F72944F32A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */,
 				F7BAADCC1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */,
 				F7BAADCC1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -3432,6 +3521,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 */,
@@ -3441,6 +3531,7 @@
 				F78302FE28B4C44700B84583 /* NCBrand.swift in Sources */,
 				F78302FE28B4C44700B84583 /* NCBrand.swift in Sources */,
 				F749B64B297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F749B64B297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F7817CF929801A3500FFBC65 /* Data+Extension.swift in Sources */,
 				F7817CF929801A3500FFBC65 /* Data+Extension.swift in Sources */,
+				F7864ACD2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */,
 				F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */,
 				F793E59F28B764F6005E4B02 /* NCContentPresenter.swift in Sources */,
 				F793E59F28B764F6005E4B02 /* NCContentPresenter.swift in Sources */,
 				F76DEE9828F808AF0041B1C9 /* LockscreenWidgetProvider.swift in Sources */,
 				F76DEE9828F808AF0041B1C9 /* LockscreenWidgetProvider.swift in Sources */,
@@ -3452,6 +3543,7 @@
 				F793E59D28B761E7005E4B02 /* NCNetworking.swift in Sources */,
 				F793E59D28B761E7005E4B02 /* NCNetworking.swift in Sources */,
 				F7BF9D832934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F7BF9D832934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F757CC8329E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F757CC8329E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
+				F74B6D962A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F749B652297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F749B652297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F783030628B4C51E00B84583 /* String+Extension.swift in Sources */,
 				F783030628B4C51E00B84583 /* String+Extension.swift in Sources */,
 				F763D29E2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F763D29E2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
@@ -3461,7 +3553,6 @@
 				F78302FB28B4C3EE00B84583 /* NCManageDatabase+Video.swift in Sources */,
 				F78302FB28B4C3EE00B84583 /* NCManageDatabase+Video.swift in Sources */,
 				F72EA95228B7BA2A00C88F0C /* DashboardWidgetProvider.swift in Sources */,
 				F72EA95228B7BA2A00C88F0C /* DashboardWidgetProvider.swift in Sources */,
 				F343A4BC2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
 				F343A4BC2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
-				F793E5A228B76580005E4B02 /* NCNetworkingChunkedUpload.swift in Sources */,
 				F783031228B4C8EC00B84583 /* CCUtility.m in Sources */,
 				F783031228B4C8EC00B84583 /* CCUtility.m in Sources */,
 				F72EA95828B7BC4F00C88F0C /* FilesData.swift in Sources */,
 				F72EA95828B7BC4F00C88F0C /* FilesData.swift in Sources */,
 				F793E59E28B763C2005E4B02 /* NCAskAuthorization.swift in Sources */,
 				F793E59E28B763C2005E4B02 /* NCAskAuthorization.swift in Sources */,
@@ -3497,7 +3588,10 @@
 				F343A4B72A1E084300DDA874 /* PHAsset+Extension.swift in Sources */,
 				F343A4B72A1E084300DDA874 /* PHAsset+Extension.swift in Sources */,
 				F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */,
 				F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */,
 				F798F0E725880609000DAFFD /* UIColor+Extension.swift in Sources */,
 				F798F0E725880609000DAFFD /* UIColor+Extension.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 */,
 				AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F78A10C329322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
 				F78A10C329322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
@@ -3509,7 +3603,6 @@
 				F749B64E297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F749B64E297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				AF817EF3274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
 				AF817EF3274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
 				F771E3F320E239A600AFB62D /* FileProviderData.swift in Sources */,
 				F771E3F320E239A600AFB62D /* FileProviderData.swift in Sources */,
-				F7B8CD9B261AF401007C1359 /* NCNetworkingChunkedUpload.swift in Sources */,
 				F7A0D1372591FBC5008F8A13 /* String+Extension.swift in Sources */,
 				F7A0D1372591FBC5008F8A13 /* String+Extension.swift in Sources */,
 				F771E3D720E2392D00AFB62D /* FileProviderEnumerator.swift in Sources */,
 				F771E3D720E2392D00AFB62D /* FileProviderEnumerator.swift in Sources */,
 				F74AF3A6247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */,
 				F74AF3A6247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */,
@@ -3575,6 +3668,7 @@
 				F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				F758B460212C56A400515F55 /* NCScan.swift in Sources */,
 				F758B460212C56A400515F55 /* NCScan.swift in Sources */,
 				F78ACD52219046DC0088454D /* NCSectionHeaderMenu.swift in Sources */,
 				F78ACD52219046DC0088454D /* NCSectionHeaderMenu.swift in Sources */,
+				F72944F52A8424F800246839 /* NCEndToEndMetadataV1.swift in Sources */,
 				F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */,
 				F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */,
 				F765E9CD295C585800A09ED8 /* NCUploadScanDocument.swift in Sources */,
 				F765E9CD295C585800A09ED8 /* NCUploadScanDocument.swift in Sources */,
 				F77A697D250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift in Sources */,
 				F77A697D250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift in Sources */,
@@ -3594,9 +3688,9 @@
 				F7BAADC81ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */,
 				F7BAADC81ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */,
 				F75C0C4823D1FAE300163CC8 /* NCRichWorkspaceCommon.swift in Sources */,
 				F75C0C4823D1FAE300163CC8 /* NCRichWorkspaceCommon.swift in Sources */,
 				F78ACD4A21903F850088454D /* NCTrashListCell+NCTrashCellProtocol.swift in Sources */,
 				F78ACD4A21903F850088454D /* NCTrashListCell+NCTrashCellProtocol.swift in Sources */,
-				F7B8CD91261AF3F7007C1359 /* NCNetworkingChunkedUpload.swift in Sources */,
 				F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */,
 				F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */,
 				F760329F252F0F8E0015A421 /* NCTransferCell.swift in Sources */,
 				F760329F252F0F8E0015A421 /* NCTransferCell.swift in Sources */,
+				F3BB46542A3A1E9D00461F6E /* CCCellMore.swift in Sources */,
 				AF68326A27BE65A90010BF0B /* NCMenuAction.swift in Sources */,
 				AF68326A27BE65A90010BF0B /* NCMenuAction.swift in Sources */,
 				F7682FE023C36B0500983A04 /* NCMainTabBar.swift in Sources */,
 				F7682FE023C36B0500983A04 /* NCMainTabBar.swift in Sources */,
 				F7A0D1352591FBC5008F8A13 /* String+Extension.swift in Sources */,
 				F7A0D1352591FBC5008F8A13 /* String+Extension.swift in Sources */,
@@ -3606,6 +3700,7 @@
 				F70460522499061800BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70460522499061800BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F78F74362163781100C2ADAD /* NCTrash.swift in Sources */,
 				F78F74362163781100C2ADAD /* NCTrash.swift in Sources */,
 				AF817EF1274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
 				AF817EF1274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
+				F39298972A3B12CB00509762 /* BaseNCMoreCell.swift in Sources */,
 				AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */,
 				AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */,
 				F7E41316294A19B300839300 /* UIView+Extension.swift in Sources */,
 				F7E41316294A19B300839300 /* UIView+Extension.swift in Sources */,
 				F31F69502A2F707E00162F76 /* SwiftUIView+Extensions.swift in Sources */,
 				F31F69502A2F707E00162F76 /* SwiftUIView+Extensions.swift in Sources */,
@@ -3617,6 +3712,7 @@
 				8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */,
 				8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */,
 				F761856C29E98543006EB3B0 /* NCIntroCollectionViewCell.swift in Sources */,
 				F761856C29E98543006EB3B0 /* NCIntroCollectionViewCell.swift in Sources */,
 				F75DD765290ABB25002EB562 /* Intent.intentdefinition in Sources */,
 				F75DD765290ABB25002EB562 /* Intent.intentdefinition in Sources */,
+				F74B6D952A7E239A00F03C5F /* NCManageDatabase+Chunk.swift in Sources */,
 				F702F2F725EE5CED008F8E80 /* NCLogin.swift in Sources */,
 				F702F2F725EE5CED008F8E80 /* NCLogin.swift in Sources */,
 				F7E98C1627E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F7E98C1627E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */,
 				F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */,
@@ -3627,6 +3723,7 @@
 				F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */,
 				F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */,
 				F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */,
 				F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */,
 				F7501C332212E57500FB1415 /* NCMedia.swift in Sources */,
 				F7501C332212E57500FB1415 /* NCMedia.swift in Sources */,
+				F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */,
 				F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */,
 				F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */,
 				F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */,
 				F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */,
@@ -3641,6 +3738,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 */,
@@ -3654,7 +3752,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 */,
@@ -3663,6 +3760,7 @@
 				F76D364628A4F8BF00214537 /* NCActivityIndicator.swift in Sources */,
 				F76D364628A4F8BF00214537 /* NCActivityIndicator.swift in Sources */,
 				F7020FCE2233D7F700B7297D /* NCCreateFormUploadVoiceNote.swift in Sources */,
 				F7020FCE2233D7F700B7297D /* NCCreateFormUploadVoiceNote.swift in Sources */,
 				F7134186259747BA00768D21 /* NCPushNotification.m in Sources */,
 				F7134186259747BA00768D21 /* NCPushNotification.m in Sources */,
+				F3BB464F2A39EBE500461F6E /* NCMoreUserCell.swift in Sources */,
 				F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */,
 				F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */,
 				F79A65C62191D95E00FF6DCC /* NCSelect.swift in Sources */,
 				F79A65C62191D95E00FF6DCC /* NCSelect.swift in Sources */,
 				F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */,
 				F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */,
@@ -3692,6 +3790,7 @@
 				F749B64A297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F749B64A297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F7C9555521F0C5470024296E /* NCActivity.swift in Sources */,
 				F7C9555521F0C5470024296E /* NCActivity.swift in Sources */,
 				F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */,
 				F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */,
+				F3BB46522A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift in Sources */,
 				F704B5E52430AA8000632F5F /* NCCreateFormUploadConflict.swift in Sources */,
 				F704B5E52430AA8000632F5F /* NCCreateFormUploadConflict.swift in Sources */,
 				F765608F23BF813600765969 /* NCContentPresenter.swift in Sources */,
 				F765608F23BF813600765969 /* NCContentPresenter.swift in Sources */,
 				F343A4BB2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
 				F343A4BB2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
@@ -3707,8 +3806,10 @@
 				F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */,
 				F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */,
 				F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */,
 				F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */,
 				F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */,
 				F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */,
+				F7864ACC2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				F7F4F11027ECDC4A008676F9 /* UIDevice+Extension.swift in Sources */,
 				F7F4F11027ECDC4A008676F9 /* UIDevice+Extension.swift in Sources */,
 				F77B0ED11D118A16002130FE /* Acknowledgements.m in Sources */,
 				F77B0ED11D118A16002130FE /* Acknowledgements.m in Sources */,
+				F79FFB262A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift in Sources */,
 				F70D8D8124A4A9BF000A5756 /* NCNetworkingProcessUpload.swift in Sources */,
 				F70D8D8124A4A9BF000A5756 /* NCNetworkingProcessUpload.swift in Sources */,
 				F7D96FCC246ED7E200536D73 /* NCNetworkingCheckRemoteUser.swift in Sources */,
 				F7D96FCC246ED7E200536D73 /* NCNetworkingCheckRemoteUser.swift in Sources */,
 				F7E4D9C422ED929B003675FD /* NCShareCommentsCell.swift in Sources */,
 				F7E4D9C422ED929B003675FD /* NCShareCommentsCell.swift in Sources */,
@@ -3735,7 +3836,9 @@
 				F75DD767290ABB25002EB562 /* Intent.intentdefinition in Sources */,
 				F75DD767290ABB25002EB562 /* Intent.intentdefinition in Sources */,
 				F749B64C297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F749B64C297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F7A8D73F28F181EF008BBE1C /* NCGlobal.swift in Sources */,
 				F7A8D73F28F181EF008BBE1C /* NCGlobal.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 */,
@@ -3750,6 +3853,7 @@
 				F72FD3B7297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F72FD3B7297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F7A8D74128F18254008BBE1C /* UIColor+Extension.swift in Sources */,
 				F7A8D74128F18254008BBE1C /* UIColor+Extension.swift in Sources */,
 				F7A8D73428F17E12008BBE1C /* NCDatabase.swift in Sources */,
 				F7A8D73428F17E12008BBE1C /* NCDatabase.swift in Sources */,
+				F7864ACE2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
 				F7A8D74028F18212008BBE1C /* UIImage+Extension.swift in Sources */,
 				F7A8D74028F18212008BBE1C /* UIImage+Extension.swift in Sources */,
 				F757CC8429E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F757CC8429E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F78E2D6729AF02DB0024D4F3 /* Database.swift in Sources */,
 				F78E2D6729AF02DB0024D4F3 /* Database.swift in Sources */,
@@ -4566,7 +4670,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 4;
+				CURRENT_PROJECT_VERSION = 16;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -4592,7 +4696,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 					"@executable_path/../../Frameworks",
 				);
 				);
-				MARKETING_VERSION = 4.8.6;
+				MARKETING_VERSION = 4.9.0;
 				ONLY_ACTIVE_ARCH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
 				SDKROOT = iphoneos;
@@ -4631,7 +4735,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 4;
+				CURRENT_PROJECT_VERSION = 16;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
 				ENABLE_TESTABILITY = YES;
@@ -4654,7 +4758,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 					"@executable_path/../../Frameworks",
 				);
 				);
-				MARKETING_VERSION = 4.8.6;
+				MARKETING_VERSION = 4.9.0;
 				ONLY_ACTIVE_ARCH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
 				SDKROOT = iphoneos;
@@ -4938,7 +5042,7 @@
 			repositoryURL = "https://github.com/nextcloud/NextcloudKit";
 			repositoryURL = "https://github.com/nextcloud/NextcloudKit";
 			requirement = {
 			requirement = {
 				kind = exactVersion;
 				kind = exactVersion;
-				version = 2.7.0;
+				version = 2.8.0;
 			};
 			};
 		};
 		};
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {
@@ -4981,6 +5085,14 @@
 				minimumVersion = 10.1.1;
 				minimumVersion = 10.1.1;
 			};
 			};
 		};
 		};
+		F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/1024jp/GzipSwift";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 6.0.0;
+			};
+		};
 /* End XCRemoteSwiftPackageReference section */
 /* End XCRemoteSwiftPackageReference section */
 
 
 /* Begin XCSwiftPackageProductDependency section */
 /* Begin XCSwiftPackageProductDependency section */
@@ -5259,6 +5371,11 @@
 			package = F77BC3E9293E5268005F2B08 /* XCRemoteSwiftPackageReference "swifter" */;
 			package = F77BC3E9293E5268005F2B08 /* XCRemoteSwiftPackageReference "swifter" */;
 			productName = Swifter;
 			productName = Swifter;
 		};
 		};
+		F77CB6A82AA08053000C3CA4 /* OpenSSL */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F77333862927A72100466E35 /* XCRemoteSwiftPackageReference "OpenSSL" */;
+			productName = OpenSSL;
+		};
 		F783030C28B4C59A00B84583 /* SwiftEntryKit */ = {
 		F783030C28B4C59A00B84583 /* SwiftEntryKit */ = {
 			isa = XCSwiftPackageProductDependency;
 			isa = XCSwiftPackageProductDependency;
 			package = F73ADD1A265546880069EA0D /* XCRemoteSwiftPackageReference "SwiftEntryKit" */;
 			package = F73ADD1A265546880069EA0D /* XCRemoteSwiftPackageReference "SwiftEntryKit" */;
@@ -5334,6 +5451,16 @@
 			package = F7ED547A25EEA65400956C55 /* XCRemoteSwiftPackageReference "QRCodeReader" */;
 			package = F7ED547A25EEA65400956C55 /* XCRemoteSwiftPackageReference "QRCodeReader" */;
 			productName = QRCodeReader;
 			productName = QRCodeReader;
 		};
 		};
+		F7F623B42A5EF4D30022D3D4 /* Gzip */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */;
+			productName = Gzip;
+		};
+		F7F623B62A5EFA0C0022D3D4 /* Gzip */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F7F623B32A5EF4D30022D3D4 /* XCRemoteSwiftPackageReference "GzipSwift" */;
+			productName = Gzip;
+		};
 /* End XCSwiftPackageProductDependency section */
 /* End XCSwiftPackageProductDependency section */
 	};
 	};
 	rootObject = F7F67BA01A24D27800EE80DA /* Project object */;
 	rootObject = F7F67BA01A24D27800EE80DA /* Project object */;

+ 0 - 1
Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme

@@ -96,7 +96,6 @@
       buildConfiguration = "Debug"
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      enableThreadSanitizer = "YES"
       launchStyle = "0"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
       useCustomWorkingDirectory = "NO"
       ignoresPersistentStateOnLaunch = "NO"
       ignoresPersistentStateOnLaunch = "NO"

+ 2 - 2
Notification Service Extension/NotificationService.swift

@@ -46,7 +46,7 @@ class NotificationService: UNNotificationServiceExtension {
                         if var json = try JSONSerialization.jsonObject(with: data) as? [String: AnyObject],
                         if var json = try JSONSerialization.jsonObject(with: data) as? [String: AnyObject],
                            let subject = json["subject"] as? String {
                            let subject = json["subject"] as? String {
                             bestAttemptContent.body = subject
                             bestAttemptContent.body = subject
-                            if let pref = UserDefaults.init(suiteName: NCBrandOptions.shared.capabilitiesGroups) {
+                            if let pref = UserDefaults(suiteName: NCBrandOptions.shared.capabilitiesGroups) {
                                 json["account"] = tableAccount.account as AnyObject
                                 json["account"] = tableAccount.account as AnyObject
                                 pref.set(json, forKey: "NOTIFICATION_DATA")
                                 pref.set(json, forKey: "NOTIFICATION_DATA")
                                 pref.synchronize()
                                 pref.synchronize()
@@ -65,7 +65,7 @@ class NotificationService: UNNotificationServiceExtension {
     override func serviceExtensionTimeWillExpire() {
     override func serviceExtensionTimeWillExpire() {
         // Called just before the extension will be terminated by the system.
         // Called just before the extension will be terminated by the system.
         // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
         // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
-        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
+        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
             bestAttemptContent.title = ""
             bestAttemptContent.title = ""
             bestAttemptContent.body = "Nextcloud notification"
             bestAttemptContent.body = "Nextcloud notification"
             contentHandler(bestAttemptContent)
             contentHandler(bestAttemptContent)

+ 1 - 1
README.md

@@ -38,7 +38,7 @@ branch. Maybe start working on [starter issues](https://github.com/nextcloud/ios
 
 
 Easy starting points are also reviewing [pull requests](https://github.com/nextcloud/ios/pulls)
 Easy starting points are also reviewing [pull requests](https://github.com/nextcloud/ios/pulls)
 
 
-### Xcode 14.2 Project Setup
+### Xcode 15 Project Setup
 
 
 #### Dependencies
 #### Dependencies
 
 

+ 1 - 0
Share/NCShareExtension+DataSource.swift

@@ -65,6 +65,7 @@ extension NCShareExtension: UICollectionViewDataSource {
         cell.delegate = self
         cell.delegate = self
 
 
         cell.fileObjectId = metadata.ocId
         cell.fileObjectId = metadata.ocId
+        cell.indexPath = indexPath
         cell.fileUser = metadata.ownerId
         cell.fileUser = metadata.ownerId
         cell.labelTitle.text = metadata.fileNameView
         cell.labelTitle.text = metadata.fileNameView
         cell.labelTitle.textColor = .label
         cell.labelTitle.textColor = .label

+ 2 - 1
Share/NCShareExtension+NCDelegate.swift

@@ -90,7 +90,7 @@ extension NCShareExtension: NCEmptyDataSetDelegate, NCAccountRequestDelegate {
             userId: activeAccount.userId,
             userId: activeAccount.userId,
             password: CCUtility.getPassword(activeAccount.account),
             password: CCUtility.getPassword(activeAccount.account),
             urlBase: activeAccount.urlBase,
             urlBase: activeAccount.urlBase,
-            userAgent: CCUtility.getUserAgent(),
+            userAgent: userAgent,
             nextcloudVersion: 0,
             nextcloudVersion: 0,
             delegate: NCNetworking.shared)
             delegate: NCNetworking.shared)
 
 
@@ -127,6 +127,7 @@ extension NCShareExtension: NCShareCellDelegate, NCRenameFileDelegate, NCListCel
         let resultInternalType = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileName, mimeType: "", directory: false)
         let resultInternalType = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileName, mimeType: "", directory: false)
         vcRename.delegate = self
         vcRename.delegate = self
         vcRename.fileName = fileName
         vcRename.fileName = fileName
+        vcRename.indexPath = IndexPath()
         if let previewImage = UIImage.downsample(imageAt: URL(fileURLWithPath: NSTemporaryDirectory() + fileName), to: CGSize(width: 140, height: 140)) {
         if let previewImage = UIImage.downsample(imageAt: URL(fileURLWithPath: NSTemporaryDirectory() + fileName), to: CGSize(width: 140, height: 140)) {
             vcRename.imagePreview = previewImage
             vcRename.imagePreview = previewImage
         } else {
         } else {

+ 12 - 4
Share/NCShareExtension.swift

@@ -65,7 +65,6 @@ class NCShareExtension: UIViewController {
     var autoUploadDirectory = ""
     var autoUploadDirectory = ""
     let refreshControl = UIRefreshControl()
     let refreshControl = UIRefreshControl()
     var activeAccount: tableAccount!
     var activeAccount: tableAccount!
-    let chunckSize = CCUtility.getChunkSize() * 1000000
     var progress: CGFloat = 0
     var progress: CGFloat = 0
     var counterUploaded: Int = 0
     var counterUploaded: Int = 0
     var uploadErrors: [tableMetadata] = []
     var uploadErrors: [tableMetadata] = []
@@ -337,8 +336,18 @@ extension NCShareExtension {
         metadata.contentType = results.mimeType
         metadata.contentType = results.mimeType
         metadata.iconName = results.iconName
         metadata.iconName = results.iconName
         metadata.classFile = results.classFile
         metadata.classFile = results.classFile
-        // CHUNCK
-        metadata.chunk = chunckSize != 0 && metadata.size > chunckSize
+        // CHUNK
+        var chunkSize = NCGlobal.shared.chunkSizeMBCellular
+        if NCNetworking.shared.networkReachability == NKCommon.TypeReachability.reachableEthernetOrWiFi {
+            chunkSize = NCGlobal.shared.chunkSizeMBEthernetOrWiFi
+        }
+        if metadata.size > chunkSize {
+            metadata.chunk = chunkSize
+        } else {
+            metadata.chunk = 0
+        }
+        // E2EE
+        metadata.e2eEncrypted = metadata.isDirectoryE2EE
 
 
         hud.textLabel.text = NSLocalizedString("_upload_file_", comment: "") + " \(counterUploaded + 1) " + NSLocalizedString("_of_", comment: "") + " \(filesName.count)"
         hud.textLabel.text = NSLocalizedString("_upload_file_", comment: "") + " \(counterUploaded + 1) " + NSLocalizedString("_of_", comment: "") + " \(filesName.count)"
         hud.show(in: self.view)
         hud.show(in: self.view)
@@ -351,7 +360,6 @@ extension NCShareExtension {
             if error != .success {
             if error != .success {
                 let path = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)!
                 let path = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)!
                 NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
                 NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
-                NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
                 NCUtilityFileSystem.shared.deleteFile(filePath: path)
                 NCUtilityFileSystem.shared.deleteFile(filePath: path)
                 self.uploadErrors.append(metadata)
                 self.uploadErrors.append(metadata)
             }
             }

+ 19 - 15
iOSClient/Extensions/UIApplication+Extension.swift → Tests/NextcloudIntegrationTests/BaseIntegrationXCTestCase.swift

@@ -1,12 +1,11 @@
 //
 //
-//  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>
+//  BaseIntegrationXCTestCase.swift
+//  
+// 
+//  Created by Milen Pivchev on 20.06.23.
+//  Copyright © 2023 Milen Pivchev. All rights reserved.
 //
 //
+//  Author: Milen Pivchev <milen.pivchev@nextcloud.com>
 //  This program is free software: you can redistribute it and/or modify
 //  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
 //  it under the terms of the GNU General Public License as published by
 //  the Free Software Foundation, either version 3 of the License, or
 //  the Free Software Foundation, either version 3 of the License, or
@@ -20,15 +19,20 @@
 //  You should have received a copy of the GNU General Public License
 //  You should have received a copy of the GNU General Public License
 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //  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
+import XCTest
+@testable import NextcloudKit
+
+class BaseIntegrationXCTestCase: XCTestCase {
+    internal let baseUrl = EnvVars.testServerUrl
+    internal let user = EnvVars.testUser
+    internal let userId = EnvVars.testUser
+    internal let password = EnvVars.testAppPassword
+    internal lazy var account = "\(userId) \(baseUrl)"
+
+    internal var randomInt: Int {
+        get {
+            return Int.random(in: 1000...Int.max)
         }
         }
     }
     }
 }
 }

+ 2 - 8
Tests/NextcloudIntegrationTests/FilesIntegrationTests.swift

@@ -10,13 +10,7 @@ import XCTest
 import NextcloudKit
 import NextcloudKit
 @testable import Nextcloud
 @testable import Nextcloud
 
 
-final class FilesIntegrationTests: XCTestCase {
-    private let baseUrl = EnvVars.testServerUrl
-    private let user = EnvVars.testUser
-    private let userId = EnvVars.testUser
-    private let password = EnvVars.testAppPassword
-    private lazy var account = "\(userId) \(baseUrl)"
-
+final class FilesIntegrationTests: BaseIntegrationXCTestCase {
     private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
     private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
 
 
     override func setUp() {
     override func setUp() {
@@ -26,7 +20,7 @@ final class FilesIntegrationTests: XCTestCase {
     func test_createReadDeleteFolder_withProperParams_shouldCreateReadDeleteFolder() throws {
     func test_createReadDeleteFolder_withProperParams_shouldCreateReadDeleteFolder() throws {
         let expectation = expectation(description: "Should finish last callback")
         let expectation = expectation(description: "Should finish last callback")
 
 
-        let folderName = "TestFolder10"
+        let folderName = "TestFolder\(randomInt)"
         let serverUrl = "\(baseUrl)/remote.php/dav/files/\(userId)"
         let serverUrl = "\(baseUrl)/remote.php/dav/files/\(userId)"
         let serverUrlFileName = "\(serverUrl)/\(folderName)"
         let serverUrlFileName = "\(serverUrl)/\(folderName)"
 
 

+ 1 - 1
Tests/NextcloudUITests/LoginUITests.swift

@@ -47,7 +47,7 @@ final class LoginUITests: BaseUIXCTestCase {
         usernameTextField.typeText(user)
         usernameTextField.typeText(user)
         let passwordTextField = element.children(matching: .other).element(boundBy: 4).children(matching: .secureTextField).element
         let passwordTextField = element.children(matching: .other).element(boundBy: 4).children(matching: .secureTextField).element
         passwordTextField.tap()
         passwordTextField.tap()
-        passwordTextField.typeText(user)
+        passwordTextField.typeText(password)
         let loginButton3 = webViewsQuery/*@START_MENU_TOKEN@*/.buttons["Log in"]/*[[".otherElements[\"Login – Nextcloud\"]",".otherElements[\"main\"].buttons[\"Log in\"]",".buttons[\"Log in\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/
         let loginButton3 = webViewsQuery/*@START_MENU_TOKEN@*/.buttons["Log in"]/*[[".otherElements[\"Login – Nextcloud\"]",".otherElements[\"main\"].buttons[\"Log in\"]",".buttons[\"Log in\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/
         XCTAssert(loginButton3.waitForExistence(timeout: timeoutSeconds))
         XCTAssert(loginButton3.waitForExistence(timeout: timeoutSeconds))
         loginButton3.tap()
         loginButton3.tap()

+ 7 - 13
Widget/Dashboard/DashboardData.swift

@@ -51,12 +51,6 @@ struct DashboardData: Identifiable, Hashable {
     let imageColor: UIColor?
     let imageColor: UIColor?
 }
 }
 
 
-struct DashboardDataButton: Hashable {
-    let type: String
-    let Text: String
-    let link: String
-}
-
 let dashboardDatasTest: [DashboardData] = [
 let dashboardDatasTest: [DashboardData] = [
     .init(id: 0, title: "title0", subTitle: "subTitle-description0", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(named: "widget")!, template: true, avatar: false, imageColor: nil),
     .init(id: 0, title: "title0", subTitle: "subTitle-description0", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(named: "widget")!, template: true, avatar: false, imageColor: nil),
     .init(id: 1, title: "title1", subTitle: "subTitle-description1", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(named: "widget")!, template: true, avatar: false, imageColor: nil),
     .init(id: 1, title: "title1", subTitle: "subTitle-description1", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(named: "widget")!, template: true, avatar: false, imageColor: nil),
@@ -71,7 +65,7 @@ let dashboardDatasTest: [DashboardData] = [
 ]
 ]
 
 
 func getDashboardItems(displaySize: CGSize, withButton: Bool) -> Int {
 func getDashboardItems(displaySize: CGSize, withButton: Bool) -> Int {
-    
+
     if withButton {
     if withButton {
         let height = Int((displaySize.height - 85) / 50)
         let height = Int((displaySize.height - 85) / 50)
         return height
         return height
@@ -81,7 +75,7 @@ func getDashboardItems(displaySize: CGSize, withButton: Bool) -> Int {
     }
     }
 }
 }
 
 
-func convertDataToImage(data: Data?, size:CGSize, fileNameToWrite: String?) -> UIImage? {
+func convertDataToImage(data: Data?, size: CGSize, fileNameToWrite: String?) -> UIImage? {
 
 
     guard let data = data else { return nil }
     guard let data = data else { return nil }
     var imageData: UIImage?
     var imageData: UIImage?
@@ -134,7 +128,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
     guard NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion25 else {
     guard NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion25 else {
         return completion(DashboardDataEntry(date: Date(), datas: datasPlaceholder, dashboard: nil, buttons: nil, isPlaceholder: true, isEmpty: false, titleImage: UIImage(named: "widget")!, title: "Dashboard", footerImage: "xmark.icloud", footerText: NSLocalizedString("_widget_available_nc25_", comment: "")))
         return completion(DashboardDataEntry(date: Date(), datas: datasPlaceholder, dashboard: nil, buttons: nil, isPlaceholder: true, isEmpty: false, titleImage: UIImage(named: "widget")!, title: "Dashboard", footerImage: "xmark.icloud", footerText: NSLocalizedString("_widget_available_nc25_", comment: "")))
     }
     }
-        
+
     // NETWORKING
     // NETWORKING
     let password = CCUtility.getPassword(account.account)!
     let password = CCUtility.getPassword(account.account)!
     NextcloudKit.shared.setup(
     NextcloudKit.shared.setup(
@@ -143,7 +137,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
         userId: account.userId,
         userId: account.userId,
         password: password,
         password: password,
         urlBase: account.urlBase,
         urlBase: account.urlBase,
-        userAgent: CCUtility.getUserAgent(),
+        userAgent: userAgent,
         nextcloudVersion: 0,
         nextcloudVersion: 0,
         delegate: NCNetworking.shared)
         delegate: NCNetworking.shared)
 
 
@@ -161,7 +155,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
     } else {
     } else {
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start \(NCBrandOptions.shared.brand) dashboard widget session with level \(levelLog) " + versionNextcloudiOS)
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start \(NCBrandOptions.shared.brand) dashboard widget session with level \(levelLog) " + versionNextcloudiOS)
     }
     }
-    
+
     let (tableDashboard, tableButton) = NCManageDatabase.shared.getDashboardWidget(account: account.account, id: id)
     let (tableDashboard, tableButton) = NCManageDatabase.shared.getDashboardWidget(account: account.account, id: id)
     let existsButton = (tableButton?.isEmpty ?? true) ? false : true
     let existsButton = (tableButton?.isEmpty ?? true) ? false : true
     let title = tableDashboard?.title ?? id
     let title = tableDashboard?.title ?? id
@@ -215,7 +209,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
                                     if let item = CCUtility.value(forKey: "fileId", fromQueryItems: queryItems) {
                                     if let item = CCUtility.value(forKey: "fileId", fromQueryItems: queryItems) {
                                         iconFileName = item
                                         iconFileName = item
                                     } else if pathComponents.contains("avatar") {
                                     } else if pathComponents.contains("avatar") {
-                                        iconFileName = pathComponents[pathComponents.count-2]
+                                        iconFileName = pathComponents[pathComponents.count - 2]
                                         imageAvatar = true
                                         imageAvatar = true
                                     } else if pathComponents.contains("getCalendarDotSvg") {
                                     } else if pathComponents.contains("getCalendarDotSvg") {
                                         imageColorized = true
                                         imageColorized = true
@@ -257,7 +251,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
             }
             }
 
 
             let alias = (account.alias.isEmpty) ? "" : (" (" + account.alias + ")")
             let alias = (account.alias.isEmpty) ? "" : (" (" + account.alias + ")")
-            let footerText = "Dashboard " + NSLocalizedString("_of_", comment: "") +  " " + account.displayName + alias
+            let footerText = "Dashboard " + NSLocalizedString("_of_", comment: "") + " " + account.displayName + alias
 
 
             if error != .success {
             if error != .success {
                 completion(DashboardDataEntry(date: Date(), datas: datasPlaceholder, dashboard: tableDashboard, buttons: buttons, isPlaceholder: true, isEmpty: false, titleImage: titleImage, title: title, footerImage: "xmark.icloud", footerText: error.errorDescription))
                 completion(DashboardDataEntry(date: Date(), datas: datasPlaceholder, dashboard: tableDashboard, buttons: buttons, isPlaceholder: true, isEmpty: false, titleImage: titleImage, title: title, footerImage: "xmark.icloud", footerText: error.errorDescription))

+ 8 - 7
Widget/Dashboard/DashboardWidgetView.swift

@@ -27,9 +27,9 @@ import WidgetKit
 struct DashboardWidgetView: View {
 struct DashboardWidgetView: View {
 
 
     var entry: DashboardDataEntry
     var entry: DashboardDataEntry
-    
+
     var body: some View {
     var body: some View {
-        
+
         GeometryReader { geo in
         GeometryReader { geo in
 
 
             if entry.isEmpty {
             if entry.isEmpty {
@@ -49,14 +49,14 @@ struct DashboardWidgetView: View {
 
 
             ZStack(alignment: .topLeading) {
             ZStack(alignment: .topLeading) {
 
 
-                HStack() {
+                HStack {
 
 
                     Image(uiImage: entry.titleImage)
                     Image(uiImage: entry.titleImage)
                         .renderingMode(.template)
                         .renderingMode(.template)
                         .resizable()
                         .resizable()
                         .scaledToFill()
                         .scaledToFill()
                         .frame(width: 20, height: 20)
                         .frame(width: 20, height: 20)
-                    
+
                     Text(entry.title)
                     Text(entry.title)
                         .font(.system(size: 15))
                         .font(.system(size: 15))
                         .fontWeight(.bold)
                         .fontWeight(.bold)
@@ -160,8 +160,8 @@ struct DashboardWidgetView: View {
                         let brandTextColor = Color(NCBrandColor.shared.brandText)
                         let brandTextColor = Color(NCBrandColor.shared.brandText)
 
 
                         ForEach(buttons, id: \.index) { element in
                         ForEach(buttons, id: \.index) { element in
-                            Link(destination: URL(string: element.link)! , label: {
-                                
+                            Link(destination: URL(string: element.link)!, label: {
+
                                 Text(element.text)
                                 Text(element.text)
                                     .font(.system(size: 15))
                                     .font(.system(size: 15))
                                     .padding(7)
                                     .padding(7)
@@ -174,7 +174,7 @@ struct DashboardWidgetView: View {
                     }
                     }
                     .frame(width: geo.size.width - 10, height: geo.size.height - 25, alignment: .bottomTrailing)
                     .frame(width: geo.size.width - 10, height: geo.size.height - 25, alignment: .bottomTrailing)
                 }
                 }
-                
+
                 HStack {
                 HStack {
 
 
                     Image(systemName: entry.footerImage)
                     Image(systemName: entry.footerImage)
@@ -192,6 +192,7 @@ struct DashboardWidgetView: View {
                 .frame(maxWidth: geo.size.width, maxHeight: geo.size.height - 2, alignment: .bottomTrailing)
                 .frame(maxWidth: geo.size.width, maxHeight: geo.size.height - 2, alignment: .bottomTrailing)
             }
             }
         }
         }
+        .widgetBackground(Color(UIColor.systemBackground))
     }
     }
 }
 }
 
 

+ 5 - 5
Widget/Files/FilesData.swift

@@ -79,7 +79,7 @@ func getTitleFilesWidget(account: tableAccount?) -> String {
 }
 }
 
 
 func getFilesItems(displaySize: CGSize) -> Int {
 func getFilesItems(displaySize: CGSize) -> Int {
-    
+
     let height = Int((displaySize.height - 100) / 50)
     let height = Int((displaySize.height - 100) / 50)
     return height
     return height
 }
 }
@@ -131,7 +131,7 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi
         userId: account.userId,
         userId: account.userId,
         password: password,
         password: password,
         urlBase: account.urlBase,
         urlBase: account.urlBase,
-        userAgent: CCUtility.getUserAgent(),
+        userAgent: userAgent,
         nextcloudVersion: 0,
         nextcloudVersion: 0,
         delegate: NCNetworking.shared)
         delegate: NCNetworking.shared)
 
 
@@ -205,7 +205,7 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi
     } else {
     } else {
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start \(NCBrandOptions.shared.brand) widget session with level \(levelLog) " + versionNextcloudiOS)
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start \(NCBrandOptions.shared.brand) widget session with level \(levelLog) " + versionNextcloudiOS)
     }
     }
-    
+
     let options = NKRequestOptions(timeout: 90, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
     let options = NKRequestOptions(timeout: 90, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
     NextcloudKit.shared.searchBodyRequest(serverUrl: account.urlBase, requestBody: requestBody, showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { _, files, data, error in
     NextcloudKit.shared.searchBodyRequest(serverUrl: account.urlBase, requestBody: requestBody, showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { _, files, data, error in
         Task {
         Task {
@@ -249,13 +249,13 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi
                 let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryE2EE)
                 let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryE2EE)
 
 
                 // DATA
                 // DATA
-                let data = FilesData.init(id: metadata.ocId, image: imageRecent, title: metadata.fileNameView, subTitle: subTitle, url: url)
+                let data = FilesData(id: metadata.ocId, image: imageRecent, title: metadata.fileNameView, subTitle: subTitle, url: url)
                 datas.append(data)
                 datas.append(data)
                 if datas.count == filesItems { break}
                 if datas.count == filesItems { break}
             }
             }
 
 
             let alias = (account.alias.isEmpty) ? "" : (" (" + account.alias + ")")
             let alias = (account.alias.isEmpty) ? "" : (" (" + account.alias + ")")
-            let footerText = "Files " + NSLocalizedString("_of_", comment: "") +  " " + account.displayName + alias
+            let footerText = "Files " + NSLocalizedString("_of_", comment: "") + " " + account.displayName + alias
 
 
             if error != .success {
             if error != .success {
                 completion(FilesDataEntry(date: Date(), datas: datasPlaceholder, isPlaceholder: true, isEmpty: false, userId: account.userId, url: account.urlBase, tile: title, footerImage: "xmark.icloud", footerText: error.errorDescription))
                 completion(FilesDataEntry(date: Date(), datas: datasPlaceholder, isPlaceholder: true, isEmpty: false, userId: account.userId, url: account.urlBase, tile: title, footerImage: "xmark.icloud", footerText: error.errorDescription))

+ 6 - 5
Widget/Files/FilesWidgetView.swift

@@ -25,7 +25,7 @@ import SwiftUI
 import WidgetKit
 import WidgetKit
 
 
 struct FilesWidgetView: View {
 struct FilesWidgetView: View {
-    
+
     var entry: FilesDataEntry
     var entry: FilesDataEntry
 
 
     var body: some View {
     var body: some View {
@@ -55,9 +55,9 @@ struct FilesWidgetView: View {
             }
             }
 
 
             ZStack(alignment: .topLeading) {
             ZStack(alignment: .topLeading) {
-                
-                HStack() {
-                    
+
+                HStack {
+
                     Text(entry.tile)
                     Text(entry.tile)
                         .font(.system(size: 12))
                         .font(.system(size: 12))
                         .fontWeight(.bold)
                         .fontWeight(.bold)
@@ -172,7 +172,7 @@ struct FilesWidgetView: View {
                         .scaledToFit()
                         .scaledToFit()
                         .frame(width: 15, height: 15)
                         .frame(width: 15, height: 15)
                         .foregroundColor(entry.isPlaceholder ? Color(.systemGray4) : Color(NCBrandColor.shared.brand))
                         .foregroundColor(entry.isPlaceholder ? Color(.systemGray4) : Color(NCBrandColor.shared.brand))
-                
+
                     Text(entry.footerText)
                     Text(entry.footerText)
                         .font(.caption2)
                         .font(.caption2)
                         .lineLimit(1)
                         .lineLimit(1)
@@ -182,6 +182,7 @@ struct FilesWidgetView: View {
                 .frame(maxWidth: geo.size.width, maxHeight: geo.size.height - 2, alignment: .bottomTrailing)
                 .frame(maxWidth: geo.size.width, maxHeight: geo.size.height - 2, alignment: .bottomTrailing)
             }
             }
         }
         }
+        .widgetBackground(Color(UIColor.systemBackground))
     }
     }
 }
 }
 
 

+ 1 - 1
Widget/Lockscreen/LockscreenData.swift

@@ -70,7 +70,7 @@ func getLockscreenDataEntry(configuration: AccountIntent?, isPreview: Bool, fami
         userId: account.userId,
         userId: account.userId,
         password: password,
         password: password,
         urlBase: account.urlBase,
         urlBase: account.urlBase,
-        userAgent: CCUtility.getUserAgent(),
+        userAgent: userAgent,
         nextcloudVersion: 0,
         nextcloudVersion: 0,
         delegate: NCNetworking.shared)
         delegate: NCNetworking.shared)
 
 

+ 3 - 0
Widget/Lockscreen/LockscreenWidgetView.swift

@@ -43,6 +43,7 @@ struct LockscreenWidgetView: View {
                     }
                     }
                 )
                 )
                 .gaugeStyle(.accessoryCircularCapacity)
                 .gaugeStyle(.accessoryCircularCapacity)
+                .widgetBackground(Color.clear)
             } else {
             } else {
                 Gauge(
                 Gauge(
                     value: entry.quotaRelative,
                     value: entry.quotaRelative,
@@ -56,6 +57,7 @@ struct LockscreenWidgetView: View {
                 )
                 )
                 .gaugeStyle(.accessoryCircular)
                 .gaugeStyle(.accessoryCircular)
                 .redacted(reason: entry.isPlaceholder ? .placeholder : [])
                 .redacted(reason: entry.isPlaceholder ? .placeholder : [])
+                .widgetBackground(Color.clear)
             }
             }
         case .accessoryRectangular:
         case .accessoryRectangular:
             VStack(alignment: .leading, spacing: 1) {
             VStack(alignment: .leading, spacing: 1) {
@@ -84,6 +86,7 @@ struct LockscreenWidgetView: View {
             }
             }
             .widgetURL(entry.link)
             .widgetURL(entry.link)
             .redacted(reason: entry.isPlaceholder ? .placeholder : [])
             .redacted(reason: entry.isPlaceholder ? .placeholder : [])
+            .widgetBackground(Color.clear)
         default:
         default:
             Text("Not implemented")
             Text("Not implemented")
         }
         }

+ 1 - 3
Widget/Toolbar/ToolbarWidgetView.swift

@@ -41,9 +41,6 @@ struct ToolbarWidgetView: View {
 
 
             ZStack(alignment: .topLeading) {
             ZStack(alignment: .topLeading) {
 
 
-                Color(.black).opacity(0.9)
-                    .ignoresSafeArea()
-
                 HStack(spacing: 0) {
                 HStack(spacing: 0) {
 
 
                     let sizeButton: CGFloat = 65
                     let sizeButton: CGFloat = 65
@@ -114,6 +111,7 @@ struct ToolbarWidgetView: View {
                 .frame(maxWidth: geo.size.width - 5, maxHeight: geo.size.height - 2, alignment: .bottomTrailing)
                 .frame(maxWidth: geo.size.width - 5, maxHeight: geo.size.height - 2, alignment: .bottomTrailing)
             }
             }
         }
         }
+        .widgetBackground(Color.black.opacity(0.9))
     }
     }
 }
 }
 
 

+ 16 - 0
Widget/Widget.swift

@@ -47,6 +47,7 @@ struct DashboardWidget: Widget {
         .supportedFamilies([.systemLarge])
         .supportedFamilies([.systemLarge])
         .configurationDisplayName("Dashboard")
         .configurationDisplayName("Dashboard")
         .description(NSLocalizedString("_description_dashboardwidget_", comment: ""))
         .description(NSLocalizedString("_description_dashboardwidget_", comment: ""))
+        .contentMarginsDisabled()
     }
     }
 }
 }
 
 
@@ -60,6 +61,7 @@ struct FilesWidget: Widget {
         .supportedFamilies([.systemLarge])
         .supportedFamilies([.systemLarge])
         .configurationDisplayName("Files")
         .configurationDisplayName("Files")
         .description(NSLocalizedString("_description_fileswidget_", comment: ""))
         .description(NSLocalizedString("_description_fileswidget_", comment: ""))
+        .contentMarginsDisabled()
     }
     }
 }
 }
 
 
@@ -73,6 +75,7 @@ struct ToolbarWidget: Widget {
         .supportedFamilies([.systemMedium])
         .supportedFamilies([.systemMedium])
         .configurationDisplayName("Toolbar")
         .configurationDisplayName("Toolbar")
         .description(NSLocalizedString("_description_toolbarwidget_", comment: ""))
         .description(NSLocalizedString("_description_toolbarwidget_", comment: ""))
+        .contentMarginsDisabled()
     }
     }
 }
 }
 
 
@@ -87,8 +90,21 @@ struct LockscreenWidget: Widget {
             .supportedFamilies([.accessoryRectangular, .accessoryCircular])
             .supportedFamilies([.accessoryRectangular, .accessoryCircular])
             .configurationDisplayName(NSLocalizedString("_title_lockscreenwidget_", comment: ""))
             .configurationDisplayName(NSLocalizedString("_title_lockscreenwidget_", comment: ""))
             .description(NSLocalizedString("_description_lockscreenwidget_", comment: ""))
             .description(NSLocalizedString("_description_lockscreenwidget_", comment: ""))
+            .contentMarginsDisabled()
         } else {
         } else {
             return EmptyWidgetConfiguration()
             return EmptyWidgetConfiguration()
         }
         }
     }
     }
 }
 }
+
+extension View {
+    func widgetBackground(_ backgroundView: some View) -> some View {
+        if #available(iOSApplicationExtension 17.0, *) {
+            return containerBackground(for: .widget) {
+                backgroundView
+            }
+        } else {
+            return background(backgroundView)
+        }
+    }
+}

+ 16 - 23
iOSClient/Activity/NCActivity.swift

@@ -39,7 +39,9 @@ class NCActivity: UIViewController, NCSharePagingContent {
     var metadata: tableMetadata?
     var metadata: tableMetadata?
     var showComments: Bool = false
     var showComments: Bool = false
 
 
+    // swiftlint:disable force_cast
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
 
 
     var allItems: [DateCompareable] = []
     var allItems: [DateCompareable] = []
     var sectionDates: [Date] = []
     var sectionDates: [Date] = []
@@ -101,13 +103,11 @@ class NCActivity: UIViewController, NCSharePagingContent {
 
 
         navigationController?.setFileAppreance()
         navigationController?.setFileAppreance()
 
 
-        NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil)
-        initialize()
+        fetchAll(isInitial: true)
     }
     }
 
 
     override func viewWillDisappear(_ animated: Bool) {
     override func viewWillDisappear(_ animated: Bool) {
         super.viewWillDisappear(animated)
         super.viewWillDisappear(animated)
-        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil)
     }
     }
 
 
     override func viewWillLayoutSubviews() {
     override func viewWillLayoutSubviews() {
@@ -119,14 +119,6 @@ class NCActivity: UIViewController, NCSharePagingContent {
         viewContainerConstraint.constant = height
         viewContainerConstraint.constant = height
     }
     }
 
 
-    // MARK: - NotificationCenter
-
-    @objc func initialize() {
-        loadDataSource()
-        fetchAll(isInitial: true)
-        view.setNeedsLayout()
-    }
-
     func makeTableFooterView() -> UIView {
     func makeTableFooterView() -> UIView {
         let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 100))
         let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 100))
         view.backgroundColor = .clear
         view.backgroundColor = .clear
@@ -172,7 +164,7 @@ extension NCActivity: UITableViewDelegate {
         label.textAlignment = .center
         label.textAlignment = .center
         label.layer.cornerRadius = 11
         label.layer.cornerRadius = 11
         label.layer.masksToBounds = true
         label.layer.masksToBounds = true
-        label.layer.backgroundColor = UIColor(red: 152.0/255.0, green: 167.0/255.0, blue: 181.0/255.0, alpha: 0.8).cgColor
+        label.layer.backgroundColor = UIColor(red: 152.0 / 255.0, green: 167.0 / 255.0, blue: 181.0 / 255.0, alpha: 0.8).cgColor
         let widthFrame = label.intrinsicContentSize.width + 30
         let widthFrame = label.intrinsicContentSize.width + 30
         let xFrame = tableView.bounds.width / 2 - widthFrame / 2
         let xFrame = tableView.bounds.width / 2 - widthFrame / 2
         label.frame = CGRect(x: xFrame, y: 10, width: widthFrame, height: 22)
         label.frame = CGRect(x: xFrame, y: 10, width: widthFrame, height: 22)
@@ -213,6 +205,7 @@ extension NCActivity: UITableViewDataSource {
             return UITableViewCell()
             return UITableViewCell()
         }
         }
 
 
+        cell.indexPath = indexPath
         cell.tableComments = comment
         cell.tableComments = comment
         cell.delegate = self
         cell.delegate = self
         cell.sizeToFit()
         cell.sizeToFit()
@@ -247,7 +240,7 @@ extension NCActivity: UITableViewDataSource {
         var orderKeysId: [String] = []
         var orderKeysId: [String] = []
 
 
         cell.idActivity = activity.idActivity
         cell.idActivity = activity.idActivity
-
+        cell.indexPath = indexPath
         cell.avatar.image = nil
         cell.avatar.image = nil
         cell.avatar.isHidden = true
         cell.avatar.isHidden = true
         cell.subjectTrailingConstraint.constant = 10
         cell.subjectTrailingConstraint.constant = 10
@@ -256,7 +249,7 @@ extension NCActivity: UITableViewDataSource {
         cell.viewController = self
         cell.viewController = self
 
 
         // icon
         // icon
-        if activity.icon.count > 0 {
+        if !activity.icon.isEmpty {
 
 
             let fileNameIcon = (activity.icon as NSString).lastPathComponent
             let fileNameIcon = (activity.icon as NSString).lastPathComponent
             let fileNameLocalPath = CCUtility.getDirectoryUserData() + "/" + fileNameIcon
             let fileNameLocalPath = CCUtility.getDirectoryUserData() + "/" + fileNameIcon
@@ -278,7 +271,7 @@ extension NCActivity: UITableViewDataSource {
         }
         }
 
 
         // avatar
         // avatar
-        if activity.user.count > 0 && activity.user != appDelegate.userId {
+        if !activity.user.isEmpty && activity.user != appDelegate.userId {
 
 
             cell.subjectTrailingConstraint.constant = 50
             cell.subjectTrailingConstraint.constant = 50
             cell.avatar.isHidden = false
             cell.avatar.isHidden = false
@@ -291,7 +284,7 @@ extension NCActivity: UITableViewDataSource {
 
 
         // subject
         // subject
         cell.subject.text = activity.subject
         cell.subject.text = activity.subject
-        if activity.subjectRich.count > 0 {
+        if !activity.subjectRich.isEmpty {
 
 
             var subject = activity.subjectRich
             var subject = activity.subjectRich
             var keys: [String] = []
             var keys: [String] = []
@@ -325,7 +318,7 @@ extension NCActivity: UITableViewDataSource {
 
 
         // CollectionView
         // CollectionView
         cell.activityPreviews = NCManageDatabase.shared.getActivityPreview(account: activity.account, idActivity: activity.idActivity, orderKeysId: orderKeysId)
         cell.activityPreviews = NCManageDatabase.shared.getActivityPreview(account: activity.account, idActivity: activity.idActivity, orderKeysId: orderKeysId)
-        if cell.activityPreviews.count == 0 {
+        if cell.activityPreviews.isEmpty {
             cell.collectionViewHeightConstraint.constant = 0
             cell.collectionViewHeightConstraint.constant = 0
         } else {
         } else {
             cell.collectionViewHeightConstraint.constant = 60
             cell.collectionViewHeightConstraint.constant = 60
@@ -358,9 +351,9 @@ extension NCActivity {
 
 
         var bottom: CGFloat = 0
         var bottom: CGFloat = 0
         if let mainTabBar = self.tabBarController?.tabBar as? NCMainTabBar {
         if let mainTabBar = self.tabBarController?.tabBar as? NCMainTabBar {
-            bottom = -mainTabBar.getHight()
+            bottom = -mainTabBar.getHeight()
         }
         }
-        NCActivityIndicator.shared.start(backgroundView: self.view, bottom: bottom-5, style: .medium)
+        NCActivityIndicator.shared.start(backgroundView: self.view, bottom: bottom - 5, style: .medium)
 
 
         let dispatchGroup = DispatchGroup()
         let dispatchGroup = DispatchGroup()
         loadComments(disptachGroup: dispatchGroup)
         loadComments(disptachGroup: dispatchGroup)
@@ -407,7 +400,7 @@ extension NCActivity {
         guard showComments, let metadata = metadata else { return }
         guard showComments, let metadata = metadata else { return }
         disptachGroup?.enter()
         disptachGroup?.enter()
 
 
-        NextcloudKit.shared.getComments(fileId: metadata.fileId) { account, comments, data, error in
+        NextcloudKit.shared.getComments(fileId: metadata.fileId) { _, comments, _, error in
             if error == .success, let comments = comments {
             if error == .success, let comments = comments {
                 NCManageDatabase.shared.addComments(comments, account: metadata.account, objectId: metadata.fileId)
                 NCManageDatabase.shared.addComments(comments, account: metadata.account, objectId: metadata.fileId)
             } else if error.errorCode != NCGlobal.shared.errorResourceNotFound {
             } else if error.errorCode != NCGlobal.shared.errorResourceNotFound {
@@ -436,7 +429,7 @@ extension NCActivity {
             limit: 1,
             limit: 1,
             objectId: nil,
             objectId: nil,
             objectType: objectType,
             objectType: objectType,
-            previews: true) { account, _, activityFirstKnown, activityLastGiven, data, error in
+            previews: true) { account, _, activityFirstKnown, activityLastGiven, _, error in
                 defer { disptachGroup.leave() }
                 defer { disptachGroup.leave() }
 
 
                 let largestActivityId = max(activityFirstKnown, activityLastGiven)
                 let largestActivityId = max(activityFirstKnown, activityLastGiven)
@@ -463,7 +456,7 @@ extension NCActivity {
             limit: min(limit, 200),
             limit: min(limit, 200),
             objectId: metadata?.fileId,
             objectId: metadata?.fileId,
             objectType: objectType,
             objectType: objectType,
-            previews: true) { account, activities, activityFirstKnown, activityLastGiven, data, error in
+            previews: true) { account, activities, activityFirstKnown, activityLastGiven, _, error in
                 defer { disptachGroup.leave() }
                 defer { disptachGroup.leave() }
                 guard error == .success,
                 guard error == .success,
                       account == self.appDelegate.account,
                       account == self.appDelegate.account,
@@ -516,7 +509,7 @@ extension NCActivity: NCShareCommentsCellDelegate {
                     })
                     })
 
 
                     alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
                     alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
-                        guard let message = alert.textFields?.first?.text, message != "" else { return }
+                        guard let message = alert.textFields?.first?.text, !message.isEmpty else { return }
 
 
                         NextcloudKit.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message) { _, error in
                         NextcloudKit.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message) { _, error in
                             if error == .success {
                             if error == .success {

+ 14 - 5
iOSClient/Activity/NCActivityTableViewCell.swift

@@ -31,6 +31,7 @@ class NCActivityCollectionViewCell: UICollectionViewCell {
     @IBOutlet weak var imageView: UIImageView!
     @IBOutlet weak var imageView: UIImageView!
 
 
     var fileId = ""
     var fileId = ""
+    var indexPath = IndexPath()
 
 
     override func awakeFromNib() {
     override func awakeFromNib() {
         super.awakeFromNib()
         super.awakeFromNib()
@@ -39,7 +40,9 @@ class NCActivityCollectionViewCell: UICollectionViewCell {
 
 
 class NCActivityTableViewCell: UITableViewCell, NCCellProtocol {
 class NCActivityTableViewCell: UITableViewCell, NCCellProtocol {
 
 
+    // swiftlint:disable force_cast
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
 
 
     @IBOutlet weak var collectionView: UICollectionView!
     @IBOutlet weak var collectionView: UICollectionView!
     @IBOutlet weak var icon: UIImageView!
     @IBOutlet weak var icon: UIImageView!
@@ -49,14 +52,19 @@ class NCActivityTableViewCell: UITableViewCell, NCCellProtocol {
     @IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!
 
 
     private var user: String = ""
     private var user: String = ""
+    private var index = IndexPath()
 
 
     var idActivity: Int = 0
     var idActivity: Int = 0
     var activityPreviews: [tableActivityPreview] = []
     var activityPreviews: [tableActivityPreview] = []
     var didSelectItemEnable: Bool = true
     var didSelectItemEnable: Bool = true
     var viewController = UIViewController()
     var viewController = UIViewController()
 
 
+    var indexPath: IndexPath {
+        get { return index }
+        set { index = newValue }
+    }
     var fileAvatarImageView: UIImageView? {
     var fileAvatarImageView: UIImageView? {
-        get { return avatar }
+        return avatar
     }
     }
     var fileUser: String? {
     var fileUser: String? {
         get { return user }
         get { return user }
@@ -89,8 +97,6 @@ extension NCActivityTableViewCell: UICollectionViewDelegate {
             return
             return
         }
         }
 
 
-        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as? NCActivityCollectionViewCell
-
         let activityPreview = activityPreviews[indexPath.row]
         let activityPreview = activityPreviews[indexPath.row]
 
 
         if activityPreview.view == "trashbin" {
         if activityPreview.view == "trashbin" {
@@ -142,9 +148,12 @@ extension NCActivityTableViewCell: UICollectionViewDataSource {
 
 
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
 
 
-        let cell: NCActivityCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as! NCActivityCollectionViewCell
+        guard let cell: NCActivityCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as? NCActivityCollectionViewCell else {
+            return UICollectionViewCell()
+        }
 
 
         cell.imageView.image = nil
         cell.imageView.image = nil
+        cell.indexPath = indexPath
 
 
         let activityPreview = activityPreviews[indexPath.row]
         let activityPreview = activityPreviews[indexPath.row]
         let fileId = String(activityPreview.fileId)
         let fileId = String(activityPreview.fileId)
@@ -181,7 +190,7 @@ extension NCActivityTableViewCell: UICollectionViewDataSource {
                 if let activitySubjectRich = NCManageDatabase.shared.getActivitySubjectRich(account: activityPreview.account, idActivity: idActivity, id: fileId) {
                 if let activitySubjectRich = NCManageDatabase.shared.getActivitySubjectRich(account: activityPreview.account, idActivity: idActivity, id: fileId) {
 
 
                     let fileNamePath = CCUtility.getDirectoryUserData() + "/" + activitySubjectRich.name
                     let fileNamePath = CCUtility.getDirectoryUserData() + "/" + activitySubjectRich.name
-                    
+
                     if FileManager.default.fileExists(atPath: fileNamePath), let image = UIImage(contentsOfFile: fileNamePath) {
                     if FileManager.default.fileExists(atPath: fileNamePath), let image = UIImage(contentsOfFile: fileNamePath) {
                         cell.imageView.image = image
                         cell.imageView.image = image
                     } else {
                     } else {

+ 161 - 204
iOSClient/AppDelegate.swift

@@ -47,22 +47,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     @objc var activeViewController: UIViewController?
     @objc var activeViewController: UIViewController?
     var mainTabBar: NCMainTabBar?
     var mainTabBar: NCMainTabBar?
     var activeMetadata: tableMetadata?
     var activeMetadata: tableMetadata?
-
-    let listFilesVC = ThreadSafeDictionary<String,NCFiles>()
-    let listFavoriteVC = ThreadSafeDictionary<String,NCFavorite>()
-    let listOfflineVC = ThreadSafeDictionary<String,NCOffline>()
-    let listGroupfoldersVC = ThreadSafeDictionary<String,NCGroupfolders>()
+    let listFilesVC = ThreadSafeDictionary<String, NCFiles>()
 
 
     var disableSharesView: Bool = false
     var disableSharesView: Bool = false
     var documentPickerViewController: NCDocumentPickerViewController?
     var documentPickerViewController: NCDocumentPickerViewController?
     var timerErrorNetworking: Timer?
     var timerErrorNetworking: Timer?
 
 
+    var isAppRefresh: Bool = false
+    var isAppProcessing: Bool = false
+
     private var privacyProtectionWindow: UIWindow?
     private var privacyProtectionWindow: UIWindow?
 
 
     var isUiTestingEnabled: Bool {
     var isUiTestingEnabled: Bool {
-         get {
-             return ProcessInfo.processInfo.arguments.contains("UI_TESTING")
-         }
+        return ProcessInfo.processInfo.arguments.contains("UI_TESTING")
      }
      }
 
 
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
@@ -72,12 +69,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
         NCSettingsBundleHelper.checkAndExecuteSettings(delay: 0)
         NCSettingsBundleHelper.checkAndExecuteSettings(delay: 0)
 
 
-        let userAgent = CCUtility.getUserAgent() as String
         let versionNextcloudiOS = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility.shared.getVersionApp())
         let versionNextcloudiOS = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility.shared.getVersionApp())
 
 
-        // Register initialize
-        NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil)
-
         UserDefaults.standard.register(defaults: ["UserAgent": userAgent])
         UserDefaults.standard.register(defaults: ["UserAgent": userAgent])
         if !CCUtility.getDisableCrashservice() && !NCBrandOptions.shared.disable_crash_service {
         if !CCUtility.getDisableCrashservice() && !NCBrandOptions.shared.disable_crash_service {
             FirebaseApp.configure()
             FirebaseApp.configure()
@@ -86,12 +79,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         CCUtility.createDirectoryStandard()
         CCUtility.createDirectoryStandard()
         CCUtility.emptyTemporaryDirectory()
         CCUtility.emptyTemporaryDirectory()
 
 
+        // Activated singleton
+        _ = NCActionCenter.shared
+        _ = NCNetworking.shared
+
         NextcloudKit.shared.setup(delegate: NCNetworking.shared)
         NextcloudKit.shared.setup(delegate: NCNetworking.shared)
         NextcloudKit.shared.setup(userAgent: userAgent)
         NextcloudKit.shared.setup(userAgent: userAgent)
 
 
         startTimerErrorNetworking()
         startTimerErrorNetworking()
 
 
-        // LOG
         var levelLog = 0
         var levelLog = 0
         if let pathDirectoryGroup = CCUtility.getDirectoryGroup()?.path {
         if let pathDirectoryGroup = CCUtility.getDirectoryGroup()?.path {
             NextcloudKit.shared.nkCommonInstance.pathLog = pathDirectoryGroup
             NextcloudKit.shared.nkCommonInstance.pathLog = pathDirectoryGroup
@@ -107,10 +103,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             levelLog = CCUtility.getLogLevel()
             levelLog = CCUtility.getLogLevel()
             NextcloudKit.shared.nkCommonInstance.levelLog = levelLog
             NextcloudKit.shared.nkCommonInstance.levelLog = levelLog
             NextcloudKit.shared.nkCommonInstance.copyLogToDocumentDirectory = true
             NextcloudKit.shared.nkCommonInstance.copyLogToDocumentDirectory = true
-            NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start session with level \(levelLog) " + versionNextcloudiOS + " in state \(UIApplication.shared.applicationState.rawValue) where (0 active, 1 inactive, 2 background).")
+            NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start session with level \(levelLog) " + versionNextcloudiOS)
         }
         }
 
 
-        // LOG Account
         if let account = NCManageDatabase.shared.getActiveAccount() {
         if let account = NCManageDatabase.shared.getActiveAccount() {
             NextcloudKit.shared.nkCommonInstance.writeLog("Account active \(account.account)")
             NextcloudKit.shared.nkCommonInstance.writeLog("Account active \(account.account)")
             if CCUtility.getPassword(account.account).isEmpty {
             if CCUtility.getPassword(account.account).isEmpty {
@@ -118,12 +113,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             }
             }
         }
         }
 
 
-        // Activate user account
         if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
         if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
 
 
-            settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), initialize: false)
+            account = activeAccount.account
+            urlBase = activeAccount.urlBase
+            user = activeAccount.user
+            userId = activeAccount.userId
+            password = CCUtility.getPassword(account)
+
+            NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase)
+            NCManageDatabase.shared.setCapabilities(account: account)
+
             NCBrandColor.shared.settingThemingColor(account: activeAccount.account)
             NCBrandColor.shared.settingThemingColor(account: activeAccount.account)
-            initialize()
 
 
         } else {
         } else {
 
 
@@ -131,10 +132,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             if let bundleID = Bundle.main.bundleIdentifier {
             if let bundleID = Bundle.main.bundleIdentifier {
                 UserDefaults.standard.removePersistentDomain(forName: bundleID)
                 UserDefaults.standard.removePersistentDomain(forName: bundleID)
             }
             }
+
             NCBrandColor.shared.createImagesThemingColor()
             NCBrandColor.shared.createImagesThemingColor()
         }
         }
 
 
-        // Create user color
         NCBrandColor.shared.createUserColors()
         NCBrandColor.shared.createUserColors()
 
 
         // Push Notification & display notification
         // Push Notification & display notification
@@ -142,16 +143,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         UNUserNotificationCenter.current().delegate = self
         UNUserNotificationCenter.current().delegate = self
         UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in }
         UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in }
 
 
-        // Store review
         if !NCUtility.shared.isSimulatorOrTestFlight() {
         if !NCUtility.shared.isSimulatorOrTestFlight() {
             let review = NCStoreReview()
             let review = NCStoreReview()
             review.incrementAppRuns()
             review.incrementAppRuns()
             review.showStoreReview()
             review.showStoreReview()
         }
         }
 
 
-        // Background task: register
+        // Background task register
         BGTaskScheduler.shared.register(forTaskWithIdentifier: NCGlobal.shared.refreshTask, using: nil) { task in
         BGTaskScheduler.shared.register(forTaskWithIdentifier: NCGlobal.shared.refreshTask, using: nil) { task in
-            self.handleRefreshTask(task)
+            self.handleAppRefresh(task)
         }
         }
         BGTaskScheduler.shared.register(forTaskWithIdentifier: NCGlobal.shared.processingTask, using: nil) { task in
         BGTaskScheduler.shared.register(forTaskWithIdentifier: NCGlobal.shared.processingTask, using: nil) { task in
             self.handleProcessingTask(task)
             self.handleProcessingTask(task)
@@ -166,14 +166,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         } else {
         } else {
             if !CCUtility.getIntro() {
             if !CCUtility.getIntro() {
                 if let viewController = UIStoryboard(name: "NCIntro", bundle: nil).instantiateInitialViewController() {
                 if let viewController = UIStoryboard(name: "NCIntro", bundle: nil).instantiateInitialViewController() {
-                    let navigationController = NCLoginNavigationController.init(rootViewController: viewController)
+                    let navigationController = NCLoginNavigationController(rootViewController: viewController)
                     window?.rootViewController = navigationController
                     window?.rootViewController = navigationController
                     window?.makeKeyAndVisible()
                     window?.makeKeyAndVisible()
                 }
                 }
             }
             }
         }
         }
 
 
-        // Passcode
         self.presentPasscode {
         self.presentPasscode {
             self.enableTouchFaceID()
             self.enableTouchFaceID()
         }
         }
@@ -190,7 +189,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
         NCSettingsBundleHelper.setVersionAndBuildNumber()
         NCSettingsBundleHelper.setVersionAndBuildNumber()
         NCSettingsBundleHelper.checkAndExecuteSettings(delay: 0.5)
         NCSettingsBundleHelper.checkAndExecuteSettings(delay: 0.5)
-        
+
         // START OBSERVE/TIMER UPLOAD PROCESS
         // START OBSERVE/TIMER UPLOAD PROCESS
         NCNetworkingProcessUpload.shared.observeTableMetadata()
         NCNetworkingProcessUpload.shared.observeTableMetadata()
         NCNetworkingProcessUpload.shared.startTimer()
         NCNetworkingProcessUpload.shared.startTimer()
@@ -199,11 +198,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             hidePrivacyProtectionWindow()
             hidePrivacyProtectionWindow()
         }
         }
 
 
-        if !account.isEmpty {
-            NCNetworkingProcessUpload.shared.verifyUploadZombie()
-        }
+        NCService.shared.startRequestServicesServer()
 
 
-        // Start Auto Upload
         NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
         NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
             NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Initialize Auto upload with \(items) uploads")
             NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Initialize Auto upload with \(items) uploads")
         }
         }
@@ -211,36 +207,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidBecomeActive)
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidBecomeActive)
     }
     }
 
 
-    // L' applicazione entrerà in primo piano (dopo il background)
-    func applicationWillEnterForeground(_ application: UIApplication) {
-        guard !account.isEmpty, let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return }
-
-        NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Application will enter in foreground")
-
-        if activeAccount.account != account {
-            settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account))
-        } else {
-            // Request Service Server Nextcloud
-            NCService.shared.startRequestServicesServer()
-        }
-
-        // Required unsubscribing / subscribing
-        NCPushNotification.shared().pushNotification()
-
-        // Request TouchID, FaceID
-        enableTouchFaceID()
-        
-        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterRichdocumentGrabFocus)
-        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetwork, second: 2)
-    }
-
     // L' applicazione si dimetterà dallo stato di attivo
     // L' applicazione si dimetterà dallo stato di attivo
     func applicationWillResignActive(_ application: UIApplication) {
     func applicationWillResignActive(_ application: UIApplication) {
-        // Nextcloud update share accounts
-        if let error = updateShareAccounts() {
-            NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Create share accounts \(error.localizedDescription)")
-        }
+
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Application will resign active")
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Application will resign active")
+
         guard !account.isEmpty else { return }
         guard !account.isEmpty else { return }
 
 
         // STOP OBSERVE/TIMER UPLOAD PROCESS
         // STOP OBSERVE/TIMER UPLOAD PROCESS
@@ -248,18 +219,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NCNetworkingProcessUpload.shared.stopTimer()
         NCNetworkingProcessUpload.shared.stopTimer()
 
 
         if CCUtility.getPrivacyScreenEnabled() {
         if CCUtility.getPrivacyScreenEnabled() {
-            // Privacy
             showPrivacyProtectionWindow()
             showPrivacyProtectionWindow()
         }
         }
 
 
         // Reload Widget
         // Reload Widget
         WidgetCenter.shared.reloadAllTimelines()
         WidgetCenter.shared.reloadAllTimelines()
 
 
-        // Clear operation queue
-        NCOperationQueue.shared.cancelAllQueue()
-        // Clear download
-        NCNetworking.shared.cancelAllDownloadTransfer()
-
         // Clear older files
         // Clear older files
         let days = CCUtility.getCleanUpDay()
         let days = CCUtility.getCleanUpDay()
         if let directory = CCUtility.getDirectoryProviderStorage() {
         if let directory = CCUtility.getDirectoryProviderStorage() {
@@ -269,16 +234,32 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationWillResignActive)
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationWillResignActive)
     }
     }
 
 
+    // L' applicazione entrerà in primo piano (dopo il background)
+    func applicationWillEnterForeground(_ application: UIApplication) {
+
+        NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Application will enter in foreground")
+
+        guard !account.isEmpty else { return }
+
+        enableTouchFaceID()
+
+        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterRichdocumentGrabFocus)
+        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetwork, second: 2)
+    }
+
     // L' applicazione è entrata nello sfondo
     // L' applicazione è entrata nello sfondo
     func applicationDidEnterBackground(_ application: UIApplication) {
     func applicationDidEnterBackground(_ application: UIApplication) {
-        guard !account.isEmpty else { return }
 
 
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Application did enter in background")
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Application did enter in background")
 
 
-        scheduleAppRefresh()
-        scheduleAppProcessing()
+        guard !account.isEmpty else { return }
+
+        if let error = updateShareAccounts() {
+            NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Create share accounts \(error.localizedDescription)")
+        }
+
+        NCNetworking.shared.cancelSessions(inBackground: false)
 
 
-        // Passcode
         presentPasscode { }
         presentPasscode { }
 
 
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidEnterBackground)
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidEnterBackground)
@@ -287,7 +268,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     // L'applicazione terminerà
     // L'applicazione terminerà
     func applicationWillTerminate(_ application: UIApplication) {
     func applicationWillTerminate(_ application: UIApplication) {
 
 
-        NCNetworking.shared.cancelAllDownloadTransfer()
+        NCNetworking.shared.cancelSessions(inBackground: false)
 
 
         if UIApplication.shared.backgroundRefreshStatus == .available {
         if UIApplication.shared.backgroundRefreshStatus == .available {
 
 
@@ -302,34 +283,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NextcloudKit.shared.nkCommonInstance.writeLog("bye bye")
         NextcloudKit.shared.nkCommonInstance.writeLog("bye bye")
     }
     }
 
 
-    // MARK: -
-
-    @objc private func initialize() {
-        guard !account.isEmpty else { return }
-
-        NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] initialize Main")
-
-        // Registeration push notification
-        NCPushNotification.shared().pushNotification()
-
-        // Unlock E2EE
-        NCNetworkingE2EE.shared.unlockAll(account: account)
-
-        // Start services
-        NCService.shared.startRequestServicesServer()
-
-        // close detail
-        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMenuDetailClose)
-
-        // Reload Widget
-        WidgetCenter.shared.reloadAllTimelines()
-
-        // Registeration domain File Provider
-        // FileProviderDomain *fileProviderDomain = [FileProviderDomain new];
-        // [fileProviderDomain removeAllDomains];
-        // [fileProviderDomain registerDomains];
-    }
-
     // MARK: - Background Task
     // MARK: - Background Task
 
 
     /*
     /*
@@ -342,7 +295,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         request.earliestBeginDate = Date(timeIntervalSinceNow: 60) // Refresh after 60 seconds.
         request.earliestBeginDate = Date(timeIntervalSinceNow: 60) // Refresh after 60 seconds.
         do {
         do {
             try BGTaskScheduler.shared.submit(request)
             try BGTaskScheduler.shared.submit(request)
-            NextcloudKit.shared.nkCommonInstance.writeLog("[SUCCESS] Refresh task success submit request 60 seconds \(request)")
         } catch {
         } catch {
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Refresh task failed to submit request: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Refresh task failed to submit request: \(error)")
         }
         }
@@ -360,20 +312,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         request.requiresExternalPower = false
         request.requiresExternalPower = false
         do {
         do {
             try BGTaskScheduler.shared.submit(request)
             try BGTaskScheduler.shared.submit(request)
-            NextcloudKit.shared.nkCommonInstance.writeLog("[SUCCESS] Background Processing task success submit request 5 minutes \(request)")
         } catch {
         } catch {
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Background Processing task failed to submit request: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Background Processing task failed to submit request: \(error)")
         }
         }
     }
     }
 
 
-    func handleRefreshTask(_ task: BGTask) {
+    func handleAppRefresh(_ task: BGTask) {
         scheduleAppRefresh()
         scheduleAppRefresh()
-        
-        guard !account.isEmpty else {
-            task.setTaskCompleted(success: true)
-            return
+
+        guard !account.isEmpty, !isAppProcessing else {
+            return task.setTaskCompleted(success: true)
         }
         }
 
 
+        isAppRefresh = true
         NextcloudKit.shared.setup(delegate: NCNetworking.shared)
         NextcloudKit.shared.setup(delegate: NCNetworking.shared)
 
 
         NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
         NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
@@ -381,20 +332,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             NCNetworkingProcessUpload.shared.start { items in
             NCNetworkingProcessUpload.shared.start { items in
                 NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Refresh task upload process with \(items) uploads")
                 NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Refresh task upload process with \(items) uploads")
                 task.setTaskCompleted(success: true)
                 task.setTaskCompleted(success: true)
+                self.isAppRefresh = false
             }
             }
         }
         }
     }
     }
 
 
     func handleProcessingTask(_ task: BGTask) {
     func handleProcessingTask(_ task: BGTask) {
         scheduleAppProcessing()
         scheduleAppProcessing()
-        
-        guard !account.isEmpty else {
-            task.setTaskCompleted(success: true)
-            return
+
+        guard !account.isEmpty, !isAppRefresh else {
+            return task.setTaskCompleted(success: true)
         }
         }
 
 
-        NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Processing task")
-        task.setTaskCompleted(success: true)
+        isAppProcessing = true
+        NextcloudKit.shared.setup(delegate: NCNetworking.shared)
+
+        NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
+            NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Processing task auto upload with \(items) uploads")
+            NCNetworkingProcessUpload.shared.start { items in
+                NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Processing task upload process with \(items) uploads")
+                task.setTaskCompleted(success: true)
+                self.isAppProcessing = false
+            }
+        }
     }
     }
 
 
     // MARK: - Background Networking Session
     // MARK: - Background Networking Session
@@ -402,7 +362,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
     func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
 
 
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start handle Events For Background URLSession: \(identifier)")
         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Start handle Events For Background URLSession: \(identifier)")
-        // Reload Widget
         WidgetCenter.shared.reloadAllTimelines()
         WidgetCenter.shared.reloadAllTimelines()
         backgroundSessionCompletionHandler = completionHandler
         backgroundSessionCompletionHandler = completionHandler
     }
     }
@@ -415,7 +374,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
     func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
 
 
-        if let pref = UserDefaults.init(suiteName: NCBrandOptions.shared.capabilitiesGroups),
+        if let pref = UserDefaults(suiteName: NCBrandOptions.shared.capabilitiesGroups),
            let data = pref.object(forKey: "NOTIFICATION_DATA") as? [String: AnyObject] {
            let data = pref.object(forKey: "NOTIFICATION_DATA") as? [String: AnyObject] {
             nextcloudPushNotificationAction(data: data)
             nextcloudPushNotificationAction(data: data)
             pref.set(nil, forKey: "NOTIFICATION_DATA")
             pref.set(nil, forKey: "NOTIFICATION_DATA")
@@ -439,36 +398,33 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
     }
 
 
     func nextcloudPushNotificationAction(data: [String: AnyObject]) {
     func nextcloudPushNotificationAction(data: [String: AnyObject]) {
-        NCApplicationHandle().nextcloudPushNotificationAction(data: data) {
 
 
-            var findAccount: Bool = false
+        guard let data = NCApplicationHandle().nextcloudPushNotificationAction(data: data) else { return }
+        var findAccount: Bool = false
 
 
-            if let accountPush = data["account"] as? String,
-               let app = data["app"] as? String,
-               app == NCGlobal.shared.twoFactorNotificatioName {
-                if accountPush == self.account {
-                    findAccount = true
-                } else {
-                    let accounts = NCManageDatabase.shared.getAllAccount()
-                    for account in accounts {
-                        if account.account == accountPush {
-                            self.changeAccount(account.account)
-                            findAccount = true
-                        }
+        if let accountPush = data["account"] as? String {
+            if accountPush == self.account {
+                findAccount = true
+            } else {
+                let accounts = NCManageDatabase.shared.getAllAccount()
+                for account in accounts {
+                    if account.account == accountPush {
+                        self.changeAccount(account.account, userProfile: nil)
+                        findAccount = true
                     }
                     }
                 }
                 }
-                if findAccount, let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification {
-                    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
-                        let navigationController = UINavigationController(rootViewController: viewController)
-                        navigationController.modalPresentationStyle = .fullScreen
-                        self.window?.rootViewController?.present(navigationController, animated: true)
-                    }
-                } else if !findAccount {
-                    let message = NSLocalizedString("_the_account_", comment: "") + " " + accountPush + " " + NSLocalizedString("_does_not_exist_", comment: "")
-                    let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert)
-                    alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
-                    self.window?.rootViewController?.present(alertController, animated: true, completion: { })
+            }
+            if findAccount, let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification {
+                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                    let navigationController = UINavigationController(rootViewController: viewController)
+                    navigationController.modalPresentationStyle = .fullScreen
+                    self.window?.rootViewController?.present(navigationController, animated: true)
                 }
                 }
+            } else if !findAccount {
+                let message = NSLocalizedString("_the_account_", comment: "") + " " + accountPush + " " + NSLocalizedString("_does_not_exist_", comment: "")
+                let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert)
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
+                self.window?.rootViewController?.present(alertController, animated: true, completion: { })
             }
             }
         }
         }
     }
     }
@@ -532,7 +488,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
         if contextViewController == nil {
         if contextViewController == nil {
             if let viewController = viewController {
             if let viewController = viewController {
-                let navigationController = NCLoginNavigationController.init(rootViewController: viewController)
+                let navigationController = NCLoginNavigationController(rootViewController: viewController)
                 navigationController.navigationBar.barStyle = .black
                 navigationController.navigationBar.barStyle = .black
                 navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText
                 navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText
                 navigationController.navigationBar.barTintColor = NCBrandColor.shared.customer
                 navigationController.navigationBar.barTintColor = NCBrandColor.shared.customer
@@ -542,11 +498,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             }
             }
         } else if contextViewController is UINavigationController {
         } else if contextViewController is UINavigationController {
             if let contextViewController = contextViewController, let viewController = viewController {
             if let contextViewController = contextViewController, let viewController = viewController {
-                (contextViewController as! UINavigationController).pushViewController(viewController, animated: true)
+                (contextViewController as? UINavigationController)?.pushViewController(viewController, animated: true)
             }
             }
         } else {
         } else {
             if let viewController = viewController, let contextViewController = contextViewController {
             if let viewController = viewController, let contextViewController = contextViewController {
-                let navigationController = NCLoginNavigationController.init(rootViewController: viewController)
+                let navigationController = NCLoginNavigationController(rootViewController: viewController)
                 navigationController.modalPresentationStyle = .fullScreen
                 navigationController.modalPresentationStyle = .fullScreen
                 navigationController.navigationBar.barStyle = .black
                 navigationController.navigationBar.barStyle = .black
                 navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText
                 navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText
@@ -556,17 +512,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             }
             }
         }
         }
     }
     }
-    
+
     @objc func startTimerErrorNetworking() {
     @objc func startTimerErrorNetworking() {
         timerErrorNetworking = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(checkErrorNetworking), userInfo: nil, repeats: true)
         timerErrorNetworking = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(checkErrorNetworking), userInfo: nil, repeats: true)
     }
     }
 
 
     @objc private func checkErrorNetworking() {
     @objc private func checkErrorNetworking() {
-        if account != "" && CCUtility.getPassword(account)!.count == 0 {
-            openLogin(viewController: window?.rootViewController, selector: NCGlobal.shared.introLogin, openLoginWeb: true)
-        }
+        guard !account.isEmpty, CCUtility.getPassword(account)!.isEmpty else { return }
+        openLogin(viewController: window?.rootViewController, selector: NCGlobal.shared.introLogin, openLoginWeb: true)
     }
     }
-    
+
     func trustCertificateError(host: String) {
     func trustCertificateError(host: String) {
 
 
         guard let currentHost = URL(string: self.urlBase)?.host,
         guard let currentHost = URL(string: self.urlBase)?.host,
@@ -584,15 +539,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
         let alertController = UIAlertController(title: title, message: NSLocalizedString("_server_is_trusted_", comment: ""), preferredStyle: .alert)
         let alertController = UIAlertController(title: title, message: NSLocalizedString("_server_is_trusted_", comment: ""), preferredStyle: .alert)
 
 
-        alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { action in
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_", comment: ""), style: .default, handler: { _ in
             NCNetworking.shared.writeCertificate(host: host)
             NCNetworking.shared.writeCertificate(host: host)
         }))
         }))
 
 
-        alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { action in }))
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { _ in }))
 
 
-        alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { action in
-            if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController {
-                let viewController = navigationController.topViewController as! NCViewCertificateDetails
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { _ in
+            if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController,
+               let viewController = navigationController.topViewController as? NCViewCertificateDetails {
                 viewController.delegate = self
                 viewController.delegate = self
                 viewController.host = host
                 viewController.host = host
                 self.window?.rootViewController?.present(navigationController, animated: true)
                 self.window?.rootViewController?.present(navigationController, animated: true)
@@ -608,31 +563,38 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     // MARK: - Account
     // MARK: - Account
 
 
-    @objc func settingAccount(_ account: String, urlBase: String, user: String, userId: String, password: String, initialize: Bool = true) {
+    @objc func changeAccount(_ account: String, userProfile: NKUserProfile?) {
 
 
-        let accountTestBackup = self.account + "/" + self.userId
-        let accountTest = account +  "/" + userId
+        guard let tableAccount = NCManageDatabase.shared.setAccountActive(account) else { return }
 
 
-        self.account = account
-        self.urlBase = urlBase
-        self.user = user
-        self.userId = userId
-        self.password = password
+        NCNetworking.shared.cancelSessions(inBackground: false)
 
 
-        _ = NCActionCenter.shared
+        self.account = tableAccount.account
+        self.urlBase = tableAccount.urlBase
+        self.user = tableAccount.user
+        self.userId = tableAccount.userId
+        self.password = CCUtility.getPassword(tableAccount.account)
 
 
         NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase)
         NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase)
         NCManageDatabase.shared.setCapabilities(account: account)
         NCManageDatabase.shared.setCapabilities(account: account)
 
 
+        if let userProfile {
+            NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile)
+        }
+
         if NCGlobal.shared.capabilityServerVersionMajor > 0 {
         if NCGlobal.shared.capabilityServerVersionMajor > 0 {
             NextcloudKit.shared.setup(nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor)
             NextcloudKit.shared.setup(nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor)
         }
         }
 
 
-        DispatchQueue.main.async {
-            if initialize, UIApplication.shared.applicationState != .background && accountTestBackup != accountTest {
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize, second: 0.2)
-            }
+        NCPushNotification.shared().pushNotification()
+
+        NCService.shared.startRequestServicesServer()
+
+        NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
+            NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Initialize Auto upload with \(items) uploads")
         }
         }
+
+        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeUser)
     }
     }
 
 
     @objc func deleteAccount(_ account: String, wipe: Bool) {
     @objc func deleteAccount(_ account: String, wipe: Bool) {
@@ -640,23 +602,28 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         if let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) {
         if let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) {
             NCPushNotification.shared().unsubscribingNextcloudServerPushNotification(account.account, urlBase: account.urlBase, user: account.user, withSubscribing: false)
             NCPushNotification.shared().unsubscribingNextcloudServerPushNotification(account.account, urlBase: account.urlBase, user: account.user, withSubscribing: false)
         }
         }
-        
+
         let results = NCManageDatabase.shared.getTableLocalFiles(predicate: NSPredicate(format: "account == %@", account), sorted: "ocId", ascending: false)
         let results = NCManageDatabase.shared.getTableLocalFiles(predicate: NSPredicate(format: "account == %@", account), sorted: "ocId", ascending: false)
         for result in results {
         for result in results {
             CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(result.ocId))
             CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(result.ocId))
         }
         }
         NCManageDatabase.shared.clearDatabase(account: account, removeAccount: true)
         NCManageDatabase.shared.clearDatabase(account: account, removeAccount: true)
-        
+
         CCUtility.clearAllKeysEnd(toEnd: account)
         CCUtility.clearAllKeysEnd(toEnd: account)
         CCUtility.clearAllKeysPushNotification(account)
         CCUtility.clearAllKeysPushNotification(account)
         CCUtility.setPassword(account, password: nil)
         CCUtility.setPassword(account, password: nil)
 
 
+        self.account = ""
+        self.urlBase = ""
+        self.user = ""
+        self.userId = ""
+        self.password = ""
+
         if wipe {
         if wipe {
-            settingAccount("", urlBase: "", user: "", userId: "", password: "")
             let accounts = NCManageDatabase.shared.getAccounts()
             let accounts = NCManageDatabase.shared.getAccounts()
             if accounts?.count ?? 0 > 0 {
             if accounts?.count ?? 0 > 0 {
                 if let newAccount = accounts?.first {
                 if let newAccount = accounts?.first {
-                    self.changeAccount(newAccount)
+                    self.changeAccount(newAccount, userProfile: nil)
                 }
                 }
             } else {
             } else {
                 openLogin(viewController: window?.rootViewController, selector: NCGlobal.shared.introLogin, openLoginWeb: false)
                 openLogin(viewController: window?.rootViewController, selector: NCGlobal.shared.introLogin, openLoginWeb: false)
@@ -664,25 +631,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         }
         }
     }
     }
 
 
-    @objc func deleteAllAccounts() {
+    func deleteAllAccounts() {
         let accounts = NCManageDatabase.shared.getAccounts()
         let accounts = NCManageDatabase.shared.getAccounts()
         accounts?.forEach({ account in
         accounts?.forEach({ account in
             deleteAccount(account, wipe: true)
             deleteAccount(account, wipe: true)
         })
         })
     }
     }
 
 
-    @objc func changeAccount(_ account: String) {
-
-        NCManageDatabase.shared.setAccountActive(account)
-        if let tableAccount = NCManageDatabase.shared.getActiveAccount() {
-
-            NCOperationQueue.shared.cancelAllQueue()
-            NCNetworking.shared.cancelAllTask()
-
-            settingAccount(tableAccount.account, urlBase: tableAccount.urlBase, user: tableAccount.user, userId: tableAccount.userId, password: CCUtility.getPassword(tableAccount.account))
-        }
-    }
-
     func updateShareAccounts() -> Error? {
     func updateShareAccounts() -> Error? {
         guard let dirGroupApps = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroupApps) else { return nil }
         guard let dirGroupApps = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroupApps) else { return nil }
 
 
@@ -702,9 +657,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     // MARK: - Account Request
     // MARK: - Account Request
 
 
     func accountRequestChangeAccount(account: String) {
     func accountRequestChangeAccount(account: String) {
-        changeAccount(account)
+        changeAccount(account, userProfile: nil)
     }
     }
-    
+
     func requestAccount() {
     func requestAccount() {
 
 
         if isPasscodePresented() { return }
         if isPasscodePresented() { return }
@@ -713,7 +668,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         let accounts = NCManageDatabase.shared.getAllAccount()
         let accounts = NCManageDatabase.shared.getAllAccount()
 
 
         if accounts.count > 1 {
         if accounts.count > 1 {
-            
+
             if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest {
             if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest {
 
 
                 vcAccountRequest.activeAccount = NCManageDatabase.shared.getActiveAccount()
                 vcAccountRequest.activeAccount = NCManageDatabase.shared.getActiveAccount()
@@ -723,15 +678,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
                 vcAccountRequest.dismissDidEnterBackground = false
                 vcAccountRequest.dismissDidEnterBackground = false
                 vcAccountRequest.delegate = self
                 vcAccountRequest.delegate = self
 
 
-                let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/5)
+                let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height / 5)
                 let numberCell = accounts.count
                 let numberCell = accounts.count
                 let height = min(CGFloat(numberCell * Int(vcAccountRequest.heightCell) + 45), screenHeighMax)
                 let height = min(CGFloat(numberCell * Int(vcAccountRequest.heightCell) + 45), screenHeighMax)
 
 
-                let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height+20)
+                let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height + 20)
                 popup.backgroundAlpha = 0.8
                 popup.backgroundAlpha = 0.8
 
 
                 window?.rootViewController?.present(popup, animated: true)
                 window?.rootViewController?.present(popup, animated: true)
-                
+
                 vcAccountRequest.startTimer()
                 vcAccountRequest.startTimer()
             }
             }
         }
         }
@@ -739,7 +694,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     // MARK: - Passcode
     // MARK: - Passcode
 
 
-    func presentPasscode(completion: @escaping () -> ()) {
+    func presentPasscode(completion: @escaping () -> Void) {
 
 
         let laContext = LAContext()
         let laContext = LAContext()
         var error: NSError?
         var error: NSError?
@@ -757,9 +712,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         passcodeViewController.keypadButtonShowLettering = false
         passcodeViewController.keypadButtonShowLettering = false
         if CCUtility.getEnableTouchFaceID() && laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
         if CCUtility.getEnableTouchFaceID() && laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
             if error == nil {
             if error == nil {
-                if laContext.biometryType == .faceID  {
+                if laContext.biometryType == .faceID {
                     passcodeViewController.biometryType = .faceID
                     passcodeViewController.biometryType = .faceID
-                } else if laContext.biometryType == .touchID  {
+                } else if laContext.biometryType == .touchID {
                     passcodeViewController.biometryType = .touchID
                     passcodeViewController.biometryType = .touchID
                 }
                 }
                 passcodeViewController.allowBiometricValidation = true
                 passcodeViewController.allowBiometricValidation = true
@@ -785,7 +740,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         else { return }
         else { return }
 
 
         DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
         DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
-            LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: NCBrandOptions.shared.brand) { (success, error) in
+            LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: NCBrandOptions.shared.brand) { success, _ in
                 if success {
                 if success {
                     DispatchQueue.main.async {
                     DispatchQueue.main.async {
                         passcodeViewController.dismiss(animated: true) {
                         passcodeViewController.dismiss(animated: true) {
@@ -884,27 +839,28 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
                     return false
                     return false
                 }
                 }
 
 
-
                 switch actionScheme {
                 switch actionScheme {
                 case NCGlobal.shared.actionUploadAsset:
                 case NCGlobal.shared.actionUploadAsset:
 
 
                     NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: rootViewController) { hasPermission in
                     NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: rootViewController) { hasPermission in
                         if hasPermission {
                         if hasPermission {
-                            NCPhotosPickerViewController.init(viewController: rootViewController, maxSelectedAssets: 0, singleSelectedMode: false)
+                            NCPhotosPickerViewController(viewController: rootViewController, maxSelectedAssets: 0, singleSelectedMode: false)
                         }
                         }
                     }
                     }
-                    
+
                 case NCGlobal.shared.actionScanDocument:
                 case NCGlobal.shared.actionScanDocument:
 
 
                     NCDocumentCamera.shared.openScannerDocument(viewController: rootViewController)
                     NCDocumentCamera.shared.openScannerDocument(viewController: rootViewController)
 
 
                 case NCGlobal.shared.actionTextDocument:
                 case NCGlobal.shared.actionTextDocument:
-                    
-                    guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController(), let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: account), let directEditingCreator = directEditingCreators.first(where: { $0.editor == NCGlobal.shared.editorText}) else { return false }
-                    
+
+                    guard let navigationController = UIStoryboard(name: "NCCreateFormUploadDocuments", bundle: nil).instantiateInitialViewController(),
+                          let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: account),
+                          let directEditingCreator = directEditingCreators.first(where: { $0.editor == NCGlobal.shared.editorText}),
+                          let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments else { return false }
+
                     navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                     navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                    let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
                     viewController.editorId = NCGlobal.shared.editorText
                     viewController.editorId = NCGlobal.shared.editorText
                     viewController.creatorId = directEditingCreator.identifier
                     viewController.creatorId = directEditingCreator.identifier
                     viewController.typeTemplate = NCGlobal.shared.templateDocument
                     viewController.typeTemplate = NCGlobal.shared.templateDocument
@@ -912,20 +868,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
                     viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
                     viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
 
 
                     rootViewController.present(navigationController, animated: true, completion: nil)
                     rootViewController.present(navigationController, animated: true, completion: nil)
-                    
+
                 case NCGlobal.shared.actionVoiceMemo:
                 case NCGlobal.shared.actionVoiceMemo:
-                    
+
                     NCAskAuthorization.shared.askAuthorizationAudioRecord(viewController: rootViewController) { hasPermission in
                     NCAskAuthorization.shared.askAuthorizationAudioRecord(viewController: rootViewController) { hasPermission in
                         if hasPermission {
                         if hasPermission {
                             let fileName = CCUtility.createFileNameDate(NSLocalizedString("_voice_memo_filename_", comment: ""), extension: "m4a")!
                             let fileName = CCUtility.createFileNameDate(NSLocalizedString("_voice_memo_filename_", comment: ""), extension: "m4a")!
-                            let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as! NCAudioRecorderViewController
+                            if let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as? NCAudioRecorderViewController {
 
 
-                            viewController.delegate = self
-                            viewController.createRecorder(fileName: fileName)
-                            viewController.modalTransitionStyle = .crossDissolve
-                            viewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
+                                viewController.delegate = self
+                                viewController.createRecorder(fileName: fileName)
+                                viewController.modalTransitionStyle = .crossDissolve
+                                viewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
 
 
-                            rootViewController.present(viewController, animated: true, completion: nil)
+                                rootViewController.present(viewController, animated: true, completion: nil)
+                            }
                         }
                         }
                     }
                     }
 
 
@@ -1019,7 +976,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
                 for account in accounts {
                 for account in accounts {
                     let urlBase = URL(string: account.urlBase)
                     let urlBase = URL(string: account.urlBase)
                     if url.contains(urlBase?.host ?? "") && userId == account.userId {
                     if url.contains(urlBase?.host ?? "") && userId == account.userId {
-                        changeAccount(account.account)
+                        changeAccount(account.account, userProfile: nil)
                         return account
                         return account
                     }
                     }
                 }
                 }

+ 2 - 2
iOSClient/BrowserWeb/NCBrowserWeb.swift

@@ -94,8 +94,8 @@ class NCBrowserWeb: UIViewController {
 
 
         request.addValue("true", forHTTPHeaderField: "OCS-APIRequest")
         request.addValue("true", forHTTPHeaderField: "OCS-APIRequest")
         request.addValue(language, forHTTPHeaderField: "Accept-Language")
         request.addValue(language, forHTTPHeaderField: "Accept-Language")
-        
-        webView.customUserAgent = CCUtility.getUserAgent()
+
+        webView.customUserAgent = userAgent
         webView.load(request)
         webView.load(request)
     }
     }
 }
 }

+ 1 - 1
iOSClient/Color/NCColorPicker.swift

@@ -199,7 +199,7 @@ class NCColorPicker: UIViewController {
             let serverUrl = metadata.serverUrl + "/" + metadata.fileName
             let serverUrl = metadata.serverUrl + "/" + metadata.fileName
             if NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, colorFolder: hexColor, account: metadata.account) != nil {
             if NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, colorFolder: hexColor, account: metadata.account) != nil {
                 self.dismiss(animated: true)
                 self.dismiss(animated: true)
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": metadata.serverUrl])
+                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
             }
             }
         }
         }
         self.dismiss(animated: true)
         self.dismiss(animated: true)

+ 7 - 96
iOSClient/Data/NCDataSource.swift

@@ -35,7 +35,6 @@ class NCDataSource: NSObject {
     private var sectionsValue: [String] = []
     private var sectionsValue: [String] = []
     private var providers: [NKSearchProvider]?
     private var providers: [NKSearchProvider]?
     private var searchResults: [NKSearchResult]?
     private var searchResults: [NKSearchResult]?
-    private var localFiles: [tableLocalFile] = []
 
 
     private var ascending: Bool = true
     private var ascending: Bool = true
     private var sort: String = ""
     private var sort: String = ""
@@ -51,10 +50,9 @@ class NCDataSource: NSObject {
         super.init()
         super.init()
 
 
         self.metadatas = metadatas.filter({
         self.metadatas = metadatas.filter({
-            !NCGlobal.shared.includeHiddenFiles.contains($0.fileNameView)
+            !(NCGlobal.shared.includeHiddenFiles.contains($0.fileNameView) || $0.isTransferInForeground)
         })
         })
         self.directory = directory
         self.directory = directory
-        self.localFiles = NCManageDatabase.shared.getTableLocalFile(account: account)
         self.sort = sort ?? "none"
         self.sort = sort ?? "none"
         self.ascending = ascending ?? false
         self.ascending = ascending ?? false
         self.directoryOnTop = directoryOnTop ?? true
         self.directoryOnTop = directoryOnTop ?? true
@@ -78,7 +76,6 @@ class NCDataSource: NSObject {
         self.sectionsValue.removeAll()
         self.sectionsValue.removeAll()
         self.providers = nil
         self.providers = nil
         self.searchResults = nil
         self.searchResults = nil
-        self.localFiles.removeAll()
     }
     }
 
 
     func clearDirectory() {
     func clearDirectory() {
@@ -175,7 +172,6 @@ class NCDataSource: NSObject {
         let metadatas = self.metadatas.filter({ getSectionValue(metadata: $0) == sectionValue})
         let metadatas = self.metadatas.filter({ getSectionValue(metadata: $0) == sectionValue})
         let metadataForSection = NCMetadataForSection(sectionValue: sectionValue,
         let metadataForSection = NCMetadataForSection(sectionValue: sectionValue,
                                                       metadatas: metadatas,
                                                       metadatas: metadatas,
-                                                      localFiles: self.localFiles,
                                                       lastSearchResult: searchResult,
                                                       lastSearchResult: searchResult,
                                                       sort: self.sort,
                                                       sort: self.sort,
                                                       ascending: self.ascending,
                                                       ascending: self.ascending,
@@ -218,79 +214,6 @@ class NCDataSource: NSObject {
         return indexPaths
         return indexPaths
     }
     }
 
 
-    @discardableResult
-    func addMetadata(_ metadata: tableMetadata) -> (indexPath: IndexPath?, sameSections: Bool) {
-
-        let numberOfSections = self.numberOfSections()
-        let sectionValue = getSectionValue(metadata: metadata)
-
-        // ADD metadatasSource
-        if let rowIndex = self.metadatas.firstIndex(where: {$0.fileNameView == metadata.fileNameView || $0.ocId == metadata.ocId}) {
-            self.metadatas[rowIndex] = metadata
-        } else {
-            self.metadatas.append(metadata)
-        }
-
-        // ADD metadataForSection
-        if let sectionIndex = getSectionIndex(sectionValue), let metadataForSection = getMetadataForSection(sectionIndex) {
-            if let rowIndex = metadataForSection.metadatas.firstIndex(where: {$0.fileNameView == metadata.fileNameView || $0.ocId == metadata.ocId}) {
-                metadataForSection.metadatas[rowIndex] = metadata
-                return (IndexPath(row: rowIndex, section: sectionIndex), self.isSameNumbersOfSections(numberOfSections: numberOfSections))
-            } else {
-                metadataForSection.metadatas.append(metadata)
-                metadataForSection.createMetadatas()
-                if let rowIndex = metadataForSection.metadatas.firstIndex(where: {$0.ocId == metadata.ocId}) {
-                    return (IndexPath(row: rowIndex, section: sectionIndex), self.isSameNumbersOfSections(numberOfSections: numberOfSections))
-                }
-                return (nil, self.isSameNumbersOfSections(numberOfSections: numberOfSections))
-            }
-        } else {
-            // NEW section
-            createSections()
-            // get IndexPath of new section
-            if let sectionIndex = getSectionIndex(sectionValue), let metadataForSection = getMetadataForSection(sectionIndex) {
-                if let rowIndex = metadataForSection.metadatas.firstIndex(where: {$0.fileNameView == metadata.fileNameView || $0.ocId == metadata.ocId}) {
-                    return (IndexPath(row: rowIndex, section: sectionIndex), self.isSameNumbersOfSections(numberOfSections: numberOfSections))
-                }
-            }
-        }
-
-        return (nil, self.isSameNumbersOfSections(numberOfSections: numberOfSections))
-    }
-
-    func deleteMetadata(ocId: String) -> (indexPath: IndexPath?, sameSections: Bool) {
-
-        let numberOfSections = self.numberOfSections()
-        var indexPathReturn: IndexPath?
-        var sectionValue = ""
-
-        // DELETE metadataForSection (IMPORTANT FIRST)
-        let (indexPath, metadataForSection) = self.getIndexPathMetadata(ocId: ocId)
-        if let indexPath = indexPath, let metadataForSection = metadataForSection, indexPath.row < metadataForSection.metadatas.count {
-            metadataForSection.metadatas.remove(at: indexPath.row)
-            if metadataForSection.metadatas.isEmpty {
-                // REMOVE sectionsValue / metadatasForSection
-                sectionValue = metadataForSection.sectionValue
-                if let sectionIndex = getSectionIndex(sectionValue) {
-                    self.sectionsValue.remove(at: sectionIndex)
-                }
-                if let index = getIndexMetadatasForSection(sectionValue) {
-                    self.metadatasForSection.remove(at: index)
-                }
-            } else {
-                metadataForSection.createMetadatas()
-            }
-            indexPathReturn = indexPath
-        } else { return (nil, false) }
-
-        // DELETE metadatasSource (IMPORTANT LAST)
-        if let rowIndex = self.metadatas.firstIndex(where: {$0.ocId == ocId}) {
-            self.metadatas.remove(at: rowIndex)
-        }
-
-        return (indexPathReturn, self.isSameNumbersOfSections(numberOfSections: numberOfSections))
-    }
-
     @discardableResult
     @discardableResult
     func reloadMetadata(ocId: String, ocIdTemp: String? = nil) -> (indexPath: IndexPath?, sameSections: Bool) {
     func reloadMetadata(ocId: String, ocIdTemp: String? = nil) -> (indexPath: IndexPath?, sameSections: Bool) {
 
 
@@ -328,11 +251,6 @@ class NCDataSource: NSObject {
         return (IndexPath(row: rowIndex, section: sectionIndex), metadataForSection)
         return (IndexPath(row: rowIndex, section: sectionIndex), metadataForSection)
     }
     }
 
 
-    func isSameNumbersOfSections(numberOfSections: Int) -> Bool {
-        guard !self.metadatasForSection.isEmpty else { return false }
-        return numberOfSections == self.numberOfSections()
-    }
-
     func numberOfSections() -> Int {
     func numberOfSections() -> Int {
         guard !self.sectionsValue.isEmpty else { return 1 }
         guard !self.sectionsValue.isEmpty else { return 1 }
         return self.sectionsValue.count
         return self.sectionsValue.count
@@ -348,11 +266,6 @@ class NCDataSource: NSObject {
         return metadataForSection.metadatas[indexPath.row]
         return metadataForSection.metadatas[indexPath.row]
     }
     }
 
 
-    func getSectionValue(indexPath: IndexPath) -> String {
-        guard !metadatasForSection.isEmpty, let metadataForSection = self.getMetadataForSection(indexPath.section) else { return ""}
-        return metadataForSection.sectionValue
-    }
-
     func getSectionValueLocalization(indexPath: IndexPath) -> String {
     func getSectionValueLocalization(indexPath: IndexPath) -> String {
         guard !metadatasForSection.isEmpty, let metadataForSection = self.getMetadataForSection(indexPath.section) else { return ""}
         guard !metadatasForSection.isEmpty, let metadataForSection = self.getMetadataForSection(indexPath.section) else { return ""}
         if let searchResults = self.searchResults, let searchResult = searchResults.filter({ $0.id == metadataForSection.sectionValue}).first {
         if let searchResults = self.searchResults, let searchResult = searchResults.filter({ $0.id == metadataForSection.sectionValue}).first {
@@ -378,6 +291,11 @@ class NCDataSource: NSObject {
 
 
     // MARK: -
     // MARK: -
 
 
+    internal func isSameNumbersOfSections(numberOfSections: Int) -> Bool {
+        guard !self.metadatasForSection.isEmpty else { return false }
+        return numberOfSections == self.numberOfSections()
+    }
+
     internal func getSectionValue(metadata: tableMetadata) -> String {
     internal func getSectionValue(metadata: tableMetadata) -> String {
 
 
         switch self.groupByField {
         switch self.groupByField {
@@ -419,7 +337,6 @@ class NCMetadataForSection: NSObject {
 
 
     var sectionValue: String
     var sectionValue: String
     var metadatas: [tableMetadata]
     var metadatas: [tableMetadata]
-    var localFiles: [tableLocalFile]
     var lastSearchResult: NKSearchResult?
     var lastSearchResult: NKSearchResult?
     var unifiedSearchInProgress: Bool = false
     var unifiedSearchInProgress: Bool = false
 
 
@@ -438,14 +355,11 @@ class NCMetadataForSection: NSObject {
     public var numDirectory: Int = 0
     public var numDirectory: Int = 0
     public var numFile: Int = 0
     public var numFile: Int = 0
     public var totalSize: Int64 = 0
     public var totalSize: Int64 = 0
-    public var metadataOffLine: [String] = []
-    public var directories: [tableDirectory]?
 
 
-    init(sectionValue: String, metadatas: [tableMetadata], localFiles: [tableLocalFile], lastSearchResult: NKSearchResult?, sort: String, ascending: Bool, directoryOnTop: Bool, favoriteOnTop: Bool, filterLivePhoto: Bool) {
+    init(sectionValue: String, metadatas: [tableMetadata], lastSearchResult: NKSearchResult?, sort: String, ascending: Bool, directoryOnTop: Bool, favoriteOnTop: Bool, filterLivePhoto: Bool) {
 
 
         self.sectionValue = sectionValue
         self.sectionValue = sectionValue
         self.metadatas = metadatas
         self.metadatas = metadatas
-        self.localFiles = localFiles
         self.lastSearchResult = lastSearchResult
         self.lastSearchResult = lastSearchResult
         self.sort = sort
         self.sort = sort
         self.ascending = ascending
         self.ascending = ascending
@@ -467,7 +381,6 @@ class NCMetadataForSection: NSObject {
         metadatasFavoriteFile.removeAll()
         metadatasFavoriteFile.removeAll()
         metadatasDirectory.removeAll()
         metadatasDirectory.removeAll()
         metadatasFile.removeAll()
         metadatasFile.removeAll()
-        metadataOffLine.removeAll()
 
 
         numDirectory = 0
         numDirectory = 0
         numFile = 0
         numFile = 0
@@ -552,8 +465,6 @@ class NCMetadataForSection: NSObject {
             }
             }
         }
         }
 
 
-        directories = NCManageDatabase.shared.getTablesDirectory(predicate: NSPredicate(format: "ocId IN %@", ocIds), sorted: "serverUrl", ascending: true)
-
         metadatas.removeAll()
         metadatas.removeAll()
 
 
         // Struct view : favorite dir -> favorite file -> directory -> files
         // Struct view : favorite dir -> favorite file -> directory -> files

+ 2 - 40
iOSClient/Data/NCDatabase.swift

@@ -30,20 +30,6 @@ protocol DateCompareable {
     var dateKey: Date { get }
     var dateKey: Date { get }
 }
 }
 
 
-class tableChunk: Object {
-
-    @objc dynamic var account = ""
-    @objc dynamic var chunkFolder = ""
-    @objc dynamic var fileName = ""
-    @objc dynamic var index = ""
-    @objc dynamic var ocId = ""
-    @objc dynamic var size: Int64 = 0
-
-    override static func primaryKey() -> String {
-        return "index"
-    }
-}
-
 class tableComments: Object, DateCompareable {
 class tableComments: Object, DateCompareable {
     var dateKey: Date { creationDateTime as Date }
     var dateKey: Date { creationDateTime as Date }
 
 
@@ -98,33 +84,9 @@ class tableExternalSites: Object {
 }
 }
 
 
 class tableGPS: Object {
 class tableGPS: Object {
-
-    @objc dynamic var latitude = ""
+    @objc dynamic var latitude: Double = 0
+    @objc dynamic var longitude: Double = 0
     @objc dynamic var location = ""
     @objc dynamic var location = ""
-    @objc dynamic var longitude = ""
-    @objc dynamic var placemarkAdministrativeArea = ""
-    @objc dynamic var placemarkCountry = ""
-    @objc dynamic var placemarkLocality = ""
-    @objc dynamic var placemarkPostalCode = ""
-    @objc dynamic var placemarkThoroughfare = ""
-}
-
-class tableLocalFile: Object {
-
-    @objc dynamic var account = ""
-    @objc dynamic var etag = ""
-    @objc dynamic var exifDate: NSDate?
-    @objc dynamic var exifLatitude = ""
-    @objc dynamic var exifLongitude = ""
-    @objc dynamic var exifLensModel: String?
-    @objc dynamic var favorite: Bool = false
-    @objc dynamic var fileName = ""
-    @objc dynamic var ocId = ""
-    @objc dynamic var offline: Bool = false
-
-    override static func primaryKey() -> String {
-        return "ocId"
-    }
 }
 }
 
 
 class tablePhotoLibrary: Object {
 class tablePhotoLibrary: Object {

+ 20 - 20
iOSClient/Data/NCManageDatabase+Account.swift

@@ -88,7 +88,7 @@ class tableAccount: Object, NCUserBaseUrl {
 
 
 extension NCManageDatabase {
 extension NCManageDatabase {
 
 
-    @objc func addAccount(_ account: String, urlBase: String, user: String, password: String) {
+    func addAccount(_ account: String, urlBase: String, user: String, userId: String, password: String) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
@@ -110,7 +110,7 @@ extension NCManageDatabase {
 
 
                 addObject.urlBase = urlBase
                 addObject.urlBase = urlBase
                 addObject.user = user
                 addObject.user = user
-                addObject.userId = user
+                addObject.userId = userId
 
 
                 realm.add(addObject, update: .all)
                 realm.add(addObject, update: .all)
             }
             }
@@ -148,10 +148,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return nil }
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return nil }
             return tableAccount.init(value: result)
             return tableAccount.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -161,12 +162,13 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableAccount.self).sorted(byKeyPath: "account", ascending: true)
             let results = realm.objects(tableAccount.self).sorted(byKeyPath: "account", ascending: true)
             if !results.isEmpty {
             if !results.isEmpty {
                 return Array(results.map { $0.account })
                 return Array(results.map { $0.account })
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -176,10 +178,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableAccount.self).filter(predicate).first else { return nil }
             guard let result = realm.objects(tableAccount.self).filter(predicate).first else { return nil }
             return tableAccount.init(value: result)
             return tableAccount.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -189,11 +192,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "user", ascending: true)]
             let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "user", ascending: true)]
             let results = realm.objects(tableAccount.self).sorted(by: sorted)
             let results = realm.objects(tableAccount.self).sorted(by: sorted)
             return Array(results.map { tableAccount.init(value: $0) })
             return Array(results.map { tableAccount.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
@@ -203,11 +207,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "alias", ascending: true), SortDescriptor(keyPath: "user", ascending: true)]
             let sorted = [SortDescriptor(keyPath: "active", ascending: false), SortDescriptor(keyPath: "alias", ascending: true), SortDescriptor(keyPath: "user", ascending: true)]
             let results = realm.objects(tableAccount.self).sorted(by: sorted)
             let results = realm.objects(tableAccount.self).sorted(by: sorted)
             return Array(results.map { tableAccount.init(value: $0) })
             return Array(results.map { tableAccount.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
@@ -217,6 +222,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return "" }
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return "" }
             if result.autoUploadFileName.isEmpty {
             if result.autoUploadFileName.isEmpty {
                 return NCBrandOptions.shared.folderDefaultAutoUpload
                 return NCBrandOptions.shared.folderDefaultAutoUpload
@@ -224,7 +230,7 @@ extension NCManageDatabase {
                 return result.autoUploadFileName
                 return result.autoUploadFileName
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return ""
         return ""
@@ -234,6 +240,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return "" }
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return "" }
             if result.autoUploadDirectory.isEmpty {
             if result.autoUploadDirectory.isEmpty {
                 return NCUtilityFileSystem.shared.getHomeServer(urlBase: urlBase, userId: userId)
                 return NCUtilityFileSystem.shared.getHomeServer(urlBase: urlBase, userId: userId)
@@ -246,7 +253,7 @@ extension NCManageDatabase {
                 }
                 }
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return ""
         return ""
@@ -266,24 +273,23 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return NCGlobal.shared.subfolderGranularityMonthly }
             guard let result = realm.objects(tableAccount.self).filter("active == true").first else { return NCGlobal.shared.subfolderGranularityMonthly }
             return result.autoUploadSubfolderGranularity
             return result.autoUploadSubfolderGranularity
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return NCGlobal.shared.subfolderGranularityMonthly
         return NCGlobal.shared.subfolderGranularityMonthly
     }
     }
 
 
-    @discardableResult
-    @objc func setAccountActive(_ account: String) -> tableAccount? {
+    func setAccountActive(_ account: String) -> tableAccount? {
 
 
         var accountReturn = tableAccount()
         var accountReturn = tableAccount()
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-
                 let results = realm.objects(tableAccount.self)
                 let results = realm.objects(tableAccount.self)
                 for result in results {
                 for result in results {
                     if result.account == account {
                     if result.account == account {
@@ -307,7 +313,6 @@ extension NCManageDatabase {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-
                 if let result = realm.objects(tableAccount.self).filter("account == %@", account).first {
                 if let result = realm.objects(tableAccount.self).filter("account == %@", account).first {
                     result.password = "********"
                     result.password = "********"
                 }
                 }
@@ -383,7 +388,7 @@ extension NCManageDatabase {
         }
         }
     }
     }
 
 
-    @objc func setAccountUserProfile(account: String, userProfile: NKUserProfile) -> tableAccount? {
+    @objc func setAccountUserProfile(account: String, userProfile: NKUserProfile) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
@@ -414,14 +419,9 @@ extension NCManageDatabase {
                     result.website = userProfile.website
                     result.website = userProfile.website
                 }
                 }
             }
             }
-            if let result = realm.objects(tableAccount.self).filter("account == %@", account).first {
-                return tableAccount.init(value: result)
-            }
         } catch let error {
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
         }
-
-        return nil
     }
     }
 
 
     @objc func setAccountMediaPath(_ path: String, account: String) {
     @objc func setAccountMediaPath(_ path: String, account: String) {

+ 12 - 6
iOSClient/Data/NCManageDatabase+Activity.swift

@@ -196,6 +196,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableActivity.self).filter(predicate).sorted(byKeyPath: "idActivity", ascending: false)
             let results = realm.objects(tableActivity.self).filter(predicate).sorted(byKeyPath: "idActivity", ascending: false)
             let allActivity = Array(results.map(tableActivity.init))
             let allActivity = Array(results.map(tableActivity.init))
             guard let filterFileId = filterFileId else {
             guard let filterFileId = filterFileId else {
@@ -205,7 +206,7 @@ extension NCManageDatabase {
             let filtered = allActivity.filter({ String($0.objectId) == filterFileId && $0.type != "comments" })
             let filtered = allActivity.filter({ String($0.objectId) == filterFileId && $0.type != "comments" })
             return (all: allActivity, filter: filtered)
             return (all: allActivity, filter: filtered)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return([], [])
         return([], [])
@@ -215,10 +216,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && key == %@", account, idActivity, key).first
             let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && key == %@", account, idActivity, key).first
             return results.map { tableActivitySubjectRich.init(value: $0) }
             return results.map { tableActivitySubjectRich.init(value: $0) }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -228,6 +230,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && id == %@", account, idActivity, id)
             let results = realm.objects(tableActivitySubjectRich.self).filter("account == %@ && idActivity == %d && id == %@", account, idActivity, id)
             var activitySubjectRich = results.first
             var activitySubjectRich = results.first
             if results.count == 2 {
             if results.count == 2 {
@@ -239,7 +242,7 @@ extension NCManageDatabase {
             }
             }
             return activitySubjectRich.map { tableActivitySubjectRich.init(value: $0) }
             return activitySubjectRich.map { tableActivitySubjectRich.init(value: $0) }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -251,6 +254,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             for id in orderKeysId {
             for id in orderKeysId {
                 if let result = realm.objects(tableActivityPreview.self).filter("account == %@ && idActivity == %d && fileId == %d", account, idActivity, Int(id) ?? 0).first {
                 if let result = realm.objects(tableActivityPreview.self).filter("account == %@ && idActivity == %d && fileId == %d", account, idActivity, Int(id) ?? 0).first {
                     results.append(result)
                     results.append(result)
@@ -258,7 +262,7 @@ extension NCManageDatabase {
             }
             }
             return results
             return results
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
@@ -284,9 +288,10 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             return realm.objects(tableActivityLatestId.self).filter("account == %@", account).first
             return realm.objects(tableActivityLatestId.self).filter("account == %@", account).first
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -328,10 +333,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableComments.self).filter("account == %@ AND objectId == %@", account, objectId).sorted(byKeyPath: "creationDateTime", ascending: false)
             let results = realm.objects(tableComments.self).filter("account == %@ AND objectId == %@", account, objectId).sorted(byKeyPath: "creationDateTime", ascending: false)
             return Array(results.map(tableComments.init))
             return Array(results.map(tableComments.init))
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []

+ 4 - 2
iOSClient/Data/NCManageDatabase+Avatar.swift

@@ -60,10 +60,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first else { return nil }
             guard let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first else { return nil }
             return tableAvatar.init(value: result)
             return tableAvatar.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -116,6 +117,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first
             let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first
             if result == nil {
             if result == nil {
                 NCUtilityFileSystem.shared.deleteFile(filePath: fileNameLocalPath)
                 NCUtilityFileSystem.shared.deleteFile(filePath: fileNameLocalPath)
@@ -125,7 +127,7 @@ extension NCManageDatabase {
             }
             }
             return UIImage(contentsOfFile: fileNameLocalPath)
             return UIImage(contentsOfFile: fileNameLocalPath)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         NCUtilityFileSystem.shared.deleteFile(filePath: fileNameLocalPath)
         NCUtilityFileSystem.shared.deleteFile(filePath: fileNameLocalPath)

+ 7 - 1
iOSClient/Data/NCManageDatabase+Capabilities.swift

@@ -56,10 +56,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else { return nil }
             guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else { return nil }
             return result.jsondata
             return result.jsondata
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -285,6 +286,10 @@ extension NCManageDatabase {
             NCGlobal.shared.capabilityServerVersion = json.ocs.data.version.string
             NCGlobal.shared.capabilityServerVersion = json.ocs.data.version.string
             NCGlobal.shared.capabilityServerVersionMajor = json.ocs.data.version.major
             NCGlobal.shared.capabilityServerVersionMajor = json.ocs.data.version.major
 
 
+            if NCGlobal.shared.capabilityServerVersionMajor > 0 {
+                NextcloudKit.shared.setup(nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor)
+            }
+
             NCGlobal.shared.capabilityFileSharingApiEnabled = json.ocs.data.capabilities.filessharing?.apienabled ?? false
             NCGlobal.shared.capabilityFileSharingApiEnabled = json.ocs.data.capabilities.filessharing?.apienabled ?? false
             NCGlobal.shared.capabilityFileSharingDefaultPermission = json.ocs.data.capabilities.filessharing?.defaultpermissions ?? 0
             NCGlobal.shared.capabilityFileSharingDefaultPermission = json.ocs.data.capabilities.filessharing?.defaultpermissions ?? 0
             NCGlobal.shared.capabilityFileSharingPubPasswdEnforced = json.ocs.data.capabilities.filessharing?.ncpublic?.password?.enforced ?? false
             NCGlobal.shared.capabilityFileSharingPubPasswdEnforced = json.ocs.data.capabilities.filessharing?.ncpublic?.password?.enforced ?? false
@@ -328,6 +333,7 @@ extension NCManageDatabase {
             NCGlobal.shared.capabilityFilesUndelete = json.ocs.data.capabilities.files?.undelete ?? false
             NCGlobal.shared.capabilityFilesUndelete = json.ocs.data.capabilities.files?.undelete ?? false
             NCGlobal.shared.capabilityFilesLockVersion = json.ocs.data.capabilities.files?.locking ?? ""
             NCGlobal.shared.capabilityFilesLockVersion = json.ocs.data.capabilities.files?.locking ?? ""
             NCGlobal.shared.capabilityFilesComments = json.ocs.data.capabilities.files?.comments ?? false
             NCGlobal.shared.capabilityFilesComments = json.ocs.data.capabilities.files?.comments ?? false
+            NCGlobal.shared.capabilityFilesBigfilechunking = json.ocs.data.capabilities.files?.bigfilechunking ?? false
 
 
             NCGlobal.shared.capabilityUserStatusEnabled = json.ocs.data.capabilities.files?.undelete ?? false
             NCGlobal.shared.capabilityUserStatusEnabled = json.ocs.data.capabilities.files?.undelete ?? false
             if json.ocs.data.capabilities.external != nil {
             if json.ocs.data.capabilities.external != nil {

+ 127 - 0
iOSClient/Data/NCManageDatabase+Chunk.swift

@@ -0,0 +1,127 @@
+//
+//  NCManageDatabase+Chunk.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 05/08/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@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 Foundation
+import RealmSwift
+import NextcloudKit
+
+class tableChunk: Object {
+
+    @Persisted var account = ""
+    @Persisted var chunkFolder = ""
+    @Persisted(primaryKey: true) var index = ""
+    @Persisted var fileName: Int = 0
+    @Persisted var ocId = ""
+    @Persisted var size: Int64 = 0
+}
+
+extension NCManageDatabase {
+
+    func getChunkFolder(account: String, ocId: String) -> String {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            guard let result = realm.objects(tableChunk.self).filter("account == %@ AND ocId == %@", account, ocId).first else { return NSUUID().uuidString }
+            return result.chunkFolder
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+
+        return NSUUID().uuidString
+    }
+
+    func getChunks(account: String, ocId: String) -> [(fileName: String, size: Int64)] {
+
+        var filesChunk: [(fileName: String, size: Int64)] = []
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            let results = realm.objects(tableChunk.self).filter("account == %@ AND ocId == %@", account, ocId).sorted(byKeyPath: "fileName", ascending: true)
+            for result in results {
+                filesChunk.append((fileName: "\(result.fileName)", size: result.size))
+            }
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+
+        return filesChunk
+    }
+
+    func addChunks(account: String, ocId: String, chunkFolder: String, filesChunk: [(fileName: String, size: Int64)]) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let results = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@", account, ocId))
+                realm.delete(results)
+                for fileChunk in filesChunk {
+                    let object = tableChunk()
+                    object.account = account
+                    object.chunkFolder = chunkFolder
+                    object.fileName = Int(fileChunk.fileName) ?? 0
+                    object.index = ocId + fileChunk.fileName
+                    object.ocId = ocId
+                    object.size = fileChunk.size
+                    realm.add(object, update: .all)
+                }
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func deleteChunk(account: String, ocId: String, fileChunk: (fileName: String, size: Int64), directory: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let result = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@ AND fileName == %d", account, ocId, Int(fileChunk.fileName) ?? 0))
+                realm.delete(result)
+                let filePath = directory + "/\(fileChunk.fileName)"
+                NCUtilityFileSystem.shared.deleteFile(filePath: filePath)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func deleteChunks(account: String, ocId: String, directory: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let results = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@", account, ocId))
+                for result in results {
+                    let filePath = directory + "/\(result.fileName)"
+                    NCUtilityFileSystem.shared.deleteFile(filePath: filePath)
+                }
+                realm.delete(results)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+}

+ 4 - 2
iOSClient/Data/NCManageDatabase+DashboardWidget.swift

@@ -54,11 +54,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let resultDashboard = realm.objects(tableDashboardWidget.self).filter("account == %@ AND id == %@", account, id).first else { return (nil, nil) }
             guard let resultDashboard = realm.objects(tableDashboardWidget.self).filter("account == %@ AND id == %@", account, id).first else { return (nil, nil) }
             let resultsButton = realm.objects(tableDashboardWidgetButton.self).filter("account == %@ AND id == %@", account, id).sorted(byKeyPath: "type", ascending: true)
             let resultsButton = realm.objects(tableDashboardWidgetButton.self).filter("account == %@ AND id == %@", account, id).sorted(byKeyPath: "type", ascending: true)
             return (tableDashboardWidget.init(value: resultDashboard), Array(resultsButton.map { tableDashboardWidgetButton.init(value: $0) }))
             return (tableDashboardWidget.init(value: resultDashboard), Array(resultsButton.map { tableDashboardWidgetButton.init(value: $0) }))
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return (nil, nil)
         return (nil, nil)
@@ -68,11 +69,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let sortProperties = [SortDescriptor(keyPath: "order", ascending: true), SortDescriptor(keyPath: "title", ascending: true)]
             let sortProperties = [SortDescriptor(keyPath: "order", ascending: true), SortDescriptor(keyPath: "title", ascending: true)]
             let results = realm.objects(tableDashboardWidget.self).filter("account == %@", account).sorted(by: sortProperties)
             let results = realm.objects(tableDashboardWidget.self).filter("account == %@", account).sorted(by: sortProperties)
             return Array(results.map { tableDashboardWidget.init(value: $0) })
             return Array(results.map { tableDashboardWidget.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []

+ 31 - 5
iOSClient/Data/NCManageDatabase+Directory.swift

@@ -52,9 +52,8 @@ extension NCManageDatabase {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
                 var addObject = tableDirectory()
                 var addObject = tableDirectory()
-                let result = realm.objects(tableDirectory.self).filter("ocId == %@", ocId).first
-                if result != nil {
-                    addObject = result!
+                if let result = realm.objects(tableDirectory.self).filter("ocId == %@", ocId).first {
+                    addObject = result
                 } else {
                 } else {
                     addObject.ocId = ocId
                     addObject.ocId = ocId
                 }
                 }
@@ -128,19 +127,46 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableDirectory.self).filter(predicate).first else { return nil }
             guard let result = realm.objects(tableDirectory.self).filter(predicate).first else { return nil }
             return tableDirectory.init(value: result)
             return tableDirectory.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func getTableDirectory(account: String, serverUrl: String) -> tableDirectory? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
     }
     }
 
 
+    func getTableDirectory(ocId: String) -> tableDirectory? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableDirectory.self).filter("ocId == %@", ocId).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+        return nil
+    }
+
     func getTablesDirectory(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableDirectory]? {
     func getTablesDirectory(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableDirectory]? {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableDirectory.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
             let results = realm.objects(tableDirectory.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
             if results.isEmpty {
             if results.isEmpty {
                 return nil
                 return nil
@@ -148,7 +174,7 @@ extension NCManageDatabase {
                 return Array(results.map { tableDirectory.init(value: $0) })
                 return Array(results.map { tableDirectory.init(value: $0) })
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil

+ 289 - 79
iOSClient/Data/NCManageDatabase+E2EE.swift

@@ -25,42 +25,47 @@ import Foundation
 import RealmSwift
 import RealmSwift
 import NextcloudKit
 import NextcloudKit
 
 
-class tableE2eEncryption: Object {
-
-    @objc dynamic var account = ""
-    @objc dynamic var authenticationTag: String = ""
-    @objc dynamic var blob = "files"
-    @objc dynamic var fileName = ""
-    @objc dynamic var fileNameIdentifier = ""
-    @objc dynamic var fileNamePath = ""
-    @objc dynamic var key = ""
-    @objc dynamic var initializationVector = ""
-    @objc dynamic var metadataKey = ""
-    @objc dynamic var metadataKeyFiledrop = ""
-    @objc dynamic var metadataKeyIndex: Int = 0
-    @objc dynamic var metadataVersion: Double = 0
-    @objc dynamic var mimeType = ""
-    @objc dynamic var serverUrl = ""
-
-    override static func primaryKey() -> String {
-        return "fileNamePath"
-    }
-}
-
 class tableE2eEncryptionLock: Object {
 class tableE2eEncryptionLock: Object {
 
 
-    @objc dynamic var account = ""
-    @objc dynamic var date = NSDate()
-    @objc dynamic var fileId = ""
-    @objc dynamic var serverUrl = ""
-    @objc dynamic var e2eToken = ""
+    @Persisted(primaryKey: true) var fileId = ""
+    @Persisted var account = ""
+    @Persisted var date = Date()
+    @Persisted var serverUrl = ""
+    @Persisted var e2eToken = ""
+}
 
 
-    override static func primaryKey() -> String {
-        return "fileId"
-    }
+typealias tableE2eEncryption = tableE2eEncryptionV3
+class tableE2eEncryptionV3: Object {
+
+    @Persisted(primaryKey: true) var primaryKey = ""
+    @Persisted var account = ""
+    @Persisted var authenticationTag: String = ""
+    @Persisted var blob = "files"
+    @Persisted var fileName = ""
+    @Persisted var fileNameIdentifier = ""
+    @Persisted var key = ""
+    @Persisted var initializationVector = ""
+    @Persisted var metadataKey = ""
+    @Persisted var metadataKeyFiledrop = ""
+    @Persisted var metadataKeyIndex: Int = 0
+    @Persisted var metadataVersion: Double = 0
+    @Persisted var mimeType = ""
+    @Persisted var ocIdServerUrl: String = ""
+    @Persisted var serverUrl = ""
+
+    convenience init(account: String, ocIdServerUrl: String, fileNameIdentifier: String) {
+        self.init()
+        self.primaryKey = account + ocIdServerUrl + fileNameIdentifier
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.fileNameIdentifier = fileNameIdentifier
+     }
 }
 }
 
 
-class tableE2eMetadata: Object {
+// MARK: -
+// MARK: Table V1, V1.2
+
+class tableE2eMetadata12: Object {
 
 
     @Persisted(primaryKey: true) var serverUrl = ""
     @Persisted(primaryKey: true) var serverUrl = ""
     @Persisted var account = ""
     @Persisted var account = ""
@@ -68,24 +73,102 @@ class tableE2eMetadata: Object {
     @Persisted var version: Double = 0
     @Persisted var version: Double = 0
 }
 }
 
 
+// MARK: -
+// MARK: Table V2
+
+typealias tableE2eMetadata = tableE2eMetadataV2
+class tableE2eMetadataV2: Object {
+
+    @Persisted(primaryKey: true) var primaryKey = ""
+    @Persisted var account = ""
+    @Persisted var deleted: Bool = false
+    @Persisted var folders = Map<String, String>()
+    @Persisted var keyChecksums = List<String>()
+    @Persisted var ocIdServerUrl: String = ""
+    @Persisted var serverUrl: String = ""
+    @Persisted var version: String = NCGlobal.shared.e2eeVersionV20
+
+    convenience init(account: String, ocIdServerUrl: String) {
+        self.init()
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.primaryKey = account + ocIdServerUrl
+     }
+}
+
+class tableE2eCounter: Object {
+
+    @Persisted(primaryKey: true) var primaryKey: String
+    @Persisted var account: String
+    @Persisted var counter: Int
+    @Persisted var ocIdServerUrl: String
+
+    convenience init(account: String, ocIdServerUrl: String, counter: Int) {
+        self.init()
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.primaryKey = account + ocIdServerUrl
+        self.counter = counter
+     }
+}
+
+class tableE2eUsers: Object {
+
+    @Persisted(primaryKey: true) var primaryKey = ""
+    @Persisted var account = ""
+    @Persisted var certificate = ""
+    @Persisted var encryptedMetadataKey: String?
+    @Persisted var metadataKey: Data?
+    @Persisted var ocIdServerUrl: String = ""
+    @Persisted var serverUrl: String = ""
+    @Persisted var userId = ""
+
+    convenience init(account: String, ocIdServerUrl: String, userId: String) {
+        self.init()
+        self.primaryKey = account + ocIdServerUrl + userId
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.userId = userId
+     }
+}
+
+class tableE2eUsersFiledrop: Object {
+
+    @Persisted(primaryKey: true) var primaryKey = ""
+    @Persisted var account = ""
+    @Persisted var certificate = ""
+    @Persisted var encryptedFiledropKey: String?
+    @Persisted var ocIdServerUrl: String = ""
+    @Persisted var serverUrl: String = ""
+    @Persisted var userId = ""
+
+    convenience init(account: String, ocIdServerUrl: String, userId: String) {
+        self.init()
+        self.primaryKey = account + ocIdServerUrl + userId
+        self.account = account
+        self.ocIdServerUrl = ocIdServerUrl
+        self.userId = userId
+     }
+}
+
 extension NCManageDatabase {
 extension NCManageDatabase {
 
 
     // MARK: -
     // MARK: -
-    // MARK: Table e2e Encryption
+    // MARK: tableE2eEncryption
 
 
-    @objc func addE2eEncryption(_ e2e: tableE2eEncryption) {
+    func addE2eEncryption(_ object: tableE2eEncryption) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                realm.add(e2e, update: .all)
+                realm.add(object, update: .all)
             }
             }
         } catch let error {
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
         }
     }
     }
 
 
-    @objc func deleteE2eEncryption(predicate: NSPredicate) {
+    func deleteE2eEncryption(predicate: NSPredicate) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
@@ -98,52 +181,41 @@ extension NCManageDatabase {
         }
         }
     }
     }
 
 
-    @objc func getE2eEncryption(predicate: NSPredicate) -> tableE2eEncryption? {
+    func getE2eEncryption(predicate: NSPredicate) -> tableE2eEncryption? {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             guard let result = realm.objects(tableE2eEncryption.self).filter(predicate).sorted(byKeyPath: "metadataKeyIndex", ascending: false).first else { return nil }
             guard let result = realm.objects(tableE2eEncryption.self).filter(predicate).sorted(byKeyPath: "metadataKeyIndex", ascending: false).first else { return nil }
             return tableE2eEncryption.init(value: result)
             return tableE2eEncryption.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
     }
     }
 
 
-    @objc func getE2eEncryptions(predicate: NSPredicate) -> [tableE2eEncryption]? {
-
-        guard self.getActiveAccount() != nil else { return nil }
+    func getE2eEncryptions(predicate: NSPredicate) -> [tableE2eEncryption] {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             let results: Results<tableE2eEncryption>
             let results: Results<tableE2eEncryption>
             results = realm.objects(tableE2eEncryption.self).filter(predicate)
             results = realm.objects(tableE2eEncryption.self).filter(predicate)
-            if results.isEmpty {
-                return nil
-            } else {
-                return Array(results.map { tableE2eEncryption.init(value: $0) })
-            }
+            return Array(results.map { tableE2eEncryption.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
-        return nil
+        return []
     }
     }
 
 
-    @objc func renameFileE2eEncryption(serverUrl: String, fileNameIdentifier: String, newFileName: String, newFileNamePath: String) {
-
-        guard let activeAccount = self.getActiveAccount() else { return }
+    func renameFileE2eEncryption(account: String, serverUrl: String, fileNameIdentifier: String, newFileName: String, newFileNamePath: String) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                guard let result = realm.objects(tableE2eEncryption.self).filter("account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", activeAccount.account, serverUrl, fileNameIdentifier).first else { return }
-                let object = tableE2eEncryption.init(value: result)
-                realm.delete(result)
-                object.fileName = newFileName
-                object.fileNamePath = newFileNamePath
-                realm.add(object)
+                guard let result = realm.objects(tableE2eEncryption.self).filter("account == %@ AND serverUrl == %@ AND fileNameIdentifier == %@", account, serverUrl, fileNameIdentifier).first else { return }
+                result.fileName = newFileName
+                realm.add(result, update: .all)
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
@@ -153,20 +225,20 @@ extension NCManageDatabase {
     // MARK: -
     // MARK: -
     // MARK: Table e2e Encryption Lock
     // MARK: Table e2e Encryption Lock
 
 
-    @objc func getE2ETokenLock(account: String, serverUrl: String) -> tableE2eEncryptionLock? {
+    func getE2ETokenLock(account: String, serverUrl: String) -> tableE2eEncryptionLock? {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             guard let result = realm.objects(tableE2eEncryptionLock.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return nil }
             guard let result = realm.objects(tableE2eEncryptionLock.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return nil }
             return tableE2eEncryptionLock.init(value: result)
             return tableE2eEncryptionLock.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
     }
     }
 
 
-    @objc func getE2EAllTokenLock(account: String) -> [tableE2eEncryptionLock] {
+    func getE2EAllTokenLock(account: String) -> [tableE2eEncryptionLock] {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
@@ -177,30 +249,30 @@ extension NCManageDatabase {
                 return Array(results.map { tableE2eEncryptionLock.init(value: $0) })
                 return Array(results.map { tableE2eEncryptionLock.init(value: $0) })
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
     }
     }
 
 
-    @objc func setE2ETokenLock(account: String, serverUrl: String, fileId: String, e2eToken: String) {
+    func setE2ETokenLock(account: String, serverUrl: String, fileId: String, e2eToken: String) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                let addObject = tableE2eEncryptionLock()
-                addObject.account = account
-                addObject.fileId = fileId
-                addObject.serverUrl = serverUrl
-                addObject.e2eToken = e2eToken
-                realm.add(addObject, update: .all)
+                let object = tableE2eEncryptionLock()
+                object.account = account
+                object.fileId = fileId
+                object.serverUrl = serverUrl
+                object.e2eToken = e2eToken
+                realm.add(object, update: .all)
             }
             }
         } catch let error {
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
         }
     }
     }
 
 
-    @objc func deleteE2ETokenLock(account: String, serverUrl: String) {
+    func deleteE2ETokenLock(account: String, serverUrl: String) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
@@ -215,16 +287,16 @@ extension NCManageDatabase {
     }
     }
 
 
     // MARK: -
     // MARK: -
-    // MARK: Table e2ee Metadata
+    // MARK: V1
 
 
-    func getE2eMetadata(account: String, serverUrl: String) -> tableE2eMetadata? {
+    func getE2eMetadata(account: String, serverUrl: String) -> tableE2eMetadata12? {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
-            guard let result = realm.objects(tableE2eMetadata.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return nil }
-            return tableE2eMetadata.init(value: result)
+            guard let result = realm.objects(tableE2eMetadata12.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return nil }
+            return tableE2eMetadata12.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -235,15 +307,153 @@ extension NCManageDatabase {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                let addObject = tableE2eMetadata()
-                addObject.account = account
-                addObject.metadataKey = metadataKey
-                addObject.serverUrl = serverUrl
-                addObject.version = version
-                realm.add(addObject, update: .all)
+                let object = tableE2eMetadata12()
+                object.account = account
+                object.metadataKey = metadataKey
+                object.serverUrl = serverUrl
+                object.version = version
+                realm.add(object, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    // MARK: -
+    // MARK: V2
+
+    func addE2EUsers(account: String,
+                     serverUrl: String,
+                     ocIdServerUrl: String,
+                     userId: String,
+                     certificate: String,
+                     encryptedMetadataKey: String?,
+                     metadataKey: Data?) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let object = tableE2eUsers.init(account: account, ocIdServerUrl: ocIdServerUrl, userId: userId)
+                object.certificate = certificate
+                object.encryptedMetadataKey = encryptedMetadataKey
+                object.metadataKey = metadataKey
+                object.serverUrl = serverUrl
+                realm.add(object, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func deleteE2EUsers(account: String, ocIdServerUrl: String, userId: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                if let result = realm.objects(tableE2eUsers.self).filter("account == %@ AND ocIdServerUrl == %@ AND userId == %@", account, ocIdServerUrl, userId).first {
+                    realm.delete(result)
+                }
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func getE2EUsers(account: String, ocIdServerUrl: String) -> Results<tableE2eUsers>? {
+
+        do {
+            let realm = try Realm()
+            return realm.objects(tableE2eUsers.self).filter("account == %@ AND ocIdServerUrl == %@", account, ocIdServerUrl)
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func getE2EUsers(account: String, ocIdServerUrl: String, userId: String) -> tableE2eUsers? {
+
+        do {
+            let realm = try Realm()
+            return realm.objects(tableE2eUsers.self).filter("account == %@ && ocIdServerUrl == %@ AND userId == %@", account, ocIdServerUrl, userId).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func getE2EUsersFiledrop(account: String, ocIdServerUrl: String, userId: String) -> tableE2eUsersFiledrop? {
+
+        do {
+            let realm = try Realm()
+            return realm.objects(tableE2eUsersFiledrop.self).filter("account == %@ && ocIdServerUrl == %@ AND userId == %@", account, ocIdServerUrl, userId).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func getE2eMetadata(account: String, ocIdServerUrl: String) -> tableE2eMetadata? {
+
+        do {
+            let realm = try Realm()
+            return realm.objects(tableE2eMetadata.self).filter("account == %@ && ocIdServerUrl == %@", account, ocIdServerUrl).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func addE2eMetadata(account: String, serverUrl: String, ocIdServerUrl: String, keyChecksums: [String]?, deleted: Bool, folders: [String: String]?, version: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let object = tableE2eMetadata.init(account: account, ocIdServerUrl: ocIdServerUrl)
+                if let keyChecksums {
+                    object.keyChecksums.append(objectsIn: keyChecksums)
+                }
+                object.deleted = deleted
+                let foldersDictionary = object.folders
+                if let folders {
+                    for folder in folders {
+                        foldersDictionary[folder.key] = folder.value
+                    }
+                }
+                object.serverUrl = serverUrl
+                object.version = version
+                realm.add(object, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func updateCounterE2eMetadata(account: String, ocIdServerUrl: String, counter: Int) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let object = tableE2eCounter.init(account: account, ocIdServerUrl: ocIdServerUrl, counter: counter)
+                realm.add(object, update: .all)
             }
             }
         } catch let error {
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
         }
         }
     }
     }
+
+    func getCounterE2eMetadata(account: String, ocIdServerUrl: String) -> Int? {
+
+        do {
+            let realm = try Realm()
+            return realm.objects(tableE2eCounter.self).filter("account == %@ && ocIdServerUrl == %@", account, ocIdServerUrl).first?.counter
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
 }
 }

+ 2 - 1
iOSClient/Data/NCManageDatabase+LayoutForView.swift

@@ -117,13 +117,14 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             if let result = realm.objects(NCDBLayoutForView.self).filter("index == %@", index).first {
             if let result = realm.objects(NCDBLayoutForView.self).filter("index == %@", index).first {
                 return NCDBLayoutForView(value: result)
                 return NCDBLayoutForView(value: result)
             } else {
             } else {
                 return setLayoutForView(account: account, key: key, serverUrl: serverUrl)
                 return setLayoutForView(account: account, key: key, serverUrl: serverUrl)
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return setLayoutForView(account: account, key: key, serverUrl: serverUrl)
         return setLayoutForView(account: account, key: key, serverUrl: serverUrl)

+ 209 - 0
iOSClient/Data/NCManageDatabase+LocalFile.swift

@@ -0,0 +1,209 @@
+//
+//  NCManageDatabase+LocalFile.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 01/08/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@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 Foundation
+import RealmSwift
+import NextcloudKit
+
+class tableLocalFile: Object {
+
+    @objc dynamic var account = ""
+    @objc dynamic var etag = ""
+    @objc dynamic var exifDate: NSDate?
+    @objc dynamic var exifLatitude = ""
+    @objc dynamic var exifLongitude = ""
+    @objc dynamic var exifLensModel: String?
+    @objc dynamic var favorite: Bool = false
+    @objc dynamic var fileName = ""
+    @objc dynamic var ocId = ""
+    @objc dynamic var offline: Bool = false
+
+    override static func primaryKey() -> String {
+        return "ocId"
+    }
+}
+extension NCManageDatabase {
+
+    // MARK: -
+    // MARK: Table LocalFile - return RESULT
+
+    func getTableLocalFile(ocId: String) -> tableLocalFile? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+        return nil
+    }
+
+    // MARK: -
+    // MARK: Table LocalFile
+
+    func addLocalFile(metadata: tableMetadata) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let addObject = getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) ?? tableLocalFile()
+                addObject.account = metadata.account
+                addObject.etag = metadata.etag
+                addObject.exifDate = NSDate()
+                addObject.exifLatitude = "-1"
+                addObject.exifLongitude = "-1"
+                addObject.ocId = metadata.ocId
+                addObject.fileName = metadata.fileName
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func addLocalFile(account: String, etag: String, ocId: String, fileName: String) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let addObject = tableLocalFile()
+                addObject.account = account
+                addObject.etag = etag
+                addObject.exifDate = NSDate()
+                addObject.exifLatitude = "-1"
+                addObject.exifLongitude = "-1"
+                addObject.ocId = ocId
+                addObject.fileName = fileName
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func deleteLocalFile(predicate: NSPredicate) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let results = realm.objects(tableLocalFile.self).filter(predicate)
+                realm.delete(results)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func setLocalFile(ocId: String, fileName: String?, etag: String?) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
+                if let fileName = fileName {
+                    result?.fileName = fileName
+                }
+                if let etag = etag {
+                    result?.etag = etag
+                }
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    @objc func setLocalFile(ocId: String, exifDate: NSDate?, exifLatitude: String, exifLongitude: String, exifLensModel: String?) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                if let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first {
+                    result.exifDate = exifDate
+                    result.exifLatitude = exifLatitude
+                    result.exifLongitude = exifLongitude
+                    if exifLensModel?.count ?? 0 > 0 {
+                        result.exifLensModel = exifLensModel
+                    }
+                }
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func setLocalFile(ocId: String, offline: Bool) {
+
+        do {
+            let realm = try Realm()
+            try realm.write {
+                let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
+                result?.offline = offline
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func getTableLocalFile(account: String) -> [tableLocalFile] {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            let results = realm.objects(tableLocalFile.self).filter("account == %@", account)
+            return Array(results.map { tableLocalFile.init(value: $0) })
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return []
+    }
+
+    func getTableLocalFile(predicate: NSPredicate) -> tableLocalFile? {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            guard let result = realm.objects(tableLocalFile.self).filter(predicate).first else { return nil }
+            return tableLocalFile.init(value: result)
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return nil
+    }
+
+    func getTableLocalFiles(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableLocalFile] {
+
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            let results = realm.objects(tableLocalFile.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
+            return Array(results.map { tableLocalFile.init(value: $0) })
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+
+        return []
+    }
+}

+ 97 - 52
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -38,7 +38,7 @@ class tableMetadata: Object, NCUserBaseUrl {
     @objc dynamic var account = ""
     @objc dynamic var account = ""
     @objc dynamic var assetLocalIdentifier = ""
     @objc dynamic var assetLocalIdentifier = ""
     @objc dynamic var checksums = ""
     @objc dynamic var checksums = ""
-    @objc dynamic var chunk: Bool = false
+    @objc dynamic var chunk: Int = 0
     @objc dynamic var classFile = ""
     @objc dynamic var classFile = ""
     @objc dynamic var commentsUnread: Bool = false
     @objc dynamic var commentsUnread: Bool = false
     @objc dynamic var contentType = ""
     @objc dynamic var contentType = ""
@@ -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"
@@ -211,10 +215,18 @@ extension tableMetadata {
         return classFile == NKCommon.TypeClassFile.document.rawValue && editors.contains(NCGlobal.shared.editorText) && ((editors.contains(NCGlobal.shared.editorOnlyoffice) || isRichDocument))
         return classFile == NKCommon.TypeClassFile.document.rawValue && editors.contains(NCGlobal.shared.editorText) && ((editors.contains(NCGlobal.shared.editorOnlyoffice) || isRichDocument))
     }
     }
 
 
-    var isDownloadUpload: Bool {
+    var isWaitingTransfer: Bool {
+        status == NCGlobal.shared.metadataStatusWaitDownload || status == NCGlobal.shared.metadataStatusWaitUpload || status == NCGlobal.shared.metadataStatusUploadError
+    }
+
+    var isInTransfer: Bool {
         status == NCGlobal.shared.metadataStatusInDownload || status == NCGlobal.shared.metadataStatusDownloading || status == NCGlobal.shared.metadataStatusInUpload || status == NCGlobal.shared.metadataStatusUploading
         status == NCGlobal.shared.metadataStatusInDownload || status == NCGlobal.shared.metadataStatusDownloading || status == NCGlobal.shared.metadataStatusInUpload || status == NCGlobal.shared.metadataStatusUploading
     }
     }
 
 
+    var isTransferInForeground: Bool {
+        (status > 0 && (chunk > 0 || e2eEncrypted))
+    }
+
     var isDownload: Bool {
     var isDownload: Bool {
         status == NCGlobal.shared.metadataStatusInDownload || status == NCGlobal.shared.metadataStatusDownloading
         status == NCGlobal.shared.metadataStatusInDownload || status == NCGlobal.shared.metadataStatusDownloading
     }
     }
@@ -224,7 +236,11 @@ extension tableMetadata {
     }
     }
 
 
     @objc var isDirectoryE2EE: Bool {
     @objc var isDirectoryE2EE: Bool {
-        NCUtility.shared.isDirectoryE2EE(serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId)
+        NCUtility.shared.isDirectoryE2EE(account: account, urlBase: urlBase, userId: userId, serverUrl: serverUrl)
+    }
+
+    var isDirectoryE2EETop: Bool {
+        NCUtility.shared.isDirectoryE2EETop(account: account, serverUrl: serverUrl)
     }
     }
 
 
     /// Returns false if the user is lokced out of the file. I.e. The file is locked but by somone else
     /// Returns false if the user is lokced out of the file. I.e. The file is locked but by somone else
@@ -232,19 +248,14 @@ extension tableMetadata {
         return !lock || (lockOwner == user && lockOwnerType == 0)
         return !lock || (lockOwner == user && lockOwnerType == 0)
     }
     }
 
 
-    // Return if is sharable (temp)
-    // TODO: modifify for E2EE 2.0
+    // Return if is sharable
     func isSharable() -> Bool {
     func isSharable() -> Bool {
         guard NCGlobal.shared.capabilityFileSharingApiEnabled else { return false }
         guard NCGlobal.shared.capabilityFileSharingApiEnabled else { return false }
-
-        if !e2eEncrypted && !isDirectoryE2EE {
+        if isDirectoryE2EE || e2eEncrypted {
+            guard directory, NCGlobal.shared.capabilityE2EEEnabled else { return false }
             return true
             return true
-        } else if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion26 && directory {
-            // E2EE DIRECTORY SECURE FILE DROP (SHARE AVAILABLE)
-            return true
-        } else {
-            return false
         }
         }
+        return true
     }
     }
 }
 }
 
 
@@ -319,6 +330,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 {
@@ -416,7 +431,6 @@ extension NCManageDatabase {
         let fileName = fileName.trimmingCharacters(in: .whitespacesAndNewlines)
         let fileName = fileName.trimmingCharacters(in: .whitespacesAndNewlines)
 
 
         metadata.account = account
         metadata.account = account
-        metadata.chunk = false
         metadata.creationDate = Date() as NSDate
         metadata.creationDate = Date() as NSDate
         metadata.date = Date() as NSDate
         metadata.date = Date() as NSDate
         metadata.hasPreview = true
         metadata.hasPreview = true
@@ -518,7 +532,7 @@ extension NCManageDatabase {
     }
     }
 
 
     @discardableResult
     @discardableResult
-    func updateMetadatas(_ metadatas: [tableMetadata], metadatasResult: [tableMetadata], addCompareLivePhoto: Bool = true, addExistsInLocal: Bool = false, addCompareEtagLocal: Bool = false, addDirectorySynchronized: Bool = false) -> (metadatasUpdate: [tableMetadata], metadatasLocalUpdate: [tableMetadata], metadatasDelete: [tableMetadata]) {
+    func updateMetadatas(_ metadatas: [tableMetadata], metadatasResult: [tableMetadata], addCompareLivePhoto: Bool = true, addExistsInLocal: Bool = false, addCompareEtagLocal: Bool = false) -> (metadatasUpdate: [tableMetadata], metadatasLocalUpdate: [tableMetadata], metadatasDelete: [tableMetadata]) {
 
 
         var ocIdsUdate: [String] = []
         var ocIdsUdate: [String] = []
         var ocIdsLocalUdate: [String] = []
         var ocIdsLocalUdate: [String] = []
@@ -617,28 +631,29 @@ extension NCManageDatabase {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first
-                if let newFileName = newFileName {
-                    result?.fileName = newFileName
-                    result?.fileNameView = newFileName
-                }
-                if let session = session {
-                    result?.session = session
-                }
-                if let sessionError = sessionError {
-                    result?.sessionError = sessionError
-                }
-                if let sessionSelector = sessionSelector {
-                    result?.sessionSelector = sessionSelector
-                }
-                if let sessionTaskIdentifier = sessionTaskIdentifier {
-                    result?.sessionTaskIdentifier = sessionTaskIdentifier
-                }
-                if let status = status {
-                    result?.status = status
-                }
-                if let etag = etag {
-                    result?.etag = etag
+                if let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first {
+                    if let newFileName = newFileName {
+                        result.fileName = newFileName
+                        result.fileNameView = newFileName
+                    }
+                    if let session = session {
+                        result.session = session
+                    }
+                    if let sessionError = sessionError {
+                        result.sessionError = sessionError
+                    }
+                    if let sessionSelector = sessionSelector {
+                        result.sessionSelector = sessionSelector
+                    }
+                    if let sessionTaskIdentifier = sessionTaskIdentifier {
+                        result.sessionTaskIdentifier = sessionTaskIdentifier
+                    }
+                    if let status = status {
+                        result.status = status
+                    }
+                    if let etag = etag {
+                        result.etag = etag
+                    }
                 }
                 }
             }
             }
         } catch let error {
         } catch let error {
@@ -744,10 +759,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableMetadata.self).filter(predicate).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter(predicate).first else { return nil }
             return tableMetadata.init(value: result)
             return tableMetadata.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -757,10 +773,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending).first else { return nil }
             return tableMetadata.init(value: result)
             return tableMetadata.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -773,6 +790,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             if (tableMetadata().objectSchema.properties.contains { $0.name == sorted }) {
             if (tableMetadata().objectSchema.properties.contains { $0.name == sorted }) {
                 results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
                 results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
             } else {
             } else {
@@ -797,7 +815,7 @@ extension NCManageDatabase {
                 }
                 }
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         if finals.isEmpty {
         if finals.isEmpty {
@@ -811,10 +829,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableMetadata.self).filter(predicate)
             let results = realm.objects(tableMetadata.self).filter(predicate)
             return Array(results.map { tableMetadata.init(value: $0) })
             return Array(results.map { tableMetadata.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
@@ -826,6 +845,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
             let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
             if !results.isEmpty {
             if !results.isEmpty {
                 if page == 0 || limit == 0 {
                 if page == 0 || limit == 0 {
@@ -842,7 +862,7 @@ extension NCManageDatabase {
                 }
                 }
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return metadatas
         return metadatas
@@ -852,6 +872,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
             let results = realm.objects(tableMetadata.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
             if results.isEmpty {
             if results.isEmpty {
                 return nil
                 return nil
@@ -859,7 +880,7 @@ extension NCManageDatabase {
                 return tableMetadata.init(value: results[index])
                 return tableMetadata.init(value: results[index])
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -867,27 +888,42 @@ extension NCManageDatabase {
 
 
     func getMetadataFromOcId(_ ocId: String?) -> tableMetadata? {
     func getMetadataFromOcId(_ ocId: String?) -> tableMetadata? {
 
 
+        guard let ocId else { return nil }
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
-            guard let ocId = ocId else { return nil }
+            realm.refresh()
             guard let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first else { return nil }
             return tableMetadata.init(value: result)
             return tableMetadata.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
     }
     }
 
 
+    func getTableMetadataFromOcId(_ ocId: String?) -> tableMetadata? {
+
+        guard let ocId else { return nil }
+        do {
+            let realm = try Realm()
+            realm.refresh()
+            return realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
+        }
+        return nil
+    }
+
     func getMetadataFromFileId(_ fileId: String?) -> tableMetadata? {
     func getMetadataFromFileId(_ fileId: String?) -> tableMetadata? {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let fileId = fileId else { return nil }
             guard let fileId = fileId else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter("fileId == %@", fileId).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter("fileId == %@", fileId).first else { return nil }
             return tableMetadata.init(value: result)
             return tableMetadata.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -911,10 +947,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableMetadata.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).first else { return nil }
             return tableMetadata.init(value: result)
             return tableMetadata.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -927,13 +964,14 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableMetadata.self).filter("account == %@ AND directory == true AND favorite == true", account).sorted(byKeyPath: "fileNameView", ascending: true)
             let results = realm.objects(tableMetadata.self).filter("account == %@ AND directory == true AND favorite == true", account).sorted(byKeyPath: "fileNameView", ascending: true)
             for result in results {
             for result in results {
                 counter += 1
                 counter += 1
                 listIdentifierRank[result.ocId] = NSNumber(value: Int64(counter))
                 listIdentifierRank[result.ocId] = NSNumber(value: Int64(counter))
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return listIdentifierRank
         return listIdentifierRank
@@ -973,12 +1011,13 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier != '' AND deleteAssetLocalIdentifier == true", account)
             let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier != '' AND deleteAssetLocalIdentifier == true", account)
             for result in results {
             for result in results {
                 assetLocalIdentifiers.append(result.assetLocalIdentifier)
                 assetLocalIdentifiers.append(result.assetLocalIdentifier)
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return assetLocalIdentifiers
         return assetLocalIdentifiers
@@ -988,6 +1027,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             try realm.write {
             try realm.write {
                 let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier IN %@", account, assetLocalIdentifiers)
                 let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier IN %@", account, assetLocalIdentifiers)
                 for result in results {
                 for result in results {
@@ -1019,10 +1059,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView CONTAINS[cd] %@ AND ocId != %@ AND classFile == %@", metadata.account, metadata.serverUrl, fileName, metadata.ocId, classFile)).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter(NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView CONTAINS[cd] %@ AND ocId != %@ AND classFile == %@", metadata.account, metadata.serverUrl, fileName, metadata.ocId, classFile)).first else { return nil }
             return tableMetadata.init(value: result)
             return tableMetadata.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -1034,6 +1075,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             try realm.write {
             try realm.write {
                 let sortProperties = [SortDescriptor(keyPath: "serverUrl", ascending: false), SortDescriptor(keyPath: "fileNameView", ascending: false)]
                 let sortProperties = [SortDescriptor(keyPath: "serverUrl", ascending: false), SortDescriptor(keyPath: "fileNameView", ascending: false)]
                 let results = realm.objects(tableMetadata.self).filter(predicate).sorted(by: sortProperties)
                 let results = realm.objects(tableMetadata.self).filter(predicate).sorted(by: sortProperties)
@@ -1118,9 +1160,10 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             return realm.objects(tableMetadata.self).filter(NSPredicate(format: "status == %i || status == %i", NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading)).count
             return realm.objects(tableMetadata.self).filter(NSPredicate(format: "status == %i || status == %i", NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading)).count
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return 0
         return 0
@@ -1130,11 +1173,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let directory = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return nil }
             guard let directory = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter("ocId == %@", directory.ocId).first else { return nil }
             guard let result = realm.objects(tableMetadata.self).filter("ocId == %@", directory.ocId).first else { return nil }
             return tableMetadata.init(value: result)
             return tableMetadata.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -1147,6 +1191,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let groupfolders = realm.objects(TableGroupfolders.self).filter("account == %@", account)
             let groupfolders = realm.objects(TableGroupfolders.self).filter("account == %@", account)
             for groupfolder in groupfolders {
             for groupfolder in groupfolders {
                 let mountPoint = groupfolder.mountPoint.hasPrefix("/") ? groupfolder.mountPoint : "/" + groupfolder.mountPoint
                 let mountPoint = groupfolder.mountPoint.hasPrefix("/") ? groupfolder.mountPoint : "/" + groupfolder.mountPoint
@@ -1157,7 +1202,7 @@ extension NCManageDatabase {
                 }
                 }
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return metadatas
         return metadatas

+ 23 - 8
iOSClient/Data/NCManageDatabase+Share.swift

@@ -81,8 +81,6 @@ extension NCManageDatabase {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                let result = realm.objects(tableShare.self).filter("account == %@", account)
-                realm.delete(result)
                 for share in shares {
                 for share in shares {
                     let serverUrlPath = home + share.path
                     let serverUrlPath = home + share.path
                     guard let serverUrl = NCUtilityFileSystem.shared.deleteLastPath(serverUrlPath: serverUrlPath, home: home) else { continue }
                     guard let serverUrl = NCUtilityFileSystem.shared.deleteLastPath(serverUrlPath: serverUrlPath, home: home) else { continue }
@@ -141,11 +139,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let results = realm.objects(tableShare.self).filter("account == %@", account).sorted(by: sortProperties)
             let results = realm.objects(tableShare.self).filter("account == %@", account).sorted(by: sortProperties)
             return Array(results.map { tableShare.init(value: $0) })
             return Array(results.map { tableShare.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
@@ -155,6 +154,7 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let firstShareLink = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@ AND shareType == 3", metadata.account, metadata.serverUrl, metadata.fileName).first
             let firstShareLink = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@ AND shareType == 3", metadata.account, metadata.serverUrl, metadata.fileName).first
             if let firstShareLink = firstShareLink {
             if let firstShareLink = firstShareLink {
@@ -165,7 +165,7 @@ extension NCManageDatabase {
                 return(firstShareLink: firstShareLink, share: Array(results.map { tableShare.init(value: $0) }))
                 return(firstShareLink: firstShareLink, share: Array(results.map { tableShare.init(value: $0) }))
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return (nil, nil)
         return (nil, nil)
@@ -175,10 +175,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableShare.self).filter("account = %@ AND idShare = %d", account, idShare).first else { return nil }
             guard let result = realm.objects(tableShare.self).filter("account = %@ AND idShare = %d", account, idShare).first else { return nil }
             return tableShare.init(value: result)
             return tableShare.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil
@@ -188,11 +189,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).sorted(by: sortProperties)
             let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).sorted(by: sortProperties)
             return Array(results.map { tableShare.init(value: $0) })
             return Array(results.map { tableShare.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
@@ -202,11 +204,12 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let sortProperties = [SortDescriptor(keyPath: "shareType", ascending: false), SortDescriptor(keyPath: "idShare", ascending: false)]
             let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).sorted(by: sortProperties)
             let results = realm.objects(tableShare.self).filter("account == %@ AND serverUrl == %@ AND fileName == %@", account, serverUrl, fileName).sorted(by: sortProperties)
             return Array(results.map { tableShare.init(value: $0) })
             return Array(results.map { tableShare.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return []
         return []
@@ -225,11 +228,23 @@ extension NCManageDatabase {
         }
         }
     }
     }
 
 
-    func deleteTableShare(account: String) {
+    func deleteTableShare(account: String, path: String) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            try realm.write {
+                let result = realm.objects(tableShare.self).filter("account == %@ AND path == %@", account, path)
+                realm.delete(result)
+            }
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
 
 
+    func deleteTableShare(account: String) {
+
+        do {
+            let realm = try Realm()
             try realm.write {
             try realm.write {
                 let result = realm.objects(tableShare.self).filter("account == %@", account)
                 let result = realm.objects(tableShare.self).filter("account == %@", account)
                 realm.delete(result)
                 realm.delete(result)

+ 2 - 1
iOSClient/Data/NCManageDatabase+Video.swift

@@ -140,10 +140,11 @@ extension NCManageDatabase {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else { return nil }
             guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else { return nil }
             return tableVideo.init(value: result)
             return tableVideo.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not access database: \(error)")
         }
         }
 
 
         return nil
         return nil

+ 54 - 260
iOSClient/Data/NCManageDatabase.swift

@@ -34,6 +34,8 @@ class NCManageDatabase: NSObject {
         return instance
         return instance
     }()
     }()
 
 
+    let serialQueue = DispatchQueue(label: "realmSerialQueue")
+
     override init() {
     override init() {
 
 
         let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroups)
         let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroups)
@@ -69,7 +71,26 @@ class NCManageDatabase: NSObject {
             let config = Realm.Configuration(
             let config = Realm.Configuration(
                 fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName),
                 fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName),
                 schemaVersion: databaseSchemaVersion,
                 schemaVersion: databaseSchemaVersion,
-                objectTypes: [tableMetadata.self, tableLocalFile.self, tableDirectory.self, tableTag.self, tableAccount.self, tableCapabilities.self, tablePhotoLibrary.self, tableE2eEncryption.self, tableE2eEncryptionLock.self, tableE2eMetadata.self, tableShare.self, tableChunk.self, tableAvatar.self, tableDashboardWidget.self, tableDashboardWidgetButton.self, NCDBLayoutForView.self]
+                objectTypes: [tableMetadata.self,
+                              tableLocalFile.self,
+                              tableDirectory.self,
+                              tableTag.self,
+                              tableAccount.self,
+                              tableCapabilities.self,
+                              tablePhotoLibrary.self,
+                              tableE2eEncryption.self,
+                              tableE2eEncryptionLock.self,
+                              tableE2eMetadata12.self,
+                              tableE2eMetadata.self,
+                              tableE2eUsers.self,
+                              tableE2eCounter.self,
+                              tableE2eUsersFiledrop.self,
+                              tableShare.self,
+                              tableChunk.self,
+                              tableAvatar.self,
+                              tableDashboardWidget.self,
+                              tableDashboardWidgetButton.self,
+                              NCDBLayoutForView.self]
             )
             )
 
 
             Realm.Configuration.defaultConfiguration = config
             Realm.Configuration.defaultConfiguration = config
@@ -98,6 +119,13 @@ class NCManageDatabase: NSObject {
                         migration.deleteData(forType: tableVideo.className())
                         migration.deleteData(forType: tableVideo.className())
                     }
                     }
 
 
+                    if oldSchemaVersion < 306 {
+                        migration.deleteData(forType: tableChunk.className())
+                        migration.deleteData(forType: tableMetadata.className())
+                        migration.deleteData(forType: tableDirectory.className())
+                        migration.deleteData(forType: tableE2eEncryptionLock.className())
+                    }
+
                 }, shouldCompactOnLaunch: { totalBytes, usedBytes in
                 }, shouldCompactOnLaunch: { totalBytes, usedBytes in
 
 
                     // totalBytes refers to the size of the file on disk in bytes (data + free space)
                     // totalBytes refers to the size of the file on disk in bytes (data + free space)
@@ -194,9 +222,6 @@ class NCManageDatabase: NSObject {
         self.clearTable(tableDirectEditingCreators.self, account: account)
         self.clearTable(tableDirectEditingCreators.self, account: account)
         self.clearTable(tableDirectEditingEditors.self, account: account)
         self.clearTable(tableDirectEditingEditors.self, account: account)
         self.clearTable(tableDirectory.self, account: account)
         self.clearTable(tableDirectory.self, account: account)
-        self.clearTable(tableE2eEncryption.self, account: account)
-        self.clearTable(tableE2eEncryptionLock.self, account: account)
-        self.clearTable(tableE2eMetadata.self, account: account)
         self.clearTable(tableExternalSites.self, account: account)
         self.clearTable(tableExternalSites.self, account: account)
         self.clearTable(tableGPS.self, account: nil)
         self.clearTable(tableGPS.self, account: nil)
         self.clearTable(TableGroupfolders.self, account: account)
         self.clearTable(TableGroupfolders.self, account: account)
@@ -211,12 +236,24 @@ class NCManageDatabase: NSObject {
         self.clearTable(tableTrash.self, account: account)
         self.clearTable(tableTrash.self, account: account)
         self.clearTable(tableUserStatus.self, account: account)
         self.clearTable(tableUserStatus.self, account: account)
         self.clearTable(tableVideo.self, account: account)
         self.clearTable(tableVideo.self, account: account)
+        self.clearTablesE2EE(account: account)
 
 
         if removeAccount {
         if removeAccount {
             self.clearTable(tableAccount.self, account: account)
             self.clearTable(tableAccount.self, account: account)
         }
         }
     }
     }
 
 
+    func clearTablesE2EE(account: String?) {
+
+        self.clearTable(tableE2eEncryption.self, account: account)
+        self.clearTable(tableE2eEncryptionLock.self, account: account)
+        self.clearTable(tableE2eMetadata12.self, account: account)
+        self.clearTable(tableE2eMetadata.self, account: account)
+        self.clearTable(tableE2eUsers.self, account: account)
+        self.clearTable(tableE2eCounter.self, account: account)
+        self.clearTable(tableE2eUsersFiledrop.self, account: account)
+    }
+
     @objc func removeDB() {
     @objc func removeDB() {
 
 
         let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
         let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
@@ -257,108 +294,6 @@ class NCManageDatabase: NSObject {
         return object.isInvalidated
         return object.isInvalidated
     }
     }
 
 
-    // MARK: -
-    // MARK: Table Chunk
-
-    func getChunkFolder(account: String, ocId: String) -> String {
-
-        do {
-            let realm = try Realm()
-            guard let result = realm.objects(tableChunk.self).filter("account == %@ AND ocId == %@", account, ocId).first else { return NSUUID().uuidString }
-            return result.chunkFolder
-        } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-
-        return NSUUID().uuidString
-    }
-
-    func getChunks(account: String, ocId: String) -> [String] {
-
-        var filesNames: [String] = []
-
-        do {
-            let realm = try Realm()
-            let results = realm.objects(tableChunk.self).filter("account == %@ AND ocId == %@", account, ocId).sorted(byKeyPath: "fileName", ascending: true)
-            for result in results {
-                filesNames.append(result.fileName)
-            }
-            return filesNames
-        } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-
-        return filesNames
-    }
-
-    func addChunks(account: String, ocId: String, chunkFolder: String, fileNames: [String]) {
-
-        var size: Int64 = 0
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-
-                for fileName in fileNames {
-
-                    let object = tableChunk()
-                    size += NCUtilityFileSystem.shared.getFileSize(filePath: CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!)
-
-                    object.account = account
-                    object.chunkFolder = chunkFolder
-                    object.fileName = fileName
-                    object.index = ocId + fileName
-                    object.ocId = ocId
-                    object.size = size
-
-                    realm.add(object, update: .all)
-                }
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    func getChunk(account: String, fileName: String) -> tableChunk? {
-
-        do {
-            let realm = try Realm()
-            guard let result = realm.objects(tableChunk.self).filter("account == %@ AND fileName == %@", account, fileName).first else { return nil }
-            return tableChunk.init(value: result)
-        } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-
-        return nil
-    }
-
-    func deleteChunk(account: String, ocId: String, fileName: String) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-                let result = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@ AND fileName == %@", account, ocId, fileName))
-                realm.delete(result)
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    func deleteChunks(account: String, ocId: String) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-
-                let result = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@", account, ocId))
-                realm.delete(result)
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
     // MARK: -
     // MARK: -
     // MARK: Table Direct Editing
     // MARK: Table Direct Editing
 
 
@@ -420,6 +355,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableDirectEditingCreators.self).filter("account == %@", account)
             let results = realm.objects(tableDirectEditingCreators.self).filter("account == %@", account)
             if results.isEmpty {
             if results.isEmpty {
                 return nil
                 return nil
@@ -437,6 +373,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableDirectEditingCreators.self).filter(predicate)
             let results = realm.objects(tableDirectEditingCreators.self).filter(predicate)
             if results.isEmpty {
             if results.isEmpty {
                 return nil
                 return nil
@@ -454,6 +391,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableDirectEditingEditors.self).filter("account == %@", account)
             let results = realm.objects(tableDirectEditingEditors.self).filter("account == %@", account)
             if results.isEmpty {
             if results.isEmpty {
                 return nil
                 return nil
@@ -509,6 +447,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableExternalSites.self).filter("account == %@", account).sorted(byKeyPath: "idExternalSite", ascending: true)
             let results = realm.objects(tableExternalSites.self).filter("account == %@", account).sorted(byKeyPath: "idExternalSite", ascending: true)
             if results.isEmpty {
             if results.isEmpty {
                 return nil
                 return nil
@@ -525,21 +464,17 @@ class NCManageDatabase: NSObject {
     // MARK: -
     // MARK: -
     // MARK: Table GPS
     // MARK: Table GPS
 
 
-    @objc func addGeocoderLocation(_ location: String, placemarkAdministrativeArea: String, placemarkCountry: String, placemarkLocality: String, placemarkPostalCode: String, placemarkThoroughfare: String, latitude: String, longitude: String) {
+    @objc func addGeocoderLocation(_ location: String, latitude: Double, longitude: Double) {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard realm.objects(tableGPS.self).filter("latitude == %@ AND longitude == %@", latitude, longitude).first == nil else { return }
             guard realm.objects(tableGPS.self).filter("latitude == %@ AND longitude == %@", latitude, longitude).first == nil else { return }
             try realm.write {
             try realm.write {
                 let addObject = tableGPS()
                 let addObject = tableGPS()
                 addObject.latitude = latitude
                 addObject.latitude = latitude
                 addObject.location = location
                 addObject.location = location
                 addObject.longitude = longitude
                 addObject.longitude = longitude
-                addObject.placemarkAdministrativeArea = placemarkAdministrativeArea
-                addObject.placemarkCountry = placemarkCountry
-                addObject.placemarkLocality = placemarkLocality
-                addObject.placemarkPostalCode = placemarkPostalCode
-                addObject.placemarkThoroughfare = placemarkThoroughfare
                 realm.add(addObject)
                 realm.add(addObject)
             }
             }
         } catch let error as NSError {
         } catch let error as NSError {
@@ -547,10 +482,10 @@ class NCManageDatabase: NSObject {
         }
         }
     }
     }
 
 
-    @objc func getLocationFromGeoLatitude(_ latitude: String, longitude: String) -> String? {
-
+    @objc func getLocationFromLatAndLong(latitude: Double, longitude: Double) -> String? {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let result = realm.objects(tableGPS.self).filter("latitude == %@ AND longitude == %@", latitude, longitude).first
             let result = realm.objects(tableGPS.self).filter("latitude == %@ AND longitude == %@", latitude, longitude).first
             return result?.location
             return result?.location
         } catch let error as NSError {
         } catch let error as NSError {
@@ -560,152 +495,6 @@ class NCManageDatabase: NSObject {
         return nil
         return nil
     }
     }
 
 
-    // MARK: -
-    // MARK: Table LocalFile
-
-    func addLocalFile(metadata: tableMetadata) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-                let addObject = getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) ?? tableLocalFile()
-                addObject.account = metadata.account
-                addObject.etag = metadata.etag
-                addObject.exifDate = NSDate()
-                addObject.exifLatitude = "-1"
-                addObject.exifLongitude = "-1"
-                addObject.ocId = metadata.ocId
-                addObject.fileName = metadata.fileName
-                realm.add(addObject, update: .all)
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    func addLocalFile(account: String, etag: String, ocId: String, fileName: String) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-                let addObject = tableLocalFile()
-                addObject.account = account
-                addObject.etag = etag
-                addObject.exifDate = NSDate()
-                addObject.exifLatitude = "-1"
-                addObject.exifLongitude = "-1"
-                addObject.ocId = ocId
-                addObject.fileName = fileName
-                realm.add(addObject, update: .all)
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    func deleteLocalFile(predicate: NSPredicate) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-                let results = realm.objects(tableLocalFile.self).filter(predicate)
-                realm.delete(results)
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    func setLocalFile(ocId: String, fileName: String?, etag: String?) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-                let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
-                if let fileName = fileName {
-                    result?.fileName = fileName
-                }
-                if let etag = etag {
-                    result?.etag = etag
-                }
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    @objc func setLocalFile(ocId: String, exifDate: NSDate?, exifLatitude: String, exifLongitude: String, exifLensModel: String?) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-                if let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first {
-                    result.exifDate = exifDate
-                    result.exifLatitude = exifLatitude
-                    result.exifLongitude = exifLongitude
-                    if exifLensModel?.count ?? 0 > 0 {
-                        result.exifLensModel = exifLensModel
-                    }
-                }
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    func getTableLocalFile(account: String) -> [tableLocalFile] {
-
-        do {
-            let realm = try Realm()
-            let results = realm.objects(tableLocalFile.self).filter("account == %@", account)
-            return Array(results.map { tableLocalFile.init(value: $0) })
-        } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-
-        return []
-    }
-
-    func getTableLocalFile(predicate: NSPredicate) -> tableLocalFile? {
-
-        do {
-            let realm = try Realm()
-            guard let result = realm.objects(tableLocalFile.self).filter(predicate).first else { return nil }
-            return tableLocalFile.init(value: result)
-        } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-
-        return nil
-    }
-
-    func getTableLocalFiles(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableLocalFile] {
-
-        do {
-            let realm = try Realm()
-            let results = realm.objects(tableLocalFile.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
-            return Array(results.map { tableLocalFile.init(value: $0) })
-        } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-
-        return []
-    }
-
-    func setLocalFile(ocId: String, offline: Bool) {
-
-        do {
-            let realm = try Realm()
-            try realm.write {
-                let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
-                result?.offline = offline
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    // MARK: -
     // MARK: Table Photo Library
     // MARK: Table Photo Library
 
 
     @discardableResult
     @discardableResult
@@ -753,6 +542,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tablePhotoLibrary.self).filter(predicate)
             let results = realm.objects(tablePhotoLibrary.self).filter(predicate)
             let idsAsset = results.map { $0.idAsset }
             let idsAsset = results.map { $0.idAsset }
             return Array(idsAsset)
             return Array(idsAsset)
@@ -799,6 +589,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableTag.self).filter(predicate)
             let results = realm.objects(tableTag.self).filter(predicate)
             return Array(results.map { tableTag.init(value: $0) })
             return Array(results.map { tableTag.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
@@ -812,6 +603,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableTag.self).filter(predicate).first else { return nil }
             guard let result = realm.objects(tableTag.self).filter(predicate).first else { return nil }
             return tableTag.init(value: result)
             return tableTag.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {
@@ -933,6 +725,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             let results = realm.objects(tableTrash.self).filter("account == %@ AND filePath == %@", account, filePath).sorted(byKeyPath: sort, ascending: ascending)
             let results = realm.objects(tableTrash.self).filter("account == %@ AND filePath == %@", account, filePath).sorted(byKeyPath: sort, ascending: ascending)
             return Array(results.map { tableTrash.init(value: $0) })
             return Array(results.map { tableTrash.init(value: $0) })
         } catch let error as NSError {
         } catch let error as NSError {
@@ -946,6 +739,7 @@ class NCManageDatabase: NSObject {
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
+            realm.refresh()
             guard let result = realm.objects(tableTrash.self).filter("account == %@ AND fileId == %@", account, fileId).first else { return nil }
             guard let result = realm.objects(tableTrash.self).filter("account == %@ AND fileId == %@", account, fileId).first else { return nil }
             return tableTrash.init(value: result)
             return tableTrash.init(value: result)
         } catch let error as NSError {
         } catch let error as NSError {

+ 0 - 1
iOSClient/EmptyView/NCEmptyDataSet.swift

@@ -45,7 +45,6 @@ class NCEmptyDataSet: NSObject {
     private var centerXAnchor: NSLayoutConstraint?
     private var centerXAnchor: NSLayoutConstraint?
     private var centerYAnchor: NSLayoutConstraint?
     private var centerYAnchor: NSLayoutConstraint?
 
 
-
     init(view: UIView, offset: CGFloat = 0, delegate: NCEmptyDataSetDelegate?) {
     init(view: UIView, offset: CGFloat = 0, delegate: NCEmptyDataSetDelegate?) {
         super.init()
         super.init()
 
 

+ 9 - 3
iOSClient/Extensions/UIAlertController+Extension.swift

@@ -38,9 +38,15 @@ extension UIAlertController {
             guard let fileNameFolder = alertController.textFields?.first?.text else { return }
             guard let fileNameFolder = alertController.textFields?.first?.text else { return }
             if markE2ee {
             if markE2ee {
                 Task {
                 Task {
-                    let error = await NCNetworkingE2EECreateFolder.shared.createFolderAndMarkE2EE(fileName: fileNameFolder, serverUrl: serverUrl, account: urlBase.account)
-                    if error != .success {
-                        NCContentPresenter.shared.showError(error: error)
+
+                    let createFolderResults = await NextcloudKit.shared.createFolder(serverUrlFileName: serverUrl + "/" + fileNameFolder)
+                    if createFolderResults.error == .success {
+                        let error = await NCNetworkingE2EEMarkFolder().markFolderE2ee(account: urlBase.account, fileName: fileNameFolder, serverUrl: serverUrl, userId: urlBase.userId)
+                        if error != .success {
+                            NCContentPresenter.shared.showError(error: error)
+                        }
+                    } else {
+                        NCContentPresenter.shared.showError(error: createFolderResults.error)
                     }
                     }
                 }
                 }
             } else {
             } else {

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

@@ -36,3 +36,16 @@ 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/Extensions/UINavigationController+Extension.swift

@@ -51,7 +51,7 @@ extension UINavigationController {
         navigationBar.scrollEdgeAppearance = scrollEdgeAppearance
         navigationBar.scrollEdgeAppearance = scrollEdgeAppearance
     }
     }
 
 
-    func setGroupeAppreance() {
+    func setGroupAppearance() {
 
 
         navigationBar.tintColor = .systemBlue
         navigationBar.tintColor = .systemBlue
 
 

+ 2 - 2
iOSClient/Extensions/UIToolbar+Extension.swift

@@ -24,7 +24,7 @@
 import UIKit
 import UIKit
 
 
 extension UIToolbar {
 extension UIToolbar {
-    static func toolbar(onClear: (() -> Void)?, completion: @escaping () -> Void) -> UIToolbar {
+    static func toolbar(onClear: (() -> Void)?, onDone: @escaping () -> Void) -> UIToolbar {
         let toolbar = UIToolbar()
         let toolbar = UIToolbar()
         toolbar.sizeToFit()
         toolbar.sizeToFit()
         var buttons: [UIBarButtonItem] = []
         var buttons: [UIBarButtonItem] = []
@@ -37,7 +37,7 @@ extension UIToolbar {
         }
         }
         buttons.append(UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil))
         buttons.append(UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil))
         let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
         let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
-            completion()
+            onDone()
         }
         }
         buttons.append(doneButton)
         buttons.append(doneButton)
         toolbar.setItems(buttons, animated: false)
         toolbar.setItems(buttons, animated: false)

+ 34 - 51
iOSClient/Favorites/NCFavorite.swift

@@ -49,29 +49,33 @@ class NCFavorite: NCCollectionViewCommon {
 
 
     // MARK: - DataSource + NC Endpoint
     // MARK: - DataSource + NC Endpoint
 
 
-    override func reloadDataSource(forced: Bool = true) {
-        super.reloadDataSource()
+    override func queryDB(isForced: Bool) {
 
 
-        DispatchQueue.global().async {
-            var metadatas: [tableMetadata] = []
+        var metadatas: [tableMetadata] = []
 
 
-            if self.serverUrl.isEmpty {
-                metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND favorite == true", self.appDelegate.account))
-            } else {
-                metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
-            }
+        if self.serverUrl.isEmpty {
+            metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND favorite == true", self.appDelegate.account))
+        } else {
+            metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
+        }
 
 
-            self.dataSource = NCDataSource(metadatas: metadatas,
-                                           account: self.appDelegate.account,
-                                           sort: self.layoutForView?.sort,
-                                           ascending: self.layoutForView?.ascending,
-                                           directoryOnTop: self.layoutForView?.directoryOnTop,
-                                           favoriteOnTop: true,
-                                           filterLivePhoto: true,
-                                           groupByField: self.groupByField,
-                                           providers: self.providers,
-                                           searchResults: self.searchResults)
+        self.dataSource = NCDataSource(metadatas: metadatas,
+                                       account: self.appDelegate.account,
+                                       sort: self.layoutForView?.sort,
+                                       ascending: self.layoutForView?.ascending,
+                                       directoryOnTop: self.layoutForView?.directoryOnTop,
+                                       favoriteOnTop: true,
+                                       filterLivePhoto: true,
+                                       groupByField: self.groupByField,
+                                       providers: self.providers,
+                                       searchResults: self.searchResults)
+    }
+
+    override func reloadDataSource(isForced: Bool = true) {
+        super.reloadDataSource()
 
 
+        DispatchQueue.global().async {
+            self.queryDB(isForced: isForced)
             DispatchQueue.main.async {
             DispatchQueue.main.async {
                 self.refreshControl.endRefreshing()
                 self.refreshControl.endRefreshing()
                 self.collectionView.reloadData()
                 self.collectionView.reloadData()
@@ -79,46 +83,25 @@ class NCFavorite: NCCollectionViewCommon {
         }
         }
     }
     }
 
 
-    override func reloadDataSourceNetwork(forced: Bool = false) {
-        super.reloadDataSourceNetwork(forced: forced)
+    override func reloadDataSourceNetwork(isForced: Bool = false) {
+        super.reloadDataSourceNetwork(isForced: isForced)
+
+        NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network favorite forced \(isForced)")
 
 
         isReloadDataSourceNetworkInProgress = true
         isReloadDataSourceNetworkInProgress = true
         collectionView?.reloadData()
         collectionView?.reloadData()
 
 
-        if serverUrl.isEmpty {
+        NextcloudKit.shared.listingFavorites(showHiddenFiles: CCUtility.getShowHiddenFiles(),
+                                             options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { account, files, _, error in
 
 
-            NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorListingFavorite) { _, _, error in
-                if error != .success {
-                    NCContentPresenter.shared.showError(error: error)
-                }
-
-                DispatchQueue.main.async {
-                    self.refreshControl.endRefreshing()
-                    self.isReloadDataSourceNetworkInProgress = false
+            self.isReloadDataSourceNetworkInProgress = false
+            if error == .success {
+                NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
+                    NCManageDatabase.shared.updateMetadatasFavorite(account: account, metadatas: metadatas)
                     self.reloadDataSource()
                     self.reloadDataSource()
                 }
                 }
             }
             }
-
-        } else {
-
-            networkReadFolder(forced: forced) { tableDirectory, metadatas, metadatasUpdate, metadatasDelete, error in
-                if error == .success, let metadatas = metadatas {
-                    for metadata in metadatas where (!metadata.directory && NCManageDatabase.shared.isDownloadMetadata(metadata, download: false)) {
-                        NCOperationQueue.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile)
-                    }
-                }
-
-                DispatchQueue.main.async {
-                    self.refreshControl.endRefreshing()
-                    self.isReloadDataSourceNetworkInProgress = false
-                    self.richWorkspaceText = tableDirectory?.richWorkspace
-                    if metadatasUpdate?.count ?? 0 > 0 || metadatasDelete?.count ?? 0 > 0 || forced {
-                        self.reloadDataSource()
-                    } else {
-                        self.collectionView?.reloadData()
-                    }
-                }
-            }
+            self.reloadDataSource()
         }
         }
     }
     }
 }
 }

+ 70 - 44
iOSClient/Files/NCFiles.swift

@@ -40,11 +40,45 @@ class NCFiles: NCCollectionViewCommon {
         enableSearchBar = true
         enableSearchBar = true
         headerMenuButtonsView = true
         headerMenuButtonsView = true
         headerRichWorkspaceDisable = false
         headerRichWorkspaceDisable = false
+        headerMenuTransferView = true
         emptyImage = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
         emptyImage = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
         emptyTitle = "_files_no_files_"
         emptyTitle = "_files_no_files_"
         emptyDescription = "_no_file_pull_down_"
         emptyDescription = "_no_file_pull_down_"
     }
     }
 
 
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        if isRoot {
+            NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in
+
+                self.navigationController?.popToRootViewController(animated: false)
+
+                self.serverUrl = NCUtilityFileSystem.shared.getHomeServer(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)
+                self.appDelegate.activeServerUrl = self.serverUrl
+
+                self.isSearchingMode = false
+                self.isEditMode = false
+                self.selectOcId.removeAll()
+                self.selectIndexPath.removeAll()
+
+                self.layoutForView = NCManageDatabase.shared.getLayoutForView(account: self.appDelegate.account, key: self.layoutKey, serverUrl: self.serverUrl)
+                self.gridLayout.itemForLine = CGFloat(self.layoutForView?.itemForLine ?? 3)
+                if self.layoutForView?.layout == NCGlobal.shared.layoutList {
+                    self.collectionView?.collectionViewLayout = self.listLayout
+                } else {
+                    self.collectionView?.collectionViewLayout = self.gridLayout
+                }
+
+                self.titleCurrentFolder = self.getNavigationTitle()
+                self.setNavigationItem()
+
+                self.reloadDataSource(isForced: false)
+                self.reloadDataSourceNetwork()
+            }
+        }
+    }
+
     override func viewWillAppear(_ animated: Bool) {
     override func viewWillAppear(_ animated: Bool) {
 
 
         if isRoot {
         if isRoot {
@@ -52,7 +86,6 @@ class NCFiles: NCCollectionViewCommon {
             titleCurrentFolder = getNavigationTitle()
             titleCurrentFolder = getNavigationTitle()
         }
         }
         super.viewWillAppear(animated)
         super.viewWillAppear(animated)
-
         navigationController?.setFileAppreance()
         navigationController?.setFileAppreance()
     }
     }
 
 
@@ -63,57 +96,47 @@ class NCFiles: NCCollectionViewCommon {
         fileNameOpen = nil
         fileNameOpen = nil
     }
     }
 
 
-    // MARK: - NotificationCenter
+    // MARK: - DataSource + NC Endpoint
+    //
+    // forced: do no make the etag of directory test (default)
+    //
 
 
-    override func initialize() {
+    override func queryDB(isForced: Bool) {
 
 
-        if isRoot {
-            serverUrl = NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId)
-            titleCurrentFolder = getNavigationTitle()
+        let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
+        let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
+        let metadataTransfer = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "status != %i AND serverUrl == %@", NCGlobal.shared.metadataStatusNormal, self.serverUrl))
+        if self.metadataFolder == nil {
+            self.metadataFolder = NCManageDatabase.shared.getMetadataFolder(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, serverUrl: self.serverUrl)
         }
         }
-        super.initialize()
 
 
-        reloadDataSource(forced: false)
-        reloadDataSourceNetwork()
-    }
+        if !isForced, let directory, directory.etag == self.dataSource.directory?.etag, metadataTransfer == nil, self.fileNameBlink == nil, self.fileNameOpen == nil {
+            return
+        }
 
 
-    // MARK: - DataSource + NC Endpoint
-    //
-    // forced: do no make the etag of directory test (default)
-    //
+        self.richWorkspaceText = directory?.richWorkspace
+        self.dataSource = NCDataSource(
+            metadatas: metadatas,
+            account: self.appDelegate.account,
+            directory: directory,
+            sort: self.layoutForView?.sort,
+            ascending: self.layoutForView?.ascending,
+            directoryOnTop: self.layoutForView?.directoryOnTop,
+            favoriteOnTop: true,
+            filterLivePhoto: true,
+            groupByField: self.groupByField,
+            providers: self.providers,
+            searchResults: self.searchResults)
+    }
 
 
-    override func reloadDataSource(forced: Bool = true) {
+    override func reloadDataSource(isForced: Bool = true) {
         super.reloadDataSource()
         super.reloadDataSource()
 
 
         DispatchQueue.main.async { self.refreshControl.endRefreshing() }
         DispatchQueue.main.async { self.refreshControl.endRefreshing() }
         DispatchQueue.global().async {
         DispatchQueue.global().async {
             guard !self.isSearchingMode, !self.appDelegate.account.isEmpty, !self.appDelegate.urlBase.isEmpty, !self.serverUrl.isEmpty else { return }
             guard !self.isSearchingMode, !self.appDelegate.account.isEmpty, !self.appDelegate.urlBase.isEmpty, !self.serverUrl.isEmpty else { return }
 
 
-            let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
-            if self.metadataFolder == nil {
-                self.metadataFolder = NCManageDatabase.shared.getMetadataFolder(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, serverUrl: self.serverUrl)
-            }
-            let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
-            let metadataTransfer = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "status != %i AND serverUrl == %@", NCGlobal.shared.metadataStatusNormal, self.serverUrl))
-            self.richWorkspaceText = directory?.richWorkspace
-
-            // FORCED false: test the directory.etag
-            if !forced, let directory = directory, directory.etag == self.dataSource.directory?.etag, metadataTransfer == nil, self.fileNameBlink == nil, self.fileNameOpen == nil {
-                return
-            }
-
-            self.dataSource = NCDataSource(
-                metadatas: metadatas,
-                account: self.appDelegate.account,
-                directory: directory,
-                sort: self.layoutForView?.sort,
-                ascending: self.layoutForView?.ascending,
-                directoryOnTop: self.layoutForView?.directoryOnTop,
-                favoriteOnTop: true,
-                filterLivePhoto: true,
-                groupByField: self.groupByField,
-                providers: self.providers,
-                searchResults: self.searchResults)
+            self.queryDB(isForced: isForced)
 
 
             DispatchQueue.main.async {
             DispatchQueue.main.async {
                 self.collectionView.reloadData()
                 self.collectionView.reloadData()
@@ -127,16 +150,19 @@ class NCFiles: NCCollectionViewCommon {
         }
         }
     }
     }
 
 
-    override func reloadDataSourceNetwork(forced: Bool = false) {
-        super.reloadDataSourceNetwork(forced: forced)
+    override func reloadDataSourceNetwork(isForced: Bool = false) {
+        super.reloadDataSourceNetwork(isForced: isForced)
         guard !isSearchingMode else {
         guard !isSearchingMode else {
             networkSearch()
             networkSearch()
             return
             return
         }
         }
+
+        NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network files forced \(isForced)")
+
         isReloadDataSourceNetworkInProgress = true
         isReloadDataSourceNetworkInProgress = true
         collectionView?.reloadData()
         collectionView?.reloadData()
 
 
-        networkReadFolder(forced: forced) { tableDirectory, metadatas, metadatasUpdate, metadatasDelete, error in
+        networkReadFolder(isForced: isForced) { tableDirectory, metadatas, metadatasUpdate, metadatasDelete, error in
             if error == .success {
             if error == .success {
                 for metadata in metadatas ?? [] where !metadata.directory && NCManageDatabase.shared.isDownloadMetadata(metadata, download: false) {
                 for metadata in metadatas ?? [] where !metadata.directory && NCManageDatabase.shared.isDownloadMetadata(metadata, download: false) {
                     NCOperationQueue.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile)
                     NCOperationQueue.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile)
@@ -146,7 +172,7 @@ class NCFiles: NCCollectionViewCommon {
             self.isReloadDataSourceNetworkInProgress = false
             self.isReloadDataSourceNetworkInProgress = false
             self.richWorkspaceText = tableDirectory?.richWorkspace
             self.richWorkspaceText = tableDirectory?.richWorkspace
 
 
-            if metadatasUpdate?.count ?? 0 > 0 || metadatasDelete?.count ?? 0 > 0 || forced {
+            if metadatasUpdate?.count ?? 0 > 0 || metadatasDelete?.count ?? 0 > 0 || isForced {
                 self.reloadDataSource()
                 self.reloadDataSource()
             } else if self.dataSource.getMetadataSourceForAllSections().isEmpty {
             } else if self.dataSource.getMetadataSourceForAllSections().isEmpty {
                 DispatchQueue.main.async {
                 DispatchQueue.main.async {

+ 28 - 35
iOSClient/Groupfolders/NCGroupfolders.swift

@@ -49,8 +49,7 @@ class NCGroupfolders: NCCollectionViewCommon {
 
 
     // MARK: - DataSource + NC Endpoint
     // MARK: - DataSource + NC Endpoint
 
 
-    override func reloadDataSource(forced: Bool = true) {
-        super.reloadDataSource()
+    override func queryDB(isForced: Bool) {
 
 
         var metadatas: [tableMetadata] = []
         var metadatas: [tableMetadata] = []
 
 
@@ -71,7 +70,12 @@ class NCGroupfolders: NCCollectionViewCommon {
             groupByField: self.groupByField,
             groupByField: self.groupByField,
             providers: self.providers,
             providers: self.providers,
             searchResults: self.searchResults)
             searchResults: self.searchResults)
+    }
+
+    override func reloadDataSource(isForced: Bool = true) {
+        super.reloadDataSource()
 
 
+        self.queryDB(isForced: isForced)
         DispatchQueue.main.async {
         DispatchQueue.main.async {
             self.isReloadDataSourceNetworkInProgress = false
             self.isReloadDataSourceNetworkInProgress = false
             self.refreshControl.endRefreshing()
             self.refreshControl.endRefreshing()
@@ -79,48 +83,37 @@ class NCGroupfolders: NCCollectionViewCommon {
         }
         }
     }
     }
 
 
-    override func reloadDataSourceNetwork(forced: Bool = false) {
-        super.reloadDataSourceNetwork(forced: forced)
+    override func reloadDataSourceNetwork(isForced: Bool = false) {
+        super.reloadDataSourceNetwork(isForced: isForced)
+
+        NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Reload data source network groupfolders forced \(isForced)")
 
 
         isReloadDataSourceNetworkInProgress = true
         isReloadDataSourceNetworkInProgress = true
         collectionView?.reloadData()
         collectionView?.reloadData()
 
 
-        if serverUrl.isEmpty {
-
-            let homeServerUrl = NCUtilityFileSystem.shared.getHomeServer(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)
-            let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
-
-            NextcloudKit.shared.getGroupfolders(options: options) { account, results, _, error in
-
-                if error == .success, let groupfolders = results {
-
-                    NCManageDatabase.shared.addGroupfolders(account: account, groupfolders: groupfolders)
-
-                    Task {
-                        for groupfolder in groupfolders {
-                            let mountPoint = groupfolder.mountPoint.hasPrefix("/") ? groupfolder.mountPoint : "/" + groupfolder.mountPoint
-                            let serverUrlFileName = homeServerUrl + mountPoint
-                            if NCManageDatabase.shared.getMetadataFromDirectory(account: self.appDelegate.account, serverUrl: serverUrlFileName) == nil {
-                                let results = await NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles())
-                                if results.error == .success, let file = results.files.first {
-                                    let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(file: file)
-                                    let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryE2EE)
-                                    NCManageDatabase.shared.addMetadata(metadata)
-                                    NCManageDatabase.shared.addDirectory(encrypted: isDirectoryE2EE, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: serverUrlFileName, account: metadata.account)
-                                }
+        let homeServerUrl = NCUtilityFileSystem.shared.getHomeServer(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)
+
+        NextcloudKit.shared.getGroupfolders(options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { account, results, _, error in
+
+            if error == .success, let groupfolders = results {
+                NCManageDatabase.shared.addGroupfolders(account: account, groupfolders: groupfolders)
+                Task {
+                    for groupfolder in groupfolders {
+                        let mountPoint = groupfolder.mountPoint.hasPrefix("/") ? groupfolder.mountPoint : "/" + groupfolder.mountPoint
+                        let serverUrlFileName = homeServerUrl + mountPoint
+                        if NCManageDatabase.shared.getMetadataFromDirectory(account: self.appDelegate.account, serverUrl: serverUrlFileName) == nil {
+                            let results = await NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrlFileName, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles())
+                            if results.error == .success, let file = results.files.first {
+                                let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(file: file)
+                                let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryE2EE)
+                                NCManageDatabase.shared.addMetadata(metadata)
+                                NCManageDatabase.shared.addDirectory(encrypted: isDirectoryE2EE, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: serverUrlFileName, account: metadata.account)
                             }
                             }
                         }
                         }
-                        self.reloadDataSource()
                     }
                     }
-                } else if error != .success {
                     self.reloadDataSource()
                     self.reloadDataSource()
-                    NCContentPresenter.shared.showError(error: error)
                 }
                 }
-            }
-        } else {
-
-            networkReadFolder(forced: forced) { _, _, _, _, _ in
-
+            } else if error != .success {
                 self.reloadDataSource()
                 self.reloadDataSource()
             }
             }
         }
         }

+ 40 - 29
iOSClient/Login/NCLogin.swift

@@ -36,7 +36,10 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
     @IBOutlet weak var qrCode: UIButton!
     @IBOutlet weak var qrCode: UIButton!
     @IBOutlet weak var certificate: UIButton!
     @IBOutlet weak var certificate: UIButton!
 
 
+    // swiftlint:disable force_cast
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
+
     private var textColor: UIColor = .white
     private var textColor: UIColor = .white
     private var textColorOpponent: UIColor = .black
     private var textColorOpponent: UIColor = .black
     private var activeTextfieldDiff: CGFloat = 0
     private var activeTextfieldDiff: CGFloat = 0
@@ -153,7 +156,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
         if self.shareAccounts != nil, let image = UIImage(systemName: "person.badge.plus")?.withTintColor(.white, renderingMode: .alwaysOriginal), let backgroundColor = NCBrandColor.shared.brandElement.lighter(by: 10) {
         if self.shareAccounts != nil, let image = UIImage(systemName: "person.badge.plus")?.withTintColor(.white, renderingMode: .alwaysOriginal), let backgroundColor = NCBrandColor.shared.brandElement.lighter(by: 10) {
             let title = String(format: NSLocalizedString("_apps_nextcloud_detect_", comment: ""), NCBrandOptions.shared.brand)
             let title = String(format: NSLocalizedString("_apps_nextcloud_detect_", comment: ""), NCBrandOptions.shared.brand)
             let description = String(format: NSLocalizedString("_add_existing_account_", comment: ""), NCBrandOptions.shared.brand)
             let description = String(format: NSLocalizedString("_add_existing_account_", comment: ""), NCBrandOptions.shared.brand)
-            NCContentPresenter.shared.alertAction(image: image, contentModeImage: .scaleAspectFit, sizeImage: CGSize(width: 45, height: 45),backgroundColor: backgroundColor, textColor: textColor, title: title, description: description, textCancelButton: "_cancel_", textOkButton: "_ok_", attributes: EKAttributes.topFloat) { identifier in
+            NCContentPresenter.shared.alertAction(image: image, contentModeImage: .scaleAspectFit, sizeImage: CGSize(width: 45, height: 45), backgroundColor: backgroundColor, textColor: textColor, title: title, description: description, textCancelButton: "_cancel_", textOkButton: "_ok_", attributes: EKAttributes.topFloat) { identifier in
                 if identifier == "ok" {
                 if identifier == "ok" {
                     self.openShareAccountsViewController()
                     self.openShareAccountsViewController()
                 }
                 }
@@ -213,7 +216,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
 
 
         guard var url = baseUrl.text?.trimmingCharacters(in: .whitespacesAndNewlines) else { return }
         guard var url = baseUrl.text?.trimmingCharacters(in: .whitespacesAndNewlines) else { return }
         if url.hasSuffix("/") { url = String(url.dropLast()) }
         if url.hasSuffix("/") { url = String(url.dropLast()) }
-        if url.count == 0 { return }
+        if url.isEmpty { return }
 
 
         // Check whether baseUrl contain protocol. If not add https:// by default.
         // Check whether baseUrl contain protocol. If not add https:// by default.
         if url.hasPrefix("https") == false && url.hasPrefix("http") == false {
         if url.hasPrefix("https") == false && url.hasPrefix("http") == false {
@@ -244,11 +247,11 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             vc.dismissDidEnterBackground = false
             vc.dismissDidEnterBackground = false
             vc.delegate = self
             vc.delegate = self
 
 
-            let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/5)
+            let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height / 5)
             let numberCell = shareAccounts.count
             let numberCell = shareAccounts.count
             let height = min(CGFloat(numberCell * Int(vc.heightCell) + 45), screenHeighMax)
             let height = min(CGFloat(numberCell * Int(vc.heightCell) + 45), screenHeighMax)
 
 
-            let popup = NCPopupViewController(contentController: vc, popupWidth: 300, popupHeight: height+20)
+            let popup = NCPopupViewController(contentController: vc, popupWidth: 300, popupHeight: height + 20)
 
 
             self.present(popup, animated: true)
             self.present(popup, animated: true)
         }
         }
@@ -269,7 +272,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                     NCNetworking.shared.writeCertificate(host: host)
                     NCNetworking.shared.writeCertificate(host: host)
                 }
                 }
 
 
-                NextcloudKit.shared.getLoginFlowV2(serverUrl: url) { token, endpoint, login, data, error in
+                NextcloudKit.shared.getLoginFlowV2(serverUrl: url) { token, endpoint, login, _, error in
 
 
                     self.loginButton.isEnabled = true
                     self.loginButton.isEnabled = true
 
 
@@ -327,8 +330,8 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { _ in }))
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_", comment: ""), style: .default, handler: { _ in }))
 
 
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { _ in
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_certificate_details_", comment: ""), style: .default, handler: { _ in
-                        if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController {
-                            let viewController = navigationController.topViewController as! NCViewCertificateDetails
+                        if let navigationController = UIStoryboard(name: "NCViewCertificateDetails", bundle: nil).instantiateInitialViewController() as? UINavigationController,
+                           let viewController = navigationController.topViewController as? NCViewCertificateDetails {
                             if let host = URL(string: url)?.host {
                             if let host = URL(string: url)?.host {
                                 viewController.host = host
                                 viewController.host = host
                             }
                             }
@@ -387,31 +390,41 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             if let host = URL(string: url)?.host {
             if let host = URL(string: url)?.host {
                 NCNetworking.shared.writeCertificate(host: host)
                 NCNetworking.shared.writeCertificate(host: host)
             }
             }
+            let urlBase = url
+            let account = user + " " + user
 
 
-            let account = user + " " + url
+            NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase)
+            NextcloudKit.shared.getUserProfile { _, userProfile, _, error in
 
 
-            if NCManageDatabase.shared.getAccounts() == nil {
-                NCUtility.shared.removeAllSettings()
-            }
-                           
-            NCManageDatabase.shared.deleteAccount(account)
-            NCManageDatabase.shared.addAccount(account, urlBase: url, user: user, password: password)
+                if error == .success, let userProfile {
 
 
-            if let activeAccount = NCManageDatabase.shared.setAccountActive(account) {
-                appDelegate.settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account))
-            }
+                    if NCManageDatabase.shared.getAccounts() == nil {
+                        NCUtility.shared.removeAllSettings()
+                    }
 
 
-            if CCUtility.getIntro() {
-                self.dismiss(animated: true)
-            } else {
-                CCUtility.setIntro(true)
-                if self.presentingViewController == nil {
-                    let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
-                    viewController?.modalPresentationStyle = .fullScreen
-                    self.appDelegate.window?.rootViewController = viewController
-                    self.appDelegate.window?.makeKey()
+                    NCManageDatabase.shared.deleteAccount(account)
+                    NCManageDatabase.shared.addAccount(account, urlBase: url, user: user, userId: userProfile.userId, password: password)
+
+                    self.appDelegate.changeAccount(account, userProfile: userProfile)
+
+                    if CCUtility.getIntro() {
+                        self.dismiss(animated: true)
+                    } else {
+                        CCUtility.setIntro(true)
+                        if self.presentingViewController == nil {
+                            let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
+                            viewController?.modalPresentationStyle = .fullScreen
+                            self.appDelegate.window?.rootViewController = viewController
+                            self.appDelegate.window?.makeKey()
+                        } else {
+                            self.dismiss(animated: true)
+                        }
+                    }
                 } else {
                 } else {
-                    self.dismiss(animated: true)
+
+                    let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert)
+                    alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
+                    self.present(alertController, animated: true)
                 }
                 }
             }
             }
 
 
@@ -439,9 +452,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
 
 
             let message = NSLocalizedString("_not_possible_connect_to_server_", comment: "") + ".\n" + error.errorDescription
             let message = NSLocalizedString("_not_possible_connect_to_server_", comment: "") + ".\n" + error.errorDescription
             let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: message, preferredStyle: .alert)
             let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: message, preferredStyle: .alert)
-
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
-
             self.present(alertController, animated: true, completion: { })
             self.present(alertController, animated: true, completion: { })
         }
         }
     }
     }

+ 47 - 58
iOSClient/Login/NCLoginWeb.swift

@@ -29,12 +29,16 @@ import FloatingPanel
 class NCLoginWeb: UIViewController {
 class NCLoginWeb: UIViewController {
 
 
     var webView: WKWebView?
     var webView: WKWebView?
+
+    // swiftlint:disable force_cast
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
+
     var titleView: String = ""
     var titleView: String = ""
 
 
     var urlBase = ""
     var urlBase = ""
     var user: String?
     var user: String?
-    
+
     var configServerUrl: String?
     var configServerUrl: String?
     var configUsername: String?
     var configUsername: String?
     var configPassword: String?
     var configPassword: String?
@@ -55,7 +59,7 @@ class NCLoginWeb: UIViewController {
         // load AppConfig
         // load AppConfig
         if (NCBrandOptions.shared.disable_multiaccount == false) || (NCBrandOptions.shared.disable_multiaccount == true && accountCount == 0) {
         if (NCBrandOptions.shared.disable_multiaccount == false) || (NCBrandOptions.shared.disable_multiaccount == true && accountCount == 0) {
             if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), NCBrandOptions.shared.use_AppConfig {
             if let configurationManaged = UserDefaults.standard.dictionary(forKey: "com.apple.configuration.managed"), NCBrandOptions.shared.use_AppConfig {
-                
+
                 if let serverUrl = configurationManaged[NCGlobal.shared.configuration_serverUrl] as? String {
                 if let serverUrl = configurationManaged[NCGlobal.shared.configuration_serverUrl] as? String {
                     self.configServerUrl = serverUrl
                     self.configServerUrl = serverUrl
                 }
                 }
@@ -104,7 +108,7 @@ class NCLoginWeb: UIViewController {
                 urlBase = serverUrl
                 urlBase = serverUrl
             }
             }
         }
         }
-        
+
         // ADD end point for Web Flow
         // ADD end point for Web Flow
         if urlBase != NCBrandOptions.shared.linkloginPreferredProviders {
         if urlBase != NCBrandOptions.shared.linkloginPreferredProviders {
             if loginFlowV2Available {
             if loginFlowV2Available {
@@ -171,7 +175,7 @@ class NCLoginWeb: UIViewController {
             let deviceUserAgent = String(cString: deviceName, encoding: .ascii) {
             let deviceUserAgent = String(cString: deviceName, encoding: .ascii) {
             webView.customUserAgent = deviceUserAgent
             webView.customUserAgent = deviceUserAgent
         } else {
         } else {
-            webView.customUserAgent = CCUtility.getUserAgent()
+            webView.customUserAgent = userAgent
         }
         }
 
 
         request.addValue("true", forHTTPHeaderField: "OCS-APIRequest")
         request.addValue("true", forHTTPHeaderField: "OCS-APIRequest")
@@ -179,10 +183,10 @@ class NCLoginWeb: UIViewController {
 
 
         webView.load(request)
         webView.load(request)
     }
     }
-    
+
     func getAppPassword(serverUrl: String, username: String, password: String) {
     func getAppPassword(serverUrl: String, username: String, password: String) {
-        
-        NextcloudKit.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password) { token, data, error in
+
+        NextcloudKit.shared.getAppPassword(serverUrl: serverUrl, username: username, password: password) { token, _, error in
             if error == .success, let password = token {
             if error == .success, let password = token {
                 self.createAccount(server: serverUrl, username: username, password: password)
                 self.createAccount(server: serverUrl, username: username, password: password)
             } else {
             } else {
@@ -232,7 +236,7 @@ extension NCLoginWeb: WKNavigationDelegate {
                 if value.contains("password:") { password = value }
                 if value.contains("password:") { password = value }
             }
             }
 
 
-            if server != "" && user != "" && password != "" {
+            if !server.isEmpty, !user.isEmpty, !password.isEmpty {
 
 
                 let server: String = server.replacingOccurrences(of: "/server:", with: "")
                 let server: String = server.replacingOccurrences(of: "/server:", with: "")
                 let username: String = user.replacingOccurrences(of: "user:", with: "").replacingOccurrences(of: "+", with: " ")
                 let username: String = user.replacingOccurrences(of: "user:", with: "").replacingOccurrences(of: "+", with: " ")
@@ -243,22 +247,6 @@ extension NCLoginWeb: WKNavigationDelegate {
         }
         }
     }
     }
 
 
-    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
-
-        var errorMessage = error.localizedDescription
-
-        for (key, value) in (error as NSError).userInfo {
-            let message = "\(key) \(value)\n"
-            errorMessage += message
-        }
-
-        let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorMessage, preferredStyle: .alert)
-
-        alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
-
-        self.present(alertController, animated: true)
-    }
-
     func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
     func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
         DispatchQueue.global().async {
         DispatchQueue.global().async {
             if let serverTrust = challenge.protectionSpace.serverTrust {
             if let serverTrust = challenge.protectionSpace.serverTrust {
@@ -283,7 +271,7 @@ extension NCLoginWeb: WKNavigationDelegate {
 
 
         if loginFlowV2Available {
         if loginFlowV2Available {
             DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
             DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
-                NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, data, error in
+                NextcloudKit.shared.getLoginFlowV2Poll(token: self.loginFlowV2Token, endpoint: self.loginFlowV2Endpoint) { server, loginName, appPassword, _, error in
                     if error == .success && server != nil && loginName != nil && appPassword != nil {
                     if error == .success && server != nil && loginName != nil && appPassword != nil {
                         self.createAccount(server: server!, username: loginName!, password: appPassword!)
                         self.createAccount(server: server!, username: loginName!, password: appPassword!)
                     }
                     }
@@ -297,47 +285,48 @@ extension NCLoginWeb: WKNavigationDelegate {
     func createAccount(server: String, username: String, password: String) {
     func createAccount(server: String, username: String, password: String) {
 
 
         var urlBase = server
         var urlBase = server
-
-        // Normalized
-        if urlBase.last == "/" {
-            urlBase = String(urlBase.dropLast())
-        }
-
-        // Create account
+        if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) }
         let account: String = "\(username) \(urlBase)"
         let account: String = "\(username) \(urlBase)"
+        let user = username
 
 
-        // NO account found, clear all
-        if NCManageDatabase.shared.getAccounts() == nil {
-            NCUtility.shared.removeAllSettings()
-        }
-        
-        // Add new account
-        NCManageDatabase.shared.deleteAccount(account)
-        NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: username, password: password)
+        NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase)
+        NextcloudKit.shared.getUserProfile { _, userProfile, _, error in
 
 
-        guard let tableAccount = NCManageDatabase.shared.setAccountActive(account) else {
-            self.dismiss(animated: true, completion: nil)
-            return
-        }
+            if error == .success, let userProfile {
 
 
-        appDelegate.settingAccount(account, urlBase: urlBase, user: username, userId: tableAccount.userId, password: password)
+                if NCManageDatabase.shared.getAccounts() == nil {
+                    NCUtility.shared.removeAllSettings()
+                }
 
 
-        if CCUtility.getIntro() {
-            self.dismiss(animated: true)
-        } else {
-            CCUtility.setIntro(true)
-            if self.presentingViewController == nil {
-                if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
-                    viewController.modalPresentationStyle = .fullScreen
-                    viewController.view.alpha = 0
-                    appDelegate.window?.rootViewController = viewController
-                    appDelegate.window?.makeKeyAndVisible()
-                    UIView.animate(withDuration: 0.5) {
-                        viewController.view.alpha = 1
+                NCManageDatabase.shared.deleteAccount(account)
+                NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password)
+
+                self.appDelegate.changeAccount(account, userProfile: userProfile)
+
+                if CCUtility.getIntro() {
+                    self.dismiss(animated: true)
+                } else {
+                    CCUtility.setIntro(true)
+                    if self.presentingViewController == nil {
+                        if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
+                            viewController.modalPresentationStyle = .fullScreen
+                            viewController.view.alpha = 0
+                            self.appDelegate.window?.rootViewController = viewController
+                            self.appDelegate.window?.makeKeyAndVisible()
+                            UIView.animate(withDuration: 0.5) {
+                                viewController.view.alpha = 1
+                            }
+                        }
+                    } else {
+                        self.dismiss(animated: true)
                     }
                     }
                 }
                 }
+
             } else {
             } else {
-                self.dismiss(animated: true)
+
+                let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert)
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
+                self.present(alertController, animated: true)
             }
             }
         }
         }
     }
     }

+ 1 - 1
iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift

@@ -143,7 +143,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate {
 
 
         voiceRecordHUD.update(CGFloat(rate))
         voiceRecordHUD.update(CGFloat(rate))
         voiceRecordHUD.fillColor = UIColor.green
         voiceRecordHUD.fillColor = UIColor.green
-        
+
         let formatter = DateComponentsFormatter()
         let formatter = DateComponentsFormatter()
         formatter.allowedUnits = [.second]
         formatter.allowedUnits = [.second]
         formatter.unitsStyle = .full
         formatter.unitsStyle = .full

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 226 - 345
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift


+ 15 - 14
iOSClient/Main/Collection Common/NCGridCell.swift

@@ -36,7 +36,8 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     @IBOutlet weak var imageVisualEffect: UIVisualEffectView!
     @IBOutlet weak var imageVisualEffect: UIVisualEffectView!
     @IBOutlet weak var progressView: UIProgressView!
     @IBOutlet weak var progressView: UIProgressView!
 
 
-    internal var objectId = ""
+    var objectId = ""
+    var indexPath = IndexPath()
     private var user = ""
     private var user = ""
 
 
     weak var delegate: NCGridCellDelegate?
     weak var delegate: NCGridCellDelegate?
@@ -99,7 +100,7 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
         imageVisualEffect.clipsToBounds = true
         imageVisualEffect.clipsToBounds = true
         imageVisualEffect.alpha = 0.5
         imageVisualEffect.alpha = 0.5
 
 
-        progressView.tintColor = NCBrandColor.shared.brandElement
+        progressView.tintColor = NCBrandColor.shared.brand
         progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5)
         progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5)
         progressView.trackTintColor = .clear
         progressView.trackTintColor = .clear
 
 
@@ -134,20 +135,20 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     }
     }
 
 
     @IBAction func touchUpInsideMore(_ sender: Any) {
     @IBAction func touchUpInsideMore(_ sender: Any) {
-        delegate?.tapMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, sender: sender)
+        delegate?.tapMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, indexPath: indexPath, sender: sender)
     }
     }
 
 
     @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) {
     @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) {
-        delegate?.longPressMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, gestureRecognizer: gestureRecognizer)
+        delegate?.longPressMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, indexPath: indexPath, gestureRecognizer: gestureRecognizer)
     }
     }
 
 
     @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) {
     @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) {
-        delegate?.longPressGridItem(with: objectId, gestureRecognizer: gestureRecognizer)
+        delegate?.longPressGridItem(with: objectId, indexPath: indexPath, gestureRecognizer: gestureRecognizer)
     }
     }
 
 
     fileprivate func setA11yActions() {
     fileprivate func setA11yActions() {
         let moreName = namedButtonMore == NCGlobal.shared.buttonMoreStop ? "_cancel_" : "_more_"
         let moreName = namedButtonMore == NCGlobal.shared.buttonMoreStop ? "_cancel_" : "_more_"
-        
+
         self.accessibilityCustomActions = [
         self.accessibilityCustomActions = [
             UIAccessibilityCustomAction(
             UIAccessibilityCustomAction(
                 name: NSLocalizedString(moreName, comment: ""),
                 name: NSLocalizedString(moreName, comment: ""),
@@ -155,7 +156,7 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
                 selector: #selector(touchUpInsideMore))
                 selector: #selector(touchUpInsideMore))
         ]
         ]
     }
     }
-    
+
     func setButtonMore(named: String, image: UIImage) {
     func setButtonMore(named: String, image: UIImage) {
         namedButtonMore = named
         namedButtonMore = named
         buttonMore.setImage(image, for: .normal)
         buttonMore.setImage(image, for: .normal)
@@ -180,7 +181,7 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     }
     }
 
 
     func selected(_ status: Bool) {
     func selected(_ status: Bool) {
-        guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId), !metadata.isDownloadUpload else {
+        guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId), !metadata.isInTransfer else {
             imageSelect.isHidden = true
             imageSelect.isHidden = true
             imageVisualEffect.isHidden = true
             imageVisualEffect.isHidden = true
             return
             return
@@ -218,16 +219,16 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
 }
 }
 
 
 protocol NCGridCellDelegate: AnyObject {
 protocol NCGridCellDelegate: AnyObject {
-    func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any)
-    func longPressMoreGridItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer)
-    func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer)
+    func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any)
+    func longPressMoreGridItem(with objectId: String, namedButtonMore: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer)
+    func longPressGridItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer)
 }
 }
 
 
 // optional func
 // optional func
 extension NCGridCellDelegate {
 extension NCGridCellDelegate {
-    func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) {}
-    func longPressMoreGridItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) {}
-    func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) {}
+    func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any) {}
+    func longPressMoreGridItem(with objectId: String, namedButtonMore: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {}
+    func longPressGridItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {}
 }
 }
 
 
 // MARK: - Grid Layout
 // MARK: - Grid Layout

+ 19 - 18
iOSClient/Main/Collection Common/NCListCell.swift

@@ -48,12 +48,13 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
 
 
     private var objectId = ""
     private var objectId = ""
     private var user = ""
     private var user = ""
+    var indexPath = IndexPath()
 
 
     weak var delegate: NCListCellDelegate?
     weak var delegate: NCListCellDelegate?
     var namedButtonMore = ""
     var namedButtonMore = ""
 
 
     var fileAvatarImageView: UIImageView? {
     var fileAvatarImageView: UIImageView? {
-        get { return imageShared }
+        return imageShared
     }
     }
     var fileObjectId: String? {
     var fileObjectId: String? {
         get { return objectId }
         get { return objectId }
@@ -120,7 +121,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
         accessibilityValue = nil
         accessibilityValue = nil
         isAccessibilityElement = true
         isAccessibilityElement = true
 
 
-        progressView.tintColor = NCBrandColor.shared.brandElement
+        progressView.tintColor = NCBrandColor.shared.brand
         progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5)
         progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5)
         progressView.trackTintColor = .clear
         progressView.trackTintColor = .clear
 
 
@@ -156,21 +157,21 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? {
     override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? {
         return nil
         return nil
     }
     }
-    
+
     @IBAction func touchUpInsideShare(_ sender: Any) {
     @IBAction func touchUpInsideShare(_ sender: Any) {
-        delegate?.tapShareListItem(with: objectId, sender: sender)
+        delegate?.tapShareListItem(with: objectId, indexPath: indexPath, sender: sender)
     }
     }
 
 
     @IBAction func touchUpInsideMore(_ sender: Any) {
     @IBAction func touchUpInsideMore(_ sender: Any) {
-        delegate?.tapMoreListItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, sender: sender)
+        delegate?.tapMoreListItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, indexPath: indexPath, sender: sender)
     }
     }
 
 
     @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) {
     @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) {
-        delegate?.longPressMoreListItem(with: objectId, namedButtonMore: namedButtonMore, gestureRecognizer: gestureRecognizer)
+        delegate?.longPressMoreListItem(with: objectId, namedButtonMore: namedButtonMore, indexPath: indexPath, gestureRecognizer: gestureRecognizer)
     }
     }
 
 
     @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) {
     @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) {
-        delegate?.longPressListItem(with: objectId, gestureRecognizer: gestureRecognizer)
+        delegate?.longPressListItem(with: objectId, indexPath: indexPath, gestureRecognizer: gestureRecognizer)
     }
     }
 
 
     fileprivate func setA11yActions() {
     fileprivate func setA11yActions() {
@@ -196,7 +197,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
         titleTrailingConstraint.constant = 90
         titleTrailingConstraint.constant = 90
         infoTrailingConstraint.constant = 90
         infoTrailingConstraint.constant = 90
     }
     }
-    
+
     func setButtonMore(named: String, image: UIImage) {
     func setButtonMore(named: String, image: UIImage) {
         namedButtonMore = named
         namedButtonMore = named
         imageMore.image = image
         imageMore.image = image
@@ -240,7 +241,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     }
     }
 
 
     func selected(_ status: Bool) {
     func selected(_ status: Bool) {
-        guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId), !metadata.isDownloadUpload else {
+        guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId), !metadata.isInTransfer else {
             backgroundView = nil
             backgroundView = nil
             separator.isHidden = false
             separator.isHidden = false
             return
             return
@@ -291,7 +292,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
                 tag0.text = tag
                 tag0.text = tag
                 if tags.count > 1 {
                 if tags.count > 1 {
                     tag1.isHidden = false
                     tag1.isHidden = false
-                    tag1.text = "+\(tags.count-1)"
+                    tag1.text = "+\(tags.count - 1)"
                 }
                 }
             }
             }
         }
         }
@@ -299,18 +300,18 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
 }
 }
 
 
 protocol NCListCellDelegate: AnyObject {
 protocol NCListCellDelegate: AnyObject {
-    func tapShareListItem(with objectId: String, sender: Any)
-    func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any)
-    func longPressMoreListItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer)
-    func longPressListItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer)
+    func tapShareListItem(with objectId: String, indexPath: IndexPath, sender: Any)
+    func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any)
+    func longPressMoreListItem(with objectId: String, namedButtonMore: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer)
+    func longPressListItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer)
 }
 }
 
 
 // optional func
 // optional func
 extension NCListCellDelegate {
 extension NCListCellDelegate {
-    func tapShareListItem(with objectId: String, sender: Any) {}
-    func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, sender: Any) {}
-    func longPressMoreListItem(with objectId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) {}
-    func longPressListItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) {}
+    func tapShareListItem(with objectId: String, indexPath: IndexPath, sender: Any) {}
+    func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any) {}
+    func longPressMoreListItem(with objectId: String, namedButtonMore: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {}
+    func longPressListItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {}
 }
 }
 
 
 // MARK: - List Layout
 // MARK: - List Layout

+ 7 - 5
iOSClient/Main/Collection Common/NCSelectableNavigationView.swift

@@ -40,13 +40,14 @@ protocol NCSelectableNavigationView: AnyObject {
     var collectionView: UICollectionView! { get set }
     var collectionView: UICollectionView! { get set }
     var isEditMode: Bool { get set }
     var isEditMode: Bool { get set }
     var selectOcId: [String] { get set }
     var selectOcId: [String] { get set }
+    var selectIndexPath: [IndexPath] { get set }
     var titleCurrentFolder: String { get }
     var titleCurrentFolder: String { get }
     var navigationItem: UINavigationItem { get }
     var navigationItem: UINavigationItem { get }
     var navigationController: UINavigationController? { get }
     var navigationController: UINavigationController? { get }
     var layoutKey: String { get }
     var layoutKey: String { get }
     var selectActions: [NCMenuAction] { get }
     var selectActions: [NCMenuAction] { get }
 
 
-    func reloadDataSource(forced: Bool)
+    func reloadDataSource(isForced: Bool)
     func setNavigationItem()
     func setNavigationItem()
 
 
     func tapSelectMenu()
     func tapSelectMenu()
@@ -77,6 +78,7 @@ extension NCSelectableNavigationView {
     func tapSelect() {
     func tapSelect() {
         isEditMode = !isEditMode
         isEditMode = !isEditMode
         selectOcId.removeAll()
         selectOcId.removeAll()
+        selectIndexPath.removeAll()
         self.setNavigationItem()
         self.setNavigationItem()
         self.collectionView.reloadData()
         self.collectionView.reloadData()
     }
     }
@@ -152,13 +154,13 @@ extension NCSelectableNavigationView where Self: UIViewController {
             actions.append(.saveMediaAction(selectedMediaMetadatas: selectedMediaMetadatas, completion: tapSelect))
             actions.append(.saveMediaAction(selectedMediaMetadatas: selectedMediaMetadatas, completion: tapSelect))
         }
         }
         actions.append(.setAvailableOfflineAction(selectedMetadatas: selectedMetadatas, isAnyOffline: isAnyOffline, viewController: self, completion: {
         actions.append(.setAvailableOfflineAction(selectedMetadatas: selectedMetadatas, isAnyOffline: isAnyOffline, viewController: self, completion: {
-            self.reloadDataSource(forced: true)
+            self.reloadDataSource(isForced: true)
             self.tapSelect()
             self.tapSelect()
         }))
         }))
 
 
-        actions.append(.moveOrCopyAction(selectedMetadatas: selectedMetadatas, completion: tapSelect))
-        actions.append(.copyAction(selectOcId: selectOcId, hudView: self.view, completion: tapSelect))
-        actions.append(.deleteAction(selectedMetadatas: selectedMetadatas, viewController: self, completion: tapSelect))
+        actions.append(.moveOrCopyAction(selectedMetadatas: selectedMetadatas, indexPath: selectIndexPath, completion: tapSelect))
+        actions.append(.copyAction(selectOcId: selectOcId, completion: tapSelect))
+        actions.append(.deleteAction(selectedMetadatas: selectedMetadatas, indexPath: selectIndexPath, viewController: self, completion: tapSelect))
         return actions
         return actions
     }
     }
 }
 }

+ 18 - 19
iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift

@@ -27,7 +27,7 @@ import NextcloudKit
 import Photos
 import Photos
 import JGProgressHUD
 import JGProgressHUD
 
 
-protocol NCCreateFormUploadConflictDelegate {
+protocol NCCreateFormUploadConflictDelegate: AnyObject {
     func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?)
     func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?)
 }
 }
 
 
@@ -58,7 +58,7 @@ class NCCreateFormUploadConflict: UIViewController {
 
 
     var metadatasConflictNewFiles: [String] = []
     var metadatasConflictNewFiles: [String] = []
     var metadatasConflictAlreadyExistingFiles: [String] = []
     var metadatasConflictAlreadyExistingFiles: [String] = []
-    let fileNamesPath = ThreadSafeDictionary<String,String>()
+    let fileNamesPath = ThreadSafeDictionary<String, String>()
     var blurView: UIVisualEffectView!
     var blurView: UIVisualEffectView!
 
 
     // MARK: - View Life Cycle
     // MARK: - View Life Cycle
@@ -256,7 +256,7 @@ class NCCreateFormUploadConflict: UIViewController {
                 metadata.fileNameView = newFileName
                 metadata.fileNameView = newFileName
 
 
                 // This is not an asset - [file]
                 // This is not an asset - [file]
-                if metadata.assetLocalIdentifier == "" || metadata.isExtractFile {
+                if metadata.assetLocalIdentifier.isEmpty || metadata.isExtractFile {
                     let newPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: newFileName)
                     let newPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: newFileName)
                     CCUtility.moveFile(atPath: oldPath, toPath: newPath)
                     CCUtility.moveFile(atPath: oldPath, toPath: newPath)
                 }
                 }
@@ -311,8 +311,8 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
             cell.backgroundColor = tableView.backgroundColor
             cell.backgroundColor = tableView.backgroundColor
             cell.switchNewFile.onTintColor = NCBrandColor.shared.brand
             cell.switchNewFile.onTintColor = NCBrandColor.shared.brand
             cell.switchAlreadyExistingFile.onTintColor = NCBrandColor.shared.brand
             cell.switchAlreadyExistingFile.onTintColor = NCBrandColor.shared.brand
-            
-            let metadataNewFile =  tableMetadata.init(value: metadatasUploadInConflict[indexPath.row])
+
+            let metadataNewFile = tableMetadata.init(value: metadatasUploadInConflict[indexPath.row])
 
 
             cell.ocId = metadataNewFile.ocId
             cell.ocId = metadataNewFile.ocId
             cell.delegate = self
             cell.delegate = self
@@ -324,7 +324,7 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
 
 
             guard let metadataAlreadyExists = NCManageDatabase.shared.getMetadataConflict(account: metadataNewFile.account, serverUrl: metadataNewFile.serverUrl, fileNameView: metadataNewFile.fileNameView) else { return UITableViewCell() }
             guard let metadataAlreadyExists = NCManageDatabase.shared.getMetadataConflict(account: metadataNewFile.account, serverUrl: metadataNewFile.serverUrl, fileNameView: metadataNewFile.fileNameView) else { return UITableViewCell() }
             if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadataAlreadyExists.ocId, etag: metadataAlreadyExists.etag)) {
             if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadataAlreadyExists.ocId, etag: metadataAlreadyExists.etag)) {
-                cell.imageAlreadyExistingFile.image =  UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadataAlreadyExists.ocId, etag: metadataAlreadyExists.etag))
+                cell.imageAlreadyExistingFile.image = UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadataAlreadyExists.ocId, etag: metadataAlreadyExists.etag))
             } else if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageOcId(metadataAlreadyExists.ocId, fileNameView: metadataAlreadyExists.fileNameView)) && metadataAlreadyExists.contentType == "application/pdf" {
             } else if FileManager().fileExists(atPath: CCUtility.getDirectoryProviderStorageOcId(metadataAlreadyExists.ocId, fileNameView: metadataAlreadyExists.fileNameView)) && metadataAlreadyExists.contentType == "application/pdf" {
 
 
                 let url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadataAlreadyExists.ocId, fileNameView: metadataAlreadyExists.fileNameView))
                 let url = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadataAlreadyExists.ocId, fileNameView: metadataAlreadyExists.fileNameView))
@@ -335,10 +335,10 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
                 }
                 }
 
 
             } else {
             } else {
-                if metadataAlreadyExists.iconName.count > 0 {
-                    cell.imageAlreadyExistingFile.image = UIImage(named: metadataAlreadyExists.iconName)
-                } else {
+                if metadataAlreadyExists.iconName.isEmpty {
                     cell.imageAlreadyExistingFile.image = UIImage(named: "file")
                     cell.imageAlreadyExistingFile.image = UIImage(named: "file")
+                } else {
+                    cell.imageAlreadyExistingFile.image = UIImage(named: metadataAlreadyExists.iconName)
                 }
                 }
             }
             }
             cell.labelDetailAlreadyExistingFile.text = CCUtility.dateDiff(metadataAlreadyExists.date as Date) + "\n" + CCUtility.transformedSize(metadataAlreadyExists.size)
             cell.labelDetailAlreadyExistingFile.text = CCUtility.dateDiff(metadataAlreadyExists.date as Date) + "\n" + CCUtility.transformedSize(metadataAlreadyExists.size)
@@ -351,13 +351,13 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
 
 
             // -----> New File
             // -----> New File
 
 
-            if metadataNewFile.iconName.count > 0 {
-                cell.imageNewFile.image = UIImage(named: metadataNewFile.iconName)
-            } else {
+            if metadataNewFile.iconName.isEmpty {
                 cell.imageNewFile.image = UIImage(named: "file")
                 cell.imageNewFile.image = UIImage(named: "file")
+            } else {
+                cell.imageNewFile.image = UIImage(named: metadataNewFile.iconName)
             }
             }
             let filePathNewFile = CCUtility.getDirectoryProviderStorageOcId(metadataNewFile.ocId, fileNameView: metadataNewFile.fileNameView)!
             let filePathNewFile = CCUtility.getDirectoryProviderStorageOcId(metadataNewFile.ocId, fileNameView: metadataNewFile.fileNameView)!
-            if metadataNewFile.assetLocalIdentifier.count > 0 {
+            if !metadataNewFile.assetLocalIdentifier.isEmpty {
 
 
                 let result = PHAsset.fetchAssets(withLocalIdentifiers: [metadataNewFile.assetLocalIdentifier], options: nil)
                 let result = PHAsset.fetchAssets(withLocalIdentifiers: [metadataNewFile.assetLocalIdentifier], options: nil)
                 let date = result.firstObject!.modificationDate
                 let date = result.firstObject!.modificationDate
@@ -378,7 +378,7 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
                         }
                         }
 
 
                         let fileDictionary = try FileManager.default.attributesOfItem(atPath: fileNamePath)
                         let fileDictionary = try FileManager.default.attributesOfItem(atPath: fileNamePath)
-                        let fileSize = fileDictionary[FileAttributeKey.size] as! Int64
+                        let fileSize = fileDictionary[FileAttributeKey.size] as? Int64 ?? 0
 
 
                         cell.labelDetailNewFile.text = CCUtility.dateDiff(date) + "\n" + CCUtility.transformedSize(fileSize)
                         cell.labelDetailNewFile.text = CCUtility.dateDiff(date) + "\n" + CCUtility.transformedSize(fileSize)
 
 
@@ -388,12 +388,12 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
 
 
                     // PREVIEW
                     // PREVIEW
                     let cameraRoll = NCCameraRoll()
                     let cameraRoll = NCCameraRoll()
-                    cameraRoll.extractImageVideoFromAssetLocalIdentifier(metadata: metadataNewFile, modifyMetadataForUpload: false, viewController: self, hud: JGProgressHUD()) { metadata, fileNamePath, error in
+                    cameraRoll.extractImageVideoFromAssetLocalIdentifier(metadata: metadataNewFile, modifyMetadataForUpload: false, viewController: self, hud: JGProgressHUD()) { _, fileNamePath, error in
                         if !error {
                         if !error {
                             self.fileNamesPath[metadataNewFile.fileNameView] = fileNamePath!
                             self.fileNamesPath[metadataNewFile.fileNameView] = fileNamePath!
                             do {
                             do {
                                 let fileDictionary = try FileManager.default.attributesOfItem(atPath: fileNamePath!)
                                 let fileDictionary = try FileManager.default.attributesOfItem(atPath: fileNamePath!)
-                                let fileSize = fileDictionary[FileAttributeKey.size] as! Int64
+                                let fileSize = fileDictionary[FileAttributeKey.size] as? Int64 ?? 0
                                 if mediaType == PHAssetMediaType.image {
                                 if mediaType == PHAssetMediaType.image {
                                     let data = try Data(contentsOf: URL(fileURLWithPath: fileNamePath!))
                                     let data = try Data(contentsOf: URL(fileURLWithPath: fileNamePath!))
                                     if let image = UIImage(data: data) {
                                     if let image = UIImage(data: data) {
@@ -413,7 +413,7 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
             } else if FileManager().fileExists(atPath: filePathNewFile) {
             } else if FileManager().fileExists(atPath: filePathNewFile) {
 
 
                 do {
                 do {
-                    if metadataNewFile.classFile ==  NKCommon.TypeClassFile.image.rawValue {
+                    if metadataNewFile.classFile == NKCommon.TypeClassFile.image.rawValue {
                         // preserver memory especially for very large files in Share extension
                         // preserver memory especially for very large files in Share extension
                         if let image = UIImage.downsample(imageAt: URL(fileURLWithPath: filePathNewFile), to: cell.imageNewFile.frame.size) {
                         if let image = UIImage.downsample(imageAt: URL(fileURLWithPath: filePathNewFile), to: cell.imageNewFile.frame.size) {
                             cell.imageNewFile.image = image
                             cell.imageNewFile.image = image
@@ -421,7 +421,7 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
                     }
                     }
 
 
                     let fileDictionary = try FileManager.default.attributesOfItem(atPath: filePathNewFile)
                     let fileDictionary = try FileManager.default.attributesOfItem(atPath: filePathNewFile)
-                    let fileSize = fileDictionary[FileAttributeKey.size] as! Int64
+                    let fileSize = fileDictionary[FileAttributeKey.size] as? Int64 ?? 0
 
 
                     cell.labelDetailNewFile.text = CCUtility.dateDiff(metadataNewFile.date as Date) + "\n" + CCUtility.transformedSize(fileSize)
                     cell.labelDetailNewFile.text = CCUtility.dateDiff(metadataNewFile.date as Date) + "\n" + CCUtility.transformedSize(fileSize)
 
 
@@ -521,7 +521,6 @@ struct UploadConflictView: UIViewControllerRepresentable {
     var metadatasUploadInConflict: [tableMetadata]
     var metadatasUploadInConflict: [tableMetadata]
     var metadatasNOConflict: [tableMetadata]
     var metadatasNOConflict: [tableMetadata]
 
 
-
     func makeUIViewController(context: Context) -> UIViewControllerType {
     func makeUIViewController(context: Context) -> UIViewControllerType {
 
 
         let storyboard = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil)
         let storyboard = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil)

+ 62 - 72
iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift

@@ -33,7 +33,9 @@ import XLForm
     @IBOutlet weak var collectionView: UICollectionView!
     @IBOutlet weak var collectionView: UICollectionView!
     @IBOutlet weak var collectionViewHeigth: NSLayoutConstraint!
     @IBOutlet weak var collectionViewHeigth: NSLayoutConstraint!
 
 
+    // swiftlint:disable force_cast
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
 
 
     var editorId = ""
     var editorId = ""
     var creatorId = ""
     var creatorId = ""
@@ -83,8 +85,6 @@ import XLForm
         getTemplate()
         getTemplate()
     }
     }
 
 
-
-
     // MARK: - Tableview (XLForm)
     // MARK: - Tableview (XLForm)
 
 
     func initializeForm() {
     func initializeForm() {
@@ -105,7 +105,7 @@ import XLForm
         row.value = fileNameFolder
         row.value = fileNameFolder
         row.cellConfig["backgroundColor"] = tableView.backgroundColor
         row.cellConfig["backgroundColor"] = tableView.backgroundColor
 
 
-        row.cellConfig["imageView.image"] =  UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25)
+        row.cellConfig["imageView.image"] = UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25)
 
 
         row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue
         row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue
         row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
         row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
@@ -133,15 +133,15 @@ import XLForm
         section.addFormRow(row)
         section.addFormRow(row)
 
 
         self.form = form
         self.form = form
-        //tableView.reloadData()
-        //collectionView.reloadData()
+        // tableView.reloadData()
+        // collectionView.reloadData()
     }
     }
 
 
     override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
     override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
-        let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
-        header.textLabel?.font = UIFont.systemFont(ofSize: 13.0)
-        header.textLabel?.textColor = .gray
-        header.tintColor = tableView.backgroundColor
+        let header = view as? UITableViewHeaderFooterView
+        header?.textLabel?.font = UIFont.systemFont(ofSize: 13.0)
+        header?.textLabel?.textColor = .gray
+        header?.tintColor = tableView.backgroundColor
     }
     }
 
 
     // MARK: - CollectionView
     // MARK: - CollectionView
@@ -167,13 +167,13 @@ import XLForm
         let template = listOfTemplate[indexPath.row]
         let template = listOfTemplate[indexPath.row]
 
 
         // image
         // image
-        let imagePreview = cell.viewWithTag(100) as! UIImageView
-        if template.preview != "" {
+        let imagePreview = cell.viewWithTag(100) as? UIImageView
+        if !template.preview.isEmpty {
             let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + template.name + ".png"
             let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + template.name + ".png"
             if FileManager.default.fileExists(atPath: fileNameLocalPath) {
             if FileManager.default.fileExists(atPath: fileNameLocalPath) {
                 let imageURL = URL(fileURLWithPath: fileNameLocalPath)
                 let imageURL = URL(fileURLWithPath: fileNameLocalPath)
                 if let image = UIImage(contentsOfFile: imageURL.path) {
                 if let image = UIImage(contentsOfFile: imageURL.path) {
-                    imagePreview.image = image
+                    imagePreview?.image = image
                 }
                 }
             } else {
             } else {
                 getImageFromTemplate(name: template.name, preview: template.preview, indexPath: indexPath)
                 getImageFromTemplate(name: template.name, preview: template.preview, indexPath: indexPath)
@@ -181,19 +181,19 @@ import XLForm
         }
         }
 
 
         // name
         // name
-        let name = cell.viewWithTag(200) as! UILabel
-        name.text = template.name
-        name.textColor = .secondarySystemGroupedBackground
+        let name = cell.viewWithTag(200) as? UILabel
+        name?.text = template.name
+        name?.textColor = .secondarySystemGroupedBackground
 
 
         // select
         // select
-        let imageSelect = cell.viewWithTag(300) as! UIImageView
+        let imageSelect = cell.viewWithTag(300) as? UIImageView
         if selectTemplate != nil && selectTemplate?.name == template.name {
         if selectTemplate != nil && selectTemplate?.name == template.name {
             cell.backgroundColor = .label
             cell.backgroundColor = .label
-            imageSelect.image = UIImage(named: "plus100")
-            imageSelect.isHidden = false
+            imageSelect?.image = UIImage(named: "plus100")
+            imageSelect?.isHidden = false
         } else {
         } else {
             cell.backgroundColor = .secondarySystemGroupedBackground
             cell.backgroundColor = .secondarySystemGroupedBackground
-            imageSelect.isHidden = true
+            imageSelect?.isHidden = true
         }
         }
 
 
         return cell
         return cell
@@ -211,7 +211,7 @@ import XLForm
 
 
     // MARK: - Action
     // MARK: - Action
 
 
-    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) {
+    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) {
 
 
         guard let serverUrl = serverUrl else {
         guard let serverUrl = serverUrl else {
             return
             return
@@ -224,7 +224,7 @@ import XLForm
             fileNameFolder = (serverUrl as NSString).lastPathComponent
             fileNameFolder = (serverUrl as NSString).lastPathComponent
         }
         }
 
 
-        let buttonDestinationFolder: XLFormRowDescriptor  = self.form.formRow(withTag: "ButtonDestinationFolder")!
+        let buttonDestinationFolder: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")!
         buttonDestinationFolder.title = fileNameFolder
         buttonDestinationFolder.title = fileNameFolder
 
 
         self.tableView.reloadData()
         self.tableView.reloadData()
@@ -235,13 +235,14 @@ import XLForm
         self.deselectFormRow(sender)
         self.deselectFormRow(sender)
 
 
         let storyboard = UIStoryboard(name: "NCSelect", bundle: nil)
         let storyboard = UIStoryboard(name: "NCSelect", bundle: nil)
-        let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController
-        let viewController = navigationController.topViewController as! NCSelect
+        if let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController,
+           let viewController = navigationController.topViewController as? NCSelect {
 
 
-        viewController.delegate = self
-        viewController.typeOfCommandView = .selectCreateFolder
+            viewController.delegate = self
+            viewController.typeOfCommandView = .selectCreateFolder
 
 
-        self.present(navigationController, animated: true, completion: nil)
+            self.present(navigationController, animated: true, completion: nil)
+        }
     }
     }
 
 
     @objc func save() {
     @objc func save() {
@@ -251,59 +252,48 @@ import XLForm
         }
         }
         templateIdentifier = selectTemplate.identifier
         templateIdentifier = selectTemplate.identifier
 
 
-        let rowFileName: XLFormRowDescriptor  = self.form.formRow(withTag: "fileName")!
-        guard var fileNameForm = rowFileName.value else {
-            return
-        }
-
-        if fileNameForm as! String == "" {
-            return
-        } else {
+        let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")!
+        guard var fileNameForm: String = rowFileName.value as? String, !fileNameForm.isEmpty else { return }
 
 
-            //Trim whitespaces after checks above
-            fileNameForm = (fileNameForm as! String).trimmingCharacters(in: .whitespacesAndNewlines)
+        // Trim whitespaces after checks above
+        fileNameForm = fileNameForm.trimmingCharacters(in: .whitespacesAndNewlines)
 
 
-            let result = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileNameForm as! String, mimeType: "", directory: false)
-            if NCUtility.shared.isDirectEditing(account: appDelegate.account, contentType: result.mimeType).count == 0 {
-                fileNameForm = (fileNameForm as! NSString).deletingPathExtension + "." + fileNameExtension
-            }
+        let result = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileNameForm, mimeType: "", directory: false)
+        if NCUtility.shared.isDirectEditing(account: appDelegate.account, contentType: result.mimeType).isEmpty {
+            fileNameForm = (fileNameForm as NSString).deletingPathExtension + "." + fileNameExtension
+        }
 
 
-            if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileNameView: String(describing: fileNameForm)) != nil {
+        if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileNameView: String(describing: fileNameForm)) != nil {
 
 
-                let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: String(describing: fileNameForm), fileNameView: String(describing: fileNameForm), ocId: "", serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "")
+            let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: String(describing: fileNameForm), fileNameView: String(describing: fileNameForm), ocId: "", serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "")
 
 
-                guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return }
+            guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return }
 
 
-                conflict.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "")
-                conflict.alwaysNewFileNameNumber = true
-                conflict.serverUrl = serverUrl
-                conflict.metadatasUploadInConflict = [metadataForUpload]
-                conflict.delegate = self
+            conflict.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "")
+            conflict.alwaysNewFileNameNumber = true
+            conflict.serverUrl = serverUrl
+            conflict.metadatasUploadInConflict = [metadataForUpload]
+            conflict.delegate = self
 
 
-                self.present(conflict, animated: true, completion: nil)
+            self.present(conflict, animated: true, completion: nil)
 
 
-            } else {
+        } else {
 
 
-                let fileNamePath = CCUtility.returnFileNamePath(fromFileName: String(describing: fileNameForm), serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account)!
-                createDocument(fileNamePath: fileNamePath, fileName: String(describing: fileNameForm))
-            }
+            let fileNamePath = CCUtility.returnFileNamePath(fromFileName: String(describing: fileNameForm), serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account)!
+            createDocument(fileNamePath: fileNamePath, fileName: String(describing: fileNameForm))
         }
         }
     }
     }
 
 
     func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
     func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
 
 
-        if metadatas == nil || metadatas?.count == 0 {
-
+        if let metadatas {
+            let fileName = metadatas[0].fileName
+            let fileNamePath = CCUtility.returnFileNamePath(fromFileName: fileName, serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account)!
+            createDocument(fileNamePath: fileNamePath, fileName: fileName)
+        } else {
             DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
             DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                 self.cancel()
                 self.cancel()
             }
             }
-
-        } else {
-
-            let fileName = metadatas![0].fileName
-            let fileNamePath = CCUtility.returnFileNamePath(fromFileName: fileName, serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account)!
-
-            createDocument(fileNamePath: fileNamePath, fileName: fileName)
         }
         }
     }
     }
 
 
@@ -314,7 +304,7 @@ import XLForm
         UUID = "TEMP" + UUID.replacingOccurrences(of: "-", with: "")
         UUID = "TEMP" + UUID.replacingOccurrences(of: "-", with: "")
 
 
         if self.editorId == NCGlobal.shared.editorText || self.editorId == NCGlobal.shared.editorOnlyoffice {
         if self.editorId == NCGlobal.shared.editorText || self.editorId == NCGlobal.shared.editorOnlyoffice {
-            
+
             var options = NKRequestOptions()
             var options = NKRequestOptions()
             if self.editorId == NCGlobal.shared.editorOnlyoffice {
             if self.editorId == NCGlobal.shared.editorOnlyoffice {
                 options = NKRequestOptions(customUserAgent: NCUtility.shared.getCustomUserAgentOnlyOffice())
                 options = NKRequestOptions(customUserAgent: NCUtility.shared.getCustomUserAgentOnlyOffice())
@@ -322,7 +312,7 @@ import XLForm
                 options = NKRequestOptions(customUserAgent: NCUtility.shared.getCustomUserAgentNCText())
                 options = NKRequestOptions(customUserAgent: NCUtility.shared.getCustomUserAgentNCText())
             }
             }
 
 
-            NextcloudKit.shared.NCTextCreateFile(fileNamePath: fileNamePath, editorId: editorId, creatorId: creatorId, templateId: templateIdentifier, options: options) { account, url, data, error in
+            NextcloudKit.shared.NCTextCreateFile(fileNamePath: fileNamePath, editorId: editorId, creatorId: creatorId, templateId: templateIdentifier, options: options) { account, url, _, error in
                 guard error == .success, account == self.appDelegate.account, let url = url else {
                 guard error == .success, account == self.appDelegate.account, let url = url else {
                     self.navigationItem.rightBarButtonItem?.isEnabled = true
                     self.navigationItem.rightBarButtonItem?.isEnabled = true
                     NCContentPresenter.shared.showError(error: error)
                     NCContentPresenter.shared.showError(error: error)
@@ -330,7 +320,7 @@ import XLForm
                 }
                 }
 
 
                 var results = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileName, mimeType: "", directory: false)
                 var results = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileName, mimeType: "", directory: false)
-                //FIXME: iOS 12.0,* don't detect UTI text/markdown, text/x-markdown
+                // FIXME: iOS 12.0,* don't detect UTI text/markdown, text/x-markdown
                 if results.mimeType.isEmpty {
                 if results.mimeType.isEmpty {
                     results.mimeType = "text/x-markdown"
                     results.mimeType = "text/x-markdown"
                 }
                 }
@@ -346,7 +336,7 @@ import XLForm
 
 
         if self.editorId == NCGlobal.shared.editorCollabora {
         if self.editorId == NCGlobal.shared.editorCollabora {
 
 
-            NextcloudKit.shared.createRichdocuments(path: fileNamePath, templateId: templateIdentifier) { account, url, data, error in
+            NextcloudKit.shared.createRichdocuments(path: fileNamePath, templateId: templateIdentifier) { account, url, _, error in
                 guard error == .success, account == self.appDelegate.account, let url = url else {
                 guard error == .success, account == self.appDelegate.account, let url = url else {
                     self.navigationItem.rightBarButtonItem?.isEnabled = true
                     self.navigationItem.rightBarButtonItem?.isEnabled = true
                     NCContentPresenter.shared.showError(error: error)
                     NCContentPresenter.shared.showError(error: error)
@@ -385,7 +375,7 @@ import XLForm
                 options = NKRequestOptions(customUserAgent: NCUtility.shared.getCustomUserAgentNCText())
                 options = NKRequestOptions(customUserAgent: NCUtility.shared.getCustomUserAgentNCText())
             }
             }
 
 
-            NextcloudKit.shared.NCTextGetListOfTemplates(options: options) { account, templates, data, error in
+            NextcloudKit.shared.NCTextGetListOfTemplates(options: options) { account, templates, _, error in
 
 
                 self.indicator.stopAnimating()
                 self.indicator.stopAnimating()
 
 
@@ -403,7 +393,7 @@ import XLForm
                         self.listOfTemplate.append(temp)
                         self.listOfTemplate.append(temp)
 
 
                         // default: template empty
                         // default: template empty
-                        if temp.preview == "" {
+                        if temp.preview.isEmpty {
                             self.selectTemplate = temp
                             self.selectTemplate = temp
                             self.fileNameExtension = template.ext
                             self.fileNameExtension = template.ext
                             self.navigationItem.rightBarButtonItem?.isEnabled = true
                             self.navigationItem.rightBarButtonItem?.isEnabled = true
@@ -411,7 +401,7 @@ import XLForm
                     }
                     }
                 }
                 }
 
 
-                if self.listOfTemplate.count == 0 {
+                if self.listOfTemplate.isEmpty {
 
 
                     let temp = NKEditorTemplates()
                     let temp = NKEditorTemplates()
 
 
@@ -442,7 +432,7 @@ import XLForm
 
 
         if self.editorId == NCGlobal.shared.editorCollabora {
         if self.editorId == NCGlobal.shared.editorCollabora {
 
 
-            NextcloudKit.shared.getTemplatesRichdocuments(typeTemplate: typeTemplate) { account, templates, data, error in
+            NextcloudKit.shared.getTemplatesRichdocuments(typeTemplate: typeTemplate) { account, templates, _, error in
 
 
                 self.indicator.stopAnimating()
                 self.indicator.stopAnimating()
 
 
@@ -462,7 +452,7 @@ import XLForm
                         self.listOfTemplate.append(temp)
                         self.listOfTemplate.append(temp)
 
 
                         // default: template empty
                         // default: template empty
-                        if temp.preview == "" {
+                        if temp.preview.isEmpty {
                             self.selectTemplate = temp
                             self.selectTemplate = temp
                             self.fileNameExtension = temp.ext
                             self.fileNameExtension = temp.ext
                             self.navigationItem.rightBarButtonItem?.isEnabled = true
                             self.navigationItem.rightBarButtonItem?.isEnabled = true
@@ -470,7 +460,7 @@ import XLForm
                     }
                     }
                 }
                 }
 
 
-                if self.listOfTemplate.count == 0 {
+                if self.listOfTemplate.isEmpty {
 
 
                     let temp = NKEditorTemplates()
                     let temp = NKEditorTemplates()
 
 

+ 27 - 27
iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift

@@ -31,7 +31,9 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
     @IBOutlet weak var labelDuration: UILabel!
     @IBOutlet weak var labelDuration: UILabel!
     @IBOutlet weak var progressView: UIProgressView!
     @IBOutlet weak var progressView: UIProgressView!
 
 
+    // swiftlint:disable force_cast
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
 
 
     private var serverUrl = ""
     private var serverUrl = ""
     private var titleServerUrl = ""
     private var titleServerUrl = ""
@@ -67,7 +69,7 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
         // Progress view
         // Progress view
         progressView.progress = 0
         progressView.progress = 0
         progressView.progressTintColor = .green
         progressView.progressTintColor = .green
-        progressView.trackTintColor = UIColor(red: 247.0/255.0, green: 247.0/255.0, blue: 247.0/255.0, alpha: 1.0)
+        progressView.trackTintColor = UIColor(red: 247.0 / 255.0, green: 247.0 / 255.0, blue: 247.0 / 255.0, alpha: 1.0)
 
 
         labelTimer.textColor = .label
         labelTimer.textColor = .label
         labelDuration.textColor = .label
         labelDuration.textColor = .label
@@ -131,7 +133,7 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
         row.action.formSelector = #selector(changeDestinationFolder(_:))
         row.action.formSelector = #selector(changeDestinationFolder(_:))
         row.cellConfig["backgroundColor"] = cellBackgoundColor
         row.cellConfig["backgroundColor"] = cellBackgoundColor
 
 
-        row.cellConfig["imageView.image"] =  UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25)
+        row.cellConfig["imageView.image"] = UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25)
 
 
         row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue
         row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue
         row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
         row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
@@ -182,15 +184,15 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
     // MARK: TableViewDelegate
     // MARK: TableViewDelegate
 
 
     override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
     override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
-        let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
-        header.textLabel?.font = UIFont.systemFont(ofSize: 13.0)
-        header.textLabel?.textColor = .gray
-        header.tintColor = cellBackgoundColor
+        let header = view as? UITableViewHeaderFooterView
+        header?.textLabel?.font = UIFont.systemFont(ofSize: 13.0)
+        header?.textLabel?.textColor = .gray
+        header?.tintColor = cellBackgoundColor
     }
     }
 
 
     // MARK: - Action
     // MARK: - Action
 
 
-    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) {
+    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) {
 
 
         if serverUrl != nil {
         if serverUrl != nil {
 
 
@@ -203,7 +205,7 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
             }
             }
 
 
             // Update
             // Update
-            let row: XLFormRowDescriptor  = self.form.formRow(withTag: "ButtonDestinationFolder")!
+            let row: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")!
             row.title = self.titleServerUrl
             row.title = self.titleServerUrl
             self.updateFormRow(row)
             self.updateFormRow(row)
         }
         }
@@ -211,17 +213,15 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
 
 
     @objc func save() {
     @objc func save() {
 
 
-        let rowFileName: XLFormRowDescriptor  = self.form.formRow(withTag: "fileName")!
-        guard let name = rowFileName.value else {
-            return
-        }
-        let ext = (name as! NSString).pathExtension.uppercased()
+        let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")!
+        guard let name = rowFileName.value as? String else { return }
+        let ext = (name as NSString).pathExtension.uppercased()
         var fileNameSave = ""
         var fileNameSave = ""
 
 
-        if ext == "" {
-            fileNameSave = name as! String + ".m4a"
+        if ext.isEmpty {
+            fileNameSave = name + ".m4a"
         } else {
         } else {
-            fileNameSave = (name as! NSString).deletingPathExtension + ".m4a"
+            fileNameSave = (name as NSString).deletingPathExtension + ".m4a"
         }
         }
 
 
         let metadataForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileNameSave, fileNameView: fileNameSave, ocId: UUID().uuidString, serverUrl: self.serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "")
         let metadataForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileNameSave, fileNameView: fileNameSave, ocId: UUID().uuidString, serverUrl: self.serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "")
@@ -234,7 +234,7 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
         if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileNameView: fileNameSave) != nil {
         if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileNameView: fileNameSave) != nil {
 
 
             guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return }
             guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return }
-            
+
             conflict.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "")
             conflict.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "")
             conflict.serverUrl = serverUrl
             conflict.serverUrl = serverUrl
             conflict.metadatasUploadInConflict = [metadataForUpload]
             conflict.metadatasUploadInConflict = [metadataForUpload]
@@ -250,10 +250,9 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
 
 
     func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
     func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
 
 
-        if metadatas != nil && metadatas!.count > 0 {
-
+        if let metadatas {
             DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
             DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
-                self.dismissAndUpload(metadatas![0])
+                self.dismissAndUpload(metadatas[0])
             }
             }
         }
         }
     }
     }
@@ -278,20 +277,21 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud
         self.deselectFormRow(sender)
         self.deselectFormRow(sender)
 
 
         let storyboard = UIStoryboard(name: "NCSelect", bundle: nil)
         let storyboard = UIStoryboard(name: "NCSelect", bundle: nil)
-        let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController
-        let viewController = navigationController.topViewController as! NCSelect
+        if let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController,
+           let viewController = navigationController.topViewController as? NCSelect {
 
 
-        viewController.delegate = self
-        viewController.typeOfCommandView = .selectCreateFolder
-        viewController.includeDirectoryE2EEncryption = true
+            viewController.delegate = self
+            viewController.typeOfCommandView = .selectCreateFolder
+            viewController.includeDirectoryE2EEncryption = true
 
 
-        self.present(navigationController, animated: true, completion: nil)
+            self.present(navigationController, animated: true, completion: nil)
+        }
     }
     }
 
 
     // MARK: Player - Timer
     // MARK: Player - Timer
 
 
     func updateTimerUI() {
     func updateTimerUI() {
-        labelTimer.text =  String().formatSecondsToString(counterSecondPlayer)
+        labelTimer.text = String().formatSecondsToString(counterSecondPlayer)
         labelDuration.text = String().formatSecondsToString(durationPlayer)
         labelDuration.text = String().formatSecondsToString(durationPlayer)
         progressView.progress = Float(counterSecondPlayer / durationPlayer)
         progressView.progress = Float(counterSecondPlayer / durationPlayer)
     }
     }

+ 8 - 5
iOSClient/Main/Create cloud/NCCreateMenuAdd.swift

@@ -26,7 +26,10 @@ import Sheeeeeeeeet
 
 
 class NCCreateMenuAdd: NSObject {
 class NCCreateMenuAdd: NSObject {
 
 
+    // swiftlint:disable force_cast
     weak var appDelegate = UIApplication.shared.delegate as! AppDelegate
     weak var appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
+
     var isNextcloudTextAvailable = false
     var isNextcloudTextAvailable = false
 
 
     @objc init(viewController: UIViewController, view: UIView) {
     @objc init(viewController: UIViewController, view: UIView) {
@@ -68,7 +71,7 @@ class NCCreateMenuAdd: NSObject {
         items.append(MenuItem(title: NSLocalizedString("_create_folder_", comment: ""), value: 60, image: CCGraphics.changeThemingColorImage(UIImage(named: "folder"), width: 50, height: 50, color: NCBrandColor.sharedInstance.brandElement)))
         items.append(MenuItem(title: NSLocalizedString("_create_folder_", comment: ""), value: 60, image: CCGraphics.changeThemingColorImage(UIImage(named: "folder"), width: 50, height: 50, color: NCBrandColor.sharedInstance.brandElement)))
 
 
         if let richdocumentsMimetypes = NCManageDatabase.sharedInstance.getRichdocumentsMimetypes(account: appDelegate.activeAccount) {
         if let richdocumentsMimetypes = NCManageDatabase.sharedInstance.getRichdocumentsMimetypes(account: appDelegate.activeAccount) {
-            if richdocumentsMimetypes.count > 0 {
+            if !richdocumentsMimetypes.isEmpty {
                 items.append(MenuItem(title: NSLocalizedString("_create_new_document_", comment: ""), value: 70, image: UIImage(named: "create_file_document")))
                 items.append(MenuItem(title: NSLocalizedString("_create_new_document_", comment: ""), value: 70, image: UIImage(named: "create_file_document")))
                 items.append(MenuItem(title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), value: 80, image: UIImage(named: "create_file_xls")))
                 items.append(MenuItem(title: NSLocalizedString("_create_new_spreadsheet_", comment: ""), value: 80, image: UIImage(named: "create_file_xls")))
                 items.append(MenuItem(title: NSLocalizedString("_create_new_presentation_", comment: ""), value: 90, image: UIImage(named: "create_file_ppt")))
                 items.append(MenuItem(title: NSLocalizedString("_create_new_presentation_", comment: ""), value: 90, image: UIImage(named: "create_file_ppt")))
@@ -96,7 +99,7 @@ class NCCreateMenuAdd: NSObject {
                 }
                 }
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
+                let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments
                 viewController.typeTemplate = k_template_document
                 viewController.typeTemplate = k_template_document
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
                 viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
@@ -119,7 +122,7 @@ class NCCreateMenuAdd: NSObject {
                 }
                 }
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
+                let viewController = (navigationController as? UINavigationController).topViewController as? NCCreateFormUploadDocuments
                 viewController.typeTemplate = k_template_document
                 viewController.typeTemplate = k_template_document
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.titleForm = NSLocalizedString("_create_new_document_", comment: "")
                 viewController.titleForm = NSLocalizedString("_create_new_document_", comment: "")
@@ -132,7 +135,7 @@ class NCCreateMenuAdd: NSObject {
                 }
                 }
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
+                let viewController = (navigationController as? UINavigationController).topViewController as? NCCreateFormUploadDocuments
                 viewController.typeTemplate = k_template_spreadsheet
                 viewController.typeTemplate = k_template_spreadsheet
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "")
                 viewController.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "")
@@ -145,7 +148,7 @@ class NCCreateMenuAdd: NSObject {
                 }
                 }
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                 navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
+                let viewController = (navigationController as? UINavigationController).topViewController as? NCCreateFormUploadDocuments
                 viewController.typeTemplate = k_template_presentation
                 viewController.typeTemplate = k_template_presentation
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.serverUrl = self.appDelegate.activeMain.serverUrl
                 viewController.titleForm = NSLocalizedString("_create_new_presentation_", comment: "")
                 viewController.titleForm = NSLocalizedString("_create_new_presentation_", comment: "")

+ 70 - 97
iOSClient/Main/NCActionCenter.swift

@@ -121,24 +121,6 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
         case NCGlobal.shared.selectorSaveAlbum:
         case NCGlobal.shared.selectorSaveAlbum:
             saveAlbum(metadata: metadata)
             saveAlbum(metadata: metadata)
 
 
-        case NCGlobal.shared.selectorSaveAlbumLivePhotoIMG, NCGlobal.shared.selectorSaveAlbumLivePhotoMOV:
-
-            var metadata = metadata
-            var metadataMOV = metadata
-            guard let metadataTMP = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) else { break }
-
-            if selector == NCGlobal.shared.selectorSaveAlbumLivePhotoIMG {
-                metadataMOV = metadataTMP
-            }
-
-            if selector == NCGlobal.shared.selectorSaveAlbumLivePhotoMOV {
-                metadata = metadataTMP
-            }
-
-            if CCUtility.fileProviderStorageExists(metadata) && CCUtility.fileProviderStorageExists(metadataMOV) {
-                saveLivePhotoToDisk(metadata: metadata, metadataMov: metadataMOV)
-            }
-
         case NCGlobal.shared.selectorSaveAsScan:
         case NCGlobal.shared.selectorSaveAsScan:
             saveAsScan(metadata: metadata)
             saveAsScan(metadata: metadata)
 
 
@@ -162,7 +144,7 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
             }
             }
         } else if metadata.directory {
         } else if metadata.directory {
             NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, offline: true, account: appDelegate.account)
             NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, offline: true, account: appDelegate.account)
-            NCOperationQueue.shared.synchronizationMetadata(metadata, selector: NCGlobal.shared.selectorDownloadAllFile)
+            NCNetworking.shared.synchronizationServerUrl(serverUrl, account: metadata.account, selector: NCGlobal.shared.selectorSynchronizationOffline)
         } else {
         } else {
             NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadOffline) { _, _ in }
             NCNetworking.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorLoadOffline) { _, _ in }
             if let metadataLivePhoto = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) {
             if let metadataLivePhoto = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) {
@@ -339,10 +321,13 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
         let processor = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadata.count, hudView: appDelegate.window?.rootViewController?.view)
         let processor = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadata.count, hudView: appDelegate.window?.rootViewController?.view)
         for (metadata, url) in downloadMetadata {
         for (metadata, url) in downloadMetadata {
             processor.execute { completion in
             processor.execute { completion in
-                NCNetworking.shared.download(metadata: metadata, selector: "", completion: { _, _ in
+                NCNetworking.shared.download(metadata: metadata, selector: "", notificationCenterProgressTask: false) { _ in
+                } progressHandler: { progress in
+                    processor.hud?.progress = Float(progress.fractionCompleted)
+                } completion: { _, _ in
                     if CCUtility.fileProviderStorageExists(metadata) { items.append(url) }
                     if CCUtility.fileProviderStorageExists(metadata) { items.append(url) }
                     completion()
                     completion()
-                })
+                }
             }
             }
         }
         }
 
 
@@ -457,67 +442,13 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
         }
         }
     }
     }
 
 
-    func saveLivePhoto(metadata: tableMetadata, metadataMOV: tableMetadata) {
-
-        if !CCUtility.fileProviderStorageExists(metadata) {
-            NCOperationQueue.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorSaveAlbumLivePhotoIMG)
-        }
-
-        if !CCUtility.fileProviderStorageExists(metadataMOV) {
-            NCOperationQueue.shared.download(metadata: metadataMOV, selector: NCGlobal.shared.selectorSaveAlbumLivePhotoMOV)
-        }
-
-        if CCUtility.fileProviderStorageExists(metadata) && CCUtility.fileProviderStorageExists(metadataMOV) {
-            saveLivePhotoToDisk(metadata: metadata, metadataMov: metadataMOV)
-        }
-    }
-
-    func saveLivePhotoToDisk(metadata: tableMetadata, metadataMov: tableMetadata) {
-        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
-
-        let fileNameImage = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!)
-        let fileNameMov = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadataMov.ocId, fileNameView: metadataMov.fileNameView)!)
-        let hud = JGProgressHUD()
-
-        hud.indicatorView = JGProgressHUDRingIndicatorView()
-        if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
-            indicatorView.ringWidth = 1.5
-        }
-        hud.textLabel.text = NSLocalizedString("_saving_", comment: "")
-        hud.show(in: (appDelegate.window?.rootViewController?.view)!)
-
-        NCLivePhoto.generate(from: fileNameImage, videoURL: fileNameMov, progress: { progress in
-            hud.progress = Float(progress)
-        }, completion: { _, resources in
-
-            if resources != nil {
-                NCLivePhoto.saveToLibrary(resources!) { result in
-                    DispatchQueue.main.async {
-                        if !result {
-                            hud.indicatorView = JGProgressHUDErrorIndicatorView()
-                            hud.textLabel.text = NSLocalizedString("_livephoto_save_error_", comment: "")
-                        } else {
-                            hud.indicatorView = JGProgressHUDSuccessIndicatorView()
-                            hud.textLabel.text = NSLocalizedString("_success_", comment: "")
-                        }
-                        hud.dismiss(afterDelay: 1)
-                    }
-                }
-            } else {
-                hud.indicatorView = JGProgressHUDErrorIndicatorView()
-                hud.textLabel.text = NSLocalizedString("_livephoto_save_error_", comment: "")
-                hud.dismiss(afterDelay: 1)
-            }
-        })
-    }
-
     // MARK: - Copy & Paste
     // MARK: - Copy & Paste
 
 
-    func copyPasteboard(pasteboardOcIds: [String], hudView: UIView) {
+    func copyPasteboard(pasteboardOcIds: [String]) {
         var items = [[String: Any]]()
         var items = [[String: Any]]()
-        let hud = JGProgressHUD()
-        hud.textLabel.text = NSLocalizedString("_wait_", comment: "")
-        hud.show(in: hudView)
+        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
+        let hudView = appDelegate.window?.rootViewController?.view
+        var fractionCompleted: Float = 0
 
 
         // getting file data can take some time and block the main queue
         // getting file data can take some time and block the main queue
         DispatchQueue.global(qos: .userInitiated).async {
         DispatchQueue.global(qos: .userInitiated).async {
@@ -531,17 +462,24 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
                 }
                 }
             }
             }
 
 
-            DispatchQueue.main.async(execute: hud.dismiss)
-
             // do 5 downloads in parallel to optimize efficiency
             // do 5 downloads in parallel to optimize efficiency
-            let parallelizer = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadatas.count, hudView: hudView)
+            let processor = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadatas.count, hudView: hudView)
 
 
             for metadata in downloadMetadatas {
             for metadata in downloadMetadatas {
-                parallelizer.execute { completion in
-                    NCNetworking.shared.download(metadata: metadata, selector: "") { _, _ in completion() }
+                processor.execute { completion in
+                    NCNetworking.shared.download(metadata: metadata, selector: "", notificationCenterProgressTask: false) { _ in
+                    } progressHandler: { progress in
+                        if Float(progress.fractionCompleted) > fractionCompleted || fractionCompleted == 0 {
+                            processor.hud?.progress = Float(progress.fractionCompleted)
+                            fractionCompleted = Float(progress.fractionCompleted)
+                        }
+                    } completion: { _, _ in
+                        fractionCompleted = 0
+                        completion()
+                    }
                 }
                 }
             }
             }
-            parallelizer.completeWork {
+            processor.completeWork {
                 items.append(contentsOf: downloadMetadatas.compactMap({ $0.toPasteBoardItem() }))
                 items.append(contentsOf: downloadMetadatas.compactMap({ $0.toPasteBoardItem() }))
                 UIPasteboard.general.setItems(items, options: [:])
                 UIPasteboard.general.setItems(items, options: [:])
             }
             }
@@ -550,13 +488,18 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
 
 
     func pastePasteboard(serverUrl: String) {
     func pastePasteboard(serverUrl: String) {
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
+        var fractionCompleted: Float = 0
 
 
-        let parallelizer = ParallelWorker(n: 5, titleKey: "_uploading_", totalTasks: nil, hudView: appDelegate.window?.rootViewController?.view)
+        let processor = ParallelWorker(n: 5, titleKey: "_uploading_", totalTasks: nil, hudView: appDelegate.window?.rootViewController?.view)
 
 
         func uploadPastePasteboard(fileName: String, serverUrlFileName: String, fileNameLocalPath: String, serverUrl: String, completion: @escaping () -> Void) {
         func uploadPastePasteboard(fileName: String, serverUrlFileName: String, fileNameLocalPath: String, serverUrl: String, completion: @escaping () -> Void) {
             NextcloudKit.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath) { request in
             NextcloudKit.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath) { request in
                 NCNetworking.shared.uploadRequest[fileNameLocalPath] = request
                 NCNetworking.shared.uploadRequest[fileNameLocalPath] = request
-            } progressHandler: { _ in
+            } progressHandler: { progress in
+                if Float(progress.fractionCompleted) > fractionCompleted || fractionCompleted == 0 {
+                    processor.hud?.progress = Float(progress.fractionCompleted)
+                    fractionCompleted = Float(progress.fractionCompleted)
+                }
             } completionHandler: { account, ocId, etag, _, _, _, afError, error in
             } completionHandler: { account, ocId, etag, _, _, _, afError, error in
                 NCNetworking.shared.uploadRequest.removeValue(forKey: fileNameLocalPath)
                 NCNetworking.shared.uploadRequest.removeValue(forKey: fileNameLocalPath)
                 if error == .success && etag != nil && ocId != nil {
                 if error == .success && etag != nil && ocId != nil {
@@ -569,6 +512,7 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
                 } else {
                 } else {
                     NCContentPresenter.shared.showError(error: error)
                     NCContentPresenter.shared.showError(error: error)
                 }
                 }
+                fractionCompleted = 0
                 completion()
                 completion()
             }
             }
         }
         }
@@ -584,12 +528,12 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
                 let ocIdUpload = UUID().uuidString
                 let ocIdUpload = UUID().uuidString
                 let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(ocIdUpload, fileNameView: fileName)!
                 let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(ocIdUpload, fileNameView: fileName)!
                 do { try data.write(to: URL(fileURLWithPath: fileNameLocalPath)) } catch { continue }
                 do { try data.write(to: URL(fileURLWithPath: fileNameLocalPath)) } catch { continue }
-                parallelizer.execute { completion in
+                processor.execute { completion in
                     uploadPastePasteboard(fileName: fileName, serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, serverUrl: serverUrl, completion: completion)
                     uploadPastePasteboard(fileName: fileName, serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, serverUrl: serverUrl, completion: completion)
                 }
                 }
             }
             }
         }
         }
-        parallelizer.completeWork()
+        processor.completeWork()
     }
     }
 
 
     // MARK: -
     // MARK: -
@@ -652,21 +596,49 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
 
 
     // MARK: - NCSelect + Delegate
     // MARK: - NCSelect + Delegate
 
 
-    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) {
-        if serverUrl != nil && !items.isEmpty {
+    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) {
+        if let serverUrl, !items.isEmpty {
+            let hud = JGProgressHUD()
+            hud.textLabel.text = copy ? NSLocalizedString("_copying_progess_", comment: "") : NSLocalizedString("_moving_progess_", comment: "")
+            if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
+               let view = appDelegate.window?.rootViewController?.view {
+                hud.show(in: view)
+            }
             if copy {
             if copy {
-                for case let metadata as tableMetadata in items {
-                    NCOperationQueue.shared.copyMove(metadata: metadata, serverUrl: serverUrl!, overwrite: overwrite, move: false)
+                Task {
+                    var error = NKError()
+                    var ocId: [String] = []
+                    for case let metadata as tableMetadata in items where error == .success {
+                        error = await NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite)
+                        if error == .success {
+                            ocId.append(metadata.ocId)
+                        }
+                    }
+                    if error != .success {
+                        NCContentPresenter.shared.showError(error: error)
+                    }
+                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterCopyFile, userInfo: ["ocId": ocId, "indexPath": indexPath, "error": error, "hud": hud])
                 }
                 }
-            } else if move {
-                for case let metadata as tableMetadata in items {
-                    NCOperationQueue.shared.copyMove(metadata: metadata, serverUrl: serverUrl!, overwrite: overwrite, move: true)
+            } else {
+                Task {
+                    var error = NKError()
+                    var ocId: [String] = []
+                    for case let metadata as tableMetadata in items where error == .success {
+                        error = await NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite)
+                        if error == .success {
+                            ocId.append(metadata.ocId)
+                        }
+                    }
+                    if error != .success {
+                        NCContentPresenter.shared.showError(error: error)
+                    }
+                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMoveFile, userInfo: ["ocId": ocId, "indexPath": indexPath, "error": error, "hud": hud])
                 }
                 }
             }
             }
         }
         }
     }
     }
 
 
-    func openSelectView(items: [tableMetadata]) {
+    func openSelectView(items: [tableMetadata], indexPath: [IndexPath]) {
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
 
 
         let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as? UINavigationController
         let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as? UINavigationController
@@ -701,6 +673,7 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
             vc.typeOfCommandView = .copyMove
             vc.typeOfCommandView = .copyMove
             vc.items = copyItems
             vc.items = copyItems
             vc.serverUrl = serverUrl
             vc.serverUrl = serverUrl
+            vc.selectIndexPath = indexPath
 
 
             vc.navigationItem.backButtonTitle = vc.titleCurrentFolder
             vc.navigationItem.backButtonTitle = vc.titleCurrentFolder
             listViewController.insert(vc, at: 0)
             listViewController.insert(vc, at: 0)

+ 1 - 0
iOSClient/Main/NCCellProtocol.swift

@@ -39,6 +39,7 @@ protocol NCCellProtocol {
     var fileSharedImage: UIImageView? { get set }
     var fileSharedImage: UIImageView? { get set }
     var fileMoreImage: UIImageView? { get set }
     var fileMoreImage: UIImageView? { get set }
     var cellSeparatorView: UIView? { get set }
     var cellSeparatorView: UIView? { get set }
+    var indexPath: IndexPath { get set }
 
 
     func titleInfoTrailingDefault()
     func titleInfoTrailingDefault()
     func titleInfoTrailingFull()
     func titleInfoTrailingFull()

+ 27 - 14
iOSClient/Main/NCMainTabBar.swift

@@ -28,16 +28,17 @@ class NCMainTabBar: UITabBar {
 
 
     private var fillColor: UIColor!
     private var fillColor: UIColor!
     private var shapeLayer: CALayer?
     private var shapeLayer: CALayer?
+
+    // swiftlint:disable force_cast
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
+
     private let centerButtonY: CGFloat = -28
     private let centerButtonY: CGFloat = -28
 
 
     public var menuRect: CGRect {
     public var menuRect: CGRect {
-        get {
-            let tabBarItemWidth = Int(self.frame.size.width) / (self.items?.count ?? 0)
-            let rect = CGRect(x: 0, y: -5, width: tabBarItemWidth, height: Int(self.frame.size.height))
-
-            return rect
-        }
+        let tabBarItemWidth = Int(self.frame.size.width) / (self.items?.count ?? 0)
+        let rect = CGRect(x: 0, y: -5, width: tabBarItemWidth, height: Int(self.frame.size.height))
+        return rect
     }
     }
 
 
     // MARK: - Life Cycle
     // MARK: - Life Cycle
@@ -48,7 +49,6 @@ class NCMainTabBar: UITabBar {
         appDelegate.mainTabBar = self
         appDelegate.mainTabBar = self
 
 
         NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
-
         NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeNumber(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeNumber(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil)
 
 
         barTintColor = .secondarySystemBackground
         barTintColor = .secondarySystemBackground
@@ -177,7 +177,7 @@ class NCMainTabBar: UITabBar {
         }
         }
 
 
         let centerButtonHeight: CGFloat = 57
         let centerButtonHeight: CGFloat = 57
-        let centerButton = UIButton(frame: CGRect(x: (self.bounds.width / 2)-(centerButtonHeight/2), y: centerButtonY, width: centerButtonHeight, height: centerButtonHeight))
+        let centerButton = UIButton(frame: CGRect(x: (self.bounds.width / 2) - (centerButtonHeight / 2), y: centerButtonY, width: centerButtonHeight, height: centerButtonHeight))
 
 
         centerButton.setTitle("", for: .normal)
         centerButton.setTitle("", for: .normal)
         centerButton.setImage(UIImage(named: "tabBarPlus")?.image(color: .white, size: 100), for: .normal)
         centerButton.setImage(UIImage(named: "tabBarPlus")?.image(color: .white, size: 100), for: .normal)
@@ -212,15 +212,28 @@ class NCMainTabBar: UITabBar {
     @objc func updateBadgeNumber(_ notification: NSNotification) {
     @objc func updateBadgeNumber(_ notification: NSNotification) {
 
 
         guard let userInfo = notification.userInfo as NSDictionary?,
         guard let userInfo = notification.userInfo as NSDictionary?,
-              let counter = userInfo["counter"] as? Int
+              let counterDownload = userInfo["counterDownload"] as? Int,
+              let counterUpload = userInfo["counterUpload"] as? Int
         else { return }
         else { return }
 
 
-        UIApplication.shared.applicationIconBadgeNumber = counter
+        UIApplication.shared.applicationIconBadgeNumber = counterUpload
         if let item = self.items?[0] {
         if let item = self.items?[0] {
-            if counter > 0 {
-                item.badgeValue = String(counter)
-            } else {
+            if counterDownload == 0, counterUpload == 0 {
                 item.badgeValue = nil
                 item.badgeValue = nil
+            } else if counterDownload > 0, counterUpload == 0 {
+                var badgeValue = String("↓ \(counterDownload)")
+                if counterDownload >= NCGlobal.shared.maxConcurrentOperationCountDownload {
+                    badgeValue = String("↓ 10+")
+                }
+                item.badgeValue = badgeValue
+            } else if counterDownload == 0, counterUpload > 0 {
+                item.badgeValue = String("↑ \(counterUpload)")
+            } else {
+                var badgeValue = String("↓ \(counterDownload) ↑ \(counterUpload)")
+                if counterDownload >= NCGlobal.shared.maxConcurrentOperationCountDownload {
+                    badgeValue = String("↓ 10+ ↑ \(counterUpload)")
+                }
+                item.badgeValue = badgeValue
             }
             }
         }
         }
     }
     }
@@ -233,7 +246,7 @@ class NCMainTabBar: UITabBar {
         }
         }
     }
     }
 
 
-    func getHight() -> CGFloat {
+    func getHeight() -> CGFloat {
         return (frame.size.height - centerButtonY)
         return (frame.size.height - centerButtonY)
     }
     }
 }
 }

+ 8 - 2
iOSClient/Main/NCPickerViewController.swift

@@ -31,7 +31,10 @@ import NextcloudKit
 
 
 class NCPhotosPickerViewController: NSObject {
 class NCPhotosPickerViewController: NSObject {
 
 
+    // swiftlint:disable force_cast
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
+
     var sourceViewController: UIViewController
     var sourceViewController: UIViewController
     var maxSelectedAssets = 1
     var maxSelectedAssets = 1
     var singleSelectedMode = false
     var singleSelectedMode = false
@@ -115,7 +118,10 @@ class customPhotoPickerViewController: TLPhotosPickerViewController {
 
 
 class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
 class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
 
 
+    // swiftlint:disable force_cast
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
+
     var isViewerMedia: Bool
     var isViewerMedia: Bool
     var viewController: UIViewController?
     var viewController: UIViewController?
 
 
@@ -165,7 +171,7 @@ class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
                 let toPath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!
                 let toPath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!
                 let urlOut = URL(fileURLWithPath: toPath)
                 let urlOut = URL(fileURLWithPath: toPath)
 
 
-                guard let _ = self.copySecurityScopedResource(url: urlIn, urlOut: urlOut) else { continue }
+                guard self.copySecurityScopedResource(url: urlIn, urlOut: urlOut) != nil else { continue }
 
 
                 let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "")
                 let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "")
 
 
@@ -174,7 +180,7 @@ class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
                 metadataForUpload.size = NCUtilityFileSystem.shared.getFileSize(filePath: toPath)
                 metadataForUpload.size = NCUtilityFileSystem.shared.getFileSize(filePath: toPath)
                 metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
                 metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
 
 
-                if let _ = NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileNameView: fileName) {
+                if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileNameView: fileName) != nil {
                     metadatasInConflict.append(metadataForUpload)
                     metadatasInConflict.append(metadataForUpload)
                 } else {
                 } else {
                     metadatas.append(metadataForUpload)
                     metadatas.append(metadataForUpload)

+ 112 - 20
iOSClient/Main/Section Header Footer/NCSectionHeaderMenu.swift

@@ -29,19 +29,25 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate
     @IBOutlet weak var buttonSwitch: UIButton!
     @IBOutlet weak var buttonSwitch: UIButton!
     @IBOutlet weak var buttonOrder: UIButton!
     @IBOutlet weak var buttonOrder: UIButton!
     @IBOutlet weak var buttonMore: UIButton!
     @IBOutlet weak var buttonMore: UIButton!
-
+    @IBOutlet weak var buttonTransfer: UIButton!
+    @IBOutlet weak var imageButtonTransfer: UIImageView!
+    @IBOutlet weak var labelTransfer: UILabel!
+    @IBOutlet weak var progressTransfer: UIProgressView!
+    @IBOutlet weak var transferSeparatorBottom: UIView!
+    @IBOutlet weak var textViewRichWorkspace: UITextView!
+    @IBOutlet weak var labelSection: UILabel!
+    @IBOutlet weak var viewTransfer: UIView!
     @IBOutlet weak var viewButtonsView: UIView!
     @IBOutlet weak var viewButtonsView: UIView!
     @IBOutlet weak var viewSeparator: UIView!
     @IBOutlet weak var viewSeparator: UIView!
     @IBOutlet weak var viewRichWorkspace: UIView!
     @IBOutlet weak var viewRichWorkspace: UIView!
     @IBOutlet weak var viewSection: UIView!
     @IBOutlet weak var viewSection: UIView!
 
 
+    @IBOutlet weak var viewTransferHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewButtonsViewHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewButtonsViewHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewSeparatorHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewSeparatorHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewRichWorkspaceHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewRichWorkspaceHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewSectionHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var viewSectionHeightConstraint: NSLayoutConstraint!
-
-    @IBOutlet weak var textViewRichWorkspace: UITextView!
-    @IBOutlet weak var labelSection: UILabel!
+    @IBOutlet weak var transferSeparatorBottomHeightConstraint: NSLayoutConstraint!
 
 
     weak var delegate: NCSectionHeaderMenuDelegate?
     weak var delegate: NCSectionHeaderMenuDelegate?
 
 
@@ -82,6 +88,19 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate
 
 
         labelSection.text = ""
         labelSection.text = ""
         viewSectionHeightConstraint.constant = 0
         viewSectionHeightConstraint.constant = 0
+
+        buttonTransfer.backgroundColor = .clear
+        buttonTransfer.setImage(nil, for: .normal)
+        buttonTransfer.layer.cornerRadius = 6
+        buttonTransfer.layer.masksToBounds = true
+        imageButtonTransfer.image = UIImage(systemName: "stop.circle")
+        imageButtonTransfer.tintColor = .white
+        labelTransfer.text = ""
+        progressTransfer.progress = 0
+        progressTransfer.tintColor = NCBrandColor.shared.brand
+        progressTransfer.trackTintColor = NCBrandColor.shared.brand.withAlphaComponent(0.2)
+        transferSeparatorBottom.backgroundColor = .separator
+        transferSeparatorBottomHeightConstraint.constant = 0.5
     }
     }
 
 
     override func layoutSublayers(of layer: CALayer) {
     override func layoutSublayers(of layer: CALayer) {
@@ -167,6 +186,36 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate
         }
         }
     }
     }
 
 
+    // MARK: - Transfer
+
+    func setViewTransfer(isHidden: Bool, ocId: String? = nil, text: String? = nil, progress: Float? = nil) {
+
+        labelTransfer.text = text
+        viewTransfer.isHidden = isHidden
+        progressTransfer.progress = 0
+
+        if isHidden {
+            viewTransferHeightConstraint.constant = 0
+        } else {
+            var image: UIImage?
+            if let ocId,
+               let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+                image = NCUtility.shared.createFilePreviewImage(ocId: metadata.ocId, etag: metadata.etag, fileNameView: metadata.fileNameView, classFile: metadata.classFile, status: metadata.status, createPreviewMedia: true)?.darken()
+                if image == nil {
+                    image = UIImage(named: metadata.iconName)
+                    buttonTransfer.backgroundColor = .lightGray
+                } else {
+                    buttonTransfer.backgroundColor = .clear
+                }
+                buttonTransfer.setImage(image, for: .normal)
+            }
+            viewTransferHeightConstraint.constant = NCGlobal.shared.heightHeaderTransfer
+            if let progress {
+                progressTransfer.progress = progress
+            }
+        }
+    }
+
     // MARK: - Section
     // MARK: - Section
 
 
     func setSectionHeight(_ size: CGFloat) {
     func setSectionHeight(_ size: CGFloat) {
@@ -193,16 +242,8 @@ class NCSectionHeaderMenu: UICollectionReusableView, UIGestureRecognizerDelegate
         delegate?.tapButtonMore(sender)
         delegate?.tapButtonMore(sender)
     }
     }
 
 
-    @IBAction func touchUpInsideButton1(_ sender: Any) {
-       delegate?.tapButton1(sender)
-    }
-
-    @IBAction func touchUpInsideButton2(_ sender: Any) {
-        delegate?.tapButton2(sender)
-    }
-
-    @IBAction func touchUpInsideButton3(_ sender: Any) {
-        delegate?.tapButton3(sender)
+    @IBAction func touchUpTransfer(_ sender: Any) {
+       delegate?.tapButtonTransfer(sender)
     }
     }
 
 
     @objc func touchUpInsideViewRichWorkspace(_ sender: Any) {
     @objc func touchUpInsideViewRichWorkspace(_ sender: Any) {
@@ -214,9 +255,7 @@ protocol NCSectionHeaderMenuDelegate: AnyObject {
     func tapButtonSwitch(_ sender: Any)
     func tapButtonSwitch(_ sender: Any)
     func tapButtonOrder(_ sender: Any)
     func tapButtonOrder(_ sender: Any)
     func tapButtonMore(_ sender: Any)
     func tapButtonMore(_ sender: Any)
-    func tapButton1(_ sender: Any)
-    func tapButton2(_ sender: Any)
-    func tapButton3(_ sender: Any)
+    func tapButtonTransfer(_ sender: Any)
     func tapRichWorkspace(_ sender: Any)
     func tapRichWorkspace(_ sender: Any)
 }
 }
 
 
@@ -225,9 +264,7 @@ extension NCSectionHeaderMenuDelegate {
     func tapButtonSwitch(_ sender: Any) {}
     func tapButtonSwitch(_ sender: Any) {}
     func tapButtonOrder(_ sender: Any) {}
     func tapButtonOrder(_ sender: Any) {}
     func tapButtonMore(_ sender: Any) {}
     func tapButtonMore(_ sender: Any) {}
-    func tapButton1(_ sender: Any) {}
-    func tapButton2(_ sender: Any) {}
-    func tapButton3(_ sender: Any) {}
+    func tapButtonTransfer(_ sender: Any) {}
     func tapRichWorkspace(_ sender: Any) {}
     func tapRichWorkspace(_ sender: Any) {}
 }
 }
 
 
@@ -351,3 +388,58 @@ protocol NCSectionFooterDelegate: AnyObject {
 extension NCSectionFooterDelegate {
 extension NCSectionFooterDelegate {
     func tapButtonSection(_ sender: Any, metadataForSection: NCMetadataForSection?) {}
     func tapButtonSection(_ sender: Any, metadataForSection: NCMetadataForSection?) {}
 }
 }
+
+// https://stackoverflow.com/questions/16278463/darken-an-uiimage
+public extension UIImage {
+
+    private enum BlendMode {
+        case multiply // This results in colors that are at least as dark as either of the two contributing sample colors
+        case screen // This results in colors that are at least as light as either of the two contributing sample colors
+    }
+
+    // A level of zero yeilds the original image, a level of 1 results in black
+    func darken(level: CGFloat = 0.5) -> UIImage? {
+        return blend(mode: .multiply, level: level)
+    }
+
+    // A level of zero yeilds the original image, a level of 1 results in white
+    func lighten(level: CGFloat = 0.5) -> UIImage? {
+        return blend(mode: .screen, level: level)
+    }
+
+    private func blend(mode: BlendMode, level: CGFloat) -> UIImage? {
+        let context = CIContext(options: nil)
+
+        var level = level
+        if level < 0 {
+            level = 0
+        } else if level > 1 {
+            level = 1
+        }
+
+        let filterName: String
+        switch mode {
+        case .multiply: // As the level increases we get less white
+            level = abs(level - 1.0)
+            filterName = "CIMultiplyBlendMode"
+        case .screen: // As the level increases we get more white
+            filterName = "CIScreenBlendMode"
+        }
+
+        let blender = CIFilter(name: filterName)!
+        let backgroundColor = CIColor(color: UIColor(white: level, alpha: 1))
+
+        guard let inputImage = CIImage(image: self) else { return nil }
+        blender.setValue(inputImage, forKey: kCIInputImageKey)
+
+        guard let backgroundImageGenerator = CIFilter(name: "CIConstantColorGenerator") else { return nil }
+        backgroundImageGenerator.setValue(backgroundColor, forKey: kCIInputColorKey)
+        guard let backgroundImage = backgroundImageGenerator.outputImage?.cropped(to: CGRect(origin: CGPoint.zero, size: self.size)) else { return nil }
+        blender.setValue(backgroundImage, forKey: kCIInputBackgroundImageKey)
+
+        guard let blendedImage = blender.outputImage else { return nil }
+
+        guard let cgImage = context.createCGImage(blendedImage, from: blendedImage.extent) else { return nil }
+        return UIImage(cgImage: cgImage)
+    }
+}

+ 98 - 28
iOSClient/Main/Section Header Footer/NCSectionHeaderMenu.xib

@@ -3,7 +3,7 @@
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
     <dependencies>
         <deployment identifier="iOS"/>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
         <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"/>
@@ -12,7 +12,7 @@
         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
         <collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" reuseIdentifier="sectionHeaderMenu" id="tys-A2-nDX" customClass="NCSectionHeaderMenu" customModule="Nextcloud" customModuleProvider="target">
         <collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" reuseIdentifier="sectionHeaderMenu" id="tys-A2-nDX" customClass="NCSectionHeaderMenu" customModule="Nextcloud" customModuleProvider="target">
-            <rect key="frame" x="0.0" y="0.0" width="574" height="211"/>
+            <rect key="frame" x="0.0" y="0.0" width="574" height="438"/>
             <autoresizingMask key="autoresizingMask"/>
             <autoresizingMask key="autoresizingMask"/>
             <subviews>
             <subviews>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s4I-Jo-yCE">
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="s4I-Jo-yCE">
@@ -24,8 +24,7 @@
                                 <constraint firstAttribute="width" constant="25" id="D76-X9-Tw9"/>
                                 <constraint firstAttribute="width" constant="25" id="D76-X9-Tw9"/>
                                 <constraint firstAttribute="height" constant="25" id="izT-Ru-XYG"/>
                                 <constraint firstAttribute="height" constant="25" id="izT-Ru-XYG"/>
                             </constraints>
                             </constraints>
-                            <color key="tintColor" systemColor="systemGrayColor"/>
-                            <state key="normal" image="list.bullet" catalog="system"/>
+                            <state key="normal" image="switchList"/>
                             <connections>
                             <connections>
                                 <action selector="touchUpInsideSwitch:" destination="tys-A2-nDX" eventType="touchUpInside" id="iT8-1j-fib"/>
                                 <action selector="touchUpInsideSwitch:" destination="tys-A2-nDX" eventType="touchUpInside" id="iT8-1j-fib"/>
                             </connections>
                             </connections>
@@ -33,7 +32,9 @@
                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0bo-yl-t5k">
                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0bo-yl-t5k">
                             <rect key="frame" x="45" y="11" width="163" height="28"/>
                             <rect key="frame" x="45" y="11" width="163" height="28"/>
                             <fontDescription key="fontDescription" type="system" pointSize="13"/>
                             <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                            <state key="normal" title="Sort by name (from A to Z)"/>
+                            <state key="normal" title="Sort by name (from A to Z)">
+                                <color key="titleColor" systemColor="darkTextColor"/>
+                            </state>
                             <connections>
                             <connections>
                                 <action selector="touchUpInsideOrder:" destination="tys-A2-nDX" eventType="touchUpInside" id="oiL-3O-hMQ"/>
                                 <action selector="touchUpInsideOrder:" destination="tys-A2-nDX" eventType="touchUpInside" id="oiL-3O-hMQ"/>
                             </connections>
                             </connections>
@@ -68,20 +69,8 @@
                         <constraint firstAttribute="height" constant="1" id="VuP-sT-hUI"/>
                         <constraint firstAttribute="height" constant="1" id="VuP-sT-hUI"/>
                     </constraints>
                     </constraints>
                 </view>
                 </view>
-                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="f9U-NY-4OS">
-                    <rect key="frame" x="0.0" y="191" width="574" height="20"/>
-                    <constraints>
-                        <constraint firstAttribute="height" constant="20" id="ZcL-Wd-xhN"/>
-                    </constraints>
-                </view>
-                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mB5-5n-AL9">
-                    <rect key="frame" x="10" y="193" width="554" height="18"/>
-                    <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
-                    <nil key="textColor"/>
-                    <nil key="highlightedColor"/>
-                </label>
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NC1-5C-E5z" userLabel="View RichWorkspace">
                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NC1-5C-E5z" userLabel="View RichWorkspace">
-                    <rect key="frame" x="0.0" y="141" width="574" height="50"/>
+                    <rect key="frame" x="0.0" y="318" width="574" height="50"/>
                     <subviews>
                     <subviews>
                         <textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="pYo-pF-MGv">
                         <textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="pYo-pF-MGv">
                             <rect key="frame" x="5" y="0.0" width="564" height="50"/>
                             <rect key="frame" x="5" y="0.0" width="564" height="50"/>
@@ -99,31 +88,109 @@
                         <constraint firstAttribute="bottom" secondItem="pYo-pF-MGv" secondAttribute="bottom" id="t4r-dA-VyW"/>
                         <constraint firstAttribute="bottom" secondItem="pYo-pF-MGv" secondAttribute="bottom" id="t4r-dA-VyW"/>
                     </constraints>
                     </constraints>
                 </view>
                 </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="I6b-6a-TKg" userLabel="View Transfer">
+                    <rect key="frame" x="0.0" y="368" width="574" height="50"/>
+                    <subviews>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="McE-3D-mc5">
+                            <rect key="frame" x="0.0" y="49" width="574" height="1"/>
+                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="1" id="bJs-JY-WbC"/>
+                            </constraints>
+                        </view>
+                        <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aS9-DV-CXI">
+                            <rect key="frame" x="10" y="8" width="30" height="30"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="30" id="AkI-Uq-9rJ"/>
+                                <constraint firstAttribute="width" constant="30" id="S1K-Qo-eU9"/>
+                            </constraints>
+                            <connections>
+                                <action selector="touchUpTransfer:" destination="tys-A2-nDX" eventType="touchUpInside" id="8Vb-xV-6eT"/>
+                            </connections>
+                        </button>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="stop.circle" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="Pgk-le-540">
+                            <rect key="frame" x="15" y="13.5" width="20" height="19"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="20" id="3SW-CS-jiT"/>
+                                <constraint firstAttribute="height" constant="20" id="xVb-tv-en7"/>
+                            </constraints>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="text" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eER-Zj-8iK">
+                            <rect key="frame" x="50" y="14" width="514" height="18"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                            <nil key="textColor"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FOe-YO-km8">
+                            <rect key="frame" x="-1" y="46" width="576" height="4"/>
+                        </progressView>
+                    </subviews>
+                    <constraints>
+                        <constraint firstItem="Pgk-le-540" firstAttribute="centerX" secondItem="aS9-DV-CXI" secondAttribute="centerX" id="3fo-qC-duA"/>
+                        <constraint firstAttribute="trailing" secondItem="FOe-YO-km8" secondAttribute="trailing" constant="-1" id="3gk-sW-WeV"/>
+                        <constraint firstAttribute="bottom" secondItem="McE-3D-mc5" secondAttribute="bottom" id="697-ky-07J"/>
+                        <constraint firstAttribute="height" constant="50" id="86k-97-oGl"/>
+                        <constraint firstItem="Pgk-le-540" firstAttribute="centerY" secondItem="aS9-DV-CXI" secondAttribute="centerY" id="9Lm-Ql-nt0"/>
+                        <constraint firstAttribute="bottom" secondItem="FOe-YO-km8" secondAttribute="bottom" id="ESd-Gt-Xcc"/>
+                        <constraint firstItem="eER-Zj-8iK" firstAttribute="centerY" secondItem="aS9-DV-CXI" secondAttribute="centerY" id="Ko8-gC-6Zd"/>
+                        <constraint firstItem="aS9-DV-CXI" firstAttribute="centerY" secondItem="I6b-6a-TKg" secondAttribute="centerY" constant="-2" id="Mli-mT-whp"/>
+                        <constraint firstAttribute="trailing" secondItem="eER-Zj-8iK" secondAttribute="trailing" constant="10" id="QyZ-Z4-0tw"/>
+                        <constraint firstItem="McE-3D-mc5" firstAttribute="leading" secondItem="I6b-6a-TKg" secondAttribute="leading" id="TRt-jh-ZEo"/>
+                        <constraint firstAttribute="trailing" secondItem="McE-3D-mc5" secondAttribute="trailing" id="fjz-bk-gcP"/>
+                        <constraint firstItem="eER-Zj-8iK" firstAttribute="leading" secondItem="aS9-DV-CXI" secondAttribute="trailing" constant="10" id="idn-9t-2Ap"/>
+                        <constraint firstItem="aS9-DV-CXI" firstAttribute="leading" secondItem="I6b-6a-TKg" secondAttribute="leading" constant="10" id="jIP-Fr-dnx"/>
+                        <constraint firstItem="FOe-YO-km8" firstAttribute="leading" secondItem="I6b-6a-TKg" secondAttribute="leading" constant="-1" id="oDR-51-azX"/>
+                    </constraints>
+                </view>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="f9U-NY-4OS">
+                    <rect key="frame" x="0.0" y="418" width="574" height="20"/>
+                    <subviews>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mB5-5n-AL9">
+                            <rect key="frame" x="10" y="2" width="554" height="18"/>
+                            <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
+                            <nil key="textColor"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                    </subviews>
+                    <constraints>
+                        <constraint firstAttribute="trailing" secondItem="mB5-5n-AL9" secondAttribute="trailing" constant="10" id="Cct-8N-ghQ"/>
+                        <constraint firstAttribute="height" constant="20" id="ZcL-Wd-xhN"/>
+                        <constraint firstItem="mB5-5n-AL9" firstAttribute="leading" secondItem="f9U-NY-4OS" secondAttribute="leading" constant="10" id="xQp-zk-G00"/>
+                        <constraint firstAttribute="bottom" secondItem="mB5-5n-AL9" secondAttribute="bottom" id="ySZ-Z1-BQ1"/>
+                    </constraints>
+                </view>
             </subviews>
             </subviews>
             <viewLayoutGuide key="safeArea" id="pm7-uW-mZE"/>
             <viewLayoutGuide key="safeArea" id="pm7-uW-mZE"/>
             <constraints>
             <constraints>
                 <constraint firstItem="f9U-NY-4OS" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="7kv-IL-kwZ"/>
                 <constraint firstItem="f9U-NY-4OS" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="7kv-IL-kwZ"/>
                 <constraint firstItem="s4I-Jo-yCE" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="CaM-Eb-nHq"/>
                 <constraint firstItem="s4I-Jo-yCE" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="CaM-Eb-nHq"/>
                 <constraint firstItem="LZu-Te-clJ" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="CyS-jg-0vc"/>
                 <constraint firstItem="LZu-Te-clJ" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="CyS-jg-0vc"/>
-                <constraint firstAttribute="bottom" secondItem="mB5-5n-AL9" secondAttribute="bottom" id="EFG-nD-yUb"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="f9U-NY-4OS" secondAttribute="trailing" id="GbG-un-mCe"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="f9U-NY-4OS" secondAttribute="trailing" id="GbG-un-mCe"/>
+                <constraint firstItem="f9U-NY-4OS" firstAttribute="top" secondItem="I6b-6a-TKg" secondAttribute="bottom" id="JKM-HM-WpK"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="LZu-Te-clJ" secondAttribute="trailing" id="NiW-2m-3HS"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="LZu-Te-clJ" secondAttribute="trailing" id="NiW-2m-3HS"/>
-                <constraint firstAttribute="trailing" secondItem="mB5-5n-AL9" secondAttribute="trailing" constant="10" id="OO6-Qd-6hP"/>
                 <constraint firstItem="NC1-5C-E5z" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="QpF-nE-s7J"/>
                 <constraint firstItem="NC1-5C-E5z" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="QpF-nE-s7J"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="NC1-5C-E5z" secondAttribute="trailing" id="UH6-8N-JUD"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="NC1-5C-E5z" secondAttribute="trailing" id="UH6-8N-JUD"/>
-                <constraint firstItem="mB5-5n-AL9" firstAttribute="leading" secondItem="tys-A2-nDX" secondAttribute="leading" constant="10" id="bDt-8i-Gxr"/>
+                <constraint firstItem="s4I-Jo-yCE" firstAttribute="top" secondItem="pm7-uW-mZE" secondAttribute="top" id="bSn-X7-YZH"/>
+                <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="I6b-6a-TKg" secondAttribute="trailing" id="eYb-BW-clZ"/>
                 <constraint firstItem="LZu-Te-clJ" firstAttribute="top" secondItem="s4I-Jo-yCE" secondAttribute="bottom" constant="-1" id="ede-24-v8F"/>
                 <constraint firstItem="LZu-Te-clJ" firstAttribute="top" secondItem="s4I-Jo-yCE" secondAttribute="bottom" constant="-1" id="ede-24-v8F"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="bottom" secondItem="f9U-NY-4OS" secondAttribute="bottom" id="eyu-CE-rTX"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="bottom" secondItem="f9U-NY-4OS" secondAttribute="bottom" id="eyu-CE-rTX"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="s4I-Jo-yCE" secondAttribute="trailing" id="oCg-UW-8TQ"/>
                 <constraint firstItem="pm7-uW-mZE" firstAttribute="trailing" secondItem="s4I-Jo-yCE" secondAttribute="trailing" id="oCg-UW-8TQ"/>
-                <constraint firstItem="NC1-5C-E5z" firstAttribute="bottom" secondItem="f9U-NY-4OS" secondAttribute="top" id="pmY-5s-Pv2"/>
-                <constraint firstItem="s4I-Jo-yCE" firstAttribute="top" secondItem="pm7-uW-mZE" secondAttribute="top" id="pzr-LC-JPk"/>
+                <constraint firstItem="I6b-6a-TKg" firstAttribute="leading" secondItem="pm7-uW-mZE" secondAttribute="leading" id="pap-j1-yYG"/>
+                <constraint firstItem="NC1-5C-E5z" firstAttribute="bottom" secondItem="I6b-6a-TKg" secondAttribute="top" id="pmY-5s-Pv2"/>
             </constraints>
             </constraints>
             <connections>
             <connections>
                 <outlet property="buttonMore" destination="D0O-wK-14O" id="eEx-3R-zCS"/>
                 <outlet property="buttonMore" destination="D0O-wK-14O" id="eEx-3R-zCS"/>
                 <outlet property="buttonOrder" destination="0bo-yl-t5k" id="Kbw-BG-73C"/>
                 <outlet property="buttonOrder" destination="0bo-yl-t5k" id="Kbw-BG-73C"/>
                 <outlet property="buttonSwitch" destination="1LD-cd-zhc" id="Ec2-cM-CoY"/>
                 <outlet property="buttonSwitch" destination="1LD-cd-zhc" id="Ec2-cM-CoY"/>
+                <outlet property="buttonTransfer" destination="aS9-DV-CXI" id="Qsu-aQ-Vh7"/>
+                <outlet property="imageButtonTransfer" destination="Pgk-le-540" id="ljU-AW-YSt"/>
                 <outlet property="labelSection" destination="mB5-5n-AL9" id="uxf-bN-nZA"/>
                 <outlet property="labelSection" destination="mB5-5n-AL9" id="uxf-bN-nZA"/>
+                <outlet property="labelTransfer" destination="eER-Zj-8iK" id="ARz-bB-Hg9"/>
+                <outlet property="progressTransfer" destination="FOe-YO-km8" id="vyd-rg-H9B"/>
                 <outlet property="textViewRichWorkspace" destination="pYo-pF-MGv" id="2h4-LP-T1z"/>
                 <outlet property="textViewRichWorkspace" destination="pYo-pF-MGv" id="2h4-LP-T1z"/>
+                <outlet property="transferSeparatorBottom" destination="McE-3D-mc5" id="kJU-kh-04F"/>
+                <outlet property="transferSeparatorBottomHeightConstraint" destination="bJs-JY-WbC" id="P9i-Em-ycA"/>
                 <outlet property="viewButtonsView" destination="s4I-Jo-yCE" id="FOI-ZK-1oj"/>
                 <outlet property="viewButtonsView" destination="s4I-Jo-yCE" id="FOI-ZK-1oj"/>
                 <outlet property="viewButtonsViewHeightConstraint" destination="vvG-dH-6c1" id="SEQ-Tn-EE0"/>
                 <outlet property="viewButtonsViewHeightConstraint" destination="vvG-dH-6c1" id="SEQ-Tn-EE0"/>
                 <outlet property="viewRichWorkspace" destination="NC1-5C-E5z" id="NyN-tr-sJl"/>
                 <outlet property="viewRichWorkspace" destination="NC1-5C-E5z" id="NyN-tr-sJl"/>
@@ -132,18 +199,21 @@
                 <outlet property="viewSectionHeightConstraint" destination="ZcL-Wd-xhN" id="RDs-yy-I6W"/>
                 <outlet property="viewSectionHeightConstraint" destination="ZcL-Wd-xhN" id="RDs-yy-I6W"/>
                 <outlet property="viewSeparator" destination="LZu-Te-clJ" id="rz1-2Q-vEK"/>
                 <outlet property="viewSeparator" destination="LZu-Te-clJ" id="rz1-2Q-vEK"/>
                 <outlet property="viewSeparatorHeightConstraint" destination="VuP-sT-hUI" id="QHV-oY-E5w"/>
                 <outlet property="viewSeparatorHeightConstraint" destination="VuP-sT-hUI" id="QHV-oY-E5w"/>
+                <outlet property="viewTransfer" destination="I6b-6a-TKg" id="Hqx-QM-daQ"/>
+                <outlet property="viewTransferHeightConstraint" destination="86k-97-oGl" id="Pjb-mP-5dn"/>
             </connections>
             </connections>
-            <point key="canvasLocation" x="368" y="55.322338830584712"/>
+            <point key="canvasLocation" x="345.60000000000002" y="56.671664167916049"/>
         </collectionReusableView>
         </collectionReusableView>
     </objects>
     </objects>
     <resources>
     <resources>
-        <image name="list.bullet" catalog="system" width="128" height="87"/>
         <image name="moreBig" width="50" height="50"/>
         <image name="moreBig" width="50" height="50"/>
+        <image name="stop.circle" catalog="system" width="128" height="123"/>
+        <image name="switchList" width="25" height="25"/>
+        <systemColor name="darkTextColor">
+            <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
         <systemColor name="labelColor">
         <systemColor name="labelColor">
             <color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
             <color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         </systemColor>
-        <systemColor name="systemGrayColor">
-            <color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-        </systemColor>
     </resources>
     </resources>
 </document>
 </document>

+ 1 - 0
iOSClient/Media/Cell/NCGridMediaCell.swift

@@ -32,6 +32,7 @@ class NCGridMediaCell: UICollectionViewCell, NCCellProtocol {
 
 
     private var objectId: String = ""
     private var objectId: String = ""
     private var user: String = ""
     private var user: String = ""
+    var indexPath = IndexPath()
 
 
     var date: Date?
     var date: Date?
 
 

+ 97 - 87
iOSClient/Media/NCMedia.swift

@@ -23,6 +23,7 @@
 
 
 import UIKit
 import UIKit
 import NextcloudKit
 import NextcloudKit
+import JGProgressHUD
 
 
 class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
 class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
 
 
@@ -33,7 +34,9 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
     private var gridLayout: NCGridMediaLayout!
     private var gridLayout: NCGridMediaLayout!
     internal var documentPickerViewController: NCDocumentPickerViewController?
     internal var documentPickerViewController: NCDocumentPickerViewController?
 
 
+    // swiftlint:disable force_cast
     internal let appDelegate = UIApplication.shared.delegate as! AppDelegate
     internal let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
 
 
     public var metadatas: [tableMetadata] = []
     public var metadatas: [tableMetadata] = []
     private var account: String = ""
     private var account: String = ""
@@ -43,6 +46,7 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
 
 
     internal var isEditMode = false
     internal var isEditMode = false
     internal var selectOcId: [String] = []
     internal var selectOcId: [String] = []
+    internal var selectIndexPath: [IndexPath] = []
 
 
     internal var filterClassTypeImage = false
     internal var filterClassTypeImage = false
     internal var filterClassTypeVideo = false
     internal var filterClassTypeVideo = false
@@ -89,9 +93,6 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
         // Empty
         // Empty
         emptyDataSet = NCEmptyDataSet(view: collectionView, offset: 0, delegate: self)
         emptyDataSet = NCEmptyDataSet(view: collectionView, offset: 0, delegate: self)
 
 
-        // Notification
-        NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil)
-
         mediaCommandView = Bundle.main.loadNibNamed("NCMediaCommandView", owner: self, options: nil)?.first as? NCMediaCommandView
         mediaCommandView = Bundle.main.loadNibNamed("NCMediaCommandView", owner: self, options: nil)?.first as? NCMediaCommandView
         self.view.addSubview(mediaCommandView!)
         self.view.addSubview(mediaCommandView!)
         mediaCommandView?.mediaView = self
         mediaCommandView?.mediaView = self
@@ -120,6 +121,7 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
 
 
         NotificationCenter.default.addObserver(self, selector: #selector(deleteFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(deleteFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(moveFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(moveFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(copyFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCopyFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(renameFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(renameFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil)
         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)
 
 
@@ -131,15 +133,16 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
 
 
     override func viewDidAppear(_ animated: Bool) {
     override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
         super.viewDidAppear(animated)
-        
+
         mediaCommandTitle()
         mediaCommandTitle()
     }
     }
-    
+
     override func viewWillDisappear(_ animated: Bool) {
     override func viewWillDisappear(_ animated: Bool) {
         super.viewWillDisappear(animated)
         super.viewWillDisappear(animated)
 
 
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil)
+        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCopyFile), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterRenameFile), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
     }
     }
@@ -156,53 +159,44 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
 
 
     // MARK: - NotificationCenter
     // MARK: - NotificationCenter
 
 
-    @objc func initialize() {
-
-        self.reloadDataSourceWithCompletion { _ in
-            self.timerSearchNewMedia?.invalidate()
-            self.timerSearchNewMedia = Timer.scheduledTimer(timeInterval: self.timeIntervalSearchNewMedia, target: self, selector: #selector(self.searchNewMediaTimer), userInfo: nil, repeats: false)
-            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
-                self.mediaCommandTitle()
-            }
-        }
-    }
-
     @objc func deleteFile(_ notification: NSNotification) {
     @objc func deleteFile(_ notification: NSNotification) {
 
 
         guard let userInfo = notification.userInfo as NSDictionary?,
         guard let userInfo = notification.userInfo as NSDictionary?,
-              let account = userInfo["account"] as? String,
-              let ocIds = userInfo["ocId"] as? [String],
-              let error = userInfo["error"] as? NKError
-        else { return }
+              let error = userInfo["error"] as? NKError else { return }
+        let onlyLocalCache: Bool = userInfo["onlyLocalCache"] as? Bool ?? false
 
 
-        if error == .success, account == appDelegate.account {
-            var items: [IndexPath] = []
-            var index: Int = 0
-            for metadata in metadatas {
-                if ocIds.contains(metadata.ocId) {
-                    self.metadatas.remove(at: index)
-                    items.append(IndexPath(row: index, section: 0))
-                }
-                if ocIds.count == items.count { break }
-                index += 1
-            }
-            if ocIds.count == items.count {
-                self.collectionView?.deleteItems(at: items)
-            } else {
-                self.reloadDataSourceWithCompletion { _ in }
+        self.queryDB(isForced: true)
+
+        if error == .success, let indexPath = userInfo["indexPath"] as? [IndexPath], !indexPath.isEmpty, !onlyLocalCache {
+            collectionView?.performBatchUpdates({
+                collectionView?.deleteItems(at: indexPath)
+            }, completion: { _ in
+                self.collectionView?.reloadData()
+            })
+        } else {
+            if error != .success {
+                NCContentPresenter.shared.showError(error: error)
             }
             }
+            self.collectionView?.reloadData()
+        }
+
+        if let hud = userInfo["hud"] as? JGProgressHUD {
+            hud.dismiss()
         }
         }
-        self.updateMediaControlVisibility()
     }
     }
 
 
     @objc func moveFile(_ notification: NSNotification) {
     @objc func moveFile(_ notification: NSNotification) {
 
 
-        guard let userInfo = notification.userInfo as NSDictionary?,
-              let account = userInfo["account"] as? String,
-              account == appDelegate.account
-        else { return }
+        guard let userInfo = notification.userInfo as NSDictionary? else { return }
 
 
-        self.reloadDataSourceWithCompletion { _ in }
+        if let hud = userInfo["hud"] as? JGProgressHUD {
+            hud.dismiss()
+        }
+    }
+
+    @objc func copyFile(_ notification: NSNotification) {
+
+        moveFile(notification)
     }
     }
 
 
     @objc func renameFile(_ notification: NSNotification) {
     @objc func renameFile(_ notification: NSNotification) {
@@ -280,7 +274,7 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
 
 
     // MARK: Select Path
     // MARK: Select Path
 
 
-    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) {
+    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) {
 
 
         guard let serverUrl = serverUrl else { return }
         guard let serverUrl = serverUrl else { return }
         let path = CCUtility.returnPathfromServerUrl(serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account) ?? ""
         let path = CCUtility.returnPathfromServerUrl(serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId, account: appDelegate.account) ?? ""
@@ -314,10 +308,12 @@ extension NCMedia: UICollectionViewDelegate {
         if isEditMode {
         if isEditMode {
             if let index = selectOcId.firstIndex(of: metadata.ocId) {
             if let index = selectOcId.firstIndex(of: metadata.ocId) {
                 selectOcId.remove(at: index)
                 selectOcId.remove(at: index)
+                selectIndexPath.removeAll(where: { $0 == indexPath })
             } else {
             } else {
                 selectOcId.append(metadata.ocId)
                 selectOcId.append(metadata.ocId)
+                selectIndexPath.append(indexPath)
             }
             }
-            if indexPath.section <  collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
+            if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
                 collectionView.reloadItems(at: [indexPath])
                 collectionView.reloadItems(at: [indexPath])
             }
             }
         } else {
         } else {
@@ -338,7 +334,7 @@ extension NCMedia: UICollectionViewDelegate {
         return UIContextMenuConfiguration(identifier: identifier, previewProvider: {
         return UIContextMenuConfiguration(identifier: identifier, previewProvider: {
             return NCViewerProviderContextMenu(metadata: metadata, image: image)
             return NCViewerProviderContextMenu(metadata: metadata, image: image)
         }, actionProvider: { _ in
         }, actionProvider: { _ in
-            return NCContextMenu().viewMenu(ocId: metadata.ocId, viewController: self, image: image)
+            return NCContextMenu().viewMenu(ocId: metadata.ocId, indexPath: indexPath, viewController: self, image: image)
         })
         })
     }
     }
 
 
@@ -391,15 +387,17 @@ extension NCMedia: UICollectionViewDataSource {
 
 
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
 
 
+        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCGridMediaCell else { return UICollectionViewCell() }
+
         if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) && indexPath.row < metadatas.count {
         if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) && indexPath.row < metadatas.count {
 
 
-            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridMediaCell
             let metadata = metadatas[indexPath.row]
             let metadata = metadatas[indexPath.row]
 
 
             self.cellHeigth = cell.frame.size.height
             self.cellHeigth = cell.frame.size.height
 
 
             cell.date = metadata.date as Date
             cell.date = metadata.date as Date
             cell.fileObjectId = metadata.ocId
             cell.fileObjectId = metadata.ocId
+            cell.indexPath = indexPath
             cell.fileUser = metadata.ownerId
             cell.fileUser = metadata.ownerId
 
 
             if metadata.isAudioOrVideo {
             if metadata.isAudioOrVideo {
@@ -423,7 +421,7 @@ extension NCMedia: UICollectionViewDataSource {
 
 
         } else {
         } else {
 
 
-            return collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as! NCGridMediaCell
+            return cell
         }
         }
     }
     }
 }
 }
@@ -443,14 +441,7 @@ extension NCMedia {
 
 
     // MARK: - Datasource
     // MARK: - Datasource
 
 
-    @objc func reloadDataSourceWithCompletion(_ completion: @escaping (_ metadatas: [tableMetadata]) -> Void) {
-        guard !appDelegate.account.isEmpty else { return }
-
-        if account != appDelegate.account {
-            self.metadatas = []
-            account = appDelegate.account
-            collectionView?.reloadData()
-        }
+    func queryDB(isForced: Bool) {
 
 
         livePhoto = CCUtility.getLivePhoto()
         livePhoto = CCUtility.getLivePhoto()
 
 
@@ -470,18 +461,32 @@ extension NCMedia {
         }
         }
 
 
         guard let predicate = predicate else { return }
         guard let predicate = predicate else { return }
+
+        self.metadatas = NCManageDatabase.shared.getMetadatasMedia(predicate: predicate, livePhoto: self.livePhoto)
+
+        switch CCUtility.getMediaSortDate() {
+        case "date":
+            self.metadatas = self.metadatas.sorted(by: {($0.date as Date) > ($1.date as Date)})
+        case "creationDate":
+            self.metadatas = self.metadatas.sorted(by: {($0.creationDate as Date) > ($1.creationDate as Date)})
+        case "uploadDate":
+            self.metadatas = self.metadatas.sorted(by: {($0.uploadDate as Date) > ($1.uploadDate as Date)})
+        default:
+            break
+        }
+    }
+
+    @objc func reloadDataSourceWithCompletion(_ completion: @escaping (_ metadatas: [tableMetadata]) -> Void) {
+        guard !appDelegate.account.isEmpty else { return }
+
+        if account != appDelegate.account {
+            self.metadatas = []
+            account = appDelegate.account
+            DispatchQueue.main.async { self.collectionView?.reloadData() }
+        }
+
         DispatchQueue.global().async {
         DispatchQueue.global().async {
-            self.metadatas = NCManageDatabase.shared.getMetadatasMedia(predicate: predicate, livePhoto: self.livePhoto)
-            switch CCUtility.getMediaSortDate() {
-            case "date":
-                self.metadatas = self.metadatas.sorted(by: {($0.date as Date) > ($1.date as Date)} )
-            case "creationDate":
-                self.metadatas = self.metadatas.sorted(by: {($0.creationDate as Date) > ($1.creationDate as Date)} )
-            case "uploadDate":
-                self.metadatas = self.metadatas.sorted(by: {($0.uploadDate as Date) > ($1.uploadDate as Date)} )
-            default:
-                break
-            }
+            self.queryDB(isForced: true)
             DispatchQueue.main.sync {
             DispatchQueue.main.sync {
                 self.reloadDataThenPerform {
                 self.reloadDataThenPerform {
                     self.updateMediaControlVisibility()
                     self.updateMediaControlVisibility()
@@ -494,7 +499,7 @@ extension NCMedia {
 
 
     func updateMediaControlVisibility() {
     func updateMediaControlVisibility() {
 
 
-        if self.metadatas.count == 0 {
+        if self.metadatas.isEmpty {
             if !self.filterClassTypeImage && !self.filterClassTypeVideo {
             if !self.filterClassTypeImage && !self.filterClassTypeVideo {
                 self.mediaCommandView?.toggleEmptyView(isEmpty: true)
                 self.mediaCommandView?.toggleEmptyView(isEmpty: true)
                 self.mediaCommandView?.isHidden = false
                 self.mediaCommandView?.isHidden = false
@@ -513,7 +518,14 @@ extension NCMedia {
     private func searchOldMedia(value: Int = -30, limit: Int = 300) {
     private func searchOldMedia(value: Int = -30, limit: Int = 300) {
 
 
         if oldInProgress { return } else { oldInProgress = true }
         if oldInProgress { return } else { oldInProgress = true }
-        collectionView.reloadData()
+        DispatchQueue.main.async {
+            self.collectionView.reloadData()
+            var bottom: CGFloat = 0
+            if let mainTabBar = self.tabBarController?.tabBar as? NCMainTabBar {
+                bottom = -mainTabBar.getHeight()
+            }
+            NCActivityIndicator.shared.start(backgroundView: self.view, bottom: bottom - 5, style: .medium)
+        }
 
 
         var lessDate = Date()
         var lessDate = Date()
         if predicateDefault != nil {
         if predicateDefault != nil {
@@ -529,28 +541,24 @@ extension NCMedia {
             greaterDate = Calendar.current.date(byAdding: .day, value: value, to: lessDate)!
             greaterDate = Calendar.current.date(byAdding: .day, value: value, to: lessDate)!
         }
         }
 
 
-        var bottom: CGFloat = 0
-        if let mainTabBar = self.tabBarController?.tabBar as? NCMainTabBar {
-            bottom = -mainTabBar.getHight()
-        }
-        NCActivityIndicator.shared.start(backgroundView: self.view, bottom: bottom-5, style: .medium)
+        let options = NKRequestOptions(timeout: 300, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
 
 
-        let options = NKRequestOptions(timeout: 300)
-        
-        NextcloudKit.shared.searchMedia(path: mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { account, files, data, error in
+        NextcloudKit.shared.searchMedia(path: mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { account, files, _, error in
 
 
             self.oldInProgress = false
             self.oldInProgress = false
-            NCActivityIndicator.shared.stop()
-            self.collectionView.reloadData()
+            DispatchQueue.main.async {
+                NCActivityIndicator.shared.stop()
+                self.collectionView.reloadData()
+            }
 
 
             if error == .success && account == self.appDelegate.account {
             if error == .success && account == self.appDelegate.account {
-                if files.count > 0 {
+                if !files.isEmpty {
                     NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
                     NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
                         let predicateDate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate)
                         let predicateDate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate)
                         let predicateResult = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateDate, self.predicateDefault!])
                         let predicateResult = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateDate, self.predicateDefault!])
                         let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: predicateResult)
                         let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: predicateResult)
                         let metadatasChanged = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareLivePhoto: false)
                         let metadatasChanged = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareLivePhoto: false)
-                        if metadatasChanged.metadatasUpdate.count == 0 {
+                        if metadatasChanged.metadatasUpdate.isEmpty {
                             self.researchOldMedia(value: value, limit: limit, withElseReloadDataSource: true)
                             self.researchOldMedia(value: value, limit: limit, withElseReloadDataSource: true)
                         } else {
                         } else {
                             self.reloadDataSourceWithCompletion { _ in }
                             self.reloadDataSourceWithCompletion { _ in }
@@ -616,24 +624,26 @@ extension NCMedia {
 
 
         reloadDataThenPerform {
         reloadDataThenPerform {
 
 
-            let options = NKRequestOptions(timeout: 300)
-            
-            NextcloudKit.shared.searchMedia(path: self.mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { account, files, data, error in
+            let options = NKRequestOptions(timeout: 300, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
+
+            NextcloudKit.shared.searchMedia(path: self.mediaPath, lessDate: lessDate, greaterDate: greaterDate, elementDate: "d:getlastmodified/", limit: limit, showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { account, files, _, error in
 
 
                 self.newInProgress = false
                 self.newInProgress = false
-                self.mediaCommandView?.activityIndicator.stopAnimating()
+                DispatchQueue.main.async {
+                    self.mediaCommandView?.activityIndicator.stopAnimating()
+                }
 
 
-                if error == .success && account == self.appDelegate.account && files.count > 0 {
+                if error == .success, account == self.appDelegate.account, !files.isEmpty {
                     NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
                     NCManageDatabase.shared.convertFilesToMetadatas(files, useMetadataFolder: false) { _, _, metadatas in
                         let predicate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate)
                         let predicate = NSPredicate(format: "date > %@ AND date < %@", greaterDate as NSDate, lessDate as NSDate)
                         let predicateResult = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, self.predicate!])
                         let predicateResult = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, self.predicate!])
                         let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: predicateResult)
                         let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: predicateResult)
                         let updateMetadatas = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareLivePhoto: false)
                         let updateMetadatas = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareLivePhoto: false)
-                        if updateMetadatas.metadatasUpdate.count > 0 || updateMetadatas.metadatasDelete.count > 0 {
+                        if !updateMetadatas.metadatasUpdate.isEmpty || !updateMetadatas.metadatasDelete.isEmpty {
                             self.reloadDataSourceWithCompletion { _ in }
                             self.reloadDataSourceWithCompletion { _ in }
                         }
                         }
                     }
                     }
-                } else if error == .success && files.count == 0 && self.metadatas.count == 0 {
+                } else if error == .success, files.isEmpty, self.metadatas.isEmpty {
                     self.searchOldMedia()
                     self.searchOldMedia()
                 } else if error != .success {
                 } else if error != .success {
                     NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Media search new media error code \(error.errorCode) " + error.errorDescription)
                     NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Media search new media error code \(error.errorCode) " + error.errorDescription)
@@ -649,7 +659,7 @@ extension NCMedia: UIScrollViewDelegate {
 
 
     func scrollViewDidScroll(_ scrollView: UIScrollView) {
     func scrollViewDidScroll(_ scrollView: UIScrollView) {
 
 
-        if lastContentOffsetY == 0 || lastContentOffsetY + cellHeigth/2 <= scrollView.contentOffset.y  || lastContentOffsetY - cellHeigth/2 >= scrollView.contentOffset.y {
+        if lastContentOffsetY == 0 || lastContentOffsetY + cellHeigth / 2 <= scrollView.contentOffset.y || lastContentOffsetY - cellHeigth / 2 >= scrollView.contentOffset.y {
 
 
             mediaCommandTitle()
             mediaCommandTitle()
             lastContentOffsetY = scrollView.contentOffset.y
             lastContentOffsetY = scrollView.contentOffset.y

+ 4 - 4
iOSClient/Media/NCMediaCommandView.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_12" orientation="portrait" appearance="light"/>
     <device id="retina6_12" 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="22130"/>
         <capability name="Image references" minToolsVersion="12.0"/>
         <capability name="Image references" minToolsVersion="12.0"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="Safe area layout guides" minToolsVersion="9.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"/>
@@ -29,7 +29,7 @@
                                 </constraints>
                                 </constraints>
                                 <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <inset key="imageEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
                                 <inset key="imageEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
-                                <state key="normal" image="plus.slash.minus" catalog="system">
+                                <state key="normal" image="plus.forwardslash.minus" catalog="system">
                                     <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                     <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 </state>
                                 </state>
                                 <state key="disabled">
                                 <state key="disabled">
@@ -173,6 +173,6 @@
         <image name="ellipsis" catalog="system" width="128" height="37"/>
         <image name="ellipsis" catalog="system" width="128" height="37"/>
         <image name="minus" catalog="system" width="128" height="26"/>
         <image name="minus" catalog="system" width="128" height="26"/>
         <image name="plus" catalog="system" width="128" height="113"/>
         <image name="plus" catalog="system" width="128" height="113"/>
-        <image name="plus.slash.minus" catalog="system" width="128" height="115"/>
+        <image name="plus.forwardslash.minus" catalog="system" width="128" height="115"/>
     </resources>
     </resources>
 </document>
 </document>

+ 72 - 65
iOSClient/Menu/AppDelegate+Menu.swift

@@ -33,19 +33,19 @@ extension AppDelegate {
 
 
         var actions: [NCMenuAction] = []
         var actions: [NCMenuAction] = []
 
 
+        // swiftlint:disable force_cast
         let appDelegate = UIApplication.shared.delegate as! AppDelegate
         let appDelegate = UIApplication.shared.delegate as! AppDelegate
+        // swiftlint:enable force_cast
+
         let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: appDelegate.account)
         let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: appDelegate.account)
         let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(serverUrl: appDelegate.activeServerUrl, userBase: appDelegate)
         let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(serverUrl: appDelegate.activeServerUrl, userBase: appDelegate)
         let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, appDelegate.activeServerUrl))
         let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, appDelegate.activeServerUrl))
-        let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId)
-
 
 
         actions.append(
         actions.append(
             NCMenuAction(
             NCMenuAction(
                 title: NSLocalizedString("_upload_photos_videos_", comment: ""), icon: UIImage(named: "file_photo")!.image(color: UIColor.systemGray, size: 50), action: { _ in
                 title: NSLocalizedString("_upload_photos_videos_", comment: ""), icon: UIImage(named: "file_photo")!.image(color: UIColor.systemGray, size: 50), action: { _ in
                     NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in
                     NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in
-                        if hasPermission {
-                            NCPhotosPickerViewController.init(viewController: viewController, maxSelectedAssets: 0, singleSelectedMode: false)
+                        if hasPermission {NCPhotosPickerViewController(viewController: viewController, maxSelectedAssets: 0, singleSelectedMode: false)
                         }
                         }
                     }
                     }
                 }
                 }
@@ -71,14 +71,15 @@ extension AppDelegate {
                     }
                     }
                     navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                     navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                    let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
-                    viewController.editorId = NCGlobal.shared.editorText
-                    viewController.creatorId = directEditingCreator.identifier
-                    viewController.typeTemplate = NCGlobal.shared.templateDocument
-                    viewController.serverUrl = appDelegate.activeServerUrl
-                    viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
+                    if let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments {
+                        viewController.editorId = NCGlobal.shared.editorText
+                        viewController.creatorId = directEditingCreator.identifier
+                        viewController.typeTemplate = NCGlobal.shared.templateDocument
+                        viewController.serverUrl = appDelegate.activeServerUrl
+                        viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
 
 
-                    appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                        appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                    }
                 })
                 })
             )
             )
         }
         }
@@ -99,14 +100,15 @@ extension AppDelegate {
                     NCAskAuthorization.shared.askAuthorizationAudioRecord(viewController: viewController) { hasPermission in
                     NCAskAuthorization.shared.askAuthorizationAudioRecord(viewController: viewController) { hasPermission in
                         if hasPermission {
                         if hasPermission {
                             let fileName = CCUtility.createFileNameDate(NSLocalizedString("_voice_memo_filename_", comment: ""), extension: "m4a")!
                             let fileName = CCUtility.createFileNameDate(NSLocalizedString("_voice_memo_filename_", comment: ""), extension: "m4a")!
-                            let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as! NCAudioRecorderViewController
+                            if let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as? NCAudioRecorderViewController {
 
 
-                            viewController.delegate = self
-                            viewController.createRecorder(fileName: fileName)
-                            viewController.modalTransitionStyle = .crossDissolve
-                            viewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
+                                viewController.delegate = self
+                                viewController.createRecorder(fileName: fileName)
+                                viewController.modalTransitionStyle = .crossDissolve
+                                viewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
 
 
-                            appDelegate.window?.rootViewController?.present(viewController, animated: true, completion: nil)
+                                appDelegate.window?.rootViewController?.present(viewController, animated: true, completion: nil)
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
@@ -121,17 +123,16 @@ extension AppDelegate {
         let imageCreateFolder = isDirectoryE2EE ? UIImage(named: "folderEncrypted")! : UIImage(named: "folder")!
         let imageCreateFolder = isDirectoryE2EE ? UIImage(named: "folderEncrypted")! : UIImage(named: "folder")!
         actions.append(
         actions.append(
             NCMenuAction(title: titleCreateFolder,
             NCMenuAction(title: titleCreateFolder,
-                icon: imageCreateFolder.image(color: NCBrandColor.shared.brandElement, size: 50), action: { _ in
-                    guard !appDelegate.activeServerUrl.isEmpty else { return }
-                    let alertController = UIAlertController.createFolder(serverUrl: appDelegate.activeServerUrl, urlBase: appDelegate)
-                    appDelegate.window?.rootViewController?.present(alertController, animated: true, completion: nil)
-                }
-            )
+                         icon: imageCreateFolder.image(color: NCBrandColor.shared.brandElement, size: 50), action: { _ in
+                             guard !appDelegate.activeServerUrl.isEmpty else { return }
+                             let alertController = UIAlertController.createFolder(serverUrl: appDelegate.activeServerUrl, urlBase: appDelegate)
+                             appDelegate.window?.rootViewController?.present(alertController, animated: true, completion: nil)
+                         }
+                        )
         )
         )
 
 
-        // Folder encrypted (ONLY ROOT)
-        if serverUrlHome == appDelegate.activeServerUrl && CCUtility.isEnd(toEndEnabled: appDelegate.account) {
-        //if !isDirectoryE2EE && CCUtility.isEnd(toEndEnabled: appDelegate.account) {
+        // Folder encrypted
+        if !isDirectoryE2EE && CCUtility.isEnd(toEndEnabled: appDelegate.account) {
             actions.append(
             actions.append(
                 NCMenuAction(title: NSLocalizedString("_create_folder_e2ee_", comment: ""),
                 NCMenuAction(title: NSLocalizedString("_create_folder_e2ee_", comment: ""),
                              icon: UIImage(named: "folderEncrypted")!.image(color: NCBrandColor.shared.brandElement, size: 50),
                              icon: UIImage(named: "folderEncrypted")!.image(color: NCBrandColor.shared.brandElement, size: 50),
@@ -174,14 +175,15 @@ extension AppDelegate {
                         }
                         }
                         navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                         navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                        let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
-                        viewController.editorId = NCGlobal.shared.editorOnlyoffice
-                        viewController.creatorId = directEditingCreator.identifier
-                        viewController.typeTemplate = NCGlobal.shared.templateDocument
-                        viewController.serverUrl = appDelegate.activeServerUrl
-                        viewController.titleForm = NSLocalizedString("_create_new_document_", comment: "")
+                        if let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments {
+                            viewController.editorId = NCGlobal.shared.editorOnlyoffice
+                            viewController.creatorId = directEditingCreator.identifier
+                            viewController.typeTemplate = NCGlobal.shared.templateDocument
+                            viewController.serverUrl = appDelegate.activeServerUrl
+                            viewController.titleForm = NSLocalizedString("_create_new_document_", comment: "")
 
 
-                        appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                            appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                        }
                     }
                     }
                 )
                 )
             )
             )
@@ -197,14 +199,15 @@ extension AppDelegate {
                         }
                         }
                         navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                         navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                        let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
-                        viewController.editorId = NCGlobal.shared.editorOnlyoffice
-                        viewController.creatorId = directEditingCreator.identifier
-                        viewController.typeTemplate = NCGlobal.shared.templateSpreadsheet
-                        viewController.serverUrl = appDelegate.activeServerUrl
-                        viewController.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "")
+                        if let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments {
+                            viewController.editorId = NCGlobal.shared.editorOnlyoffice
+                            viewController.creatorId = directEditingCreator.identifier
+                            viewController.typeTemplate = NCGlobal.shared.templateSpreadsheet
+                            viewController.serverUrl = appDelegate.activeServerUrl
+                            viewController.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "")
 
 
-                        appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                            appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                        }
                     }
                     }
                 )
                 )
             )
             )
@@ -220,14 +223,15 @@ extension AppDelegate {
                         }
                         }
                         navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                         navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                        let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
-                        viewController.editorId = NCGlobal.shared.editorOnlyoffice
-                        viewController.creatorId = directEditingCreator.identifier
-                        viewController.typeTemplate = NCGlobal.shared.templatePresentation
-                        viewController.serverUrl = appDelegate.activeServerUrl
-                        viewController.titleForm = NSLocalizedString("_create_new_presentation_", comment: "")
+                        if let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments {
+                            viewController.editorId = NCGlobal.shared.editorOnlyoffice
+                            viewController.creatorId = directEditingCreator.identifier
+                            viewController.typeTemplate = NCGlobal.shared.templatePresentation
+                            viewController.serverUrl = appDelegate.activeServerUrl
+                            viewController.titleForm = NSLocalizedString("_create_new_presentation_", comment: "")
 
 
-                        appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                            appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                        }
                     }
                     }
                 )
                 )
             )
             )
@@ -243,13 +247,14 @@ extension AppDelegate {
                             }
                             }
                             navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                             navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                            let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
-                            viewController.editorId = NCGlobal.shared.editorCollabora
-                            viewController.typeTemplate = NCGlobal.shared.templateDocument
-                            viewController.serverUrl = appDelegate.activeServerUrl
-                            viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
+                            if let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments {
+                                viewController.editorId = NCGlobal.shared.editorCollabora
+                                viewController.typeTemplate = NCGlobal.shared.templateDocument
+                                viewController.serverUrl = appDelegate.activeServerUrl
+                                viewController.titleForm = NSLocalizedString("_create_nextcloudtext_document_", comment: "")
 
 
-                            appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                                appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                            }
                         }
                         }
                     )
                     )
                 )
                 )
@@ -262,13 +267,14 @@ extension AppDelegate {
                             }
                             }
                             navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                             navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                            let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
-                            viewController.editorId = NCGlobal.shared.editorCollabora
-                            viewController.typeTemplate = NCGlobal.shared.templateSpreadsheet
-                            viewController.serverUrl = appDelegate.activeServerUrl
-                            viewController.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "")
+                            if let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments {
+                                viewController.editorId = NCGlobal.shared.editorCollabora
+                                viewController.typeTemplate = NCGlobal.shared.templateSpreadsheet
+                                viewController.serverUrl = appDelegate.activeServerUrl
+                                viewController.titleForm = NSLocalizedString("_create_new_spreadsheet_", comment: "")
 
 
-                            appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                                appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                            }
                         }
                         }
                     )
                     )
                 )
                 )
@@ -281,13 +287,14 @@ extension AppDelegate {
                             }
                             }
                             navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
                             navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
 
 
-                            let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadDocuments
-                            viewController.editorId = NCGlobal.shared.editorCollabora
-                            viewController.typeTemplate = NCGlobal.shared.templatePresentation
-                            viewController.serverUrl = appDelegate.activeServerUrl
-                            viewController.titleForm = NSLocalizedString("_create_new_presentation_", comment: "")
+                            if let viewController = (navigationController as? UINavigationController)?.topViewController as? NCCreateFormUploadDocuments {
+                                viewController.editorId = NCGlobal.shared.editorCollabora
+                                viewController.typeTemplate = NCGlobal.shared.templatePresentation
+                                viewController.serverUrl = appDelegate.activeServerUrl
+                                viewController.titleForm = NSLocalizedString("_create_new_presentation_", comment: "")
 
 
-                            appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                                appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+                            }
                         }
                         }
                     )
                     )
                 )
                 )

+ 20 - 25
iOSClient/Menu/NCCollectionViewCommon+Menu.swift

@@ -32,20 +32,19 @@ import Queuer
 
 
 extension NCCollectionViewCommon {
 extension NCCollectionViewCommon {
 
 
-    func toggleMenu(metadata: tableMetadata, imageIcon: UIImage?) {
+    func toggleMenu(metadata: tableMetadata, indexPath: IndexPath, imageIcon: UIImage?) {
 
 
         var actions = [NCMenuAction]()
         var actions = [NCMenuAction]()
 
 
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
         let serverUrl = metadata.serverUrl + "/" + metadata.fileName
         let serverUrl = metadata.serverUrl + "/" + metadata.fileName
-        let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId)
-        let isOffline: Bool
+        var isOffline: Bool = false
 
 
         if metadata.directory, let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, serverUrl)) {
         if metadata.directory, let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, serverUrl)) {
             isOffline = directory.offline
             isOffline = directory.offline
         } else if let localFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) {
         } else if let localFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) {
             isOffline = localFile.offline
             isOffline = localFile.offline
-        } else { isOffline = false }
+        }
 
 
         let editors = NCUtility.shared.isDirectEditing(account: metadata.account, contentType: metadata.contentType)
         let editors = NCUtility.shared.isDirectEditing(account: metadata.account, contentType: metadata.contentType)
         let isRichDocument = NCUtility.shared.isRichDocument(metadata)
         let isRichDocument = NCUtility.shared.isRichDocument(metadata)
@@ -130,7 +129,7 @@ extension NCCollectionViewCommon {
                     title: NSLocalizedString("_view_in_folder_", comment: ""),
                     title: NSLocalizedString("_view_in_folder_", comment: ""),
                     icon: NCUtility.shared.loadImage(named: "questionmark.folder"),
                     icon: NCUtility.shared.loadImage(named: "questionmark.folder"),
                     order: 21,
                     order: 21,
-                    action: { menuAction in
+                    action: { _ in
                         NCActionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileNameBlink: metadata.fileName, fileNameOpen: nil)
                         NCActionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileNameBlink: metadata.fileName, fileNameOpen: nil)
                     }
                     }
                 )
                 )
@@ -145,24 +144,19 @@ extension NCCollectionViewCommon {
         }
         }
 
 
         //
         //
-        // SET FOLDER E2EE (ONLY ROOT)
+        // SET FOLDER E2EE
         //
         //
-        if metadata.serverUrl == serverUrlHome, metadata.isDirectoySettableE2EE {
+        if metadata.isDirectoySettableE2EE {
             actions.append(
             actions.append(
                 NCMenuAction(
                 NCMenuAction(
                     title: NSLocalizedString("_e2e_set_folder_encrypted_", comment: ""),
                     title: NSLocalizedString("_e2e_set_folder_encrypted_", comment: ""),
                     icon: NCUtility.shared.loadImage(named: "lock"),
                     icon: NCUtility.shared.loadImage(named: "lock"),
                     order: 30,
                     order: 30,
                     action: { _ in
                     action: { _ in
-                        NextcloudKit.shared.markE2EEFolder(fileId: metadata.fileId, delete: false) { account, error in
-                            if error == .success {
-                                NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, serverUrl))
-                                NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: true, richWorkspace: nil, account: metadata.account)
-                                NCManageDatabase.shared.setMetadataEncrypted(ocId: metadata.ocId, encrypted: true)
-
-                                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl])
-                            } else {
-                                NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_mark_folder_", comment: ""), error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error)
+                        Task {
+                            let error = await NCNetworkingE2EEMarkFolder().markFolderE2ee(account: metadata.account, fileName: metadata.fileName, serverUrl: metadata.serverUrl, userId: metadata.userId)
+                            if error != .success {
+                                NCContentPresenter.shared.showError(error: error)
                             }
                             }
                         }
                         }
                     }
                     }
@@ -180,7 +174,7 @@ extension NCCollectionViewCommon {
                     icon: NCUtility.shared.loadImage(named: "lock"),
                     icon: NCUtility.shared.loadImage(named: "lock"),
                     order: 30,
                     order: 30,
                     action: { _ in
                     action: { _ in
-                        NextcloudKit.shared.markE2EEFolder(fileId: metadata.fileId, delete: true) { account, error in
+                        NextcloudKit.shared.markE2EEFolder(fileId: metadata.fileId, delete: true) { _, error in
                             if error == .success {
                             if error == .success {
                                 NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, serverUrl))
                                 NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, serverUrl))
                                 NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: false, richWorkspace: nil, account: metadata.account)
                                 NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: false, richWorkspace: nil, account: metadata.account)
@@ -188,7 +182,7 @@ extension NCCollectionViewCommon {
 
 
                                 NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl])
                                 NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl])
                             } else {
                             } else {
-                                NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_delete_mark_folder_", comment: ""), error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error)
+                                NCContentPresenter.shared.messageNotification(NSLocalizedString("_e2e_error_", comment: ""), error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error)
                             }
                             }
                         }
                         }
                     }
                     }
@@ -247,7 +241,7 @@ extension NCCollectionViewCommon {
                 icon = NCUtility.shared.loadImage(named: "collabora")
                 icon = NCUtility.shared.loadImage(named: "collabora")
             }
             }
 
 
-            if editor != "" {
+            if !editor.isEmpty {
                 actions.append(
                 actions.append(
                     NCMenuAction(
                     NCMenuAction(
                         title: title,
                         title: title,
@@ -317,6 +311,7 @@ extension NCCollectionViewCommon {
 
 
                             vcRename.metadata = metadata
                             vcRename.metadata = metadata
                             vcRename.imagePreview = imageIcon
                             vcRename.imagePreview = imageIcon
+                            vcRename.indexPath = indexPath
 
 
                             let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
                             let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
 
 
@@ -331,16 +326,16 @@ extension NCCollectionViewCommon {
         // COPY - MOVE
         // COPY - MOVE
         //
         //
         if metadata.isCopyableMovable {
         if metadata.isCopyableMovable {
-            actions.append(.moveOrCopyAction(selectedMetadatas: [metadata], order: 130))
+            actions.append(.moveOrCopyAction(selectedMetadatas: [metadata], indexPath: [indexPath], order: 130))
         }
         }
 
 
         //
         //
         // COPY IN PASTEBOARD
         // COPY IN PASTEBOARD
         //
         //
         if metadata.isCopyableInPasteboard {
         if metadata.isCopyableInPasteboard {
-            actions.append(.copyAction(selectOcId: [metadata.ocId], hudView: self.view, order: 140))
+            actions.append(.copyAction(selectOcId: [metadata.ocId], order: 140))
         }
         }
-        
+
         //
         //
         // MODIFY WITH QUICK LOOK
         // MODIFY WITH QUICK LOOK
         //
         //
@@ -350,7 +345,7 @@ extension NCCollectionViewCommon {
                     title: NSLocalizedString("_modify_", comment: ""),
                     title: NSLocalizedString("_modify_", comment: ""),
                     icon: NCUtility.shared.loadImage(named: "pencil.tip.crop.circle"),
                     icon: NCUtility.shared.loadImage(named: "pencil.tip.crop.circle"),
                     order: 150,
                     order: 150,
-                    action: { menuAction in
+                    action: { _ in
                         if CCUtility.fileProviderStorageExists(metadata) {
                         if CCUtility.fileProviderStorageExists(metadata) {
                             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorLoadFileQuickLook, "error": NKError(), "account": metadata.account])
                             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorLoadFileQuickLook, "error": NKError(), "account": metadata.account])
                         } else {
                         } else {
@@ -381,12 +376,12 @@ extension NCCollectionViewCommon {
                 )
                 )
             )
             )
         }
         }
-        
+
         //
         //
         // DELETE
         // DELETE
         //
         //
         if metadata.isDeletable {
         if metadata.isDeletable {
-            actions.append(.deleteAction(selectedMetadatas: [metadata], metadataFolder: metadataFolder, viewController: self, order: 170))
+            actions.append(.deleteAction(selectedMetadatas: [metadata], indexPath: [indexPath], metadataFolder: metadataFolder, viewController: self, order: 170))
         }
         }
 
 
         applicationHandle.addCollectionViewCommonMenu(metadata: metadata, imageIcon: imageIcon, actions: &actions)
         applicationHandle.addCollectionViewCommonMenu(metadata: metadata, imageIcon: imageIcon, actions: &actions)

+ 11 - 13
iOSClient/Menu/NCContextMenu.swift

@@ -28,7 +28,7 @@ import JGProgressHUD
 
 
 class NCContextMenu: NSObject {
 class NCContextMenu: NSObject {
 
 
-    func viewMenu(ocId: String, viewController: UIViewController, image: UIImage?) -> UIMenu {
+    func viewMenu(ocId: String, indexPath: IndexPath, viewController: UIViewController, image: UIImage?) -> UIMenu {
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return UIMenu() }
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return UIMenu() }
 
 
         var downloadRequest: DownloadRequest?
         var downloadRequest: DownloadRequest?
@@ -41,6 +41,7 @@ class NCContextMenu: NSObject {
 
 
         let hud = JGProgressHUD()
         let hud = JGProgressHUD()
         hud.indicatorView = JGProgressHUDRingIndicatorView()
         hud.indicatorView = JGProgressHUDRingIndicatorView()
+        hud.textLabel.text = NSLocalizedString("_downloading_", comment: "")
         hud.detailTextLabel.text = NSLocalizedString("_tap_to_cancel_", comment: "")
         hud.detailTextLabel.text = NSLocalizedString("_tap_to_cancel_", comment: "")
         if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView { indicatorView.ringWidth = 1.5 }
         if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView { indicatorView.ringWidth = 1.5 }
         hud.tapOnHUDViewBlock = { _ in
         hud.tapOnHUDViewBlock = { _ in
@@ -97,7 +98,7 @@ class NCContextMenu: NSObject {
         let save = UIAction(title: titleSave,
         let save = UIAction(title: titleSave,
                             image: UIImage(systemName: "square.and.arrow.down")) { _ in
                             image: UIImage(systemName: "square.and.arrow.down")) { _ in
             if let metadataMOV = metadataMOV {
             if let metadataMOV = metadataMOV {
-                NCActionCenter.shared.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV)
+                NCOperationQueue.shared.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV)
             } else {
             } else {
                 if CCUtility.fileProviderStorageExists(metadata) {
                 if CCUtility.fileProviderStorageExists(metadata) {
                     NCActionCenter.shared.saveAlbum(metadata: metadata)
                     NCActionCenter.shared.saveAlbum(metadata: metadata)
@@ -120,13 +121,6 @@ class NCContextMenu: NSObject {
             }
             }
         }
         }
 
 
-        /*
-        let copy = UIAction(title: NSLocalizedString("_copy_file_", comment: ""),
-                            image: UIImage(systemName: "doc.on.doc")) { _ in
-            NCActionCenter.shared.copyPasteboard(pasteboardOcIds: [metadata.ocId], hudView: viewController.view)
-        }
-        */
-
         let modify = UIAction(title: NSLocalizedString("_modify_", comment: ""),
         let modify = UIAction(title: NSLocalizedString("_modify_", comment: ""),
                               image: UIImage(systemName: "pencil.tip.crop.circle")) { _ in
                               image: UIImage(systemName: "pencil.tip.crop.circle")) { _ in
             if CCUtility.fileProviderStorageExists(metadata) {
             if CCUtility.fileProviderStorageExists(metadata) {
@@ -158,16 +152,21 @@ class NCContextMenu: NSObject {
             }
             }
             let alertController = UIAlertController(title: nil, message: nil, preferredStyle: alertStyle)
             let alertController = UIAlertController(title: nil, message: nil, preferredStyle: alertStyle)
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .destructive) { _ in
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .destructive) { _ in
+                let hud = JGProgressHUD()
+                hud.textLabel.text = NSLocalizedString("_deletion_progess_", comment: "")
+                if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
+                   let view = appDelegate.window?.rootViewController?.view {
+                    hud.show(in: view)
+                }
                 Task {
                 Task {
                     var ocId: [String] = []
                     var ocId: [String] = []
-                    let account: String = metadata.account
                     let error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false)
                     let error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false)
                     if error == .success {
                     if error == .success {
                         ocId.append(metadata.ocId)
                         ocId.append(metadata.ocId)
                     } else {
                     } else {
                         NCContentPresenter.shared.showError(error: error)
                         NCContentPresenter.shared.showError(error: error)
                     }
                     }
-                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
+                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "indexPath": [indexPath], "onlyLocalCache": false, "error": error, "hud": hud])
                 }
                 }
             })
             })
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { _ in })
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { _ in })
@@ -178,14 +177,13 @@ class NCContextMenu: NSObject {
                                           image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
                                           image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
             Task {
             Task {
                 var ocId: [String] = []
                 var ocId: [String] = []
-                let account: String = metadata.account
                 let error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true)
                 let error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true)
                 if error == .success {
                 if error == .success {
                     ocId.append(metadata.ocId)
                     ocId.append(metadata.ocId)
                 } else {
                 } else {
                     NCContentPresenter.shared.showError(error: error)
                     NCContentPresenter.shared.showError(error: error)
                 }
                 }
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
+                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "indexPath": [indexPath], "onlyLocalCache": true, "error": error])
             }
             }
         }
         }
 
 

+ 4 - 5
iOSClient/Menu/NCLoginWeb+Menu.swift

@@ -52,9 +52,8 @@ extension NCLoginWeb {
                     on: account.active == true,
                     on: account.active == true,
                     action: { _ in
                     action: { _ in
                         if self.appDelegate.account != account.account {
                         if self.appDelegate.account != account.account {
-                            NCManageDatabase.shared.setAccountActive(account.account)
                             self.dismiss(animated: true) {
                             self.dismiss(animated: true) {
-                                self.appDelegate.settingAccount(account.account, urlBase: account.urlBase, user: account.user, userId: account.userId, password: CCUtility.getPassword(account.account))
+                                self.appDelegate.changeAccount(account.account, userProfile: nil)
                             }
                             }
                         }
                         }
                     }
                     }
@@ -74,10 +73,10 @@ extension NCLoginWeb {
                     self.appDelegate.deleteAccount(self.appDelegate.account, wipe: false)
                     self.appDelegate.deleteAccount(self.appDelegate.account, wipe: false)
                     self.dismiss(animated: true) {
                     self.dismiss(animated: true) {
                         let accounts = NCManageDatabase.shared.getAllAccount()
                         let accounts = NCManageDatabase.shared.getAllAccount()
-                        if accounts.count > 0 {
-                            self.appDelegate.changeAccount(accounts.first!.account)
-                        } else {
+                        if accounts.isEmpty {
                             self.appDelegate.openLogin(viewController: nil, selector: NCGlobal.shared.introLogin, openLoginWeb: false)
                             self.appDelegate.openLogin(viewController: nil, selector: NCGlobal.shared.introLogin, openLoginWeb: false)
+                        } else {
+                            self.appDelegate.changeAccount(accounts.first!.account, userProfile: nil)
                         }
                         }
                     }
                     }
                 }
                 }

+ 14 - 11
iOSClient/Menu/NCMedia+Menu.swift

@@ -29,6 +29,7 @@ extension NCMedia {
     func tapSelect() {
     func tapSelect() {
         self.isEditMode = false
         self.isEditMode = false
         self.selectOcId.removeAll()
         self.selectOcId.removeAll()
+        self.selectIndexPath.removeAll()
         self.reloadDataThenPerform { }
         self.reloadDataThenPerform { }
     }
     }
 
 
@@ -39,7 +40,7 @@ extension NCMedia {
         defer { presentMenu(with: actions) }
         defer { presentMenu(with: actions) }
 
 
         if !isEditMode {
         if !isEditMode {
-            if metadatas.count > 0 {
+            if !metadatas.isEmpty {
                 actions.append(
                 actions.append(
                     NCMenuAction(
                     NCMenuAction(
                         title: NSLocalizedString("_select_", comment: ""),
                         title: NSLocalizedString("_select_", comment: ""),
@@ -84,14 +85,16 @@ extension NCMedia {
                     title: NSLocalizedString("_select_media_folder_", comment: ""),
                     title: NSLocalizedString("_select_media_folder_", comment: ""),
                     icon: NCUtility.shared.loadImage(named: "folder"),
                     icon: NCUtility.shared.loadImage(named: "folder"),
                     action: { _ in
                     action: { _ in
-                        let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as! UINavigationController
-                        let viewController = navigationController.topViewController as! NCSelect
+                        if let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as? UINavigationController,
+                           let viewController = navigationController.topViewController as? NCSelect {
 
 
-                        viewController.delegate = self
-                        viewController.typeOfCommandView = .select
-                        viewController.type = "mediaFolder"
+                            viewController.delegate = self
+                            viewController.typeOfCommandView = .select
+                            viewController.type = "mediaFolder"
+                            viewController.selectIndexPath = self.selectIndexPath
 
 
-                        self.present(navigationController, animated: true, completion: nil)
+                            self.present(navigationController, animated: true, completion: nil)
+                        }
                     }
                     }
                 )
                 )
             )
             )
@@ -103,7 +106,7 @@ extension NCMedia {
                     title: NSLocalizedString("_play_from_files_", comment: ""),
                     title: NSLocalizedString("_play_from_files_", comment: ""),
                     icon: NCUtility.shared.loadImage(named: "play.circle"),
                     icon: NCUtility.shared.loadImage(named: "play.circle"),
                     action: { _ in
                     action: { _ in
-                        if let tabBarController =  self.appDelegate.window?.rootViewController as? UITabBarController {
+                        if let tabBarController = self.appDelegate.window?.rootViewController as? UITabBarController {
                             self.documentPickerViewController = NCDocumentPickerViewController(tabBarController: tabBarController, isViewerMedia: true, allowsMultipleSelection: false, viewController: self)
                             self.documentPickerViewController = NCDocumentPickerViewController(tabBarController: tabBarController, isViewerMedia: true, allowsMultipleSelection: false, viewController: self)
                         }
                         }
                     }
                     }
@@ -207,18 +210,18 @@ extension NCMedia {
             //
             //
             // COPY - MOVE
             // COPY - MOVE
             //
             //
-            actions.append(.moveOrCopyAction(selectedMetadatas: selectedMetadatas, completion: tapSelect))
+            actions.append(.moveOrCopyAction(selectedMetadatas: selectedMetadatas, indexPath: selectIndexPath, completion: tapSelect))
 
 
             //
             //
             // COPY
             // COPY
             //
             //
-            actions.append(.copyAction(selectOcId: selectOcId, hudView: self.view, completion: tapSelect))
+            actions.append(.copyAction(selectOcId: selectOcId, completion: tapSelect))
 
 
             //
             //
             // DELETE
             // DELETE
             // can't delete from cache because is needed for NCMedia view, and if locked can't delete from server either.
             // can't delete from cache because is needed for NCMedia view, and if locked can't delete from server either.
             if !selectedMetadatas.contains(where: { $0.lock && $0.lockOwner != appDelegate.userId }) {
             if !selectedMetadatas.contains(where: { $0.lock && $0.lockOwner != appDelegate.userId }) {
-                actions.append(.deleteAction(selectedMetadatas: selectedMetadatas, metadataFolder: nil, viewController: self, completion: tapSelect))
+                actions.append(.deleteAction(selectedMetadatas: selectedMetadatas, indexPath: selectIndexPath, metadataFolder: nil, viewController: self, completion: tapSelect))
             }
             }
         }
         }
     }
     }

+ 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 }

+ 15 - 13
iOSClient/Menu/NCMenuAction.swift

@@ -25,6 +25,7 @@
 import Foundation
 import Foundation
 import UIKit
 import UIKit
 import NextcloudKit
 import NextcloudKit
+import JGProgressHUD
 
 
 class NCMenuAction {
 class NCMenuAction {
     let title: String
     let title: String
@@ -92,20 +93,20 @@ extension NCMenuAction {
     }
     }
 
 
     /// Copy files to pasteboard
     /// Copy files to pasteboard
-    static func copyAction(selectOcId: [String], hudView: UIView, order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction {
+    static func copyAction(selectOcId: [String], order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction {
         NCMenuAction(
         NCMenuAction(
             title: NSLocalizedString("_copy_file_", comment: ""),
             title: NSLocalizedString("_copy_file_", comment: ""),
             icon: NCUtility.shared.loadImage(named: "doc.on.doc"),
             icon: NCUtility.shared.loadImage(named: "doc.on.doc"),
             order: order,
             order: order,
             action: { _ in
             action: { _ in
-                NCActionCenter.shared.copyPasteboard(pasteboardOcIds: selectOcId, hudView: hudView)
+                NCActionCenter.shared.copyPasteboard(pasteboardOcIds: selectOcId)
                 completion?()
                 completion?()
             }
             }
         )
         )
     }
     }
 
 
     /// Delete files either from cache or from Nextcloud
     /// Delete files either from cache or from Nextcloud
-    static func deleteAction(selectedMetadatas: [tableMetadata], metadataFolder: tableMetadata? = nil, viewController: UIViewController, order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction {
+    static func deleteAction(selectedMetadatas: [tableMetadata], indexPath: [IndexPath], metadataFolder: tableMetadata? = nil, viewController: UIViewController, order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction {
         var titleDelete = NSLocalizedString("_delete_", comment: "")
         var titleDelete = NSLocalizedString("_delete_", comment: "")
         if selectedMetadatas.count > 1 {
         if selectedMetadatas.count > 1 {
             titleDelete = NSLocalizedString("_delete_selected_files_", comment: "")
             titleDelete = NSLocalizedString("_delete_selected_files_", comment: "")
@@ -145,20 +146,22 @@ extension NCMenuAction {
                     preferredStyle: .alert)
                     preferredStyle: .alert)
                 if canDeleteServer {
                 if canDeleteServer {
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in
+                        let hud = JGProgressHUD()
+                        hud.textLabel.text = NSLocalizedString("_deletion_progess_", comment: "")
+                        if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
+                           let view = appDelegate.window?.rootViewController?.view {
+                            hud.show(in: view)
+                        }
                         Task {
                         Task {
                             var error = NKError()
                             var error = NKError()
                             var ocId: [String] = []
                             var ocId: [String] = []
-                            let account = selectedMetadatas.first?.account ?? ""
                             for metadata in selectedMetadatas where error == .success {
                             for metadata in selectedMetadatas where error == .success {
                                 error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false)
                                 error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false)
                                 if error == .success {
                                 if error == .success {
                                     ocId.append(metadata.ocId)
                                     ocId.append(metadata.ocId)
                                 }
                                 }
                             }
                             }
-                            if error != .success {
-                                NCContentPresenter.shared.showError(error: error)
-                            }
-                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
+                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "indexPath": indexPath, "onlyLocalCache": false, "error": error, "hud": hud])
                         }
                         }
                         completion?()
                         completion?()
                     })
                     })
@@ -170,7 +173,6 @@ extension NCMenuAction {
                         Task {
                         Task {
                             var error = NKError()
                             var error = NKError()
                             var ocId: [String] = []
                             var ocId: [String] = []
-                            let account = selectedMetadatas.first?.account ?? ""
                             for metadata in selectedMetadatas where error == .success {
                             for metadata in selectedMetadatas where error == .success {
                                 error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true)
                                 error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true)
                                 if error == .success {
                                 if error == .success {
@@ -180,7 +182,7 @@ extension NCMenuAction {
                             if error != .success {
                             if error != .success {
                                 NCContentPresenter.shared.showError(error: error)
                                 NCContentPresenter.shared.showError(error: error)
                             }
                             }
-                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
+                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "indexPath": indexPath, "onlyLocalCache": true, "error": error])
                         }
                         }
                         completion?()
                         completion?()
                     })
                     })
@@ -220,7 +222,7 @@ extension NCMenuAction {
             action: { _ in
             action: { _ in
                 for metadata in selectedMediaMetadatas {
                 for metadata in selectedMediaMetadatas {
                     if let metadataMOV = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) {
                     if let metadataMOV = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) {
-                        NCActionCenter.shared.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV)
+                        NCOperationQueue.shared.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV)
                     } else {
                     } else {
                         if CCUtility.fileProviderStorageExists(metadata) {
                         if CCUtility.fileProviderStorageExists(metadata) {
                             NCActionCenter.shared.saveAlbum(metadata: metadata)
                             NCActionCenter.shared.saveAlbum(metadata: metadata)
@@ -261,13 +263,13 @@ extension NCMenuAction {
     }
     }
 
 
     /// Open view that lets the user move or copy the files within Nextcloud
     /// Open view that lets the user move or copy the files within Nextcloud
-    static func moveOrCopyAction(selectedMetadatas: [tableMetadata], order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction {
+    static func moveOrCopyAction(selectedMetadatas: [tableMetadata], indexPath: [IndexPath], order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction {
         NCMenuAction(
         NCMenuAction(
             title: NSLocalizedString("_move_or_copy_selected_files_", comment: ""),
             title: NSLocalizedString("_move_or_copy_selected_files_", comment: ""),
             icon: NCUtility.shared.loadImage(named: "arrow.up.right.square"),
             icon: NCUtility.shared.loadImage(named: "arrow.up.right.square"),
             order: order,
             order: order,
             action: { _ in
             action: { _ in
-                NCActionCenter.shared.openSelectView(items: selectedMetadatas)
+                NCActionCenter.shared.openSelectView(items: selectedMetadatas, indexPath: indexPath)
                 completion?()
                 completion?()
             }
             }
         )
         )

+ 15 - 1
iOSClient/Menu/NCShare+Menu.swift

@@ -22,6 +22,7 @@
 //
 //
 
 
 import Foundation
 import Foundation
+import NextcloudKit
 
 
 extension NCShare {
 extension NCShare {
     func toggleShareMenu(for share: tableShare) {
     func toggleShareMenu(for share: tableShare) {
@@ -62,7 +63,20 @@ extension NCShare {
                 title: NSLocalizedString("_share_unshare_", comment: ""),
                 title: NSLocalizedString("_share_unshare_", comment: ""),
                 icon: NCUtility.shared.loadImage(named: "trash"),
                 icon: NCUtility.shared.loadImage(named: "trash"),
                 action: { _ in
                 action: { _ in
-                    self.networking?.unShare(idShare: share.idShare)
+                    Task {
+                        if share.shareType != NCShareCommon.shared.SHARE_TYPE_LINK, let metadata = self.metadata, metadata.e2eEncrypted && NCGlobal.shared.capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 {
+                            let serverUrl = metadata.serverUrl + "/" + metadata.fileName
+                            if NCNetworkingE2EE.shared.isInUpload(account: metadata.account, serverUrl: serverUrl) {
+                                let error = NKError(errorCode: NCGlobal.shared.errorE2EEUploadInProgress, errorDescription: NSLocalizedString("_e2e_in_upload_", comment: ""))
+                                return NCContentPresenter.shared.showInfo(error: error)
+                            }
+                            let error = await NCNetworkingE2EE().uploadMetadata(account: metadata.account, serverUrl: serverUrl, userId: metadata.userId, addUserId: nil, removeUserId: share.shareWith)
+                            if error != .success {
+                                return NCContentPresenter.shared.showError(error: error)
+                            }
+                        }
+                        self.networking?.unShare(idShare: share.idShare)
+                    }
                 }
                 }
             )
             )
         )
         )

+ 1 - 1
iOSClient/Menu/NCSortMenu.swift

@@ -144,6 +144,6 @@ class NCSortMenu: NSObject {
 
 
         self.sortButton?.setTitle(NSLocalizedString(layoutForView.titleButtonHeader, comment: ""), for: .normal)
         self.sortButton?.setTitle(NSLocalizedString(layoutForView.titleButtonHeader, comment: ""), for: .normal)
         NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView)
         NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView)
-        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": self.serverUrl])
+        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
     }
     }
 }
 }

+ 16 - 0
iOSClient/Menu/NCTrash+Menu.swift

@@ -30,6 +30,22 @@ import NextcloudKit
 extension NCTrash {
 extension NCTrash {
     var selectActions: [NCMenuAction] {
     var selectActions: [NCMenuAction] {
         [
         [
+            NCMenuAction(
+                title: NSLocalizedString("_cancel_", comment: ""),
+                icon: NCUtility.shared.loadImage(named: "xmark"),
+                action: { _ in
+                    self.tapSelect()
+                }
+            ),
+            NCMenuAction(
+                title: NSLocalizedString("_select_all_", comment: ""),
+                icon: NCUtility.shared.loadImage(named: "checkmark.circle.fill"),
+                action: { _ in
+                    self.selectOcId = self.datasource.map { $0.fileId }
+                    self.collectionView.reloadData()
+                }
+            ),
+            NCMenuAction.seperator(),
             NCMenuAction(
             NCMenuAction(
                 title: NSLocalizedString("_trash_restore_selected_", comment: ""),
                 title: NSLocalizedString("_trash_restore_selected_", comment: ""),
                 icon: NCUtility.shared.loadImage(named: "restore"),
                 icon: NCUtility.shared.loadImage(named: "restore"),

+ 8 - 7
iOSClient/Menu/NCViewer+Menu.swift

@@ -27,10 +27,10 @@ import NextcloudKit
 
 
 extension NCViewer {
 extension NCViewer {
 
 
-    func toggleMenu(viewController: UIViewController, metadata: tableMetadata, webView: Bool, imageIcon: UIImage?) {
+    func toggleMenu(viewController: UIViewController, metadata: tableMetadata, webView: Bool, imageIcon: UIImage?, indexPath: IndexPath = IndexPath()) {
 
 
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
-        
+
         var actions = [NCMenuAction]()
         var actions = [NCMenuAction]()
         var titleFavorite = NSLocalizedString("_add_favorites_", comment: "")
         var titleFavorite = NSLocalizedString("_add_favorites_", comment: "")
         if metadata.favorite { titleFavorite = NSLocalizedString("_remove_favorites_", comment: "") }
         if metadata.favorite { titleFavorite = NSLocalizedString("_remove_favorites_", comment: "") }
@@ -60,7 +60,7 @@ extension NCViewer {
                 NCMenuAction(
                 NCMenuAction(
                     title: NSLocalizedString("_view_in_folder_", comment: ""),
                     title: NSLocalizedString("_view_in_folder_", comment: ""),
                     icon: NCUtility.shared.loadImage(named: "questionmark.folder"),
                     icon: NCUtility.shared.loadImage(named: "questionmark.folder"),
-                    action: { menuAction in
+                    action: { _ in
                         NCActionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileNameBlink: metadata.fileName, fileNameOpen: nil)
                         NCActionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileNameBlink: metadata.fileName, fileNameOpen: nil)
                     }
                     }
                 )
                 )
@@ -119,7 +119,7 @@ extension NCViewer {
                 )
                 )
             )
             )
         }
         }
-        
+
         //
         //
         // CONVERSION VIDEO TO MPEG4 (MFFF Lib)
         // CONVERSION VIDEO TO MPEG4 (MFFF Lib)
         //
         //
@@ -182,6 +182,7 @@ extension NCViewer {
                             vcRename.metadata = metadata
                             vcRename.metadata = metadata
                             vcRename.disableChangeExt = true
                             vcRename.disableChangeExt = true
                             vcRename.imagePreview = imageIcon
                             vcRename.imagePreview = imageIcon
+                            vcRename.indexPath = indexPath
 
 
                             let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
                             let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
 
 
@@ -196,14 +197,14 @@ extension NCViewer {
         // COPY - MOVE
         // COPY - MOVE
         //
         //
         if !webView, metadata.isCopyableMovable {
         if !webView, metadata.isCopyableMovable {
-            actions.append(.moveOrCopyAction(selectedMetadatas: [metadata]))
+            actions.append(.moveOrCopyAction(selectedMetadatas: [metadata], indexPath: []))
         }
         }
 
 
         //
         //
         // COPY IN PASTEBOARD
         // COPY IN PASTEBOARD
         //
         //
         if !webView, metadata.isCopyableInPasteboard {
         if !webView, metadata.isCopyableInPasteboard {
-            actions.append(.copyAction(selectOcId: [metadata.ocId], hudView: viewController.view))
+            actions.append(.copyAction(selectOcId: [metadata.ocId]))
         }
         }
 
 
         //
         //
@@ -269,7 +270,7 @@ extension NCViewer {
         // DELETE
         // DELETE
         //
         //
         if !webView, metadata.isDeletable {
         if !webView, metadata.isDeletable {
-            actions.append(.deleteAction(selectedMetadatas: [metadata], metadataFolder: nil, viewController: viewController))
+            actions.append(.deleteAction(selectedMetadatas: [metadata], indexPath: [], metadataFolder: nil, viewController: viewController))
         }
         }
 
 
         viewController.presentMenu(with: actions)
         viewController.presentMenu(with: actions)

+ 44 - 0
iOSClient/More/Cells/BaseNCMoreCell.swift

@@ -0,0 +1,44 @@
+//
+//  BaseNCMoreCell.swift
+//  Nextcloud
+//
+//  Created by Milen on 15.06.23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+class BaseNCMoreCell: UITableViewCell {
+    let selectionColor: UIView = UIView()
+    let defaultCornerRadius: CGFloat = 10.0
+
+    override var frame: CGRect {
+        get {
+            return super.frame
+        }
+        set (newFrame) {
+            var frame = newFrame
+            let newWidth = frame.width * 0.90
+            let space = (frame.width - newWidth) / 2
+            frame.size.width = newWidth
+            frame.origin.x += space
+            super.frame = frame
+        }
+    }
+
+    override func awakeFromNib() {
+        super.awakeFromNib()
+
+        selectedBackgroundView = selectionColor
+        backgroundColor = .secondarySystemGroupedBackground
+        applyCornerRadius()
+    }
+
+    func applyCornerRadius() {
+        layer.cornerRadius = defaultCornerRadius
+    }
+
+    func removeCornerRadius() {
+        layer.cornerRadius = 0
+    }
+}

+ 18 - 0
iOSClient/More/Cells/CCCellMore.swift

@@ -0,0 +1,18 @@
+//
+//  CCCellMore.swift
+//  Nextcloud
+//
+//  Created by Milen on 14.06.23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+class CCCellMore: BaseNCMoreCell {
+    @IBOutlet weak var labelText: UILabel!
+    @IBOutlet weak var imageIcon: UIImageView!
+    @IBOutlet weak var separator: UIView!
+    @IBOutlet weak var separatorHeigth: NSLayoutConstraint!
+
+    static let reuseIdentifier = "CCCellMore"
+}

+ 57 - 0
iOSClient/More/Cells/NCMoreAppSuggestionsCell.swift

@@ -0,0 +1,57 @@
+//
+//  NCMoreAppSuggestionsCell.swift
+//  Nextcloud
+//
+//  Created by Milen on 14.06.23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+class NCMoreAppSuggestionsCell: BaseNCMoreCell {
+    @IBOutlet weak var talkView: UIStackView!
+    @IBOutlet weak var notesView: UIStackView!
+    @IBOutlet weak var moreAppsView: UIStackView!
+
+    static let reuseIdentifier = "NCMoreAppSuggestionsCell"
+
+    static func fromNib() -> UINib {
+        return UINib(nibName: "NCMoreAppSuggestionsCell", bundle: nil)
+    }
+
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        backgroundColor = .clear
+
+        talkView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(talkTapped)))
+        notesView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(notesTapped)))
+        moreAppsView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(moreAppsTapped)))
+    }
+
+    @objc func talkTapped() {
+        guard let url = URL(string: NCGlobal.shared.talkSchemeUrl) else { return }
+
+        if UIApplication.shared.canOpenURL(url) {
+            UIApplication.shared.open(url)
+        } else {
+            guard let url = URL(string: NCGlobal.shared.talkAppStoreUrl) else { return }
+            UIApplication.shared.open(url)
+        }
+    }
+
+    @objc func notesTapped() {
+        guard let url = URL(string: NCGlobal.shared.notesSchemeUrl) else { return }
+
+        if UIApplication.shared.canOpenURL(url) {
+            UIApplication.shared.open(url)
+        } else {
+            guard let url = URL(string: NCGlobal.shared.notesAppStoreUrl) else { return }
+            UIApplication.shared.open(url)
+        }
+    }
+
+    @objc func moreAppsTapped() {
+        guard let url = URL(string: NCGlobal.shared.moreAppsUrl) else { return }
+        UIApplication.shared.open(url)
+    }
+}

+ 157 - 0
iOSClient/More/Cells/NCMoreAppSuggestionsCell.xib

@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22113.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_0" orientation="portrait" appearance="dark"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22089.1"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="0.0" id="dVh-cS-UwU" userLabel="App Suggestion Cell" customClass="NCMoreAppSuggestionsCell" customModule="Nextcloud" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="1076" height="44"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="dVh-cS-UwU" id="9Ma-CX-ckc">
+                <rect key="frame" x="0.0" y="0.0" width="1076" height="44"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="ppx-X2-oTM">
+                        <rect key="frame" x="0.0" y="0.0" width="1076" height="44"/>
+                        <subviews>
+                            <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalCentering" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="Tbt-MZ-3jf">
+                                <rect key="frame" x="0.0" y="0.0" width="353.33333333333331" height="44"/>
+                                <subviews>
+                                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="749" image="talk-template" translatesAutoresizingMaskIntoConstraints="NO" id="Uby-L5-yV4" userLabel="Icon">
+                                        <rect key="frame" x="167.66666666666666" y="8" width="18" height="18"/>
+                                        <color key="tintColor" systemColor="linkColor"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="18" id="Vl1-Ip-OUw"/>
+                                            <constraint firstAttribute="width" constant="18" id="m7P-Or-Esh"/>
+                                        </constraints>
+                                    </imageView>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Talk" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9cY-LF-9EI">
+                                        <rect key="frame" x="167" y="26" width="19.333333333333343" height="10"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
+                                        <color key="textColor" systemColor="systemBlueColor"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" systemColor="secondarySystemGroupedBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="bottom" secondItem="9cY-LF-9EI" secondAttribute="bottom" constant="8" id="BIL-hp-tNO"/>
+                                    <constraint firstItem="9cY-LF-9EI" firstAttribute="top" secondItem="Uby-L5-yV4" secondAttribute="bottom" id="twR-46-lPV"/>
+                                    <constraint firstItem="Uby-L5-yV4" firstAttribute="top" secondItem="Tbt-MZ-3jf" secondAttribute="top" constant="8" id="xcP-gx-xol"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                        <integer key="value" value="8"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </stackView>
+                            <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalCentering" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="4jA-wm-kCc">
+                                <rect key="frame" x="361.33333333333337" y="0.0" width="353.33333333333337" height="44"/>
+                                <subviews>
+                                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="749" image="notes-template" translatesAutoresizingMaskIntoConstraints="NO" id="BT7-Nt-9RH" userLabel="Icon">
+                                        <rect key="frame" x="167.66666666666669" y="8" width="18" height="18"/>
+                                        <color key="tintColor" systemColor="linkColor"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="18" id="3YI-i4-Ykd"/>
+                                            <constraint firstAttribute="width" constant="18" id="Riu-Cr-O0l"/>
+                                        </constraints>
+                                    </imageView>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Notes" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tQM-o0-e3W">
+                                        <rect key="frame" x="162.33333333333331" y="26" width="28.666666666666657" height="10"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
+                                        <color key="textColor" systemColor="systemBlueColor"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" systemColor="secondarySystemGroupedBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstItem="tQM-o0-e3W" firstAttribute="top" secondItem="BT7-Nt-9RH" secondAttribute="bottom" id="1ho-7Y-4Ty"/>
+                                    <constraint firstItem="BT7-Nt-9RH" firstAttribute="top" secondItem="4jA-wm-kCc" secondAttribute="top" constant="8" id="4QH-zk-5ph"/>
+                                    <constraint firstAttribute="bottom" secondItem="tQM-o0-e3W" secondAttribute="bottom" constant="8" id="E3e-ra-dwn"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                        <integer key="value" value="8"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </stackView>
+                            <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalCentering" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="SA6-fX-Xmx">
+                                <rect key="frame" x="722.66666666666663" y="0.0" width="353.33333333333337" height="44"/>
+                                <subviews>
+                                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="749" image="more-apps-template" translatesAutoresizingMaskIntoConstraints="NO" id="dzE-0b-iBn" userLabel="Icon">
+                                        <rect key="frame" x="167.66666666666674" y="8" width="18" height="18"/>
+                                        <color key="tintColor" systemColor="linkColor"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" constant="18" id="Yo0-sL-LJN"/>
+                                            <constraint firstAttribute="height" constant="18" id="bOc-vN-4Ry"/>
+                                        </constraints>
+                                    </imageView>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="More apps" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GIQ-5h-VeA">
+                                        <rect key="frame" x="151.33333333333337" y="26" width="51" height="12"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="10"/>
+                                        <color key="textColor" systemColor="systemBlueColor"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" systemColor="secondarySystemGroupedBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="bottom" secondItem="GIQ-5h-VeA" secondAttribute="bottom" constant="8" id="8xI-Ad-3Gc"/>
+                                    <constraint firstItem="dzE-0b-iBn" firstAttribute="top" secondItem="SA6-fX-Xmx" secondAttribute="top" constant="8" id="ixx-ut-Ss2"/>
+                                    <constraint firstItem="GIQ-5h-VeA" firstAttribute="top" secondItem="dzE-0b-iBn" secondAttribute="bottom" id="rWG-kv-J2m"/>
+                                </constraints>
+                                <userDefinedRuntimeAttributes>
+                                    <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+                                        <integer key="value" value="8"/>
+                                    </userDefinedRuntimeAttribute>
+                                </userDefinedRuntimeAttributes>
+                            </stackView>
+                        </subviews>
+                        <constraints>
+                            <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="400" id="D00-QX-V4P"/>
+                            <constraint firstAttribute="bottom" secondItem="Tbt-MZ-3jf" secondAttribute="bottom" id="hS2-sl-Kz0"/>
+                            <constraint firstItem="Tbt-MZ-3jf" firstAttribute="top" secondItem="ppx-X2-oTM" secondAttribute="top" id="u4O-GE-2yF"/>
+                        </constraints>
+                    </stackView>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="bottom" secondItem="ppx-X2-oTM" secondAttribute="bottom" id="Ler-rD-wfw"/>
+                    <constraint firstAttribute="trailing" secondItem="ppx-X2-oTM" secondAttribute="trailing" id="XRL-5j-YM1"/>
+                    <constraint firstItem="ppx-X2-oTM" firstAttribute="top" secondItem="9Ma-CX-ckc" secondAttribute="top" id="Yxe-5b-StO"/>
+                    <constraint firstItem="ppx-X2-oTM" firstAttribute="centerX" secondItem="9Ma-CX-ckc" secondAttribute="centerX" id="mtt-g7-1xb"/>
+                    <constraint firstItem="ppx-X2-oTM" firstAttribute="leading" secondItem="9Ma-CX-ckc" secondAttribute="leading" id="yEM-LQ-UIV"/>
+                </constraints>
+                <variation key="widthClass=regular">
+                    <mask key="constraints">
+                        <exclude reference="XRL-5j-YM1"/>
+                        <exclude reference="yEM-LQ-UIV"/>
+                    </mask>
+                </variation>
+            </tableViewCellContentView>
+            <connections>
+                <outlet property="moreAppsView" destination="SA6-fX-Xmx" id="fiE-FN-en3"/>
+                <outlet property="notesView" destination="4jA-wm-kCc" id="XuQ-8X-RDH"/>
+                <outlet property="talkView" destination="Tbt-MZ-3jf" id="1Tf-ff-0k1"/>
+            </connections>
+            <point key="canvasLocation" x="209.30232558139534" y="-65.665236051502148"/>
+        </tableViewCell>
+    </objects>
+    <resources>
+        <image name="more-apps-template" width="32" height="32"/>
+        <image name="notes-template" width="24" height="24"/>
+        <image name="talk-template" width="600" height="600"/>
+        <systemColor name="linkColor">
+            <color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+        <systemColor name="secondarySystemGroupedBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+        <systemColor name="systemBlueColor">
+            <color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+    </resources>
+</document>

+ 23 - 0
iOSClient/More/Cells/NCMoreUserCell.swift

@@ -0,0 +1,23 @@
+//
+//  NCMoreUserCell.swift
+//  Nextcloud
+//
+//  Created by Milen on 14.06.23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+import MarqueeLabel
+
+class NCMoreUserCell: BaseNCMoreCell {
+    @IBOutlet weak var displayName: UILabel!
+    @IBOutlet weak var avatar: UIImageView!
+    @IBOutlet weak var icon: UIImageView!
+    @IBOutlet weak var status: MarqueeLabel!
+
+    static let reuseIdentifier = "NCMoreUserCell"
+
+    static func fromNib() -> UINib {
+        return UINib(nibName: "NCMoreUserCell", bundle: nil)
+    }
+}

+ 3 - 3
iOSClient/More/NCMoreUserCell.xib → iOSClient/More/Cells/NCMoreUserCell.xib

@@ -1,15 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
     <dependencies>
         <deployment identifier="iOS"/>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     </dependencies>
     <objects>
     <objects>
         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CustomCellFileAndDirectory"/>
         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CustomCellFileAndDirectory"/>
         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
-        <tableViewCell contentMode="scaleToFill" selectionStyle="blue" indentationWidth="0.0" reuseIdentifier="userCell" rowHeight="107" id="2" customClass="NCMoreUserCell" customModule="Nextcloud" customModuleProvider="target">
+        <tableViewCell contentMode="scaleToFill" selectionStyle="blue" indentationWidth="0.0" reuseIdentifier="NCMoreUserCell" rowHeight="107" id="2" customClass="NCMoreUserCell" customModule="Nextcloud" customModuleProvider="target">
             <rect key="frame" x="0.0" y="0.0" width="600" height="75"/>
             <rect key="frame" x="0.0" y="0.0" width="600" height="75"/>
             <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/>
             <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/>
             <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2" id="sQq-jC-UEV">
             <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2" id="sQq-jC-UEV">

+ 3 - 3
iOSClient/More/NCMore.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="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<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">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
     <dependencies>
         <deployment identifier="iOS"/>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
+        <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"/>
@@ -22,7 +22,7 @@
                                 <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                                 <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                                 <inset key="separatorInset" minX="56" minY="0.0" maxX="0.0" maxY="0.0"/>
                                 <inset key="separatorInset" minX="56" minY="0.0" maxX="0.0" maxY="0.0"/>
                                 <prototypes>
                                 <prototypes>
-                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" rowHeight="50" id="qwS-lS-XzK" customClass="CCCellMore" customModule="Nextcloud" customModuleProvider="target">
+                                    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CCCellMore" rowHeight="50" id="qwS-lS-XzK" customClass="CCCellMore" customModule="Nextcloud" customModuleProvider="target">
                                         <rect key="frame" x="0.0" y="55.5" width="414" height="50"/>
                                         <rect key="frame" x="0.0" y="55.5" width="414" height="50"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" multipleTouchEnabled="YES" contentMode="center" tableViewCell="qwS-lS-XzK" id="1FG-Yi-cbC">
                                         <tableViewCellContentView key="contentView" multipleTouchEnabled="YES" contentMode="center" tableViewCell="qwS-lS-XzK" id="1FG-Yi-cbC">

+ 102 - 190
iOSClient/More/NCMore.swift

@@ -23,7 +23,6 @@
 
 
 import UIKit
 import UIKit
 import NextcloudKit
 import NextcloudKit
-import MarqueeLabel
 
 
 class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
 class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
 
 
@@ -33,16 +32,31 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
     @IBOutlet weak var progressQuota: UIProgressView!
     @IBOutlet weak var progressQuota: UIProgressView!
     @IBOutlet weak var viewQuota: UIView!
     @IBOutlet weak var viewQuota: UIView!
 
 
-    var functionMenu: [NKExternalSite] = []
-    var externalSiteMenu: [NKExternalSite] = []
-    var settingsMenu: [NKExternalSite] = []
-    var quotaMenu: [NKExternalSite] = []
+    private var functionMenu: [NKExternalSite] = []
+    private var externalSiteMenu: [NKExternalSite] = []
+    private var settingsMenu: [NKExternalSite] = []
+    private var quotaMenu: [NKExternalSite] = []
 
 
-    let appDelegate = UIApplication.shared.delegate as! AppDelegate
-    let defaultCornerRadius: CGFloat = 10.0
-    let applicationHandle = NCApplicationHandle()
-    
-    var tabAccount: tableAccount?
+    // swiftlint:disable force_cast
+    private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    // swiftlint:enable force_cast
+
+    private let applicationHandle = NCApplicationHandle()
+
+    private var tabAccount: tableAccount?
+
+    private struct Section {
+        var items: [NKExternalSite]
+        var type: SectionType
+
+        enum SectionType {
+            case account
+            case moreApps
+            case regular
+        }
+    }
+
+    private var sections: [Section] = []
 
 
     // MARK: - View Life Cycle
     // MARK: - View Life Cycle
 
 
@@ -52,36 +66,29 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         self.navigationItem.title = NSLocalizedString("_more_", comment: "")
         self.navigationItem.title = NSLocalizedString("_more_", comment: "")
         view.backgroundColor = .systemGroupedBackground
         view.backgroundColor = .systemGroupedBackground
 
 
+        tableView.insetsContentViewsToSafeArea = false
         tableView.delegate = self
         tableView.delegate = self
         tableView.dataSource = self
         tableView.dataSource = self
         tableView.backgroundColor = .systemGroupedBackground
         tableView.backgroundColor = .systemGroupedBackground
-        tableView.register(UINib(nibName: "NCMoreUserCell", bundle: nil), forCellReuseIdentifier: "userCell")
+        tableView.register(NCMoreUserCell.fromNib(), forCellReuseIdentifier: NCMoreUserCell.reuseIdentifier)
+        tableView.register(NCMoreAppSuggestionsCell.fromNib(), forCellReuseIdentifier: NCMoreAppSuggestionsCell.reuseIdentifier)
 
 
         // create tap gesture recognizer
         // create tap gesture recognizer
         let tapQuota = UITapGestureRecognizer(target: self, action: #selector(tapLabelQuotaExternalSite))
         let tapQuota = UITapGestureRecognizer(target: self, action: #selector(tapLabelQuotaExternalSite))
         labelQuotaExternalSite.isUserInteractionEnabled = true
         labelQuotaExternalSite.isUserInteractionEnabled = true
         labelQuotaExternalSite.addGestureRecognizer(tapQuota)
         labelQuotaExternalSite.addGestureRecognizer(tapQuota)
-
-        // Notification
-        NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil)
     }
     }
 
 
     override func viewWillAppear(_ animated: Bool) {
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         super.viewWillAppear(animated)
 
 
-        navigationController?.setGroupeAppreance()
-        
+        navigationController?.setGroupAppearance()
+
         appDelegate.activeViewController = self
         appDelegate.activeViewController = self
         loadItems()
         loadItems()
         tableView.reloadData()
         tableView.reloadData()
     }
     }
 
 
-    // MARK: - NotificationCenter
-
-    @objc func initialize() {
-        loadItems()
-    }
-
     // MARK: -
     // MARK: -
 
 
     func loadItems() {
     func loadItems() {
@@ -94,6 +101,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         externalSiteMenu.removeAll()
         externalSiteMenu.removeAll()
         settingsMenu.removeAll()
         settingsMenu.removeAll()
         quotaMenu.removeAll()
         quotaMenu.removeAll()
+        sections.removeAll()
         labelQuotaExternalSite.text = ""
         labelQuotaExternalSite.text = ""
         progressQuota.progressTintColor = NCBrandColor.shared.brandElement
         progressQuota.progressTintColor = NCBrandColor.shared.brandElement
 
 
@@ -179,7 +187,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         item.url = "segueSettings"
         item.url = "segueSettings"
         settingsMenu.append(item)
         settingsMenu.append(item)
 
 
-        if quotaMenu.count > 0 {
+        if !quotaMenu.isEmpty {
             let item = quotaMenu[0]
             let item = quotaMenu[0]
             labelQuotaExternalSite.text = item.name
             labelQuotaExternalSite.text = item.name
         }
         }
@@ -216,7 +224,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         if NCBrandOptions.shared.disable_more_external_site == false {
         if NCBrandOptions.shared.disable_more_external_site == false {
             if let externalSites = NCManageDatabase.shared.getAllExternalSites(account: appDelegate.account) {
             if let externalSites = NCManageDatabase.shared.getAllExternalSites(account: appDelegate.account) {
                 for externalSite in externalSites {
                 for externalSite in externalSites {
-                    if (externalSite.name != "" && externalSite.url != ""), let urlEncoded = externalSite.url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
+                    if !externalSite.name.isEmpty, !externalSite.url.isEmpty, let urlEncoded = externalSite.url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
                         item = NKExternalSite()
                         item = NKExternalSite()
                         item.name = externalSite.name
                         item.name = externalSite.name
                         item.url = urlEncoded
                         item.url = urlEncoded
@@ -229,21 +237,45 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
                 }
                 }
             }
             }
         }
         }
+
+        loadSections()
+    }
+
+    private func loadSections() {
+        if tabAccount != nil {
+            sections.append(Section(items: [NKExternalSite()], type: .account))
+        }
+
+        if !NCBrandOptions.shared.disable_show_more_nextcloud_apps_in_settings {
+            sections.append(Section(items: [NKExternalSite()], type: .moreApps))
+        }
+
+        if !functionMenu.isEmpty {
+            sections.append(Section(items: functionMenu, type: .regular))
+        }
+
+        if !externalSiteMenu.isEmpty {
+            sections.append(Section(items: externalSiteMenu, type: .regular))
+        }
+
+        if !settingsMenu.isEmpty {
+            sections.append(Section(items: settingsMenu, type: .regular))
+        }
     }
     }
 
 
     // MARK: - Action
     // MARK: - Action
 
 
     @objc func tapLabelQuotaExternalSite() {
     @objc func tapLabelQuotaExternalSite() {
 
 
-        if quotaMenu.count > 0 {
-
+        if !quotaMenu.isEmpty {
             let item = quotaMenu[0]
             let item = quotaMenu[0]
-            let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as! NCBrowserWeb
-            browserWebVC.urlBase = item.url
-            browserWebVC.isHiddenButtonExit = true
+            if let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as? NCBrowserWeb {
+                browserWebVC.urlBase = item.url
+                browserWebVC.isHiddenButtonExit = true
 
 
-            self.navigationController?.pushViewController(browserWebVC, animated: true)
-            self.navigationController?.navigationBar.isHidden = false
+                self.navigationController?.pushViewController(browserWebVC, animated: true)
+                self.navigationController?.navigationBar.isHidden = false
+            }
         }
         }
     }
     }
 
 
@@ -257,7 +289,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
     // MARK: -
     // MARK: -
 
 
     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-        if indexPath.section == 0 {
+        if sections[indexPath.section].type == .account {
             return 75
             return 75
         } else {
         } else {
             return NCGlobal.shared.heightCellSettings
             return NCGlobal.shared.heightCellSettings
@@ -265,65 +297,31 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
     }
     }
 
 
     func numberOfSections(in tableView: UITableView) -> Int {
     func numberOfSections(in tableView: UITableView) -> Int {
-
-        if externalSiteMenu.count == 0 {
-            return 3
-        } else {
-            return 4
-        }
+        return sections.count
     }
     }
-    
-    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-        
-        if section == 0 {
+
+    func tableView(_ tableView: UITableView, heightForHeaderInSection index: Int) -> CGFloat {
+        let section = sections[index]
+
+        if section.type == .account {
             return 10
             return 10
+        } else if section.type == .moreApps || sections[index - 1].type == .moreApps {
+            return 1
         } else {
         } else {
             return 20
             return 20
         }
         }
     }
     }
 
 
-    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-
-        var cont = 0
-
-        if section == 0 {
-            cont = tabAccount == nil ? 0 : 1
-        } else if section == 1 {
-            // Menu Normal
-            cont = functionMenu.count
-        } else {
-            switch numberOfSections(in: tableView) {
-            case 3:
-                // Menu Settings
-                if section == 2 {
-                    cont = settingsMenu.count
-                }
-            case 4:
-                // Menu External Site
-                if section == 2 {
-                    cont = externalSiteMenu.count
-                }
-                // Menu Settings
-                if section == 3 {
-                    cont = settingsMenu.count
-                }
-            default:
-                cont = 0
-            }
-        }
-
-        return cont
+    func tableView(_ tableView: UITableView, numberOfRowsInSection index: Int) -> Int {
+        return sections[index].items.count
     }
     }
-    
-    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 
 
-        var item = NKExternalSite()
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let section = sections[indexPath.section]
 
 
-        // change color selection and disclosure indicator
-        let selectionColor: UIView = UIView()
-        if indexPath.section == 0 {
+        if section.type == .account {
 
 
-            let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as! NCMoreUserCell
+            guard let cell = tableView.dequeueReusableCell(withIdentifier: NCMoreUserCell.reuseIdentifier, for: indexPath) as? NCMoreUserCell else { return UITableViewCell() }
 
 
             cell.avatar.image = nil
             cell.avatar.image = nil
             cell.icon.image = nil
             cell.icon.image = nil
@@ -331,20 +329,15 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
             cell.displayName.text = ""
             cell.displayName.text = ""
 
 
             if let account = tabAccount {
             if let account = tabAccount {
-                cell.avatar.image = NCUtility.shared.loadUserImage(
-                    for: account.user,
-                       displayName: account.displayName,
-                       userBaseUrl: appDelegate)
+                cell.avatar.image = NCUtility.shared.loadUserImage(for: account.user, displayName: account.displayName, userBaseUrl: appDelegate)
 
 
-                if account.alias == "" {
+                if account.alias.isEmpty {
                     cell.displayName?.text = account.displayName
                     cell.displayName?.text = account.displayName
                 } else {
                 } else {
                     cell.displayName?.text = account.displayName + " (" + account.alias + ")"
                     cell.displayName?.text = account.displayName + " (" + account.alias + ")"
                 }
                 }
                 cell.displayName.textColor = .label
                 cell.displayName.textColor = .label
             }
             }
-            cell.selectedBackgroundView = selectionColor
-            cell.backgroundColor = .secondarySystemGroupedBackground
             cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
             cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
 
 
             if NCGlobal.shared.capabilityUserStatusEnabled, let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) {
             if NCGlobal.shared.capabilityUserStatusEnabled, let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) {
@@ -359,46 +352,34 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
                     cell.status.tapToScroll = false
                     cell.status.tapToScroll = false
                 }
                 }
             }
             }
-            
-            cell.layer.cornerRadius = defaultCornerRadius
+
             cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
             cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
 
 
             return cell
             return cell
 
 
+        } else if section.type == .moreApps {
+            guard let cell = tableView.dequeueReusableCell(withIdentifier: NCMoreAppSuggestionsCell.reuseIdentifier, for: indexPath) as? NCMoreAppSuggestionsCell else { return UITableViewCell() }
+            return cell
         } else {
         } else {
+            guard let cell = tableView.dequeueReusableCell(withIdentifier: CCCellMore.reuseIdentifier, for: indexPath) as? CCCellMore else { return UITableViewCell() }
 
 
-            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CCCellMore
-
-            // Menu Normal
-            if indexPath.section == 1 {
-                item = functionMenu[indexPath.row]
-            }
-            // Menu External Site
-            if numberOfSections(in: tableView) == 4 && indexPath.section == 2 {
-                item = externalSiteMenu[indexPath.row]
-            }
-            // Menu Settings
-            if (numberOfSections(in: tableView) == 3 && indexPath.section == 2) || (numberOfSections(in: tableView) == 4 && indexPath.section == 3) {
-                item = settingsMenu[indexPath.row]
-            }
+            let item = sections[indexPath.section].items[indexPath.row]
 
 
             cell.imageIcon?.image = NCUtility.shared.loadImage(named: item.icon)
             cell.imageIcon?.image = NCUtility.shared.loadImage(named: item.icon)
             cell.imageIcon?.contentMode = .scaleAspectFit
             cell.imageIcon?.contentMode = .scaleAspectFit
             cell.labelText?.text = NSLocalizedString(item.name, comment: "")
             cell.labelText?.text = NSLocalizedString(item.name, comment: "")
             cell.labelText.textColor = .label
             cell.labelText.textColor = .label
 
 
-            cell.selectedBackgroundView = selectionColor
-            cell.backgroundColor = .secondarySystemGroupedBackground
             cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
             cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
 
 
             cell.separator.backgroundColor = .separator
             cell.separator.backgroundColor = .separator
             cell.separatorHeigth.constant = 0.4
             cell.separatorHeigth.constant = 0.4
-            
-            cell.layer.cornerRadius = 0
+
+            cell.removeCornerRadius()
             let rows = tableView.numberOfRows(inSection: indexPath.section)
             let rows = tableView.numberOfRows(inSection: indexPath.section)
-            
+
             if indexPath.row == 0 {
             if indexPath.row == 0 {
-                cell.layer.cornerRadius = defaultCornerRadius
+                cell.applyCornerRadius()
                 if indexPath.row == rows - 1 {
                 if indexPath.row == rows - 1 {
                     cell.separator.backgroundColor = .clear
                     cell.separator.backgroundColor = .clear
                     cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
                     cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner]
@@ -406,70 +387,46 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
                     cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
                     cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
                 }
                 }
             } else if indexPath.row == rows - 1 {
             } else if indexPath.row == rows - 1 {
-                cell.layer.cornerRadius = defaultCornerRadius
+                cell.applyCornerRadius()
                 cell.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
                 cell.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
                 cell.separator.backgroundColor = .clear
                 cell.separator.backgroundColor = .clear
             }
             }
-            
+
             return cell
             return cell
         }
         }
     }
     }
 
 
-    // method to run when table view cell is tapped
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        let item = sections[indexPath.section].items[indexPath.row]
 
 
-        var item = NKExternalSite()
-
-        if indexPath.section == 0 {
+        // Menu Function
+        if sections[indexPath.section].type == .account {
             tapImageLogoManageAccount()
             tapImageLogoManageAccount()
             return
             return
         }
         }
 
 
-        // Menu Function
-        if indexPath.section == 1 {
-            item = functionMenu[indexPath.row]
-        }
-
-        // Menu External Site
-        if numberOfSections(in: tableView) == 4 && indexPath.section == 2 {
-            item = externalSiteMenu[indexPath.row]
-        }
-
-        // Menu Settings
-        if (numberOfSections(in: tableView) == 3 && indexPath.section == 2) || (numberOfSections(in: tableView) == 4 && indexPath.section == 3) {
-            item = settingsMenu[indexPath.row]
-        }
-
         // Action
         // Action
         if item.url.contains("segue") && !item.url.contains("//") {
         if item.url.contains("segue") && !item.url.contains("//") {
-
             self.navigationController?.performSegue(withIdentifier: item.url, sender: self)
             self.navigationController?.performSegue(withIdentifier: item.url, sender: self)
-
         } else if item.url.contains("openStoryboard") && !item.url.contains("//") {
         } else if item.url.contains("openStoryboard") && !item.url.contains("//") {
-
             let nameStoryboard = item.url.replacingOccurrences(of: "openStoryboard", with: "")
             let nameStoryboard = item.url.replacingOccurrences(of: "openStoryboard", with: "")
             let storyboard = UIStoryboard(name: nameStoryboard, bundle: nil)
             let storyboard = UIStoryboard(name: nameStoryboard, bundle: nil)
             if let controller = storyboard.instantiateInitialViewController() {
             if let controller = storyboard.instantiateInitialViewController() {
                 controller.modalPresentationStyle = UIModalPresentationStyle.pageSheet
                 controller.modalPresentationStyle = UIModalPresentationStyle.pageSheet
                 present(controller, animated: true, completion: nil)
                 present(controller, animated: true, completion: nil)
             }
             }
-
         } else if item.url.contains("//") {
         } else if item.url.contains("//") {
-
-            let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as! NCBrowserWeb
-            browserWebVC.urlBase = item.url
-            browserWebVC.isHiddenButtonExit = true
-            browserWebVC.titleBrowser = item.name
-
-            self.navigationController?.pushViewController(browserWebVC, animated: true)
-            self.navigationController?.navigationBar.isHidden = false
-
+            if let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as? NCBrowserWeb {
+                browserWebVC.urlBase = item.url
+                browserWebVC.isHiddenButtonExit = true
+                browserWebVC.titleBrowser = item.name
+                self.navigationController?.pushViewController(browserWebVC, animated: true)
+                self.navigationController?.navigationBar.isHidden = false
+            }
         } else if item.url == "logout" {
         } else if item.url == "logout" {
-
             let alertController = UIAlertController(title: "", message: NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert)
             let alertController = UIAlertController(title: "", message: NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert)
 
 
             let actionYes = UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in
             let actionYes = UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in
-
                 let manageAccount = CCManageAccount()
                 let manageAccount = CCManageAccount()
                 manageAccount.delete(self.appDelegate.account)
                 manageAccount.delete(self.appDelegate.account)
 
 
@@ -483,53 +440,8 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
             alertController.addAction(actionYes)
             alertController.addAction(actionYes)
             alertController.addAction(actionNo)
             alertController.addAction(actionNo)
             self.present(alertController, animated: true, completion: nil)
             self.present(alertController, animated: true, completion: nil)
-
         } else {
         } else {
             applicationHandle.didSelectItem(item, viewController: self)
             applicationHandle.didSelectItem(item, viewController: self)
         }
         }
     }
     }
 }
 }
-
-class CCCellMore: UITableViewCell {
-
-    @IBOutlet weak var labelText: UILabel!
-    @IBOutlet weak var imageIcon: UIImageView!
-    @IBOutlet weak var separator: UIView!
-    @IBOutlet weak var separatorHeigth: NSLayoutConstraint!
-
-    override var frame: CGRect {
-        get {
-            return super.frame
-        }
-        set (newFrame) {
-            var frame = newFrame
-            let newWidth = frame.width * 0.90
-            let space = (frame.width - newWidth) / 2
-            frame.size.width = newWidth
-            frame.origin.x += space
-            super.frame = frame
-        }
-    }
-}
-
-class NCMoreUserCell: UITableViewCell {
-
-    @IBOutlet weak var displayName: UILabel!
-    @IBOutlet weak var avatar: UIImageView!
-    @IBOutlet weak var icon: UIImageView!
-    @IBOutlet weak var status: MarqueeLabel!
-    
-    override var frame: CGRect {
-        get {
-            return super.frame
-        }
-        set (newFrame) {
-            var frame = newFrame
-            let newWidth = frame.width * 0.90
-            let space = (frame.width - newWidth) / 2
-            frame.size.width = newWidth
-            frame.origin.x += space
-            super.frame = frame
-        }
-    }
-}

+ 69 - 51
iOSClient/NCGlobal.swift

@@ -61,14 +61,6 @@ class NCGlobal: NSObject {
         return result.reduce(0, { $0 + $1 }) % maximum
         return result.reduce(0, { $0 + $1 }) % maximum
     }
     }
 
 
-    // Struct for Progress
-    //
-    struct progressType {
-        var progress: Float
-        var totalBytes: Int64
-        var totalBytesExpected: Int64
-    }
-
     // Directory on Group
     // Directory on Group
     //
     //
     @objc let directoryProviderStorage              = "File Provider Storage"
     @objc let directoryProviderStorage              = "File Provider Storage"
@@ -108,7 +100,7 @@ class NCGlobal: NSObject {
 
 
     // Nextcloud unsupported
     // Nextcloud unsupported
     //
     //
-    let nextcloud_unsupported_version: Int          = 16
+    let nextcloud_unsupported_version: Int = 16
 
 
     // Intro selector
     // Intro selector
     //
     //
@@ -117,7 +109,7 @@ class NCGlobal: NSObject {
 
 
     // Varie size GUI
     // Varie size GUI
     //
     //
-    @objc let heightCellSettings: CGFloat           = 50
+    @objc let heightCellSettings: CGFloat = 50
 
 
     // Avatar & Preview size
     // Avatar & Preview size
     //
     //
@@ -129,7 +121,14 @@ class NCGlobal: NSObject {
     // E2EE
     // E2EE
     //
     //
     let e2eePassphraseTest                          = "more over television factory tendency independence international intellectual impress interest sentence pony"
     let e2eePassphraseTest                          = "more over television factory tendency independence international intellectual impress interest sentence pony"
-    @objc let e2eeReadVersions                      = ["1.1", "1.2"]
+    @objc let e2eeVersions                          = ["1.1", "1.2"] // ["1.1", "1.2", "2.0"]
+    let e2eeVersionV11                              = "1.1"
+    let e2eeVersionV12                              = "1.2"
+    let e2eeVersionV20                              = "2.0"
+
+    // CHUNK
+    let chunkSizeMBCellular                         = 10000000
+    let chunkSizeMBEthernetOrWiFi                   = 100000000
 
 
     // Video
     // Video
     //
     //
@@ -146,12 +145,10 @@ class NCGlobal: NSObject {
     let layoutList                                  = "typeLayoutList"
     let layoutList                                  = "typeLayoutList"
     let layoutGrid                                  = "typeLayoutGrid"
     let layoutGrid                                  = "typeLayoutGrid"
 
 
-    let layoutViewMove                              = "LayoutMove"
     let layoutViewTrash                             = "LayoutTrash"
     let layoutViewTrash                             = "LayoutTrash"
     let layoutViewOffline                           = "LayoutOffline"
     let layoutViewOffline                           = "LayoutOffline"
     let layoutViewFavorite                          = "LayoutFavorite"
     let layoutViewFavorite                          = "LayoutFavorite"
     let layoutViewFiles                             = "LayoutFiles"
     let layoutViewFiles                             = "LayoutFiles"
-    let layoutViewViewInFolder                      = "LayoutViewInFolder"
     let layoutViewTransfers                         = "LayoutTransfers"
     let layoutViewTransfers                         = "LayoutTransfers"
     let layoutViewRecent                            = "LayoutRecent"
     let layoutViewRecent                            = "LayoutRecent"
     let layoutViewShares                            = "LayoutShares"
     let layoutViewShares                            = "LayoutShares"
@@ -167,6 +164,7 @@ class NCGlobal: NSObject {
     // Standard height sections header/footer
     // Standard height sections header/footer
     //
     //
     let heightButtonsView: CGFloat                  = 50
     let heightButtonsView: CGFloat                  = 50
+    let heightHeaderTransfer: CGFloat               = 50
     let heightSection: CGFloat                      = 30
     let heightSection: CGFloat                      = 30
     let heightFooter: CGFloat                       = 1
     let heightFooter: CGFloat                       = 1
     let heightFooterButton: CGFloat                 = 30
     let heightFooterButton: CGFloat                 = 30
@@ -191,11 +189,11 @@ class NCGlobal: NSObject {
 
 
     // Rich Workspace
     // Rich Workspace
     //
     //
-    let fileNameRichWorkspace                       = "Readme.md"
+    let fileNameRichWorkspace = "Readme.md"
 
 
     // Extension
     // Extension
     //
     //
-    @objc let extensionPreview                      = "ico"
+    @objc let extensionPreview = "ico"
 
 
     // ContentPresenter
     // ContentPresenter
     //
     //
@@ -210,24 +208,42 @@ class NCGlobal: NSObject {
     @objc let errorUnauthorized401: Int             = 401
     @objc let errorUnauthorized401: Int             = 401
     @objc let errorForbidden: Int                   = 403
     @objc let errorForbidden: Int                   = 403
     @objc let errorResourceNotFound: Int            = 404
     @objc let errorResourceNotFound: Int            = 404
-    @objc let errordMethodNotSupported: Int         = 405
+    @objc let errorMethodNotSupported: Int          = 405
     @objc let errorConflict: Int                    = 409
     @objc let errorConflict: Int                    = 409
     @objc let errorPreconditionFailed: Int          = 412
     @objc let errorPreconditionFailed: Int          = 412
+    @objc let errorQuota: Int                       = 507
     @objc let errorUnauthorized997: Int             = 997
     @objc let errorUnauthorized997: Int             = 997
     @objc let errorConnectionLost: Int              = -1005
     @objc let errorConnectionLost: Int              = -1005
     @objc let errorNetworkNotAvailable: Int         = -1009
     @objc let errorNetworkNotAvailable: Int         = -1009
     @objc let errorBadServerResponse: Int           = -1011
     @objc let errorBadServerResponse: Int           = -1011
     @objc let errorInternalError: Int               = -99999
     @objc let errorInternalError: Int               = -99999
     @objc let errorFileNotSaved: Int                = -99998
     @objc let errorFileNotSaved: Int                = -99998
-    @objc let errorDecodeMetadata: Int              = -99997
-    @objc let errorE2EENotEnabled: Int              = -99996
-    @objc let errorE2EE: Int                        = -99995
-    @objc let errorOffline: Int                     = -99994
-    @objc let errorCharactersForbidden: Int         = -99993
-    @objc let errorCreationFile: Int                = -99992
-    @objc let errorReadFile: Int                    = -99991
-    @objc let errorUnauthorizedFilesPasscode: Int   = -99990
-    @objc let errorDisableFilesApp: Int             = -99989
+    @objc let errorOffline: Int                     = -99997
+    @objc let errorCharactersForbidden: Int         = -99996
+    @objc let errorCreationFile: Int                = -99995
+    @objc let errorReadFile: Int                    = -99994
+    @objc let errorUnauthorizedFilesPasscode: Int   = -99993
+    @objc let errorDisableFilesApp: Int             = -99992
+    @objc let errorUnexpectedResponseFromDB: Int    = -99991
+    // E2EE
+    @objc let errorE2EENotEnabled: Int              = -98000
+    @objc let errorE2EEVersion: Int                 = -98001
+    @objc let errorE2EEKeyChecksums: Int            = -98002
+    @objc let errorE2EEKeyEncodeMetadata: Int       = -98003
+    @objc let errorE2EEKeyDecodeMetadata: Int       = -98004
+    @objc let errorE2EEKeyVerifySignature: Int      = -98005
+    @objc let errorE2EEKeyCiphertext: Int           = -98006
+    @objc let errorE2EEKeyFiledropCiphertext: Int   = -98007
+    @objc let errorE2EEJSon: Int                    = -98008
+    @objc let errorE2EELock: Int                    = -98009
+    @objc let errorE2EEEncryptFile: Int             = -98010
+    @objc let errorE2EEEncryptPayloadFile: Int      = -98011
+    @objc let errorE2EECounter: Int                 = -98012
+    @objc let errorE2EEGenerateKey: Int             = -98013
+    @objc let errorE2EEEncodedKey: Int              = -98014
+    @objc let errorE2EENoUserFound: Int             = -98015
+    @objc let errorE2EEUploadInProgress: Int        = -98016
+
 
 
     // Constants to identify the different permissions of a file
     // Constants to identify the different permissions of a file
     //
     //
@@ -257,7 +273,7 @@ class NCGlobal: NSObject {
     @objc let permissionDefaultFileRemoteShareNoSupportShareOption: Int     = 3
     @objc let permissionDefaultFileRemoteShareNoSupportShareOption: Int     = 3
     @objc let permissionDefaultFolderRemoteShareNoSupportShareOption: Int   = 15
     @objc let permissionDefaultFolderRemoteShareNoSupportShareOption: Int   = 15
     // ATTRIBUTES
     // ATTRIBUTES
-    @objc let permissionDownloadShare: Int          = 0
+    @objc let permissionDownloadShare: Int = 0
 
 
     // Filename Mask and Type
     // Filename Mask and Type
     //
     //
@@ -271,7 +287,6 @@ class NCGlobal: NSObject {
     // Selector
     // Selector
     //
     //
     let selectorDownloadFile                        = "downloadFile"
     let selectorDownloadFile                        = "downloadFile"
-    let selectorDownloadAllFile                     = "downloadAllFile"
     let selectorReadFile                            = "readFile"
     let selectorReadFile                            = "readFile"
     let selectorListingFavorite                     = "listingFavorite"
     let selectorListingFavorite                     = "listingFavorite"
     let selectorLoadFileView                        = "loadFileView"
     let selectorLoadFileView                        = "loadFileView"
@@ -285,10 +300,10 @@ class NCGlobal: NSObject {
     let selectorUploadFileNODelete                  = "UploadFileNODelete"
     let selectorUploadFileNODelete                  = "UploadFileNODelete"
     let selectorUploadFileShareExtension            = "uploadFileShareExtension"
     let selectorUploadFileShareExtension            = "uploadFileShareExtension"
     let selectorSaveAlbum                           = "saveAlbum"
     let selectorSaveAlbum                           = "saveAlbum"
-    let selectorSaveAlbumLivePhotoIMG               = "saveAlbumLivePhotoIMG"
-    let selectorSaveAlbumLivePhotoMOV               = "saveAlbumLivePhotoMOV"
     let selectorSaveAsScan                          = "saveAsScan"
     let selectorSaveAsScan                          = "saveAsScan"
     let selectorOpenDetail                          = "openDetail"
     let selectorOpenDetail                          = "openDetail"
+    let selectorSynchronizationOffline              = "synchronizationOffline"
+    let selectorSynchronizationFavorite             = "synchronizationFavorite"
 
 
     // Metadata : Status
     // Metadata : Status
     //
     //
@@ -309,9 +324,12 @@ class NCGlobal: NSObject {
     let metadataStatusUploading: Int                = 3
     let metadataStatusUploading: Int                = 3
     let metadataStatusUploadError: Int              = 4
     let metadataStatusUploadError: Int              = 4
 
 
+    // Queue Concurrent Operation Download
+    let maxConcurrentOperationCountDownload: Int    = 10
+
     //  Hidden files included in the read
     //  Hidden files included in the read
     //
     //
-    let includeHiddenFiles: [String]                = [".LivePhoto"]
+    let includeHiddenFiles: [String] = [".LivePhoto"]
 
 
     // Auto upload subfolder granularity
     // Auto upload subfolder granularity
     //
     //
@@ -322,19 +340,19 @@ class NCGlobal: NSObject {
     // Notification Center
     // Notification Center
     //
     //
     @objc let notificationCenterApplicationDidEnterBackground   = "applicationDidEnterBackground"
     @objc let notificationCenterApplicationDidEnterBackground   = "applicationDidEnterBackground"
-    let notificationCenterApplicationDidBecomeActive            = "applicationDidBecomeActive"
-    let notificationCenterApplicationWillResignActive           = "applicationWillResignActive"
+    @objc let notificationCenterApplicationDidBecomeActive      = "applicationDidBecomeActive"
+    @objc let notificationCenterApplicationWillResignActive     = "applicationWillResignActive"
 
 
-    @objc let notificationCenterInitialize                      = "initialize"
+    @objc let notificationCenterChangeUser                      = "changeUser"
     @objc let notificationCenterChangeTheming                   = "changeTheming"
     @objc let notificationCenterChangeTheming                   = "changeTheming"
     let notificationCenterRichdocumentGrabFocus                 = "richdocumentGrabFocus"
     let notificationCenterRichdocumentGrabFocus                 = "richdocumentGrabFocus"
     let notificationCenterReloadDataNCShare                     = "reloadDataNCShare"
     let notificationCenterReloadDataNCShare                     = "reloadDataNCShare"
     let notificationCenterCloseRichWorkspaceWebView             = "closeRichWorkspaceWebView"
     let notificationCenterCloseRichWorkspaceWebView             = "closeRichWorkspaceWebView"
-    let notificationCenterUpdateBadgeNumber                     = "updateBadgeNumber"               // userInfo: counter
+    let notificationCenterUpdateBadgeNumber                     = "updateBadgeNumber"               // userInfo: counterDownload, counterUpload
     let notificationCenterReloadAvatar                          = "reloadAvatar"
     let notificationCenterReloadAvatar                          = "reloadAvatar"
 
 
-    @objc let notificationCenterReloadDataSource                = "reloadDataSource"                // userInfo: serverUrl?
-    let notificationCenterReloadDataSourceNetwork               = "reloadDataSourceNetwork"         // userInfo: serverUrl?
+    @objc let notificationCenterReloadDataSource                = "reloadDataSource"
+    let notificationCenterReloadDataSourceNetwork               = "reloadDataSourceNetwork"
     let notificationCenterReloadDataSourceNetworkForced         = "reloadDataSourceNetworkForced"
     let notificationCenterReloadDataSourceNetworkForced         = "reloadDataSourceNetworkForced"
 
 
     let notificationCenterChangeStatusFolderE2EE                = "changeStatusFolderE2EE"          // userInfo: serverUrl
     let notificationCenterChangeStatusFolderE2EE                = "changeStatusFolderE2EE"          // userInfo: serverUrl
@@ -347,25 +365,24 @@ class NCGlobal: NSObject {
     @objc let notificationCenterUploadedFile                    = "uploadedFile"                    // userInfo: ocId, serverUrl, account, fileName, ocIdTemp, error
     @objc let notificationCenterUploadedFile                    = "uploadedFile"                    // userInfo: ocId, serverUrl, account, fileName, ocIdTemp, error
     let notificationCenterUploadCancelFile                      = "uploadCancelFile"                // userInfo: ocId, serverUrl, account
     let notificationCenterUploadCancelFile                      = "uploadCancelFile"                // userInfo: ocId, serverUrl, account
 
 
-    let notificationCenterProgressTask                          = "progressTask"                    // userInfo: account, ocId, serverUrl, status, progress, totalBytes, totalBytesExpected
+    let notificationCenterProgressTask                          = "progressTask"                    // userInfo: account, ocId, serverUrl, status, chunk, e2eEncrypted, progress, totalBytes, totalBytesExpected
 
 
-    let notificationCenterCreateFolder                          = "createFolder"                    // userInfo: ocId, serverUrl, account, e2ee, withPush
-    let notificationCenterDeleteFile                            = "deleteFile"                      // userInfo: account, ocIds, error
-    let notificationCenterRenameFile                            = "renameFile"                      // userInfo: ocId, account
-    let notificationCenterMoveFile                              = "moveFile"                        // userInfo: ocId, account, serverUrlFrom
-    let notificationCenterCopyFile                              = "copyFile"                        // userInfo: ocId, serverUrlTo
+    let notificationCenterCreateFolder                          = "createFolder"                    // userInfo: ocId, serverUrl, account, withPush
+    let notificationCenterDeleteFile                            = "deleteFile"                      // userInfo: [ocId], [indexPath], onlyLocalCache, error, hud?
+    let notificationCenterMoveFile                              = "moveFile"                        // userInfo: [ocId], [indexPath], error, hud?
+    let notificationCenterCopyFile                              = "copyFile"                        // userInfo: [ocId], [indexPath], error, hud?
+    let notificationCenterRenameFile                            = "renameFile"                      // userInfo: ocId, account, indexPath
     let notificationCenterFavoriteFile                          = "favoriteFile"                    // userInfo: ocId, serverUrl
     let notificationCenterFavoriteFile                          = "favoriteFile"                    // userInfo: ocId, serverUrl
 
 
     let notificationCenterOperationReadFile                     = "operationReadFile"               // userInfo: ocId
     let notificationCenterOperationReadFile                     = "operationReadFile"               // userInfo: ocId
 
 
     let notificationCenterMenuSearchTextPDF                     = "menuSearchTextPDF"
     let notificationCenterMenuSearchTextPDF                     = "menuSearchTextPDF"
     let notificationCenterMenuGotToPageInPDF                    = "menuGotToPageInPDF"
     let notificationCenterMenuGotToPageInPDF                    = "menuGotToPageInPDF"
-    let notificationCenterMenuDetailClose                       = "menuDetailClose"
 
 
     let notificationCenterDownloadedThumbnail                   = "DownloadedThumbnail"             // userInfo: ocId
     let notificationCenterDownloadedThumbnail                   = "DownloadedThumbnail"             // userInfo: ocId
 
 
     let notificationCenterOpenMediaDetail                       = "openMediaDetail"                 // userInfo: ocId
     let notificationCenterOpenMediaDetail                       = "openMediaDetail"                 // userInfo: ocId
-    
+
     let notificationCenterDismissScanDocument                   = "dismissScanDocument"
     let notificationCenterDismissScanDocument                   = "dismissScanDocument"
     let notificationCenterDismissUploadAssets                   = "dismissUploadAssets"
     let notificationCenterDismissUploadAssets                   = "dismissUploadAssets"
 
 
@@ -378,7 +395,7 @@ class NCGlobal: NSObject {
     let tipNCCollectionViewCommonAccountRequest                 = "tipnccollectionviewcommonaccountrequest"
     let tipNCCollectionViewCommonAccountRequest                 = "tipnccollectionviewcommonaccountrequest"
     let tipNCScanAddImage                                       = "tipncscanaddimage"
     let tipNCScanAddImage                                       = "tipncscanaddimage"
     let tipNCViewerMediaDetailView                              = "tipncviewermediadetailview"
     let tipNCViewerMediaDetailView                              = "tipncviewermediadetailview"
-    
+
     // ACTION
     // ACTION
     //
     //
     let actionNoAction                                          = "no-action"
     let actionNoAction                                          = "no-action"
@@ -386,7 +403,7 @@ class NCGlobal: NSObject {
     let actionScanDocument                                      = "add-scan-document"
     let actionScanDocument                                      = "add-scan-document"
     let actionTextDocument                                      = "create-text-document"
     let actionTextDocument                                      = "create-text-document"
     let actionVoiceMemo                                         = "create-voice-memo"
     let actionVoiceMemo                                         = "create-voice-memo"
-    
+
     // WIDGET ACTION
     // WIDGET ACTION
     //
     //
     let widgetActionNoAction                                    = "nextcloud://open-action?action=no-action"
     let widgetActionNoAction                                    = "nextcloud://open-action?action=no-action"
@@ -394,7 +411,7 @@ class NCGlobal: NSObject {
     let widgetActionScanDocument                                = "nextcloud://open-action?action=add-scan-document"
     let widgetActionScanDocument                                = "nextcloud://open-action?action=add-scan-document"
     let widgetActionTextDocument                                = "nextcloud://open-action?action=create-text-document"
     let widgetActionTextDocument                                = "nextcloud://open-action?action=create-text-document"
     let widgetActionVoiceMemo                                   = "nextcloud://open-action?action=create-voice-memo"
     let widgetActionVoiceMemo                                   = "nextcloud://open-action?action=create-voice-memo"
-    
+
     // APPCONFIG
     // APPCONFIG
     //
     //
     let configuration_brand                                     = "brand"
     let configuration_brand                                     = "brand"
@@ -403,7 +420,7 @@ class NCGlobal: NSObject {
     let configuration_username                                  = "username"
     let configuration_username                                  = "username"
     let configuration_password                                  = "password"
     let configuration_password                                  = "password"
     let configuration_apppassword                               = "apppassword"
     let configuration_apppassword                               = "apppassword"
-    
+
     let configuration_disable_intro                             = "disable_intro"
     let configuration_disable_intro                             = "disable_intro"
     let configuration_disable_multiaccount                      = "disable_multiaccount"
     let configuration_disable_multiaccount                      = "disable_multiaccount"
     let configuration_disable_crash_service                     = "disable_crash_service"
     let configuration_disable_crash_service                     = "disable_crash_service"
@@ -416,7 +433,7 @@ class NCGlobal: NSObject {
     //
     //
     var capabilityServerVersionMajor: Int                       = 0
     var capabilityServerVersionMajor: Int                       = 0
     @objc var capabilityServerVersion: String                   = ""
     @objc var capabilityServerVersion: String                   = ""
-    
+
     var capabilityFileSharingApiEnabled: Bool                   = false
     var capabilityFileSharingApiEnabled: Bool                   = false
     var capabilityFileSharingPubPasswdEnforced: Bool            = false
     var capabilityFileSharingPubPasswdEnforced: Bool            = false
     var capabilityFileSharingPubExpireDateEnforced: Bool        = false
     var capabilityFileSharingPubExpireDateEnforced: Bool        = false
@@ -443,12 +460,13 @@ class NCGlobal: NSObject {
     var capabilityFilesUndelete: Bool                           = false
     var capabilityFilesUndelete: Bool                           = false
     var capabilityFilesLockVersion: String                      = ""    // NC 24
     var capabilityFilesLockVersion: String                      = ""    // NC 24
     var capabilityFilesComments: Bool                           = false // NC 20
     var capabilityFilesComments: Bool                           = false // NC 20
+    var capabilityFilesBigfilechunking: Bool                    = false
 
 
     @objc var capabilityUserStatusEnabled: Bool                 = false
     @objc var capabilityUserStatusEnabled: Bool                 = false
     var capabilityExternalSites: Bool                           = false
     var capabilityExternalSites: Bool                           = false
     var capabilityGroupfoldersEnabled: Bool                     = false // NC27
     var capabilityGroupfoldersEnabled: Bool                     = false // NC27
 
 
-    // MORE APPS
+    // MORE NEXTCLOUD APPS
     let talkSchemeUrl                                           = "nextcloudtalk://"
     let talkSchemeUrl                                           = "nextcloudtalk://"
     let notesSchemeUrl                                          = "nextcloudnotes://"
     let notesSchemeUrl                                          = "nextcloudnotes://"
     let talkAppStoreUrl                                         = "https://apps.apple.com/de/app/nextcloud-talk/id1296825574"
     let talkAppStoreUrl                                         = "https://apps.apple.com/de/app/nextcloud-talk/id1296825574"
@@ -456,5 +474,5 @@ class NCGlobal: NSObject {
     let moreAppsUrl                                             = "https://www.apple.com/us/search/nextcloud?src=globalnav"
     let moreAppsUrl                                             = "https://www.apple.com/us/search/nextcloud?src=globalnav"
 
 
     // SNAPSHOT PREVIEW
     // SNAPSHOT PREVIEW
-    let defaultSnapshotConfiguration                            = "DefaultPreviewConfiguration"
+    let defaultSnapshotConfiguration = "DefaultPreviewConfiguration"
 }
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно