Browse Source

New version 5.4.0 (#2966)

Signed-off-by: Marino Faggiana <marino@marinofaggiana.com>
Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
Marino Faggiana 10 months ago
parent
commit
e97f47ba86
100 changed files with 1248 additions and 1183 deletions
  1. 1 1
      .swiftlint.yml
  2. 1 1
      Brand/Database.swift
  3. 18 1
      Brand/Intro/NCIntroViewController.swift
  4. 52 72
      Brand/NCBrand.swift
  5. 0 24
      File Provider Extension UI/FileProviderExtensionUI-Bridging-Header.h
  6. 0 24
      File Provider Extension/FileProviderExtension-Bridging-Header.h
  7. 2 2
      File Provider Extension/FileProviderExtension.swift
  8. 233 152
      Nextcloud.xcodeproj/project.pbxproj
  9. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme
  10. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme
  11. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/Notification Service Extension.xcscheme
  12. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme
  13. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/Widget.xcscheme
  14. 0 1
      Notification Service Extension/Notification_Service_Extension-Bridging-Header.h
  15. 3 2
      Share/NCShareExtension+DataSource.swift
  16. 1 1
      Share/NCShareExtension+Files.swift
  17. 0 1
      Share/Share-Bridging-Header.h
  18. 0 75
      Tests/NextcloudUITests/LoginUITests.swift
  19. 2 2
      Widget/Files/FilesData.swift
  20. 0 1
      Widget/Widget-Brinding-header.h
  21. 0 5
      WidgetDashboardIntentHandler/WidgetDashboardIntentHandler-Brinding-header.h
  22. 187 0
      iOSClient/Account Settings/NCAccountSettingsModel.swift
  23. 283 0
      iOSClient/Account Settings/NCAccountSettingsView.swift
  24. 3 11
      iOSClient/Activity/NCActivityTableViewCell.swift
  25. 82 47
      iOSClient/AppDelegate.swift
  26. 6 1
      iOSClient/Assistant/NCAssistant.swift
  27. 1 2
      iOSClient/AudioRecorder/NCAudioRecorderViewController.swift
  28. 4 4
      iOSClient/BrowserWeb/NCBrowserWeb.swift
  29. 3 4
      iOSClient/Color/NCColorPicker.swift
  30. 4 33
      iOSClient/Data/NCManageDatabase+Account.swift
  31. 1 0
      iOSClient/Data/NCManageDatabase+Avatar.swift
  32. 37 19
      iOSClient/Data/NCManageDatabase+Directory.swift
  33. 12 0
      iOSClient/Data/NCManageDatabase+Metadata+Session.swift
  34. 6 17
      iOSClient/Data/NCManageDatabase+Metadata.swift
  35. 2 0
      iOSClient/Data/NCManageDatabase+PhotoLibrary.swift
  36. 0 4
      iOSClient/Data/NCManageDatabase+Tip.swift
  37. 23 5
      iOSClient/Data/NCManageDatabase.swift
  38. 156 0
      iOSClient/DeepLink/NCDeepLinkHandler.swift
  39. 0 203
      iOSClient/Diagnostics/NCCapabilitiesView.swift
  40. 1 0
      iOSClient/Extensions/PHAsset+Extension.swift
  41. 0 52
      iOSClient/Extensions/UIDevice+Extension.swift
  42. 25 0
      iOSClient/Extensions/View+Extension.swift
  43. 25 11
      iOSClient/Files/NCFiles.swift
  44. 1 1
      iOSClient/GUI/HUDView.swift
  45. 14 7
      iOSClient/GUI/LazyView.swift
  46. 49 0
      iOSClient/GUI/ViewOnAppear.swift
  47. 0 15
      iOSClient/Images.xcassets/address.imageset/Contents.json
  48. BIN
      iOSClient/Images.xcassets/address.imageset/address.pdf
  49. 0 15
      iOSClient/Images.xcassets/arrow.forward.square.imageset/Contents.json
  50. 0 1
      iOSClient/Images.xcassets/arrow.forward.square.imageset/arrow-right-bold-box-outline.svg
  51. 0 15
      iOSClient/Images.xcassets/arrow.up.right.square.imageset/Contents.json
  52. 0 1
      iOSClient/Images.xcassets/arrow.up.right.square.imageset/Unknown.svg
  53. 0 15
      iOSClient/Images.xcassets/autoUpload.imageset/Contents.json
  54. 0 1
      iOSClient/Images.xcassets/autoUpload.imageset/camera-outline.svg
  55. 0 15
      iOSClient/Images.xcassets/businesstype.imageset/Contents.json
  56. BIN
      iOSClient/Images.xcassets/businesstype.imageset/businesstype.pdf
  57. 0 12
      iOSClient/Images.xcassets/caldavcardav.imageset/Contents.json
  58. 0 1
      iOSClient/Images.xcassets/caldavcardav.imageset/icons8-calendario-delle-persone.svg
  59. 0 15
      iOSClient/Images.xcassets/capabilities.imageset/Contents.json
  60. 0 1
      iOSClient/Images.xcassets/capabilities.imageset/format-list-bulleted.svg
  61. 0 15
      iOSClient/Images.xcassets/checkmark.imageset/Contents.json
  62. 0 1
      iOSClient/Images.xcassets/checkmark.imageset/check.svg
  63. 5 5
      iOSClient/Images.xcassets/circle_fill.imageset/Contents.json
  64. BIN
      iOSClient/Images.xcassets/circle_fill.imageset/circle.pdf
  65. BIN
      iOSClient/Images.xcassets/circle_fill.imageset/circle_fill.pdf
  66. 0 15
      iOSClient/Images.xcassets/city.imageset/Contents.json
  67. BIN
      iOSClient/Images.xcassets/city.imageset/city.pdf
  68. 0 15
      iOSClient/Images.xcassets/clear.imageset/Contents.json
  69. BIN
      iOSClient/Images.xcassets/clear.imageset/clear.pdf
  70. 0 15
      iOSClient/Images.xcassets/comment.imageset/Contents.json
  71. BIN
      iOSClient/Images.xcassets/comment.imageset/comment.pdf
  72. 0 15
      iOSClient/Images.xcassets/comments.imageset/Contents.json
  73. BIN
      iOSClient/Images.xcassets/comments.imageset/comments.pdf
  74. 0 15
      iOSClient/Images.xcassets/company.imageset/Contents.json
  75. BIN
      iOSClient/Images.xcassets/company.imageset/company.pdf
  76. 0 15
      iOSClient/Images.xcassets/country.imageset/Contents.json
  77. BIN
      iOSClient/Images.xcassets/country.imageset/country.pdf
  78. 0 15
      iOSClient/Images.xcassets/crashservice.imageset/Contents.json
  79. 0 1
      iOSClient/Images.xcassets/crashservice.imageset/bug-outline.svg
  80. 0 15
      iOSClient/Images.xcassets/editUserProfile.imageset/Contents.json
  81. BIN
      iOSClient/Images.xcassets/editUserProfile.imageset/editUserProfile.pdf
  82. 0 15
      iOSClient/Images.xcassets/email.imageset/Contents.json
  83. BIN
      iOSClient/Images.xcassets/email.imageset/mail.pdf
  84. 0 26
      iOSClient/Images.xcassets/foldersOnTop.imageset/Contents.json
  85. BIN
      iOSClient/Images.xcassets/foldersOnTop.imageset/foldersOnTop.png
  86. BIN
      iOSClient/Images.xcassets/foldersOnTop.imageset/foldersOnTop@2x.png
  87. BIN
      iOSClient/Images.xcassets/foldersOnTop.imageset/foldersOnTop@3x.png
  88. 0 15
      iOSClient/Images.xcassets/form-textbox.imageset/Contents.json
  89. 0 1
      iOSClient/Images.xcassets/form-textbox.imageset/form-textbox.svg
  90. 0 15
      iOSClient/Images.xcassets/log.imageset/Contents.json
  91. BIN
      iOSClient/Images.xcassets/log.imageset/log.pdf
  92. 0 15
      iOSClient/Images.xcassets/role.imageset/Contents.json
  93. BIN
      iOSClient/Images.xcassets/role.imageset/role.pdf
  94. 0 26
      iOSClient/Images.xcassets/rotate.imageset/Contents.json
  95. BIN
      iOSClient/Images.xcassets/rotate.imageset/rotate.png
  96. BIN
      iOSClient/Images.xcassets/rotate.imageset/rotate@2x.png
  97. BIN
      iOSClient/Images.xcassets/rotate.imageset/rotate@3x.png
  98. BIN
      iOSClient/Images.xcassets/select.imageset/1.pdf
  99. 0 15
      iOSClient/Images.xcassets/select.imageset/Contents.json
  100. 0 15
      iOSClient/Images.xcassets/selectLight.imageset/Contents.json

+ 1 - 1
.swiftlint.yml

@@ -36,7 +36,7 @@ disabled_rules:
   - shorthand_operator
   - shorthand_operator
   - type_name
   - type_name
   - void_function_in_ternary
   - void_function_in_ternary
-
+  - switch_case_alignment
 excluded:
 excluded:
   - Carthage
   - Carthage
   - Pods
   - Pods

+ 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   = 347
+let databaseSchemaVersion: UInt64   = 348

+ 18 - 1
Brand/Intro/NCIntroViewController.swift

@@ -33,7 +33,7 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol
     @IBOutlet weak var introCollectionView: UICollectionView!
     @IBOutlet weak var introCollectionView: UICollectionView!
     @IBOutlet weak var pageControl: UIPageControl!
     @IBOutlet weak var pageControl: UIPageControl!
 
 
-    @objc weak var delegate: NCIntroViewController?
+    weak var delegate: NCIntroViewController?
 
 
     private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
     private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
     private let titles = [NSLocalizedString("_intro_1_title_", comment: ""), NSLocalizedString("_intro_2_title_", comment: ""), NSLocalizedString("_intro_3_title_", comment: ""), NSLocalizedString("_intro_4_title_", comment: "")]
     private let titles = [NSLocalizedString("_intro_1_title_", comment: ""), NSLocalizedString("_intro_2_title_", comment: ""), NSLocalizedString("_intro_3_title_", comment: ""), NSLocalizedString("_intro_4_title_", comment: "")]
@@ -98,6 +98,23 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol
 
 
         view.backgroundColor = NCBrandColor.shared.customer
         view.backgroundColor = NCBrandColor.shared.customer
         timerAutoScroll = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(NCIntroViewController.autoScroll)), userInfo: nil, repeats: true)
         timerAutoScroll = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(NCIntroViewController.autoScroll)), userInfo: nil, repeats: true)
+
+        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in
+            let window = UIApplication.shared.firstWindow
+            if window?.rootViewController is NCMainTabBarController {
+                self.dismiss(animated: true)
+            } else {
+                if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController {
+                    mainTabBarController.modalPresentationStyle = .fullScreen
+                    mainTabBarController.view.alpha = 0
+                    window?.rootViewController = mainTabBarController
+                    window?.makeKeyAndVisible()
+                    UIView.animate(withDuration: 0.5) {
+                        mainTabBarController.view.alpha = 1
+                    }
+                }
+            }
+        }
     }
     }
 
 
     override var preferredStatusBarStyle: UIStatusBarStyle {
     override var preferredStatusBarStyle: UIStatusBarStyle {

+ 52 - 72
Brand/NCBrand.swift

@@ -35,63 +35,53 @@ let userAgent: String = {
         return instance
         return instance
     }()
     }()
 
 
-    @objc public var brand: String = "Nextcloud"
-    @objc public var textCopyrightNextcloudiOS: String = "Nextcloud Hydrogen for iOS %@ © 2024"
-    @objc public var textCopyrightNextcloudServer: String = "Nextcloud Server %@"
-    @objc public var loginBaseUrl: String = "https://cloud.nextcloud.com"
-    @objc public var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com"
-    @objc public var linkLoginHost: String = "https://nextcloud.com/install"
-    @objc public var linkloginPreferredProviders: String = "https://nextcloud.com/signup-ios"
-    @objc public var webLoginAutenticationProtocol: String = "nc://"                                                // example "abc://"
-    @objc public var privacy: String = "https://nextcloud.com/privacy"
-    @objc public var sourceCode: String = "https://github.com/nextcloud/ios"
-    @objc public var mobileconfig: String = "/remote.php/dav/provisioning/apple-provisioning.mobileconfig"
-
-    // Personalized
-    @objc public var webCloseViewProtocolPersonalized: String = ""                                                  // example "abc://change/plan"      Don't touch me !!
-    @objc public var folderBrandAutoUpload: String = ""                                                             // example "_auto_upload_folder_"   Don't touch me !!
+    var brand: String = "Nextcloud"
+    var textCopyrightNextcloudiOS: String = "Nextcloud Hydrogen for iOS %@ © 2024"
+    var textCopyrightNextcloudServer: String = "Nextcloud Server %@"
+    var loginBaseUrl: String = "https://cloud.nextcloud.com"
+    @objc var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com"
+    var linkLoginHost: String = "https://nextcloud.com/install"
+    var linkloginPreferredProviders: String = "https://nextcloud.com/signup-ios"
+    var webLoginAutenticationProtocol: String = "nc://"                                                // example "abc://"
+    var privacy: String = "https://nextcloud.com/privacy"
+    var sourceCode: String = "https://github.com/nextcloud/ios"
+    var mobileconfig: String = "/remote.php/dav/provisioning/apple-provisioning.mobileconfig"
+    var appStoreUrl: String = "https://apps.apple.com/in/app/nextcloud/id1125420102"
 
 
     // Auto Upload default folder
     // Auto Upload default folder
-    @objc public var folderDefaultAutoUpload: String = "Photos"
+    var folderDefaultAutoUpload: String = "Photos"
 
 
     // Capabilities Group
     // Capabilities Group
-    @objc public var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud"
-    @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps"
+    var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud"
+    var capabilitiesGroupApps: String = "group.com.nextcloud.apps"
 
 
     // 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_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_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
-    @objc public var doNotAskPasscodeAtStartup: Bool = false
+
+    var disable_intro: Bool = false
+    var disable_request_login_url: Bool = false
+    var disable_multiaccount: Bool = false
+    var disable_more_external_site: Bool = false
+    var disable_openin_file: Bool = false                                          // Don't touch me !!
+    var disable_crash_service: Bool = false
+    var disable_log: Bool = false
+    var disable_mobileconfig: Bool = false
+    var disable_show_more_nextcloud_apps_in_settings: Bool = false
+    var doNotAskPasscodeAtStartup: 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
+    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
 
 
     // Max download/upload concurrent
     // Max download/upload concurrent
-    public let maxConcurrentOperationDownload: Int = 5
-    public let maxConcurrentOperationUpload: Int = 5
+    let maxConcurrentOperationDownload: Int = 5
+    let maxConcurrentOperationUpload: Int = 5
 
 
     // Number of failed attempts after reset app
     // Number of failed attempts after reset app
-    @objc public let resetAppPasscodeAttempts: Int = 10
-    public let passcodeSecondsFail: Int = 60
+    let resetAppPasscodeAttempts: Int = 10
+    let passcodeSecondsFail: Int = 60
 
 
     // Info Paging
     // Info Paging
     enum NCInfoPagingTab: Int, CaseIterable {
     enum NCInfoPagingTab: Int, CaseIterable {
@@ -99,11 +89,6 @@ let userAgent: String = {
     }
     }
 
 
     override init() {
     override init() {
-
-        if 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 {
 
 
@@ -122,9 +107,6 @@ let userAgent: String = {
             if let str = configurationManaged[NCGlobal.shared.configuration_disable_log] as? String {
             if let str = configurationManaged[NCGlobal.shared.configuration_disable_log] as? String {
                 disable_log = (str as NSString).boolValue
                 disable_log = (str as NSString).boolValue
             }
             }
-            if let str = configurationManaged[NCGlobal.shared.configuration_disable_manage_account] as? String {
-                disable_manage_account = (str as NSString).boolValue
-            }
             if let str = configurationManaged[NCGlobal.shared.configuration_disable_more_external_site] as? String {
             if let str = configurationManaged[NCGlobal.shared.configuration_disable_more_external_site] as? String {
                 disable_more_external_site = (str as NSString).boolValue
                 disable_more_external_site = (str as NSString).boolValue
             }
             }
@@ -140,53 +122,53 @@ let userAgent: String = {
 }
 }
 
 
 class NCBrandColor: NSObject {
 class NCBrandColor: NSObject {
-    @objc static let shared: NCBrandColor = {
+    static let shared: NCBrandColor = {
         let instance = NCBrandColor()
         let instance = NCBrandColor()
         return instance
         return instance
     }()
     }()
 
 
     // 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 var customerText: UIColor = .white
+    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
+    var customerText: UIColor = .white
 
 
-    @objc private var brand: UIColor                                                                                         // don't touch me
-    @objc public var brandElement: UIColor                                                                                  // don't touch me
-    @objc public var brandText: UIColor                                                                                     // don't touch me
+    var brand: UIColor                                                                                         // don't touch me
+    var brandElement: UIColor                                                                                  // don't touch me
+    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)
+    let nextcloud: UIColor = UIColor(red: 0.0 / 255.0, green: 130.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0)
+    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 themingColor: String = ""
-    public var themingColorElement: String = ""
-    public var themingColorText: String = ""
+    var userColors: [CGColor] = []
+    var themingColor: String = ""
+    var themingColorElement: String = ""
+    var themingColorText: String = ""
 
 
-    @objc public let iconImageColor: UIColor = .label
-    @objc public let iconImageColor2: UIColor = .secondaryLabel
-    @objc public let iconImageMultiColors: [UIColor] = [.secondaryLabel, .label]
+    let iconImageColor: UIColor = .label
+    let iconImageColor2: UIColor = .secondaryLabel
+    let iconImageMultiColors: [UIColor] = [.secondaryLabel, .label]
 
 
-    @objc public let textColor: UIColor = .label
-    @objc public let textColor2: UIColor = .secondaryLabel
+    let textColor: UIColor = .label
+    let textColor2: UIColor = .secondaryLabel
 
 
-    @objc public var systemMint: UIColor {
+    var systemMint: UIColor {
         get {
         get {
             return UIColor(red: 0.0 / 255.0, green: 199.0 / 255.0, blue: 190.0 / 255.0, alpha: 1.0)
             return UIColor(red: 0.0 / 255.0, green: 199.0 / 255.0, blue: 190.0 / 255.0, alpha: 1.0)
         }
         }
     }
     }
 
 
-    @objc public var documentIconColor: UIColor {
+    var documentIconColor: UIColor {
         get {
         get {
             return UIColor(hex: "#49abe9")!
             return UIColor(hex: "#49abe9")!
         }
         }
     }
     }
 
 
-    @objc public var spreadsheetIconColor: UIColor {
+    var spreadsheetIconColor: UIColor {
         get {
         get {
             return UIColor(hex: "#9abd4e")!
             return UIColor(hex: "#9abd4e")!
         }
         }
     }
     }
 
 
-    @objc public var presentationIconColor: UIColor {
+    var presentationIconColor: UIColor {
         get {
         get {
             return UIColor(hex: "#f0965f")!
             return UIColor(hex: "#f0965f")!
         }
         }
@@ -203,12 +185,10 @@ class NCBrandColor: NSObject {
     }
     }
 
 
     func settingThemingColor(account: String) {
     func settingThemingColor(account: String) {
-
         let darker: CGFloat = 30    // %
         let darker: CGFloat = 30    // %
         let lighter: CGFloat = 30   // %
         let lighter: CGFloat = 30   // %
 
 
         if NCBrandOptions.shared.use_themingColor {
         if NCBrandOptions.shared.use_themingColor {
-
             self.themingColor = NCGlobal.shared.capabilityThemingColor
             self.themingColor = NCGlobal.shared.capabilityThemingColor
             self.themingColorElement = NCGlobal.shared.capabilityThemingColorElement
             self.themingColorElement = NCGlobal.shared.capabilityThemingColorElement
             self.themingColorText = NCGlobal.shared.capabilityThemingColorText
             self.themingColorText = NCGlobal.shared.capabilityThemingColorText

+ 0 - 24
File Provider Extension UI/FileProviderExtensionUI-Bridging-Header.h

@@ -1,24 +0,0 @@
-//
-//  PickerFileProvider-Bridging-Header.h
-//  Nextcloud
-//
-//  Created by Marino Faggiana on 24/05/17.
-//  Copyright © 2017 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 "CCUtility.h"

+ 0 - 24
File Provider Extension/FileProviderExtension-Bridging-Header.h

@@ -1,24 +0,0 @@
-//
-//  PickerFileProvider-Bridging-Header.h
-//  Nextcloud
-//
-//  Created by Marino Faggiana on 24/05/17.
-//  Copyright © 2017 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 "CCUtility.h"

+ 2 - 2
File Provider Extension/FileProviderExtension.swift

@@ -22,6 +22,7 @@
 //
 //
 
 
 import UIKit
 import UIKit
+import UniformTypeIdentifiers
 import FileProvider
 import FileProvider
 import NextcloudKit
 import NextcloudKit
 import Alamofire
 import Alamofire
@@ -96,8 +97,7 @@ class FileProviderExtension: NSFileProviderExtension {
             // - for a directory, instantiate an enumerator of its subitems
             // - for a directory, instantiate an enumerator of its subitems
             // - for a file, instantiate an enumerator that observes changes to the file
             // - for a file, instantiate an enumerator that observes changes to the file
             let item = try self.item(for: containerItemIdentifier)
             let item = try self.item(for: containerItemIdentifier)
-
-            if item.typeIdentifier == kUTTypeFolder as String {
+            if item.contentType == UTType.folder {
                 maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier)
                 maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier)
             } else {
             } else {
                 maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier)
                 maybeEnumerator = FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier)

File diff suppressed because it is too large
+ 233 - 152
Nextcloud.xcodeproj/project.pbxproj


+ 1 - 1
Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
 <Scheme
-   LastUpgradeVersion = "1400"
+   LastUpgradeVersion = "1540"
    wasCreatedForAppExtension = "YES"
    wasCreatedForAppExtension = "YES"
    version = "2.0">
    version = "2.0">
    <BuildAction
    <BuildAction

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

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
 <Scheme
-   LastUpgradeVersion = "1400"
+   LastUpgradeVersion = "1540"
    version = "1.7">
    version = "1.7">
    <BuildAction
    <BuildAction
       parallelizeBuildables = "YES"
       parallelizeBuildables = "YES"

+ 1 - 1
Nextcloud.xcodeproj/xcshareddata/xcschemes/Notification Service Extension.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
 <Scheme
-   LastUpgradeVersion = "1400"
+   LastUpgradeVersion = "1540"
    wasCreatedForAppExtension = "YES"
    wasCreatedForAppExtension = "YES"
    version = "2.0">
    version = "2.0">
    <BuildAction
    <BuildAction

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

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
 <Scheme
-   LastUpgradeVersion = "1400"
+   LastUpgradeVersion = "1540"
    wasCreatedForAppExtension = "YES"
    wasCreatedForAppExtension = "YES"
    version = "2.0">
    version = "2.0">
    <BuildAction
    <BuildAction

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

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
 <Scheme
-   LastUpgradeVersion = "1400"
+   LastUpgradeVersion = "1540"
    wasCreatedForAppExtension = "YES"
    wasCreatedForAppExtension = "YES"
    version = "2.0">
    version = "2.0">
    <BuildAction
    <BuildAction

+ 0 - 1
Notification Service Extension/Notification_Service_Extension-Bridging-Header.h

@@ -19,5 +19,4 @@
 //  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 "CCUtility.h"
 #import "NCPushNotificationEncryption.h"
 #import "NCPushNotificationEncryption.h"

+ 3 - 2
Share/NCShareExtension+DataSource.swift

@@ -136,9 +136,10 @@ extension NCShareExtension: UICollectionViewDataSource {
     func setupDirectoryCell(_ cell: NCListCell, indexPath: IndexPath, with metadata: tableMetadata) {
     func setupDirectoryCell(_ cell: NCListCell, indexPath: IndexPath, with metadata: tableMetadata) {
         var isShare = false
         var isShare = false
         var isMounted = false
         var isMounted = false
+        let permissions = NCPermissions()
         if let metadataFolder = metadataFolder {
         if let metadataFolder = metadataFolder {
-            isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionShared)
-            isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionMounted)
+            isShare = metadata.permissions.contains(permissions.permissionShared) && !metadataFolder.permissions.contains(permissions.permissionShared)
+            isMounted = metadata.permissions.contains(permissions.permissionMounted) && !metadataFolder.permissions.contains(permissions.permissionMounted)
         }
         }
 
 
         if metadata.e2eEncrypted {
         if metadata.e2eEncrypted {

+ 1 - 1
Share/NCShareExtension+Files.swift

@@ -217,6 +217,6 @@ class NCFilesExtensionHandler {
 extension NSItemProvider {
 extension NSItemProvider {
     var typeIdentifier: String {
     var typeIdentifier: String {
         if hasItemConformingToTypeIdentifier("public.url") { return "public.url" } else
         if hasItemConformingToTypeIdentifier("public.url") { return "public.url" } else
-        if hasItemConformingToTypeIdentifier(kUTTypeItem as String) { return kUTTypeItem as String } else { return "" }
+        if hasItemConformingToTypeIdentifier(UTType.item.identifier as String) { return UTType.item.identifier as String } else { return "" }
     }
     }
 }
 }

+ 0 - 1
Share/Share-Bridging-Header.h

@@ -3,5 +3,4 @@
 //
 //
 
 
 #import "NCEndToEndEncryption.h"
 #import "NCEndToEndEncryption.h"
-#import "CCUtility.h"
 #import "UIImage+animatedGIF.h"
 #import "UIImage+animatedGIF.h"

+ 0 - 75
Tests/NextcloudUITests/LoginUITests.swift

@@ -1,75 +0,0 @@
-//
-//  NextcloudUITests.swift
-//  NextcloudUITests
-//
-//  Created by Milen Pivchev on 5/19/23.
-//  Copyright © 2023 Marino Faggiana. All rights reserved.
-//
-//  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 XCTest
-import NextcloudKit
-@testable import Nextcloud
-
-final class LoginUITests: BaseUIXCTestCase {
-    let app = XCUIApplication()
-
-    override func setUp() {
-        app.launchArguments += ["UI_TESTING"]
-    }
-
-    func test_logIn_withProperParams_shouldLogInAndGoToHomeScreen() throws {
-        app.launch()
-
-        let loginButton = app.buttons["Log in"]
-        XCTAssert(loginButton.waitForExistence(timeout: TestConstants.timeoutLong))
-        loginButton.tap()
-
-        let serverAddressHttpsTextField = app.textFields["Server address https:// …"]
-        serverAddressHttpsTextField.tap()
-        serverAddressHttpsTextField.typeText(TestConstants.server)
-        let button = app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .other).element.children(matching: .button).element(boundBy: 0)
-        button.tap()
-
-        let webViewsQuery = app.webViews.webViews.webViews
-        let loginButton2 = webViewsQuery/*@START_MENU_TOKEN@*/.buttons["Log in"]/*[[".otherElements.matching(identifier: \"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(loginButton2.waitForExistence(timeout: TestConstants.timeoutLong))
-        waitForEnabledAndHittable(object: loginButton2)
-        loginButton2.tap()
-
-        let usernameTextField = webViewsQuery.textFields["Login with username or email"]
-        XCTAssert(usernameTextField.waitForExistence(timeout: TestConstants.timeoutLong))
-        usernameTextField.tap()
-        usernameTextField.typeText(TestConstants.username)
-
-        let passwordTextField = webViewsQuery/*@START_MENU_TOKEN@*/.secureTextFields["Password"]/*[[".otherElements[\"Login – Nextcloud\"]",".otherElements[\"main\"].secureTextFields[\"Password\"]",".secureTextFields[\"Password\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/
-        XCTAssert(passwordTextField.waitForExistence(timeout: TestConstants.timeoutLong))
-        passwordTextField.tap()
-        passwordTextField.typeText(TestConstants.username)
-
-        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: TestConstants.timeoutLong))
-        loginButton3.tap()
-
-        let grantAccessButton = webViewsQuery/*@START_MENU_TOKEN@*/.buttons["Grant access"]/*[[".otherElements.matching(identifier: \"Nextcloud\")",".otherElements[\"main\"].buttons[\"Grant access\"]",".buttons[\"Grant access\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/
-        XCTAssert(grantAccessButton.waitForExistence(timeout: TestConstants.timeoutLong))
-        waitForEnabledAndHittable(object: grantAccessButton)
-        grantAccessButton.tap()
-
-        // Check if we are in the home screen
-        XCTAssert(app.navigationBars["Nextcloud"].waitForExistence(timeout: TestConstants.timeoutLong))
-        XCTAssert(app.tabBars["Tab Bar"].waitForExistence(timeout: TestConstants.timeoutLong))
-    }
-}

+ 2 - 2
Widget/Files/FilesData.swift

@@ -219,11 +219,11 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi
                 if let result = utility.createFilePreviewImage(ocId: file.ocId, etag: file.etag, fileNameView: file.fileName, classFile: file.classFile, status: 0, createPreviewMedia: false) {
                 if let result = utility.createFilePreviewImage(ocId: file.ocId, etag: file.etag, fileNameView: file.fileName, classFile: file.classFile, status: 0, createPreviewMedia: false) {
                     image = result
                     image = result
                 } else if file.hasPreview {
                 } else if file.hasPreview {
-                    let fileNamePathOrFileId = utilityFileSystem.getFileNamePath(file.fileName, serverUrl: file.serverUrl, urlBase: file.urlBase, userId: file.userId)
+
                     let fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(file.ocId, etag: file.etag)
                     let fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(file.ocId, etag: file.etag)
                     let fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(file.ocId, etag: file.etag)
                     let fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(file.ocId, etag: file.etag)
                     let sizePreview = NCUtility().getSizePreview(width: Int(file.width), height: Int(file.height))
                     let sizePreview = NCUtility().getSizePreview(width: Int(file.width), height: Int(file.height))
-                    let (_, _, imageIcon, _, _, _) = await NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePathOrFileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, widthPreview: Int(sizePreview.width), heightPreview: Int(sizePreview.height), fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, options: options)
+                    let (_, _, imageIcon, _, _, _) = await NextcloudKit.shared.downloadPreview(fileId: file.fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, fileNameIconLocalPath: fileNameIconLocalPath, widthPreview: Int(sizePreview.width), heightPreview: Int(sizePreview.height), sizeIcon: NCGlobal.shared.sizeIcon, options: options)
                     if let result = imageIcon {
                     if let result = imageIcon {
                          image = result
                          image = result
                     }
                     }

+ 0 - 1
Widget/Widget-Brinding-header.h

@@ -2,5 +2,4 @@
 //  Use this file to import your target's public headers that you would like to expose to Swift.
 //  Use this file to import your target's public headers that you would like to expose to Swift.
 //
 //
 
 
-#import "CCUtility.h"
 #import "UIImage+animatedGIF.h"
 #import "UIImage+animatedGIF.h"

+ 0 - 5
WidgetDashboardIntentHandler/WidgetDashboardIntentHandler-Brinding-header.h

@@ -1,5 +0,0 @@
-//
-//  Use this file to import your target's public headers that you would like to expose to Swift.
-//
-
-#import "CCUtility.h"

+ 187 - 0
iOSClient/Account Settings/NCAccountSettingsModel.swift

@@ -0,0 +1,187 @@
+//
+//  NCAccountSettingsModel.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 06/06/24.
+//  Copyright © 2024 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 UIKit
+import RealmSwift
+
+/// Protocol for know when the Account Settings has dimissed
+protocol NCAccountSettingsModelDelegate: AnyObject {
+    func accountSettingsDidDismiss(tableAccount: tableAccount?)
+}
+
+/// A model that allows the user to configure the account
+class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling {
+    /// AppDelegate
+    let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
+    /// Root View Controller
+    var controller: NCMainTabBarController?
+    /// All account
+    var accounts: [tableAccount] = []
+    /// Delegate
+    weak var delegate: NCAccountSettingsModelDelegate?
+    /// Timer change user
+    var timerChangeAccount: Timer?
+    /// Token observe tableAccount
+    var notificationToken: NotificationToken?
+    /// Account now active
+    @Published var activeAccount: tableAccount?
+    /// Index
+    @Published var indexActiveAccount: Int = 0
+    /// Current alias
+    @Published var alias: String = ""
+    /// Set true for dismiss the view
+    @Published var dismissView = false
+
+    /// Initialization code to set up the ViewModel with the active account
+    init(controller: NCMainTabBarController?, delegate: NCAccountSettingsModelDelegate?) {
+        self.controller = controller
+        self.delegate = delegate
+        if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
+            NCManageDatabase.shared.previewCreateDB()
+        }
+        onViewAppear()
+        observeTableAccount()
+    }
+
+    deinit {
+        timerChangeAccount?.invalidate()
+        timerChangeAccount = nil
+        notificationToken?.invalidate()
+        notificationToken = nil
+    }
+
+    /// Reload the view when change the tableAccount
+    func observeTableAccount() {
+        do {
+            let realm = try Realm()
+            let results = realm.objects(tableAccount.self)
+            notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in
+                switch changes {
+                case .initial:
+                    break
+                case .update:
+                    DispatchQueue.main.async {
+                        self?.objectWillChange.send()
+                    }
+                case .error:
+                    break
+                }
+            }
+        } catch let error as NSError {
+            NSLog("Could not access database: ", error)
+        }
+    }
+
+    /// Triggered when the view appears.
+    func onViewAppear() {
+        var indexActiveAccount = 0
+        let accounts = NCManageDatabase.shared.getAllAccount()
+        var activeAccount = NCManageDatabase.shared.getActiveAccount()
+        var alias = ""
+
+        for (index, account) in accounts.enumerated() {
+            if account.active {
+                activeAccount = account
+                indexActiveAccount = index
+                alias = account.alias
+            }
+        }
+
+        self.indexActiveAccount = indexActiveAccount
+        self.accounts = accounts
+        self.activeAccount = activeAccount
+        self.alias = alias
+    }
+
+    /// Func to get the user display name + alias
+    func getUserName() -> String {
+        guard let activeAccount else { return "" }
+        if alias.isEmpty {
+            return activeAccount.displayName
+        } else {
+            return activeAccount.displayName + " (\(alias))"
+        }
+    }
+
+    /// Func to set alias
+    func setAlias(_ value: String) {
+        guard let activeAccount else { return }
+        NCManageDatabase.shared.setAccountAlias(activeAccount.account, alias: alias)
+    }
+
+    /// Function to update the user data
+    func getUserStatus() -> (statusImage: UIImage, statusMessage: String, descriptionMessage: String) {
+        guard let activeAccount else { return (UIImage(), "", "") }
+        if NCGlobal.shared.capabilityUserStatusEnabled,
+           let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", activeAccount.account)) {
+            return NCUtility().getUserStatus(userIcon: tableAccount.userStatusIcon, userStatus: tableAccount.userStatusStatus, userMessage: tableAccount.userStatusMessage)
+        }
+        return (UIImage(), "", "")
+    }
+
+    /// Function to know the height of "account" data
+    func getTableViewHeight() -> CGFloat {
+        guard let activeAccount else { return 0 }
+        var height: CGFloat = 190
+        if NCGlobal.shared.capabilityUserStatusEnabled,
+           let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", activeAccount.account)) {
+            if !tableAccount.email.isEmpty { height += 30 }
+            if !tableAccount.phone.isEmpty { height += 30 }
+            if !tableAccount.address.isEmpty { height += 30 }
+        }
+        if height == 190 { return 170 }
+        return height
+    }
+
+    /// Function to change account after 1.5 sec of change
+    func setAccount(account: String) {
+        if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.activeAccount?.account != tableAccount.account {
+            self.activeAccount = tableAccount
+            self.alias = tableAccount.alias
+            /// Change active account
+            timerChangeAccount?.invalidate()
+            timerChangeAccount = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(changeAccount), userInfo: nil, repeats: false)
+
+        }
+    }
+
+    @objc func changeAccount() {
+        if let activeAccount {
+            self.appDelegate.changeAccount(activeAccount.account, userProfile: nil)
+        }
+    }
+
+    /// Function to delete the current account
+    func deleteAccount() {
+        if let activeAccount {
+            appDelegate.deleteAccount(activeAccount.account, wipe: false)
+            if let account = NCManageDatabase.shared.getAllAccount().first?.account {
+                appDelegate.changeAccount(account, userProfile: nil)
+            } else {
+                dismissView = true
+            }
+            onViewAppear()
+        }
+    }
+}

+ 283 - 0
iOSClient/Account Settings/NCAccountSettingsView.swift

@@ -0,0 +1,283 @@
+//
+//  NCAccountSettingsView.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 06/06/24.
+//  Copyright © 2024 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 SwiftUI
+
+struct NCAccountSettingsView: View {
+    @ObservedObject var model: NCAccountSettingsModel
+
+    @State private var isExpanded: Bool = false
+    @State private var showUserStatus = false
+    @State private var showServerCertificate = false
+    @State private var showPushCertificate = false
+    @State private var showDeleteAccountAlert: Bool = false
+    @State private var showAddAccount: Bool = false
+    @State private var animation: Bool = false
+
+    @Environment(\.presentationMode) var presentationMode
+
+    var body: some View {
+        NavigationView {
+            Form {
+                Section(content: {
+                    TabView(selection: $model.indexActiveAccount) {
+                        ForEach(0..<model.accounts.count, id: \.self) { index in
+                            let status = model.getUserStatus()
+                            let avatar = NCUtility().loadUserImage(for: model.accounts[index].user, displayName: model.accounts[index].displayName, userBaseUrl: model.accounts[index])
+                            ///
+                            /// User
+                            VStack {
+                                ZStack {
+                                    Image(uiImage: avatar)
+                                        .resizable()
+                                        .scaledToFit()
+                                        .frame(width: UIScreen.main.bounds.width, height: 75)
+                                    ZStack {
+                                        Circle()
+                                            .fill(.white)
+                                            .frame(width: 30, height: 30)
+                                        Image(uiImage: status.statusImage)
+                                            .resizable()
+                                            .scaledToFit()
+                                            .frame(width: 30, height: 30)
+                                        }
+                                        .offset(x: 30, y: 30)
+                                }
+                                .frame(maxWidth: .infinity, maxHeight: .infinity)
+                                Text(model.getUserName())
+                                    .font(.system(size: 16))
+                                Spacer()
+                                    .frame(height: 10)
+                                Text(status.statusMessage)
+                                    .font(.system(size: 10))
+                                Spacer()
+                                    .frame(height: 20)
+                                ///
+                                /// Personal data
+                                if let activeAccount = model.activeAccount {
+                                    if !activeAccount.email.isEmpty {
+                                        HStack {
+                                            Image(systemName: "mail")
+                                                .resizable()
+                                                .scaledToFit()
+                                                .font(Font.system(.body).weight(.light))
+                                                .frame(width: 20, height: 20)
+                                            Text(activeAccount.email)
+                                                .lineLimit(1)
+                                                .truncationMode(.middle)
+                                                .frame(maxWidth: .infinity, alignment: .leading)
+
+                                        }
+                                        .frame(maxWidth: .infinity, maxHeight: 30)
+                                    }
+                                    if !activeAccount.phone.isEmpty {
+                                        HStack {
+                                            Image(systemName: "phone")
+                                                .resizable()
+                                                .scaledToFit()
+                                                .font(Font.system(.body).weight(.light))
+                                                .frame(width: 20, height: 20)
+                                            Text(activeAccount.phone)
+                                                .lineLimit(1)
+                                                .truncationMode(.middle)
+                                                .frame(maxWidth: .infinity, alignment: .leading)
+                                        }
+                                        .frame(maxWidth: .infinity, maxHeight: 30)
+                                    }
+                                    if !activeAccount.address.isEmpty {
+                                        HStack {
+                                            Image(systemName: "house")
+                                                .resizable()
+                                                .scaledToFit()
+                                                .font(Font.system(.body).weight(.light))
+                                                .frame(width: 20, height: 20)
+                                            Text(activeAccount.address)
+                                                .lineLimit(1)
+                                                .truncationMode(.middle)
+                                                .frame(maxWidth: .infinity, alignment: .leading)
+                                        }
+                                        .frame(maxWidth: .infinity, maxHeight: 30)
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    .font(.system(size: 14))
+                    .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
+                    .frame(height: model.getTableViewHeight())
+                    .animation(.easeIn(duration: 0.3), value: animation)
+                    .onChange(of: model.indexActiveAccount) { index in
+                        animation.toggle()
+                        model.setAccount(account: model.accounts[index].account)
+                    }
+                    ///
+                    /// Change alias
+                    VStack {
+                        HStack {
+                            Text(NSLocalizedString("_alias_", comment: "") + ":")
+                                .font(.system(size: 17))
+                                .fontWeight(.medium)
+                            Spacer()
+                            TextField(NSLocalizedString("_alias_placeholder_", comment: ""), text: $model.alias)
+                                .font(.system(size: 16))
+                                .multilineTextAlignment(.trailing)
+                                .onChange(of: model.alias) { newValue in
+                                    model.setAlias(newValue)
+                                }
+                        }
+                        Text(NSLocalizedString("_alias_footer_", comment: ""))
+                            .frame(maxWidth: .infinity, alignment: .leading)
+                            .font(.system(size: 12))
+                            .lineLimit(2)
+                            .foregroundStyle(Color(UIColor.lightGray))
+                    }
+                    ///
+                    /// User Status
+                    Button(action: {
+                        showUserStatus = true
+                    }, label: {
+                        HStack {
+                            Image(systemName: "moon.fill")
+                                .resizable()
+                                .scaledToFit()
+                                .font(Font.system(.body).weight(.light))
+                                .frame(width: 20, height: 20)
+                                .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
+                            Text(NSLocalizedString("_set_user_status_", comment: ""))
+                                .lineLimit(1)
+                                .truncationMode(.middle)
+                                .foregroundStyle(Color(NCBrandColor.shared.textColor))
+                                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
+                        }
+                        .font(.system(size: 14))
+                    })
+                    .sheet(isPresented: $showUserStatus) {
+                        UserStatusView(showUserStatus: $showUserStatus)
+                    }
+                    .onChange(of: showUserStatus) { _ in }
+                    ///
+                    /// Certificate server
+                    Button(action: {
+                        showServerCertificate.toggle()
+                    }, label: {
+                        HStack {
+                            Image(systemName: "lock")
+                                .resizable()
+                                .scaledToFit()
+                                .font(Font.system(.body).weight(.light))
+                                .frame(width: 20, height: 20)
+                                .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
+                            Text(NSLocalizedString("_certificate_details_", comment: ""))
+                                .lineLimit(1)
+                                .truncationMode(.middle)
+                                .foregroundStyle(Color(NCBrandColor.shared.textColor))
+                                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
+                        }
+                        .font(.system(size: 14))
+                    })
+                    .sheet(isPresented: $showServerCertificate) {
+                        if let url = URL(string: model.activeAccount?.urlBase), let host = url.host {
+                            certificateDetailsView(host: host, title: NSLocalizedString("_certificate_view_", comment: ""))
+                        }
+                    }
+                    ///
+                    /// Certificate push
+                    Button(action: {
+                        showPushCertificate.toggle()
+                    }, label: {
+                        HStack {
+                            Image(systemName: "lock")
+                                .resizable()
+                                .scaledToFit()
+                                .font(Font.system(.body).weight(.light))
+                                .frame(width: 20, height: 20)
+                                .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
+                            Text(NSLocalizedString("_certificate_pn_details_", comment: ""))
+                                .lineLimit(1)
+                                .truncationMode(.middle)
+                                .foregroundStyle(Color(NCBrandColor.shared.textColor))
+                                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
+                        }
+                        .font(.system(size: 14))
+                    })
+                    .sheet(isPresented: $showPushCertificate) {
+                        if let url = URL(string: NCBrandOptions.shared.pushNotificationServerProxy), let host = url.host {
+                            certificateDetailsView(host: host, title: NSLocalizedString("_certificate_pn_view_", comment: ""))
+                        }
+                    }
+                })
+                ///
+                /// Delete account
+                Section(content: {
+                    Button(action: {
+                        showDeleteAccountAlert.toggle()
+                    }, label: {
+                        HStack {
+                            Image(systemName: "trash")
+                                .resizable()
+                                .scaledToFit()
+                                .font(Font.system(.body).weight(.light))
+                                .frame(width: 20, height: 20)
+                                .foregroundStyle(.red)
+                            Text(NSLocalizedString("_remove_local_account_", comment: ""))
+                                .lineLimit(1)
+                                .truncationMode(.middle)
+                                .foregroundStyle(.red)
+                                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
+                        }
+                        .font(.system(size: 14))
+                    })
+                    .alert(NSLocalizedString("_want_delete_account_", comment: ""), isPresented: $showDeleteAccountAlert) {
+                        Button(NSLocalizedString("_remove_local_account_", comment: ""), role: .destructive) {
+                            model.deleteAccount()
+                        }
+                        Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel) { }
+                    }
+                })
+            }
+            .navigationBarTitle(NSLocalizedString("_account_settings_", comment: ""))
+            .navigationBarTitleDisplayMode(.inline)
+            .navigationBarItems(trailing: Button(action: {
+                presentationMode.wrappedValue.dismiss()
+            }) {
+                Image(systemName: "xmark")
+                    .font(Font.system(.body).weight(.light))
+                    .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
+            })
+        }
+        .defaultViewModifier(model)
+        .navigationViewStyle(StackNavigationViewStyle())
+        .onReceive(model.$dismissView) { newValue in
+            if newValue {
+                presentationMode.wrappedValue.dismiss()
+            }
+        }
+        .onDisappear {
+            model.delegate?.accountSettingsDidDismiss(tableAccount: model.activeAccount)
+        }
+    }
+}
+
+#Preview {
+    NCAccountSettingsView(model: NCAccountSettingsModel(controller: nil, delegate: nil))
+}

+ 3 - 11
iOSClient/Activity/NCActivityTableViewCell.swift

@@ -199,7 +199,7 @@ extension NCActivityTableViewCell: UICollectionViewDataSource {
                         cell.fileId = fileId
                         cell.fileId = fileId
                         if !FileManager.default.fileExists(atPath: fileNamePath) {
                         if !FileManager.default.fileExists(atPath: fileNamePath) {
                             if NCNetworking.shared.downloadThumbnailActivityQueue.operations.filter({ ($0 as? NCOperationDownloadThumbnailActivity)?.fileId == fileId }).isEmpty {
                             if NCNetworking.shared.downloadThumbnailActivityQueue.operations.filter({ ($0 as? NCOperationDownloadThumbnailActivity)?.fileId == fileId }).isEmpty {
-                                NCNetworking.shared.downloadThumbnailActivityQueue.addOperation(NCOperationDownloadThumbnailActivity(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, fileId: fileId, cell: cell, collectionView: collectionView))
+                                NCNetworking.shared.downloadThumbnailActivityQueue.addOperation(NCOperationDownloadThumbnailActivity(fileId: fileId, fileNamePreviewLocalPath: fileNamePath, cell: cell, collectionView: collectionView))
                             }
                             }
                         }
                         }
                     }
                     }
@@ -231,12 +231,10 @@ class NCOperationDownloadThumbnailActivity: ConcurrentOperation {
 
 
     var cell: NCActivityCollectionViewCell?
     var cell: NCActivityCollectionViewCell?
     var collectionView: UICollectionView?
     var collectionView: UICollectionView?
-    var fileNamePathOrFileId: String
     var fileNamePreviewLocalPath: String
     var fileNamePreviewLocalPath: String
     var fileId: String
     var fileId: String
 
 
-    init(fileNamePathOrFileId: String, fileNamePreviewLocalPath: String, fileId: String, cell: NCActivityCollectionViewCell?, collectionView: UICollectionView?) {
-        self.fileNamePathOrFileId = fileNamePathOrFileId
+    init(fileId: String, fileNamePreviewLocalPath: String, cell: NCActivityCollectionViewCell?, collectionView: UICollectionView?) {
         self.fileNamePreviewLocalPath = fileNamePreviewLocalPath
         self.fileNamePreviewLocalPath = fileNamePreviewLocalPath
         self.fileId = fileId
         self.fileId = fileId
         self.cell = cell
         self.cell = cell
@@ -244,15 +242,9 @@ class NCOperationDownloadThumbnailActivity: ConcurrentOperation {
     }
     }
 
 
     override func start() {
     override func start() {
-
         guard !isCancelled else { return self.finish() }
         guard !isCancelled else { return self.finish() }
-
-        NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePathOrFileId,
+        NextcloudKit.shared.downloadPreview(fileId: fileId,
                                             fileNamePreviewLocalPath: fileNamePreviewLocalPath,
                                             fileNamePreviewLocalPath: fileNamePreviewLocalPath,
-                                            widthPreview: 0,
-                                            heightPreview: 0,
-                                            etag: nil,
-                                            useInternalEndpoint: false,
                                             options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, _, error in
                                             options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, _, error in
 
 
             if error == .success, let imagePreview = imagePreview {
             if error == .success, let imagePreview = imagePreview {

+ 82 - 47
iOSClient/AppDelegate.swift

@@ -29,20 +29,21 @@ import Firebase
 import WidgetKit
 import WidgetKit
 import Queuer
 import Queuer
 import EasyTipView
 import EasyTipView
+import SwiftUI
 
 
 @UIApplicationMain
 @UIApplicationMain
 class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, NCUserBaseUrl {
 class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, NCUserBaseUrl {
 
 
-    @objc var account: String = ""
-    @objc var urlBase: String = ""
-    @objc var user: String = ""
-    @objc var userId: String = ""
-    @objc var password: String = ""
+    var account: String = ""
+    var urlBase: String = ""
+    var user: String = ""
+    var userId: String = ""
+    var password: String = ""
 
 
     var tipView: EasyTipView?
     var tipView: EasyTipView?
     var backgroundSessionCompletionHandler: (() -> Void)?
     var backgroundSessionCompletionHandler: (() -> Void)?
     var activeLogin: NCLogin?
     var activeLogin: NCLogin?
-    var activeLoginWeb: NCLoginWeb?
+    var activeLoginWeb: NCLoginProvider?
     var timerErrorNetworking: Timer?
     var timerErrorNetworking: Timer?
     var timerErrorNetworkingDisabled: Bool = false
     var timerErrorNetworkingDisabled: Bool = false
     var taskAutoUploadDate: Date = Date()
     var taskAutoUploadDate: Date = Date()
@@ -51,6 +52,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
     }
     var notificationSettings: UNNotificationSettings?
     var notificationSettings: UNNotificationSettings?
 
 
+    var loginFlowV2Token = ""
+    var loginFlowV2Endpoint = ""
+    var loginFlowV2Login = ""
+
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
         if isUiTestingEnabled {
         if isUiTestingEnabled {
             deleteAllAccounts()
             deleteAllAccounts()
@@ -183,8 +188,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     @discussion Schedule a refresh task request to ask that the system launch your app briefly so that you can download data and keep your app's contents up-to-date. The system will fulfill this request intelligently based on system conditions and app usage.
     @discussion Schedule a refresh task request to ask that the system launch your app briefly so that you can download data and keep your app's contents up-to-date. The system will fulfill this request intelligently based on system conditions and app usage.
      */
      */
     func scheduleAppRefresh() {
     func scheduleAppRefresh() {
-
         let request = BGAppRefreshTaskRequest(identifier: NCGlobal.shared.refreshTask)
         let request = BGAppRefreshTaskRequest(identifier: NCGlobal.shared.refreshTask)
+
         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)
@@ -197,8 +202,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
      @discussion Schedule a processing task request to ask that the system launch your app when conditions are favorable for battery life to handle deferrable, longer-running processing, such as syncing, database maintenance, or similar tasks. The system will attempt to fulfill this request to the best of its ability within the next two days as long as the user has used your app within the past week.
      @discussion Schedule a processing task request to ask that the system launch your app when conditions are favorable for battery life to handle deferrable, longer-running processing, such as syncing, database maintenance, or similar tasks. The system will attempt to fulfill this request to the best of its ability within the next two days as long as the user has used your app within the past week.
      */
      */
     func scheduleAppProcessing() {
     func scheduleAppProcessing() {
-
         let request = BGProcessingTaskRequest(identifier: NCGlobal.shared.processingTask)
         let request = BGProcessingTaskRequest(identifier: NCGlobal.shared.processingTask)
+
         request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60) // Refresh after 5 minutes.
         request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60) // Refresh after 5 minutes.
         request.requiresNetworkConnectivity = false
         request.requiresNetworkConnectivity = false
         request.requiresExternalPower = false
         request.requiresExternalPower = false
@@ -270,7 +275,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     // MARK: - Background Networking Session
     // MARK: - Background Networking Session
 
 
     func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
     func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
-
         NextcloudKit.shared.nkCommonInstance.writeLog("[DEBUG] Start handle Events For Background URLSession: \(identifier)")
         NextcloudKit.shared.nkCommonInstance.writeLog("[DEBUG] Start handle Events For Background URLSession: \(identifier)")
         WidgetCenter.shared.reloadAllTimelines()
         WidgetCenter.shared.reloadAllTimelines()
         backgroundSessionCompletionHandler = completionHandler
         backgroundSessionCompletionHandler = completionHandler
@@ -283,7 +287,6 @@ 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(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)
@@ -296,13 +299,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
     func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
         NCNetworking.shared.checkPushNotificationServerProxyCertificateUntrusted(viewController: UIApplication.shared.firstWindow?.rootViewController) { error in
         NCNetworking.shared.checkPushNotificationServerProxyCertificateUntrusted(viewController: UIApplication.shared.firstWindow?.rootViewController) { error in
             if error == .success {
             if error == .success {
-                NCPushNotification.shared().registerForRemoteNotifications(withDeviceToken: deviceToken)
+                NCPushNotification.shared.registerForRemoteNotificationsWithDeviceToken(deviceToken)
             }
             }
         }
         }
     }
     }
 
 
     func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
     func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
-        NCPushNotification.shared().applicationdidReceiveRemoteNotification(userInfo) { result in
+        NCPushNotification.shared.applicationdidReceiveRemoteNotification(userInfo: userInfo) { result in
             completionHandler(result)
             completionHandler(result)
         }
         }
     }
     }
@@ -340,7 +343,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     // MARK: - Login
     // MARK: - Login
 
 
-    @objc func openLogin(selector: Int, openLoginWeb: Bool, windowForRootViewController: UIWindow? = nil) {
+    func openLogin(selector: Int, openLoginWeb: Bool, windowForRootViewController: UIWindow? = nil) {
         func showLoginViewController(_ viewController: UIViewController?) {
         func showLoginViewController(_ viewController: UIViewController?) {
             guard let viewController else { return }
             guard let viewController else { return }
             let navigationController = NCLoginNavigationController(rootViewController: viewController)
             let navigationController = NCLoginNavigationController(rootViewController: viewController)
@@ -361,45 +364,55 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         }
         }
 
 
         // [WEBPersonalized] [AppConfig]
         // [WEBPersonalized] [AppConfig]
-        if NCBrandOptions.shared.use_login_web_personalized || NCBrandOptions.shared.use_AppConfig {
-            if activeLoginWeb?.view.window == nil {
-                activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb
-                activeLoginWeb?.urlBase = NCBrandOptions.shared.loginBaseUrl
-                showLoginViewController(activeLoginWeb)
+        if NCBrandOptions.shared.use_AppConfig {
+            if activeLogin?.view.window == nil {
+                urlBase = NCBrandOptions.shared.loginBaseUrl
+                NextcloudKit.shared.getLoginFlowV2(serverUrl: urlBase) { token, endpoint, login, _, error in
+                    // Login Flow V2
+                    if error == .success, let token, let endpoint, let login {
+                        let vc = UIHostingController(rootView: NCLoginPoll(loginFlowV2Token: token, loginFlowV2Endpoint: endpoint, loginFlowV2Login: login, cancelButtonDisabled: NCManageDatabase.shared.getAccounts().isEmptyOrNil))
+                        UIApplication.shared.firstWindow?.rootViewController?.present(vc, animated: true)
+                    }
+                }
+
+                return
             }
             }
-            return
         }
         }
 
 
         // Nextcloud standard login
         // Nextcloud standard login
         if selector == NCGlobal.shared.introSignup {
         if selector == NCGlobal.shared.introSignup {
-            if activeLoginWeb?.view.window == nil {
-                activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb
+            if activeLogin?.view.window == nil {
+                activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin
                 if selector == NCGlobal.shared.introSignup {
                 if selector == NCGlobal.shared.introSignup {
-                    activeLoginWeb?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders
+                    activeLogin?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders
+                    let web = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginProvider") as? NCLoginProvider
+                    web?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders
+                    showLoginViewController(web)
                 } else {
                 } else {
-                    activeLoginWeb?.urlBase = self.urlBase
+                    activeLogin?.urlBase = self.urlBase
+                    showLoginViewController(activeLogin)
                 }
                 }
-                showLoginViewController(activeLoginWeb)
             }
             }
 
 
         } else if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url {
         } else if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url {
-            if activeLoginWeb?.view.window == nil {
-                activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb
-                activeLoginWeb?.urlBase = NCBrandOptions.shared.loginBaseUrl
-                showLoginViewController(activeLoginWeb)
+            if activeLogin?.view.window == nil {
+                activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin
+                activeLogin?.urlBase = NCBrandOptions.shared.loginBaseUrl
+                showLoginViewController(activeLogin)
             }
             }
-
         } else if openLoginWeb {
         } else if openLoginWeb {
             // Used also for reinsert the account (change passwd)
             // Used also for reinsert the account (change passwd)
-            if activeLoginWeb?.view.window == nil {
-                activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb
-                activeLoginWeb?.urlBase = urlBase
-                activeLoginWeb?.user = user
-                showLoginViewController(activeLoginWeb)
+            if activeLogin?.view.window == nil {
+                activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin
+                activeLogin?.urlBase = urlBase
+                activeLogin?.disableUrlField = true
+                activeLogin?.disableCloseButton = true
+                showLoginViewController(activeLogin)
             }
             }
-
         } else {
         } else {
             if activeLogin?.view.window == nil {
             if activeLogin?.view.window == nil {
+                activeLogin?.disableCloseButton = true
+
                 activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin
                 activeLogin = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin
                 showLoginViewController(activeLogin)
                 showLoginViewController(activeLogin)
             }
             }
@@ -408,7 +421,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     // MARK: - Error Networking
     // MARK: - Error Networking
 
 
-    @objc func startTimerErrorNetworking(scene: UIScene) {
+    func startTimerErrorNetworking(scene: UIScene) {
         timerErrorNetworkingDisabled = false
         timerErrorNetworkingDisabled = false
         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)
     }
     }
@@ -421,13 +434,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
     }
 
 
     func trustCertificateError(host: String) {
     func trustCertificateError(host: String) {
-
         guard let currentHost = URL(string: self.urlBase)?.host,
         guard let currentHost = URL(string: self.urlBase)?.host,
               let pushNotificationServerProxyHost = URL(string: NCBrandOptions.shared.pushNotificationServerProxy)?.host,
               let pushNotificationServerProxyHost = URL(string: NCBrandOptions.shared.pushNotificationServerProxy)?.host,
               host != pushNotificationServerProxyHost,
               host != pushNotificationServerProxyHost,
               host == currentHost
               host == currentHost
         else { return }
         else { return }
-
         let certificateHostSavedPath = NCUtilityFileSystem().directoryCertificates + "/" + host + ".der"
         let certificateHostSavedPath = NCUtilityFileSystem().directoryCertificates + "/" + host + ".der"
         var title = NSLocalizedString("_ssl_certificate_changed_", comment: "")
         var title = NSLocalizedString("_ssl_certificate_changed_", comment: "")
 
 
@@ -457,8 +468,35 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     // MARK: - Account
     // MARK: - Account
 
 
-    @objc func changeAccount(_ account: String, userProfile: NKUserProfile?) {
+    func createAccount(server: String, username: String, password: String, completion: @escaping (_ error: NKError) -> Void) {
+        var urlBase = server
+        if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) }
+        let account: String = "\(username) \(urlBase)"
+        let user = username
+
+        NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase)
+        NextcloudKit.shared.getUserProfile { _, userProfile, _, error in
+
+            if error == .success, let userProfile {
+
+                NCManageDatabase.shared.deleteAccount(account)
+                NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password)
+
+                NCKeychain().setClientCertificate(account: account, p12Data: NCNetworking.shared.p12Data, p12Password: NCNetworking.shared.p12Password)
+
+                self.changeAccount(account, userProfile: userProfile)
+            } else {
+
+                let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert)
+                alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
+                UIApplication.shared.firstWindow?.rootViewController?.present(alertController, animated: true)
+            }
+
+            completion(error)
+        }
+    }
 
 
+    func changeAccount(_ account: String, userProfile: NKUserProfile?) {
         NCNetworking.shared.cancelAllQueue()
         NCNetworking.shared.cancelAllQueue()
         NCNetworking.shared.cancelDataTask()
         NCNetworking.shared.cancelDataTask()
         NCNetworking.shared.cancelDownloadTasks()
         NCNetworking.shared.cancelDownloadTasks()
@@ -489,7 +527,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile)
             NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile)
         }
         }
 
 
-        NCPushNotification.shared().pushNotification()
+        NCPushNotification.shared.pushNotification()
 
 
         NCService().startRequestServicesServer()
         NCService().startRequestServicesServer()
 
 
@@ -500,12 +538,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeUser)
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeUser)
     }
     }
 
 
-    @objc func deleteAccount(_ account: String, wipe: Bool) {
-
+    func deleteAccount(_ account: String, wipe: Bool) {
         UIApplication.shared.allSceneSessionDestructionExceptFirst()
         UIApplication.shared.allSceneSessionDestructionExceptFirst()
 
 
         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.account, urlBase: account.urlBase, user: account.user, withSubscribing: false)
         }
         }
 
 
         NextcloudKit.shared.deleteAppPassword(serverUrl: urlBase, username: userId, password: password) { _, error in
         NextcloudKit.shared.deleteAppPassword(serverUrl: urlBase, username: userId, password: password) { _, error in
@@ -550,9 +587,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     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 }
-
         let tableAccount = NCManageDatabase.shared.getAllAccount()
         let tableAccount = NCManageDatabase.shared.getAllAccount()
         var accounts = [NKShareAccounts.DataAccounts]()
         var accounts = [NKShareAccounts.DataAccounts]()
+
         for account in tableAccount {
         for account in tableAccount {
             let name = account.alias.isEmpty ? account.displayName : account.alias
             let name = account.alias.isEmpty ? account.displayName : account.alias
             let userBaseUrl = account.user + "-" + (URL(string: account.urlBase)?.host ?? "")
             let userBaseUrl = account.user + "-" + (URL(string: account.urlBase)?.host ?? "")
@@ -566,8 +603,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
     // MARK: - Reset Application
     // MARK: - Reset Application
 
 
-    @objc func resetApplication() {
-
+    func resetApplication() {
         let utilityFileSystem = NCUtilityFileSystem()
         let utilityFileSystem = NCUtilityFileSystem()
 
 
         NCNetworking.shared.cancelAllTask()
         NCNetworking.shared.cancelAllTask()
@@ -587,7 +623,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     // MARK: - Universal Links
     // MARK: - Universal Links
 
 
     func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
     func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
-
         let applicationHandle = NCApplicationHandle()
         let applicationHandle = NCApplicationHandle()
         return applicationHandle.applicationOpenUserActivity(userActivity)
         return applicationHandle.applicationOpenUserActivity(userActivity)
     }
     }

+ 6 - 1
iOSClient/Assistant/NCAssistant.swift

@@ -29,14 +29,19 @@ struct NCAssistant: View {
             }
             }
             .toolbar {
             .toolbar {
                 ToolbarItem(placement: .topBarLeading) {
                 ToolbarItem(placement: .topBarLeading) {
-                    Button(NSLocalizedString("_close_", comment: "")) {
+                    Button(action: {
                         presentationMode.wrappedValue.dismiss()
                         presentationMode.wrappedValue.dismiss()
+                    }) {
+                        Image(systemName: "xmark")
+                            .font(Font.system(.body).weight(.light))
+                            .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
                     }
                     }
                 }
                 }
                 ToolbarItem(placement: .topBarTrailing) {
                 ToolbarItem(placement: .topBarTrailing) {
                     NavigationLink(destination: NCAssistantCreateNewTask()) {
                     NavigationLink(destination: NCAssistantCreateNewTask()) {
                         Image(systemName: "plus")
                         Image(systemName: "plus")
                             .font(Font.system(.body).weight(.light))
                             .font(Font.system(.body).weight(.light))
+                            .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
                     }
                     }
                     .disabled(model.selectedType == nil)
                     .disabled(model.selectedType == nil)
                 }
                 }

+ 1 - 2
iOSClient/AudioRecorder/NCAudioRecorderViewController.swift

@@ -138,8 +138,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate {
 }
 }
 
 
 open class NCAudioRecorder: NSObject {
 open class NCAudioRecorder: NSObject {
-
-    @objc public enum State: Int {
+    public enum State: Int {
         case none, record, play
         case none, record, play
     }
     }
 
 

+ 4 - 4
iOSClient/BrowserWeb/NCBrowserWeb.swift

@@ -30,10 +30,10 @@ import WebKit
 
 
 class NCBrowserWeb: UIViewController {
 class NCBrowserWeb: UIViewController {
 
 
-    @objc var urlBase = ""
-    @objc var isHiddenButtonExit = false
-    @objc var titleBrowser: String?
-    @objc weak var delegate: NCBrowserWebDelegate?
+    var urlBase = ""
+    var isHiddenButtonExit = false
+    var titleBrowser: String?
+    weak var delegate: NCBrowserWebDelegate?
 
 
     @IBOutlet weak var buttonExit: UIButton!
     @IBOutlet weak var buttonExit: UIButton!
 
 

+ 3 - 4
iOSClient/Color/NCColorPicker.swift

@@ -212,10 +212,9 @@ class NCColorPicker: UIViewController {
     func updateColor(hexColor: String?) {
     func updateColor(hexColor: String?) {
         if let metadata = metadata {
         if let metadata = metadata {
             let serverUrl = metadata.serverUrl + "/" + metadata.fileName
             let serverUrl = metadata.serverUrl + "/" + metadata.fileName
-            if NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, colorFolder: hexColor, account: metadata.account) != nil {
-                self.dismiss(animated: true)
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
-            }
+            NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, colorFolder: hexColor, metadata: metadata)
+            self.dismiss(animated: true)
+            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
         }
         }
         self.dismiss(animated: true)
         self.dismiss(animated: true)
     }
     }

+ 4 - 33
iOSClient/Data/NCManageDatabase+Account.swift

@@ -26,7 +26,6 @@ import RealmSwift
 import NextcloudKit
 import NextcloudKit
 
 
 class tableAccount: Object, NCUserBaseUrl {
 class tableAccount: Object, NCUserBaseUrl {
-
     @objc dynamic var account = ""
     @objc dynamic var account = ""
     @objc dynamic var active: Bool = false
     @objc dynamic var active: Bool = false
     @objc dynamic var address = ""
     @objc dynamic var address = ""
@@ -44,10 +43,6 @@ class tableAccount: Object, NCUserBaseUrl {
     @objc dynamic var backend = ""
     @objc dynamic var backend = ""
     @objc dynamic var backendCapabilitiesSetDisplayName: Bool = false
     @objc dynamic var backendCapabilitiesSetDisplayName: Bool = false
     @objc dynamic var backendCapabilitiesSetPassword: Bool = false
     @objc dynamic var backendCapabilitiesSetPassword: Bool = false
-    @objc dynamic var businessSize: String = ""
-    @objc dynamic var businessType = ""
-    @objc dynamic var city = ""
-    @objc dynamic var country = ""
     @objc dynamic var displayName = ""
     @objc dynamic var displayName = ""
     @objc dynamic var email = ""
     @objc dynamic var email = ""
     @objc dynamic var enabled: Bool = false
     @objc dynamic var enabled: Bool = false
@@ -64,7 +59,6 @@ class tableAccount: Object, NCUserBaseUrl {
     @objc dynamic var quotaRelative: Double = 0
     @objc dynamic var quotaRelative: Double = 0
     @objc dynamic var quotaTotal: Int64 = 0
     @objc dynamic var quotaTotal: Int64 = 0
     @objc dynamic var quotaUsed: Int64 = 0
     @objc dynamic var quotaUsed: Int64 = 0
-    @objc dynamic var role = ""
     @objc dynamic var storageLocation = ""
     @objc dynamic var storageLocation = ""
     @objc dynamic var subadmin = ""
     @objc dynamic var subadmin = ""
     @objc dynamic var twitter = ""
     @objc dynamic var twitter = ""
@@ -79,7 +73,6 @@ class tableAccount: Object, NCUserBaseUrl {
     @objc dynamic var userStatusStatus: String?
     @objc dynamic var userStatusStatus: String?
     @objc dynamic var userStatusStatusIsUserDefined: Bool = false
     @objc dynamic var userStatusStatusIsUserDefined: Bool = false
     @objc dynamic var website = ""
     @objc dynamic var website = ""
-    @objc dynamic var zip = ""
 
 
     override static func primaryKey() -> String {
     override static func primaryKey() -> String {
         return "account"
         return "account"
@@ -97,15 +90,6 @@ extension NCManageDatabase {
 
 
                 addObject.account = account
                 addObject.account = account
 
 
-                // Brand
-                if NCBrandOptions.shared.use_default_auto_upload {
-
-                    addObject.autoUpload = true
-                    addObject.autoUploadImage = true
-                    addObject.autoUploadVideo = true
-                    addObject.autoUploadWWAnVideo = true
-                }
-
                 NCKeychain().setPassword(account: account, password: password)
                 NCKeychain().setPassword(account: account, password: password)
 
 
                 addObject.urlBase = urlBase
                 addObject.urlBase = urlBase
@@ -148,7 +132,6 @@ 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 {
@@ -162,7 +145,6 @@ 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 })
@@ -178,7 +160,6 @@ 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 {
@@ -192,7 +173,6 @@ 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) })
@@ -207,7 +187,6 @@ 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) })
@@ -222,7 +201,6 @@ 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
@@ -240,7 +218,6 @@ 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 utilityFileSystem.getHomeServer(urlBase: urlBase, userId: userId)
                 return utilityFileSystem.getHomeServer(urlBase: urlBase, userId: userId)
@@ -272,7 +249,6 @@ 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 {
@@ -453,19 +429,14 @@ extension NCManageDatabase {
         }
         }
     }
     }
 
 
-    @objc func setAccountAlias(_ alias: String?) {
-
-        let alias = alias?.trimmingCharacters(in: .whitespacesAndNewlines)
+    @objc func setAccountAlias(_ account: String, alias: String) {
+        let alias = alias.trimmingCharacters(in: .whitespacesAndNewlines)
 
 
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                if let result = realm.objects(tableAccount.self).filter("active == true").first {
-                    if let alias = alias {
-                        result.alias = alias
-                    } else {
-                        result.alias = ""
-                    }
+                if let result = realm.objects(tableAccount.self).filter("account == %@", account).first {
+                    result.alias = alias
                 }
                 }
             }
             }
         } catch let error {
         } catch let error {

+ 1 - 0
iOSClient/Data/NCManageDatabase+Avatar.swift

@@ -22,6 +22,7 @@
 //
 //
 
 
 import Foundation
 import Foundation
+import UIKit
 import RealmSwift
 import RealmSwift
 import NextcloudKit
 import NextcloudKit
 
 

+ 37 - 19
iOSClient/Data/NCManageDatabase+Directory.swift

@@ -77,14 +77,24 @@ extension NCManageDatabase {
         }
         }
     }
     }
 
 
+    func addDirectory(directory: tableDirectory, metadata: tableMetadata) {
+        directory.account = metadata.account
+        directory.e2eEncrypted = metadata.e2eEncrypted
+        directory.favorite = metadata.favorite
+        directory.fileId = metadata.fileId
+        directory.ocId = metadata.ocId
+        directory.permissions = metadata.permissions
+        directory.richWorkspace = metadata.richWorkspace
+    }
+
     func deleteDirectoryAndSubDirectory(serverUrl: String, account: String) {
     func deleteDirectoryAndSubDirectory(serverUrl: String, account: String) {
 
 
 #if !EXTENSION
 #if !EXTENSION
         DispatchQueue.main.async {
         DispatchQueue.main.async {
             let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
             let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
             for windowScene in windowScenes {
             for windowScene in windowScenes {
-                if let mainTabBarController = windowScene.keyWindow?.rootViewController as? NCMainTabBarController {
-                    mainTabBarController.filesServerUrl.removeValue(forKey: serverUrl)
+                if let controller = windowScene.keyWindow?.rootViewController as? NCMainTabBarController {
+                    controller.filesServerUrl.removeValue(forKey: serverUrl)
                 }
                 }
             }
             }
         }
         }
@@ -174,7 +184,11 @@ extension NCManageDatabase {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             realm.refresh()
             realm.refresh()
-            return realm.objects(tableDirectory.self).filter("ocId == %@", ocId).first
+            if let result = realm.objects(tableDirectory.self).filter("ocId == %@", ocId).first {
+                return tableDirectory(value: result)
+            } else {
+                return nil
+            }
         } catch let error as NSError {
         } catch let error as NSError {
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not access database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not access database: \(error)")
         }
         }
@@ -210,12 +224,19 @@ extension NCManageDatabase {
         }
         }
     }
     }
 
 
-    func setDirectory(serverUrl: String, offline: Bool, account: String) {
+    func setDirectory(serverUrl: String, offline: Bool, metadata: tableMetadata) {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                let result = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first
-                result?.offline = offline
+                if let result = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", metadata.account, serverUrl).first {
+                    result.offline = offline
+                } else {
+                    let directory = tableDirectory()
+                    directory.serverUrl = serverUrl
+                    directory.offline = offline
+                    addDirectory(directory: directory, metadata: metadata)
+                    realm.add(directory)
+                }
             }
             }
         } catch let error {
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
@@ -255,25 +276,22 @@ extension NCManageDatabase {
         }
         }
     }
     }
 
 
-    @discardableResult
-    func setDirectory(serverUrl: String, colorFolder: String?, account: String) -> tableDirectory? {
-
-        var result: tableDirectory?
-
+    func setDirectory(serverUrl: String, colorFolder: String?, metadata: tableMetadata) {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
-                result = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", account, serverUrl).first
-                result?.colorFolder = colorFolder
+                if let result = realm.objects(tableDirectory.self).filter("account == %@ AND serverUrl == %@", metadata.account, serverUrl).first {
+                    result.colorFolder = colorFolder
+                } else {
+                    let directory = tableDirectory()
+                    directory.serverUrl = serverUrl
+                    directory.colorFolder = colorFolder
+                    addDirectory(directory: directory, metadata: metadata)
+                    realm.add(directory)
+                }
             }
             }
         } catch let error {
         } catch let error {
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
         }
         }
-
-        if let result = result {
-            return tableDirectory.init(value: result)
-        } else {
-            return nil
-        }
     }
     }
 }
 }

+ 12 - 0
iOSClient/Data/NCManageDatabase+Metadata+Session.swift

@@ -175,4 +175,16 @@ extension NCManageDatabase {
             return nil
             return nil
         }
         }
     }
     }
+
+    func getMetadata(from url: URL?, sessionTaskIdentifier: Int) -> tableMetadata? {
+        guard let url,
+              var serverUrl = url.deletingLastPathComponent().absoluteString.removingPercentEncoding
+        else { return nil }
+        let fileName = url.lastPathComponent
+
+        if serverUrl.hasSuffix("/") {
+            serverUrl = String(serverUrl.dropLast())
+        }
+        return NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "serverUrl == %@ AND fileName == %@ AND sessionTaskIdentifier == %d", serverUrl, fileName, sessionTaskIdentifier))
+    }
 }
 }

+ 6 - 17
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -166,7 +166,7 @@ extension tableMetadata {
     }
     }
 
 
     var isDocumentViewableOnly: Bool {
     var isDocumentViewableOnly: Bool {
-        sharePermissionsCollaborationServices == NCGlobal.shared.permissionReadShare && classFile == NKCommon.TypeClassFile.document.rawValue
+        sharePermissionsCollaborationServices == NCPermissions().permissionReadShare && classFile == NKCommon.TypeClassFile.document.rawValue
     }
     }
 
 
     var isAudioOrVideo: Bool {
     var isAudioOrVideo: Bool {
@@ -991,18 +991,19 @@ extension NCManageDatabase {
     }
     }
 
 
     func isMetadataShareOrMounted(metadata: tableMetadata, metadataFolder: tableMetadata?) -> Bool {
     func isMetadataShareOrMounted(metadata: tableMetadata, metadataFolder: tableMetadata?) -> Bool {
+        let permissions = NCPermissions()
         var isShare = false
         var isShare = false
         var isMounted = false
         var isMounted = false
 
 
         if metadataFolder != nil {
         if metadataFolder != nil {
 
 
-            isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionShared)
-            isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder!.permissions.contains(NCGlobal.shared.permissionMounted)
+            isShare = metadata.permissions.contains(permissions.permissionShared) && !metadataFolder!.permissions.contains(permissions.permissionShared)
+            isMounted = metadata.permissions.contains(permissions.permissionMounted) && !metadataFolder!.permissions.contains(permissions.permissionMounted)
 
 
         } else if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) {
         } else if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata.account, metadata.serverUrl)) {
 
 
-            isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !directory.permissions.contains(NCGlobal.shared.permissionShared)
-            isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !directory.permissions.contains(NCGlobal.shared.permissionMounted)
+            isShare = metadata.permissions.contains(permissions.permissionShared) && !directory.permissions.contains(permissions.permissionShared)
+            isMounted = metadata.permissions.contains(permissions.permissionMounted) && !directory.permissions.contains(permissions.permissionMounted)
         }
         }
 
 
         if isShare || isMounted {
         if isShare || isMounted {
@@ -1147,16 +1148,4 @@ extension NCManageDatabase {
 
 
         return nil
         return nil
     }
     }
-
-    func getMetadata(from url: URL?) -> tableMetadata? {
-        guard let url,
-              var serverUrl = url.deletingLastPathComponent().absoluteString.removingPercentEncoding
-        else { return nil }
-        let fileName = url.lastPathComponent
-
-        if serverUrl.hasSuffix("/") {
-            serverUrl = String(serverUrl.dropLast())
-        }
-        return NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "serverUrl == %@ AND fileName == %@", serverUrl, fileName))
-    }
 }
 }

+ 2 - 0
iOSClient/Data/NCManageDatabase+PhotoLibrary.swift

@@ -22,6 +22,8 @@
 //
 //
 
 
 import Foundation
 import Foundation
+import UIKit
+import Photos
 import RealmSwift
 import RealmSwift
 import NextcloudKit
 import NextcloudKit
 
 

+ 0 - 4
iOSClient/Data/NCManageDatabase+Tip.swift

@@ -26,14 +26,11 @@ import RealmSwift
 import NextcloudKit
 import NextcloudKit
 
 
 class tableTip: Object {
 class tableTip: Object {
-
     @Persisted(primaryKey: true) var tipName = ""
     @Persisted(primaryKey: true) var tipName = ""
 }
 }
 
 
 extension NCManageDatabase {
 extension NCManageDatabase {
-
     func tipExists(_ tipName: String) -> Bool {
     func tipExists(_ tipName: String) -> Bool {
-
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             guard (realm.objects(tableTip.self).where {
             guard (realm.objects(tableTip.self).where {
@@ -49,7 +46,6 @@ extension NCManageDatabase {
     }
     }
 
 
     func addTip(_ tipName: String) {
     func addTip(_ tipName: String) {
-
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {

+ 23 - 5
iOSClient/Data/NCManageDatabase.swift

@@ -186,8 +186,7 @@ class NCManageDatabase: NSObject {
     // MARK: -
     // MARK: -
     // MARK: Utility Database
     // MARK: Utility Database
 
 
-    @objc func clearTable(_ table: Object.Type, account: String? = nil) {
-
+    func clearTable(_ table: Object.Type, account: String? = nil) {
         do {
         do {
             let realm = try Realm()
             let realm = try Realm()
             try realm.write {
             try realm.write {
@@ -206,8 +205,7 @@ class NCManageDatabase: NSObject {
         }
         }
     }
     }
 
 
-    @objc func clearDatabase(account: String?, removeAccount: Bool) {
-
+    func clearDatabase(account: String?, removeAccount: Bool) {
         if removeAccount {
         if removeAccount {
             self.clearTable(tableAccount.self, account: account)
             self.clearTable(tableAccount.self, account: account)
         }
         }
@@ -237,7 +235,6 @@ class NCManageDatabase: NSObject {
         self.clearTable(tableShare.self, account: account)
         self.clearTable(tableShare.self, account: account)
         self.clearTable(TableSecurityGuardDiagnostics.self, account: account)
         self.clearTable(TableSecurityGuardDiagnostics.self, account: account)
         self.clearTable(tableTag.self, account: account)
         self.clearTable(tableTag.self, account: account)
-        self.clearTable(tableTip.self)
         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)
@@ -287,4 +284,25 @@ class NCManageDatabase: NSObject {
 
 
         return nil
         return nil
     }
     }
+
+    // MARK: -
+    // MARK: SWIFTUI PREVIEW
+
+    func previewCreateDB() {
+        /// Account
+        let account = "marinofaggiana https://cloudtest.nextcloud.com"
+        let account2 = "mariorossi https://cloudtest.nextcloud.com"
+        NCManageDatabase.shared.addAccount(account, urlBase: "https://cloudtest.nextcloud.com", user: "marinofaggiana", userId: "marinofaggiana", password: "password")
+        NCManageDatabase.shared.addAccount(account2, urlBase: "https://cloudtest.nextcloud.com", user: "mariorossi", userId: "mariorossi", password: "password")
+        let userProfile = NKUserProfile()
+        userProfile.displayName = "Marino Faggiana"
+        userProfile.address = "Hirschstrasse 26, 70192 Stuttgart, Germany"
+        userProfile.phone = "+49 (711) 252 428 - 90"
+        userProfile.email = "cloudtest@nextcloud.com"
+        NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile)
+        let userProfile2 = NKUserProfile()
+        userProfile2.displayName = "Mario Rossi"
+        userProfile2.email = "cloudtest@nextcloud.com"
+        NCManageDatabase.shared.setAccountUserProfile(account: account2, userProfile: userProfile2)
+    }
 }
 }

+ 156 - 0
iOSClient/DeepLink/NCDeepLinkHandler.swift

@@ -0,0 +1,156 @@
+//
+//  DeepLinkHandler.swift
+//  Nextcloud
+//
+//  Created by Amrut Waghmare on 29/05/24.
+//  Copyright © 2024 Marino Faggiana. All rights reserved.
+//
+//  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 UIKit
+import SwiftUI
+
+enum DeepLink: String {
+    case openFiles              // nextcloud://openFiles
+    case openFavorites          // nextcloud://openFavorites
+    case openMedia              // nextcloud://openMedia
+    case openShared             // nextcloud://openShared
+    case openOffline            // nextcloud://openOffline
+    case openNotifications      // nextcloud://openNotifications
+    case openDeleted            // nextcloud://openDeleted
+    case openSettings           // nextcloud://openSettings
+    case openAutoUpload         // nextcloud://openAutoUpload
+    case openUrl                // nextcloud://openUrl?url=https://nextcloud.com
+    case createNew              // nextcloud://createNew
+    case checkAppUpdate         // nextcloud://checkAppUpdate
+}
+
+enum ControllerConstants {
+    static let filesIndex = 0
+    static let favouriteIndex = 1
+    static let mediaIndex = 3
+    static let moreIndex = 4
+    static let notification = "NCNotification"
+    static let shares = "segueShares"
+    static let offline = "segueOffline"
+    static let delete = "segueTrash"
+}
+
+class NCDeepLinkHandler {
+    func parseDeepLink(_ url: URL, controller: NCMainTabBarController) {
+        guard let action = url.host, let deepLink = DeepLink(rawValue: action) else { return }
+        let params = getQueryParamsFromUrl(url: url)
+        handleDeepLink(deepLink, controller: controller, params: params)
+    }
+
+    func getQueryParamsFromUrl(url: URL) -> [String: Any]? {
+        guard
+            let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
+            let queryItems = components.queryItems else { return nil }
+        return queryItems.reduce(into: [String: Any]()) { result, item in
+            result[item.name] = item.value
+        }
+    }
+
+    func handleDeepLink(_ deepLink: DeepLink, controller: NCMainTabBarController, params: [String: Any]? = nil) {
+        switch deepLink {
+        case .openFiles:
+            navigateTo(index: ControllerConstants.filesIndex, controller: controller)
+        case .openFavorites:
+            navigateTo(index: ControllerConstants.favouriteIndex, controller: controller)
+        case .openMedia:
+            navigateTo(index: ControllerConstants.mediaIndex, controller: controller)
+        case .openShared:
+            navigateToMore(withSegue: ControllerConstants.shares, controller: controller)
+        case .openOffline:
+            navigateToMore(withSegue: ControllerConstants.offline, controller: controller)
+        case .openNotifications:
+            navigateToNotification(controller: controller)
+        case .openDeleted:
+            navigateToMore(withSegue: ControllerConstants.delete, controller: controller)
+        case .openSettings:
+            navigateToSettings(controller: controller)
+        case .openAutoUpload:
+            navigateToAutoUpload(controller: controller)
+        case .openUrl:
+            openUrl(params: params)
+        case .createNew:
+            navigateToCreateNew(controller: controller)
+        case .checkAppUpdate:
+            navigateAppUpdate()
+        }
+    }
+
+    private func navigateTo(index: Int, controller: NCMainTabBarController) {
+        controller.selectedIndex = index
+    }
+
+    private func navigateToNotification(controller: NCMainTabBarController) {
+        controller.selectedIndex = ControllerConstants.filesIndex
+        guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController,
+              let viewController = UIStoryboard(name: ControllerConstants.notification, bundle: nil).instantiateInitialViewController() as? NCNotification else { return }
+        navigationController.pushViewController(viewController, animated: true)
+    }
+
+    private func navigateToCreateNew(controller: NCMainTabBarController) {
+        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
+        controller.selectedIndex = ControllerConstants.filesIndex
+        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
+            appDelegate.toggleMenu(controller: controller)
+        }
+    }
+
+    private func navigateToMore(withSegue segue: String, controller: NCMainTabBarController) {
+        controller.selectedIndex = ControllerConstants.moreIndex
+        guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController else { return }
+        navigationController.viewControllers = navigationController.viewControllers.filter({$0.isKind(of: NCMore.self)})
+        navigationController.performSegue(withIdentifier: segue, sender: self)
+    }
+
+    private func navigateToSettings(controller: NCMainTabBarController) {
+        controller.selectedIndex = ControllerConstants.moreIndex
+        guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController else { return }
+
+        let settingsView = NCSettingsView(model: NCSettingsModel(controller: controller))
+        let settingsController = UIHostingController(rootView: settingsView)
+        navigationController.pushViewController(settingsController, animated: true)
+    }
+
+    private func navigateToAutoUpload(controller: NCMainTabBarController) {
+        controller.selectedIndex = ControllerConstants.moreIndex
+        guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController else { return }
+
+        let autoUploadView = NCAutoUploadView(model: NCAutoUploadModel(controller: controller))
+        let autoUploadController = UIHostingController(rootView: autoUploadView)
+        navigationController.pushViewController(autoUploadController, animated: true)
+    }
+
+    private func navigateAppUpdate() {
+        guard let url = URL(string: NCBrandOptions.shared.appStoreUrl) else { return }
+        handleUrl(url: url)
+    }
+
+    private func openUrl(params: [String: Any]?) {
+        guard let urlString = params?["url"] as? String, let url = URL(string: urlString) else { return }
+        handleUrl(url: url)
+    }
+
+    private func handleUrl(url: URL) {
+        if UIApplication.shared.canOpenURL(url) {
+            UIApplication.shared.open(url, options: [:], completionHandler: nil)
+        }
+    }
+}

+ 0 - 203
iOSClient/Diagnostics/NCCapabilitiesView.swift

@@ -1,203 +0,0 @@
-//
-//  NCCapabilitiesView.swift
-//  Nextcloud
-//
-//  Created by Marino Faggiana on 19/05/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 SwiftUI
-import NextcloudKit
-
-@objc class NCHostingCapabilitiesView: NSObject {
-
-    @objc func makeShipDetailsUI() -> UIViewController {
-
-        let capabilitiesStatus = NCCapabilitiesViewOO()
-        let view = NCCapabilitiesView(capabilitiesStatus: capabilitiesStatus)
-        let vc = UIHostingController(rootView: view)
-        vc.title = NSLocalizedString("_capabilities_", comment: "")
-        return vc
-    }
-}
-
-class NCCapabilitiesViewOO: ObservableObject {
-
-    struct Capability: Identifiable, Hashable {
-        let id = UUID()
-        let text: String
-        let image: UIImage
-        let resize: Bool
-        let available: Bool
-    }
-
-    @Published var capabililies: [Capability] = []
-    @Published var homeServer = ""
-    let utilityFileSystem = NCUtilityFileSystem()
-    let utility = NCUtility()
-
-    init() {
-        loadCapabilities()
-        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeUser), object: nil, queue: nil) { _ in
-            self.loadCapabilities()
-        }
-    }
-
-    func loadCapabilities() {
-        guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return }
-        var textEditor = false
-        var onlyofficeEditors = false
-
-        capabililies.removeAll()
-
-        var image = utility.loadImage(named: "person.fill.badge.plus")
-        capabililies.append(Capability(text: "File sharing", image: image, resize: false, available: NCGlobal.shared.capabilityFileSharingApiEnabled))
-
-        image = utility.loadImage(named: "network")
-        capabililies.append(Capability(text: "External site", image: image, resize: false, available: NCGlobal.shared.capabilityExternalSites))
-
-        image = utility.loadImage(named: "lock")
-        capabililies.append(Capability(text: "End-to-End Encryption", image: image, resize: false, available: NCGlobal.shared.capabilityE2EEEnabled))
-
-        image = utility.loadImage(named: "bolt")
-        capabililies.append(Capability(text: "Activity", image: image, resize: false, available: !NCGlobal.shared.capabilityActivity.isEmpty))
-
-        image = utility.loadImage(named: "bell")
-        capabililies.append(Capability(text: "Notification", image: image, resize: false, available: !NCGlobal.shared.capabilityNotification.isEmpty))
-
-        image = utility.loadImage(named: "trash")
-        capabililies.append(Capability(text: "Deleted files", image: image, resize: false, available: NCGlobal.shared.capabilityFilesUndelete))
-
-        if let editors = NCManageDatabase.shared.getDirectEditingEditors(account: activeAccount.account) {
-            for editor in editors {
-                if editor.editor == NCGlobal.shared.editorText {
-                    textEditor = true
-                } else if editor.editor == NCGlobal.shared.editorOnlyoffice {
-                    onlyofficeEditors = true
-                }
-            }
-        }
-
-        capabililies.append(Capability(text: "Text", image: utility.loadImage(named: "doc.text"), resize: false, available: textEditor))
-
-        capabililies.append(Capability(text: "ONLYOFFICE", image: utility.loadImage(named: "onlyoffice"), resize: true, available: onlyofficeEditors))
-
-        capabililies.append(Capability(text: "Collabora", image: utility.loadImage(named: "collabora"), resize: true, available: NCGlobal.shared.capabilityRichDocumentsEnabled))
-
-        capabililies.append(Capability(text: "User Status", image: utility.loadImage(named: "moon"), resize: false, available: NCGlobal.shared.capabilityUserStatusEnabled))
-
-        capabililies.append(Capability(text: "Comments", image: utility.loadImage(named: "ellipsis.bubble"), resize: false, available: NCGlobal.shared.capabilityFilesComments))
-
-        capabililies.append(Capability(text: "Lock file", image: utility.loadImage(named: "lock"), resize: false, available: !NCGlobal.shared.capabilityFilesLockVersion.isEmpty))
-
-        capabililies.append(Capability(text: "Group folders", image: utility.loadImage(named: "person.2"), resize: false, available: NCGlobal.shared.capabilityGroupfoldersEnabled))
-
-        if NCBrandOptions.shared.brand != "Nextcloud" {
-            capabililies.append(Capability(text: "Security Guard Diagnostics", image: utility.loadImage(named: "shield"), resize: false, available: NCGlobal.shared.capabilitySecurityGuardDiagnostics))
-        }
-
-        capabililies.append(Capability(text: "Assistant", image: utility.loadImage(named: "sparkles"), resize: false, available: NCGlobal.shared.capabilityAssistantEnabled))
-
-        homeServer = utilityFileSystem.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId) + "/"
-    }
-}
-
-struct NCCapabilitiesView: View {
-
-    @ObservedObject var capabilitiesViewOO: NCCapabilitiesViewOO
-
-    init(capabilitiesStatus: NCCapabilitiesViewOO) {
-        self.capabilitiesViewOO = capabilitiesStatus
-    }
-
-    var body: some View {
-        VStack {
-            List {
-                Section {
-                    ForEach(capabilitiesViewOO.capabililies, id: \.id) { capability in
-                        HStack {
-                            CapabilityName(text: Binding.constant(capability.text), image: Image(uiImage: capability.image), resize: capability.resize)
-                            CapabilityStatus(available: capability.available)
-                        }
-                    }
-                }
-                Section {
-                    CapabilityName(text: $capabilitiesViewOO.homeServer, image: Image(uiImage: NCUtility().loadImage(named: "house")), resize: false)
-                }
-            }
-        }
-        .frame(maxWidth: .infinity, alignment: .top)
-    }
-
-    struct CapabilityName: View {
-
-        @Binding var text: String
-        @State var image: Image
-        @State var resize: Bool
-
-        var body: some View {
-            Label {
-                Text(text)
-                    .font(.system(size: 15))
-            } icon: {
-                if resize {
-                    image
-                        .renderingMode(.template)
-                        .resizable()
-                        .scaledToFill()
-                        .frame(width: 23.0, height: 23.0)
-                        .foregroundColor(.primary)
-                } else {
-                    image
-                        .renderingMode(.template)
-                        .foregroundColor(.primary)
-                }
-            }
-            .frame(maxWidth: .infinity, alignment: .leading)
-        }
-    }
-
-    struct CapabilityStatus: View {
-
-        @State var available: Bool
-
-        var body: some View {
-            if available {
-                Image(systemName: "checkmark.circle.fill")
-                    .foregroundColor(.green)
-            } else {
-                Image(systemName: "multiply.circle.fill")
-                    .foregroundColor(Color(NCBrandColor.shared.textColor2))
-            }
-        }
-    }
-}
-
-#Preview {
-    func getCapabilitiesViewOOForPreview() -> NCCapabilitiesViewOO {
-        let capabilitiesViewOO = NCCapabilitiesViewOO()
-        capabilitiesViewOO.capabililies = [
-            NCCapabilitiesViewOO.Capability(text: "Collabora", image: UIImage(named: "collabora")!, resize: true, available: true),
-            NCCapabilitiesViewOO.Capability(text: "XXX site", image: UIImage(systemName: "lock.shield")!, resize: false, available: false)
-        ]
-        capabilitiesViewOO.homeServer = "https://cloud.nextcloud.com/remote.php.dav/files/marino/"
-        return capabilitiesViewOO
-    }
-
-    return NCCapabilitiesView(capabilitiesStatus: getCapabilitiesViewOOForPreview())
-}

+ 1 - 0
iOSClient/Extensions/PHAsset+Extension.swift

@@ -23,6 +23,7 @@
 
 
 import Foundation
 import Foundation
 import UIKit
 import UIKit
+import Photos
 
 
 extension PHAsset {
 extension PHAsset {
     var originalFilename: NSString {
     var originalFilename: NSString {

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

@@ -1,52 +0,0 @@
-//
-//  UIDevice+Extension.swift
-//  Nextcloud
-//
-//  Created by Federico Malagoni on 23/02/22.
-//  Copyright © 2022 Federico Malagoni. All rights reserved.
-//
-//  Author Federico Malagoni <federico.malagoni@astrairidium.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 UIKit
-
-extension UIDevice {
-
-    var hasNotch: Bool {
-        if #available(iOS 11.0, *) {
-            if UIApplication.shared.windows.isEmpty { return false }
-            let top = UIApplication.shared.windows[0].safeAreaInsets.top
-            return top > 20
-        } else {
-            // Fallback on earlier versions
-            return false
-        }
-    }
-}
-
-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
-        }
-    }
-}

+ 25 - 0
iOSClient/Extensions/View+Extension.swift

@@ -50,4 +50,29 @@ extension View {
             self
             self
         }
         }
     }
     }
+
+    func onFirstAppear(perform action: @escaping () -> Void) -> some View {
+        modifier(ViewFirstAppearModifier(perform: action))
+    }
+}
+
+struct ViewFirstAppearModifier: ViewModifier {
+    @State private var didAppearBefore = false
+    private let action: () -> Void
+
+    init(perform action: @escaping () -> Void) {
+        self.action = action
+    }
+
+    func body(content: Content) -> some View {
+        content.onAppear {
+            guard !didAppearBefore else { return }
+            didAppearBefore = true
+            action()
+        }
+    }
+}
+
+var isRunningForPreviews: Bool {
+    return ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
 }
 }

+ 25 - 11
iOSClient/Files/NCFiles.swift

@@ -161,21 +161,22 @@ class NCFiles: NCCollectionViewCommon {
         super.reloadDataSourceNetwork()
         super.reloadDataSourceNetwork()
 
 
         networkReadFolder { tableDirectory, metadatas, metadatasDifferentCount, metadatasModified, error in
         networkReadFolder { tableDirectory, metadatas, metadatasDifferentCount, metadatasModified, error in
-            if error == .success {
-                for metadata in metadatas ?? [] where !metadata.directory && downloadMetadata(metadata) {
-                    if NCNetworking.shared.downloadQueue.operations.filter({ ($0 as? NCOperationDownload)?.metadata.ocId == metadata.ocId }).isEmpty {
-                        NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile))
+            DispatchQueue.global(qos: .userInteractive).async {
+                if error == .success {
+                    for metadata in metadatas ?? [] where !metadata.directory && downloadMetadata(metadata) {
+                        if NCNetworking.shared.downloadQueue.operations.filter({ ($0 as? NCOperationDownload)?.metadata.ocId == metadata.ocId }).isEmpty {
+                            NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorDownloadFile))
+                        }
+                    }
+                    self.richWorkspaceText = tableDirectory?.richWorkspace
+                    if metadatasDifferentCount != 0 || metadatasModified != 0 {
+                        self.reloadDataSource()
+                    } else {
+                        self.reloadDataSource(withQueryDB: withQueryDB)
                     }
                     }
-                }
-                self.richWorkspaceText = tableDirectory?.richWorkspace
-
-                if metadatasDifferentCount != 0 || metadatasModified != 0 {
-                    self.reloadDataSource()
                 } else {
                 } else {
                     self.reloadDataSource(withQueryDB: withQueryDB)
                     self.reloadDataSource(withQueryDB: withQueryDB)
                 }
                 }
-            } else {
-                self.reloadDataSource(withQueryDB: withQueryDB)
             }
             }
         }
         }
     }
     }
@@ -290,4 +291,17 @@ class NCFiles: NCCollectionViewCommon {
             }
             }
         }
         }
     }
     }
+
+    // MARK: - NCAccountSettingsModelDelegate
+
+    override func accountSettingsDidDismiss(tableAccount: tableAccount?) {
+        if NCManageDatabase.shared.getAllAccount().isEmpty {
+            appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false)
+        } else if let account = tableAccount?.account, account != appDelegate.account {
+            appDelegate.changeAccount(account, userProfile: nil)
+        } else if isRoot {
+            titleCurrentFolder = getNavigationTitle()
+            navigationItem.title = titleCurrentFolder
+        }
+    }
 }
 }

+ 1 - 1
iOSClient/GUI/HUDView.swift

@@ -85,7 +85,7 @@ struct ContentView: View {
                 }
                 }
                 HUDView(showHUD: $showHUD, textLabel: NSLocalizedString("_wait_", comment: ""), image: "doc.badge.arrow.up")
                 HUDView(showHUD: $showHUD, textLabel: NSLocalizedString("_wait_", comment: ""), image: "doc.badge.arrow.up")
                     .offset(y: showHUD ? (geo.size.height / 2) : -200)
                     .offset(y: showHUD ? (geo.size.height / 2) : -200)
-                    .animation(.easeOut)
+                    .animation(.easeOut, value: showHUD)
             }
             }
         }
         }
     }
     }

+ 14 - 7
iOSClient/Settings/CCManageAccount.h → iOSClient/GUI/LazyView.swift

@@ -1,9 +1,9 @@
 //
 //
-//  CCManageAccount.h
+//  LazyView.swift
 //  Nextcloud
 //  Nextcloud
 //
 //
-//  Created by Marino Faggiana on 12/03/15.
-//  Copyright (c) 2015 Marino Faggiana. All rights reserved.
+//  Created by Marino Faggiana on 01/06/24.
+//  Copyright © 2024 Marino Faggiana. All rights reserved.
 //
 //
 //  Author Marino Faggiana <marino.faggiana@nextcloud.com>
 //  Author Marino Faggiana <marino.faggiana@nextcloud.com>
 //
 //
@@ -21,8 +21,15 @@
 //  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 <XLForm.h>
+import SwiftUI
 
 
-@interface CCManageAccount : XLFormViewController
-
-@end
+/// LazyView is a view that delays the initialization of its contained view until it is actually needed.
+struct LazyView<Content: View>: View {
+    let build: () -> Content
+    init(_ build: @escaping () -> Content) {
+        self.build = build
+    }
+    var body: Content {
+        build()
+    }
+}

+ 49 - 0
iOSClient/GUI/ViewOnAppear.swift

@@ -0,0 +1,49 @@
+//
+//  ViewOnAppear.swift
+//  Nextcloud
+//
+//  Created by Aditya Tyagi on 17/03/24.
+//  Copyright © 2024 Marino Faggiana. All rights reserved.
+//
+//  Author Aditya Tyagi <adityagi02@yahoo.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 SwiftUI
+
+/// A protocol defining methods to handle view appearance events.
+protocol ViewOnAppearHandling: ObservableObject {
+    /// Triggered when the view appears.
+    func onViewAppear()
+}
+
+extension View {
+    @discardableResult func defaultViewModifier(_ model: some ViewOnAppearHandling) -> some View {
+        return modifier(DefaultViewModifier(viewModel: model))
+    }
+}
+
+/// A view modifier that automatically calls a view model's `onViewAppear` function when the view appears on screen.
+struct DefaultViewModifier<ViewModel: ViewOnAppearHandling>: ViewModifier {
+    @ObservedObject var viewModel: ViewModel
+
+    func body(content: Content) -> some View {
+        content
+        .onAppear {
+            viewModel.onViewAppear()        // Call onViewAppear on view appearance
+        }
+    }
+}

+ 0 - 15
iOSClient/Images.xcassets/address.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "address.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/address.imageset/address.pdf


+ 0 - 15
iOSClient/Images.xcassets/arrow.forward.square.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "arrow-right-bold-box-outline.svg",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

+ 0 - 1
iOSClient/Images.xcassets/arrow.forward.square.imageset/arrow-right-bold-box-outline.svg

@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M17,12L12,17V14H8V10H12V7L17,12M3,19V5A2,2 0 0,1 5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19M5,19H19V5H5V19Z" /></svg>

+ 0 - 15
iOSClient/Images.xcassets/arrow.up.right.square.imageset/Contents.json

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

+ 0 - 1
iOSClient/Images.xcassets/arrow.up.right.square.imageset/Unknown.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M3.2 2C2.53 2 2 2.54 2 3.2v9.6c0 .67.53 1.2 1.2 1.2h9.6c.67 0 1.2-.53 1.2-1.2V8.98l-1.2-1.2v5.02H3.2V3.2h5.02L7.08 2.06 7.02 2H3.2z" fill="#000"/><path d="M8.14 1l2.29 2.29L7 6.7 9.29 9l3.42-3.43L15 7.86V1z" fill="#000"/></svg>

+ 0 - 15
iOSClient/Images.xcassets/autoUpload.imageset/Contents.json

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

+ 0 - 1
iOSClient/Images.xcassets/autoUpload.imageset/camera-outline.svg

@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M20,4H16.83L15,2H9L7.17,4H4A2,2 0 0,0 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V6A2,2 0 0,0 20,4M20,18H4V6H8.05L9.88,4H14.12L15.95,6H20V18M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15Z" /></svg>

+ 0 - 15
iOSClient/Images.xcassets/businesstype.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "businesstype.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/businesstype.imageset/businesstype.pdf


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

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

+ 0 - 1
iOSClient/Images.xcassets/caldavcardav.imageset/icons8-calendario-delle-persone.svg

@@ -1 +0,0 @@
-<svg fill="#000000" xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 50 50" width="50px" height="50px"><path d="M48.6 32H46v-1c0-.6-.4-1-1-1s-1 .4-1 1v1h-8v-1c0-.6-.4-1-1-1s-1 .4-1 1v1h-2.6c-.8 0-1.4.6-1.4 1.4v15.3c0 .7.6 1.3 1.4 1.3h17.3c.8 0 1.3-.6 1.3-1.4V33.4C49.9 32.6 49.4 32 48.6 32zM34 34c0 .6.4 1 1 1s1-.4 1-1h8c0 .6.4 1 1 1s1-.4 1-1h2v2H32v-2H34zM35 40h2v2h-2V40zM39 40h2v2h-2V40zM43 40h2v2h-2V40zM35 44h2v2h-2V44zM39 44h2v2h-2V44zM43 44h2v2h-2V44zM30.952 7.823C30.1 6.414 28.8 5.527 27.083 5.185 26.117 3.965 24.301 3.3 21.879 3.3h-.001c-3.685.083-6.378 1.21-8.005 3.35-1.926 2.533-2.287 6.416-1.076 11.546-.413.531-.785 1.38-.688 2.54.296 2.159 1.116 3.05 1.785 3.415.308 1.749 1.156 3.676 2.007 4.597v3.561c-.611 1.376-2.601 2.172-4.892 3.089-3.864 1.546-8.673 3.47-9.007 9.549L1.943 46H28V28.747c.846-.916 1.69-2.827 2.001-4.569.712-.351 1.59-1.241 1.795-3.494.095-1.126-.215-1.954-.641-2.487C32.004 15.468 32.749 10.794 30.952 7.823zM29.059 18.164l-.316.824.793.396c.089.064.329.409.269 1.125C29.669 21.988 29.2 22.383 29.1 22.4H28.19l-.086.905c-.181 1.896-1.239 3.854-1.6 4.126L26 27.719V32.5c-.018.373-1.464 1.5-4 1.5-2.489 0-4-1.042-4-1.5 0-.152-.039-.292-.1-.421V28.3l.02-.568-.504-.288c-.381-.284-1.439-2.242-1.621-4.138l-.012-.896h-.909c-.143-.056-.59-.53-.778-1.894-.069-.838.359-1.185.358-1.185l.59-.392-.174-.687c-1.213-4.783-1.012-8.28.596-10.395 1.239-1.63 3.412-2.491 6.435-2.56 1.891 0 3.252.476 3.736 1.304l.244.419L26.36 7.09c1.332.188 2.274.766 2.881 1.769C30.689 11.254 29.926 15.735 29.059 18.164z"/></svg>

+ 0 - 15
iOSClient/Images.xcassets/capabilities.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "format-list-bulleted.svg",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

+ 0 - 1
iOSClient/Images.xcassets/capabilities.imageset/format-list-bulleted.svg

@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M7,5H21V7H7V5M7,13V11H21V13H7M4,4.5A1.5,1.5 0 0,1 5.5,6A1.5,1.5 0 0,1 4,7.5A1.5,1.5 0 0,1 2.5,6A1.5,1.5 0 0,1 4,4.5M4,10.5A1.5,1.5 0 0,1 5.5,12A1.5,1.5 0 0,1 4,13.5A1.5,1.5 0 0,1 2.5,12A1.5,1.5 0 0,1 4,10.5M7,19V17H21V19H7M4,16.5A1.5,1.5 0 0,1 5.5,18A1.5,1.5 0 0,1 4,19.5A1.5,1.5 0 0,1 2.5,18A1.5,1.5 0 0,1 4,16.5Z" /></svg>

+ 0 - 15
iOSClient/Images.xcassets/checkmark.imageset/Contents.json

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

+ 0 - 1
iOSClient/Images.xcassets/checkmark.imageset/check.svg

@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" /></svg>

+ 5 - 5
iOSClient/Images.xcassets/circle_fill.imageset/Contents.json

@@ -1,15 +1,15 @@
 {
 {
   "images" : [
   "images" : [
     {
     {
-      "idiom" : "universal",
-      "filename" : "circle.pdf"
+      "filename" : "circle_fill.pdf",
+      "idiom" : "universal"
     }
     }
   ],
   ],
   "info" : {
   "info" : {
-    "version" : 1,
-    "author" : "xcode"
+    "author" : "xcode",
+    "version" : 1
   },
   },
   "properties" : {
   "properties" : {
     "preserves-vector-representation" : true
     "preserves-vector-representation" : true
   }
   }
-}
+}

BIN
iOSClient/Images.xcassets/circle_fill.imageset/circle.pdf


BIN
iOSClient/Images.xcassets/circle_fill.imageset/circle_fill.pdf


+ 0 - 15
iOSClient/Images.xcassets/city.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "city.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/city.imageset/city.pdf


+ 0 - 15
iOSClient/Images.xcassets/clear.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "clear.pdf",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/clear.imageset/clear.pdf


+ 0 - 15
iOSClient/Images.xcassets/comment.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "comment.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/comment.imageset/comment.pdf


+ 0 - 15
iOSClient/Images.xcassets/comments.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "comments.pdf",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/comments.imageset/comments.pdf


+ 0 - 15
iOSClient/Images.xcassets/company.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "company.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/company.imageset/company.pdf


+ 0 - 15
iOSClient/Images.xcassets/country.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "country.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/country.imageset/country.pdf


+ 0 - 15
iOSClient/Images.xcassets/crashservice.imageset/Contents.json

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

+ 0 - 1
iOSClient/Images.xcassets/crashservice.imageset/bug-outline.svg

@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M20,8H17.19C16.74,7.2 16.12,6.5 15.37,6L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.05,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6C7.87,6.5 7.26,7.21 6.81,8H4V10H6.09C6.03,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.03,15.67 6.09,16H4V18H6.81C8.47,20.87 12.14,21.84 15,20.18C15.91,19.66 16.67,18.9 17.19,18H20V16H17.91C17.97,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.97,10.33 17.91,10H20V8M16,15A4,4 0 0,1 12,19A4,4 0 0,1 8,15V11A4,4 0 0,1 12,7A4,4 0 0,1 16,11V15M14,10V12H10V10H14M10,14H14V16H10V14Z" /></svg>

+ 0 - 15
iOSClient/Images.xcassets/editUserProfile.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "editUserProfile.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/editUserProfile.imageset/editUserProfile.pdf


+ 0 - 15
iOSClient/Images.xcassets/email.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "mail.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/email.imageset/mail.pdf


+ 0 - 26
iOSClient/Images.xcassets/foldersOnTop.imageset/Contents.json

@@ -1,26 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "foldersOnTop.png",
-      "idiom" : "universal",
-      "scale" : "1x"
-    },
-    {
-      "filename" : "foldersOnTop@2x.png",
-      "idiom" : "universal",
-      "scale" : "2x"
-    },
-    {
-      "filename" : "foldersOnTop@3x.png",
-      "idiom" : "universal",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/foldersOnTop.imageset/foldersOnTop.png


BIN
iOSClient/Images.xcassets/foldersOnTop.imageset/foldersOnTop@2x.png


BIN
iOSClient/Images.xcassets/foldersOnTop.imageset/foldersOnTop@3x.png


+ 0 - 15
iOSClient/Images.xcassets/form-textbox.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "form-textbox.svg",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

+ 0 - 1
iOSClient/Images.xcassets/form-textbox.imageset/form-textbox.svg

@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20Z" /></svg>

+ 0 - 15
iOSClient/Images.xcassets/log.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "log.pdf",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/log.imageset/log.pdf


+ 0 - 15
iOSClient/Images.xcassets/role.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "role.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/role.imageset/role.pdf


+ 0 - 26
iOSClient/Images.xcassets/rotate.imageset/Contents.json

@@ -1,26 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "rotate.png",
-      "idiom" : "universal",
-      "scale" : "1x"
-    },
-    {
-      "filename" : "rotate@2x.png",
-      "idiom" : "universal",
-      "scale" : "2x"
-    },
-    {
-      "filename" : "rotate@3x.png",
-      "idiom" : "universal",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/rotate.imageset/rotate.png


BIN
iOSClient/Images.xcassets/rotate.imageset/rotate@2x.png


BIN
iOSClient/Images.xcassets/rotate.imageset/rotate@3x.png


BIN
iOSClient/Images.xcassets/select.imageset/1.pdf


+ 0 - 15
iOSClient/Images.xcassets/select.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "1.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

+ 0 - 15
iOSClient/Images.xcassets/selectLight.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "selectLight.png"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

Some files were not shown because too many files changed in this diff