浏览代码

Merge branch 'develop'

marinofaggiana 3 年之前
父节点
当前提交
541d12bdb8
共有 100 个文件被更改,包括 1489 次插入1068 次删除
  1. 0 2
      .gitignore
  2. 1 1
      .swiftlint.yml
  3. 1 9
      Cartfile
  4. 3 0
      Cartfile.resolved
  5. 305 137
      Nextcloud.xcodeproj/project.pbxproj
  6. 91 28
      Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  7. 1 1
      README.md
  8. 17 8
      Share/MainInterface.storyboard
  9. 82 0
      Share/NCShareCell.swift
  10. 180 0
      Share/NCShareExtension+DataSource.swift
  11. 215 0
      Share/NCShareExtension+Files.swift
  12. 159 0
      Share/NCShareExtension+NCDelegate.swift
  13. 157 766
      Share/NCShareExtension.swift
  14. 7 4
      iOSClient/AppDelegate.swift
  15. 0 1
      iOSClient/Brand/NCBrand.swift
  16. 7 0
      iOSClient/Data/NCDatabase.swift
  17. 45 0
      iOSClient/Data/NCManageDatabase.swift
  18. 31 0
      iOSClient/Extensions/UIImage+Extensions.swift
  19. 1 0
      iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift
  20. 11 14
      iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift
  21. 38 20
      iOSClient/Main/NCFunctionCenter.swift
  22. 1 1
      iOSClient/Main/NCPickerViewController.swift
  23. 21 1
      iOSClient/Menu/NCViewer+Menu.swift
  24. 2 1
      iOSClient/NCGlobal.swift
  25. 41 33
      iOSClient/Networking/NCNetworking.swift
  26. 1 1
      iOSClient/Networking/NCNetworkingE2EE.swift
  27. 9 0
      iOSClient/Networking/NCNetworkingProcessUpload.swift
  28. 3 2
      iOSClient/Rename file/NCRenameFile.swift
  29. 14 11
      iOSClient/Security/NCEndToEndEncryption.m
  30. 4 4
      iOSClient/Settings/Acknowledgements.rtf
  31. 1 1
      iOSClient/Settings/CCAdvanced.h
  32. 1 1
      iOSClient/Settings/CCManageAccount.h
  33. 1 1
      iOSClient/Settings/CCManageAutoUpload.h
  34. 1 1
      iOSClient/Settings/NCManageEndToEndEncryption.h
  35. 1 1
      iOSClient/Settings/NCSettings.h
  36. 二进制
      iOSClient/Supporting Files/af.lproj/Localizable.strings
  37. 二进制
      iOSClient/Supporting Files/ar.lproj/Localizable.strings
  38. 二进制
      iOSClient/Supporting Files/ast.lproj/Localizable.strings
  39. 二进制
      iOSClient/Supporting Files/az.lproj/Localizable.strings
  40. 二进制
      iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings
  41. 二进制
      iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings
  42. 二进制
      iOSClient/Supporting Files/br.lproj/Localizable.strings
  43. 二进制
      iOSClient/Supporting Files/bs.lproj/Localizable.strings
  44. 二进制
      iOSClient/Supporting Files/ca.lproj/Localizable.strings
  45. 二进制
      iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings
  46. 二进制
      iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings
  47. 二进制
      iOSClient/Supporting Files/da.lproj/Localizable.strings
  48. 二进制
      iOSClient/Supporting Files/de.lproj/Localizable.strings
  49. 二进制
      iOSClient/Supporting Files/el.lproj/Localizable.strings
  50. 二进制
      iOSClient/Supporting Files/en-GB.lproj/Localizable.strings
  51. 36 18
      iOSClient/Supporting Files/en.lproj/Localizable.strings
  52. 二进制
      iOSClient/Supporting Files/eo.lproj/Localizable.strings
  53. 二进制
      iOSClient/Supporting Files/es-419.lproj/Localizable.strings
  54. 二进制
      iOSClient/Supporting Files/es-AR.lproj/Localizable.strings
  55. 二进制
      iOSClient/Supporting Files/es-CL.lproj/Localizable.strings
  56. 二进制
      iOSClient/Supporting Files/es-CO.lproj/Localizable.strings
  57. 二进制
      iOSClient/Supporting Files/es-CR.lproj/Localizable.strings
  58. 二进制
      iOSClient/Supporting Files/es-DO.lproj/Localizable.strings
  59. 二进制
      iOSClient/Supporting Files/es-EC.lproj/Localizable.strings
  60. 二进制
      iOSClient/Supporting Files/es-GT.lproj/Localizable.strings
  61. 二进制
      iOSClient/Supporting Files/es-HN.lproj/Localizable.strings
  62. 二进制
      iOSClient/Supporting Files/es-MX.lproj/Localizable.strings
  63. 二进制
      iOSClient/Supporting Files/es-NI.lproj/Localizable.strings
  64. 二进制
      iOSClient/Supporting Files/es-PA.lproj/Localizable.strings
  65. 二进制
      iOSClient/Supporting Files/es-PE.lproj/Localizable.strings
  66. 二进制
      iOSClient/Supporting Files/es-PR.lproj/Localizable.strings
  67. 二进制
      iOSClient/Supporting Files/es-PY.lproj/Localizable.strings
  68. 二进制
      iOSClient/Supporting Files/es-SV.lproj/Localizable.strings
  69. 二进制
      iOSClient/Supporting Files/es-UY.lproj/Localizable.strings
  70. 二进制
      iOSClient/Supporting Files/es.lproj/Localizable.strings
  71. 二进制
      iOSClient/Supporting Files/et_EE.lproj/Localizable.strings
  72. 二进制
      iOSClient/Supporting Files/eu.lproj/Localizable.strings
  73. 二进制
      iOSClient/Supporting Files/fa.lproj/Localizable.strings
  74. 二进制
      iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings
  75. 二进制
      iOSClient/Supporting Files/fr.lproj/Localizable.strings
  76. 二进制
      iOSClient/Supporting Files/gl.lproj/Localizable.strings
  77. 二进制
      iOSClient/Supporting Files/he.lproj/Localizable.strings
  78. 二进制
      iOSClient/Supporting Files/hr.lproj/Localizable.strings
  79. 二进制
      iOSClient/Supporting Files/hu.lproj/Localizable.strings
  80. 二进制
      iOSClient/Supporting Files/ia.lproj/Localizable.strings
  81. 二进制
      iOSClient/Supporting Files/id.lproj/Localizable.strings
  82. 二进制
      iOSClient/Supporting Files/is.lproj/Localizable.strings
  83. 二进制
      iOSClient/Supporting Files/it.lproj/Localizable.strings
  84. 二进制
      iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings
  85. 二进制
      iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings
  86. 二进制
      iOSClient/Supporting Files/ko.lproj/Localizable.strings
  87. 二进制
      iOSClient/Supporting Files/lb.lproj/Localizable.strings
  88. 二进制
      iOSClient/Supporting Files/lo.lproj/Localizable.strings
  89. 二进制
      iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings
  90. 二进制
      iOSClient/Supporting Files/lv.lproj/Localizable.strings
  91. 二进制
      iOSClient/Supporting Files/mk.lproj/Localizable.strings
  92. 二进制
      iOSClient/Supporting Files/mn.lproj/Localizable.strings
  93. 二进制
      iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings
  94. 二进制
      iOSClient/Supporting Files/nl.lproj/Localizable.strings
  95. 二进制
      iOSClient/Supporting Files/nn_NO.lproj/Localizable.strings
  96. 二进制
      iOSClient/Supporting Files/oc.lproj/Localizable.strings
  97. 二进制
      iOSClient/Supporting Files/pl.lproj/Localizable.strings
  98. 二进制
      iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings
  99. 二进制
      iOSClient/Supporting Files/pt-PT.lproj/Localizable.strings
  100. 二进制
      iOSClient/Supporting Files/ro.lproj/Localizable.strings

+ 0 - 2
.gitignore

@@ -37,8 +37,6 @@ DerivedData
 
 ## Package
 Carthage/
-Package.resolved
-Cartfile.resolved
 
 ### SwiftPackageManager ###
 .swiftpm

+ 1 - 1
.swiftlint.yml

@@ -4,6 +4,7 @@ opt_in_rules: # some rules are turned off by default, so you need to opt-in
   - empty_string
   - explicit_init
   - unneeded_parentheses_in_closure_argument
+  - operator_usage_whitespace
 
 empty_count:
   severity: warning
@@ -33,7 +34,6 @@ excluded:
   - File Provider Extension/FileProviderExtension.swift
   - File Provider Extension/FileProviderUtility.swift
   - Notification Service Extension/NotificationService.swift
-  - Share/NCShareExtension.swift
   - iOSClient/Activity/NCActivity.swift
   - iOSClient/Activity/NCActivityTableViewCell.swift
   - iOSClient/AppDelegate.swift

+ 1 - 9
Cartfile

@@ -1,11 +1,3 @@
-github "tilltue/TLPhotoPicker" "2.1.4"
-github "kishikawakatsumi/UICKeyChainStore"
-github "WenchaoD/FSCalendar" "2.8.0"
-github "FabrizioBrancati/Queuer"
-github "xmartlabs/XLForm" ~> 4.1
-github "AssistoLab/DropDown" "v2.3.13"
-
 github "https://github.com/marinofaggiana/KTVHTTPCache" "2.0.2"
 github "https://github.com/marinofaggiana/TOPasscodeViewController" "master"
-github "https://github.com/marinofaggiana/OpenSSL" "master"
-github "https://github.com/marinofaggiana/ChromaColorPicker" "master"
+github "krzyzanowskim/OpenSSL"

+ 3 - 0
Cartfile.resolved

@@ -0,0 +1,3 @@
+github "krzyzanowskim/OpenSSL" "1.1.1300"
+github "marinofaggiana/KTVHTTPCache" "2.0.2"
+github "marinofaggiana/TOPasscodeViewController" "7a750031bb86d9dc9f193bf34a38bbd288b3c4fd"

文件差异内容过多而无法显示
+ 305 - 137
Nextcloud.xcodeproj/project.pbxproj


+ 91 - 28
Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -15,8 +15,8 @@
         "repositoryURL": "https://github.com/Alamofire/Alamofire",
         "state": {
           "branch": null,
-          "revision": "d120af1e8638c7da36c8481fd61a66c0c08dc4fc",
-          "version": "5.4.4"
+          "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864",
+          "version": "5.5.0"
         }
       },
       {
@@ -28,13 +28,31 @@
           "version": "0.7.2"
         }
       },
+      {
+        "package": "ChromaColorPicker",
+        "repositoryURL": "https://github.com/marinofaggiana/ChromaColorPicker",
+        "state": {
+          "branch": "master",
+          "revision": "b1b2c58c3c5617c73863a073cb6393c79195932e",
+          "version": null
+        }
+      },
       {
         "package": "CocoaLumberjack",
         "repositoryURL": "https://github.com/CocoaLumberjack/CocoaLumberjack.git",
         "state": {
           "branch": null,
-          "revision": "e518eb6e362df327574ba5e04269cd6d29f40aec",
-          "version": "3.7.2"
+          "revision": "80ada1f753b0d53d9b57c465936a7c4169375002",
+          "version": "3.7.4"
+        }
+      },
+      {
+        "package": "DropDown",
+        "repositoryURL": "https://github.com/AssistoLab/DropDown",
+        "state": {
+          "branch": "master",
+          "revision": "2ab6f6ce19f0117d1a76ea043ef8f57722c65d16",
+          "version": null
         }
       },
       {
@@ -42,8 +60,8 @@
         "repositoryURL": "https://github.com/firebase/firebase-ios-sdk",
         "state": {
           "branch": null,
-          "revision": "08686f04881483d2bc098b2696e674c0ba135e47",
-          "version": "8.10.0"
+          "revision": "5344857522053b5d4403ec8173ec0d23200a97ea",
+          "version": "8.11.0"
         }
       },
       {
@@ -55,6 +73,15 @@
           "version": "2.5.1"
         }
       },
+      {
+        "package": "FSCalendar",
+        "repositoryURL": "https://github.com/WenchaoD/FSCalendar",
+        "state": {
+          "branch": null,
+          "revision": "afaf247581eb1f8aea847f2e6c99c665ae900494",
+          "version": "2.8.3"
+        }
+      },
       {
         "package": "GoogleAppMeasurement",
         "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git",
@@ -78,8 +105,8 @@
         "repositoryURL": "https://github.com/google/GoogleUtilities.git",
         "state": {
           "branch": null,
-          "revision": "797005ad8a1f0614063933e2fa010a5d13cb09d0",
-          "version": "7.6.0"
+          "revision": "b3bb0c5551fb3f80ca939829639ab5b093edd14f",
+          "version": "7.7.0"
         }
       },
       {
@@ -101,21 +128,21 @@
         }
       },
       {
-        "package": "IHProgressHUD",
-        "repositoryURL": "https://github.com/marinofaggiana/IHProgressHUD",
+        "package": "NCCommunication",
+        "repositoryURL": "https://github.com/nextcloud/ios-communication-library/",
         "state": {
-          "branch": "master",
-          "revision": "a3d94dfb869ff9b2f9e5a4d0359a73a625072853",
-          "version": null
+          "branch": null,
+          "revision": "c7aabb42f734f30c2e325dec4000c59349f33005",
+          "version": "0.99.4"
         }
       },
       {
-        "package": "NCCommunication",
-        "repositoryURL": "https://github.com/nextcloud/ios-communication-library/",
+        "package": "JGProgressHUD",
+        "repositoryURL": "https://github.com/JonasGessner/JGProgressHUD.git",
         "state": {
           "branch": null,
-          "revision": "c8e3eac61a846775d570b1d252612a8d2d02930d",
-          "version": "0.99.3"
+          "revision": "78d7cd35f1d90ff74fd82e486f2cbe4b24be8cf9",
+          "version": "2.2.0"
         }
       },
       {
@@ -156,10 +183,10 @@
       },
       {
         "package": "Parchment",
-        "repositoryURL": "https://github.com/marinofaggiana/Parchment",
+        "repositoryURL": "https://github.com/rechsteiner/Parchment",
         "state": {
-          "branch": "master",
-          "revision": "f4081dbd1a1793217686a381330e90b6626710c7",
+          "branch": "main",
+          "revision": "cad6924f8a292eecaedc1bdefb57006f7979b9eb",
           "version": null
         }
       },
@@ -181,6 +208,15 @@
           "version": "10.1.1"
         }
       },
+      {
+        "package": "Queuer",
+        "repositoryURL": "https://github.com/FabrizioBrancati/Queuer",
+        "state": {
+          "branch": null,
+          "revision": "52515108d0ac4616d9e15ffcc7ad986e300d31ff",
+          "version": "2.1.1"
+        }
+      },
       {
         "package": "QuickLayout",
         "repositoryURL": "https://github.com/huri000/QuickLayout",
@@ -191,21 +227,21 @@
         }
       },
       {
-        "package": "Realm",
-        "repositoryURL": "https://github.com/realm/realm-cocoa",
+        "package": "RealmDatabase",
+        "repositoryURL": "https://github.com/realm/realm-core",
         "state": {
           "branch": null,
-          "revision": "f483fa0a52f6d49897d133a827510a35e21183c1",
-          "version": "10.20.1"
+          "revision": "6b81f1a7a2d421f9e0b9e7f04e76bcf736a54409",
+          "version": "11.9.0"
         }
       },
       {
-        "package": "RealmDatabase",
-        "repositoryURL": "https://github.com/realm/realm-core",
+        "package": "Realm",
+        "repositoryURL": "https://github.com/realm/realm-swift",
         "state": {
           "branch": null,
-          "revision": "c3c11a841642ac93c27bd1edd61f989fc0bfb809",
-          "version": "11.6.1"
+          "revision": "9dff9f2862240d521ad6ad599541269177ddb993",
+          "version": "10.22.0"
         }
       },
       {
@@ -270,6 +306,33 @@
           "revision": "d7a1d23f04c86c1cd2e8f19247dd15d74e0ea8be",
           "version": "5.6.0"
         }
+      },
+      {
+        "package": "TLPhotoPicker",
+        "repositoryURL": "https://github.com/tilltue/TLPhotoPicker",
+        "state": {
+          "branch": null,
+          "revision": "0d0cbbd2d20ed5fd36e5f4052209f5e2d9aaa8b7",
+          "version": "2.1.9"
+        }
+      },
+      {
+        "package": "UICKeyChainStore",
+        "repositoryURL": "https://github.com/kishikawakatsumi/UICKeyChainStore",
+        "state": {
+          "branch": "master",
+          "revision": "db869212bc69b6198a62efe03e2f5fc8e19c6b65",
+          "version": null
+        }
+      },
+      {
+        "package": "XLForm",
+        "repositoryURL": "https://github.com/xmartlabs/XLForm",
+        "state": {
+          "branch": null,
+          "revision": "870afc56602fd518e33d0b271371a2d5acd410ea",
+          "version": "4.3.0"
+        }
       }
     ]
   },

+ 1 - 1
README.md

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

+ 17 - 8
Share/MainInterface.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EAU-PF-EEd">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="EAU-PF-EEd">
     <device id="retina6_5" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -46,39 +46,42 @@
                                         <rect key="frame" x="10" y="70" width="394" height="220"/>
                                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                                         <prototypes>
-                                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="Cell" rowHeight="50" id="6Kt-n0-i8J">
-                                                <rect key="frame" x="0.0" y="24.333333969116211" width="394" height="50"/>
+                                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="Cell" rowHeight="50" id="6Kt-n0-i8J" customClass="NCShareCell" customModule="Share" customModuleProvider="target">
+                                                <rect key="frame" x="0.0" y="44.666666030883789" width="394" height="50"/>
                                                 <autoresizingMask key="autoresizingMask"/>
                                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="6Kt-n0-i8J" id="WGN-Zn-lR8">
                                                     <rect key="frame" x="0.0" y="0.0" width="394" height="50"/>
                                                     <autoresizingMask key="autoresizingMask"/>
                                                     <subviews>
-                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="10" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="uvl-De-S9p">
+                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="uvl-De-S9p">
                                                             <rect key="frame" x="10" y="5" width="40" height="40"/>
                                                             <constraints>
                                                                 <constraint firstAttribute="width" constant="40" id="Vpb-6e-ta9"/>
                                                                 <constraint firstAttribute="height" constant="40" id="wvf-Ey-woY"/>
                                                             </constraints>
                                                         </imageView>
-                                                        <label opaque="NO" userInteractionEnabled="NO" tag="20" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="filename" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rz6-pe-DB5">
+                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="filename" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rz6-pe-DB5">
                                                             <rect key="frame" x="60" y="10" width="284" height="17"/>
                                                             <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                                             <nil key="textColor"/>
                                                             <nil key="highlightedColor"/>
                                                         </label>
-                                                        <label opaque="NO" userInteractionEnabled="NO" tag="40" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="size" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QFh-Vy-b4Z">
+                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="size" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QFh-Vy-b4Z">
                                                             <rect key="frame" x="60" y="29.999999999999996" width="284" height="14.333333333333332"/>
                                                             <fontDescription key="fontDescription" type="system" pointSize="12"/>
                                                             <color key="textColor" systemColor="systemGray2Color"/>
                                                             <nil key="highlightedColor"/>
                                                         </label>
-                                                        <button opaque="NO" tag="30" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OGY-95-ZYi" customClass="NCShareExtensionButtonWithIndexPath" customModule="Share" customModuleProvider="target">
+                                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OGY-95-ZYi">
                                                             <rect key="frame" x="354" y="10" width="30" height="30"/>
                                                             <constraints>
                                                                 <constraint firstAttribute="height" constant="30" id="QqR-Uw-RnV"/>
                                                                 <constraint firstAttribute="width" constant="30" id="bpm-t5-3HA"/>
                                                             </constraints>
                                                             <state key="normal" image="more"/>
+                                                            <connections>
+                                                                <action selector="buttonTapped:" destination="6Kt-n0-i8J" eventType="touchUpInside" id="Xx7-1X-AhZ"/>
+                                                            </connections>
                                                         </button>
                                                     </subviews>
                                                     <constraints>
@@ -95,6 +98,12 @@
                                                     </constraints>
                                                 </tableViewCellContentView>
                                                 <inset key="separatorInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                                <connections>
+                                                    <outlet property="fileNameCell" destination="rz6-pe-DB5" id="e8w-G7-bBe"/>
+                                                    <outlet property="imageCell" destination="uvl-De-S9p" id="S4F-TD-YGI"/>
+                                                    <outlet property="moreButton" destination="OGY-95-ZYi" id="vA3-mU-S1e"/>
+                                                    <outlet property="sizeCell" destination="QFh-Vy-b4Z" id="rmM-qr-QXU"/>
+                                                </connections>
                                             </tableViewCell>
                                         </prototypes>
                                         <connections>

+ 82 - 0
Share/NCShareCell.swift

@@ -0,0 +1,82 @@
+//
+//  NCShareCell.swift
+//  Share
+//
+//  Created by Henrik Storch on 29.12.21.
+//  Copyright © 2021 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import UIKit
+import NCCommunication
+
+protocol NCShareCellDelegate: AnyObject {
+    var uploadStarted: Bool { get }
+    func removeFile(named fileName: String)
+    func renameFile(named fileName: String)
+}
+
+class NCShareCell: UITableViewCell {
+    @IBOutlet weak var imageCell: UIImageView!
+    @IBOutlet weak var fileNameCell: UILabel!
+    @IBOutlet weak var moreButton: UIButton!
+    @IBOutlet weak var sizeCell: UILabel!
+    weak var delegate: (NCShareCellDelegate & UIViewController)?
+    var fileName = ""
+
+    func setup(fileName: String) {
+        self.fileName = fileName
+        let resultInternalType = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: "", directory: false)
+
+        backgroundColor = NCBrandColor.shared.systemBackground
+        imageCell?.layer.cornerRadius = 6
+        imageCell?.layer.masksToBounds = true
+
+        if let image = UIImage.downsample(imageAt: URL(fileURLWithPath: NSTemporaryDirectory() + fileName), to: CGSize(width: 80, height: 80)) {
+            imageCell.image = image
+        } else {
+            if !resultInternalType.iconName.isEmpty {
+                imageCell?.image = UIImage(named: resultInternalType.iconName)
+            } else {
+                imageCell?.image = NCBrandColor.cacheImages.file
+            }
+        }
+
+        fileNameCell?.text = fileName
+
+        let fileSize = NCUtilityFileSystem.shared.getFileSize(filePath: (NSTemporaryDirectory() + fileName))
+        sizeCell?.text = CCUtility.transformedSize(fileSize)
+
+        moreButton?.setImage(NCUtility.shared.loadImage(named: "more").image(color: NCBrandColor.shared.label, size: 15), for: .normal)
+    }
+
+    @IBAction func buttonTapped(_ sender: Any) {
+        guard !fileName.isEmpty, delegate?.uploadStarted != true else { return }
+        let alertController = UIAlertController(title: "", message: fileName, preferredStyle: .alert)
+
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_rename_file_", comment: ""), style: .default) { _ in
+            self.delegate?.renameFile(named: self.fileName)
+        })
+
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_file_", comment: ""), style: .default) { _ in
+            self.delegate?.removeFile(named: self.fileName)
+        })
+
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { _ in })
+        delegate?.present(alertController, animated: true, completion: nil)
+    }
+}

+ 180 - 0
Share/NCShareExtension+DataSource.swift

@@ -0,0 +1,180 @@
+//
+//  NCShareExtension+DataSource.swift
+//  Share
+//
+//  Created by Henrik Storch on 29.12.21.
+//  Copyright © 2021 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import UIKit
+import NCCommunication
+
+// MARK: - Collection View (target folder)
+
+extension NCShareExtension: UICollectionViewDelegate {
+
+    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        guard let metadata = dataSource.cellForItemAt(indexPath: indexPath),
+              let serverUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName) else {
+                  return showAlert(description: "_invalid_url_")
+              }
+
+        if metadata.e2eEncrypted && !CCUtility.isEnd(toEndEnabled: activeAccount.account) {
+            showAlert(title: "_info_", description: "_e2e_goto_settings_for_enable_")
+        }
+
+        self.serverUrl = serverUrl
+        reloadDatasource(withLoadFolder: true)
+        setNavigationBar(navigationTitle: metadata.fileNameView)
+    }
+}
+
+extension NCShareExtension: UICollectionViewDataSource {
+
+    func numberOfSections(in collectionView: UICollectionView) -> Int {
+        return 1
+    }
+
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        let numberOfItems = dataSource.numberOfItems()
+        emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section)
+        return numberOfItems
+    }
+
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+
+        guard let metadata = dataSource.cellForItemAt(indexPath: indexPath), let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as? NCListCell else {
+            return UICollectionViewCell()
+        }
+
+        cell.delegate = self
+
+        cell.fileObjectId = metadata.ocId
+        cell.fileUser = metadata.ownerId
+        cell.labelTitle.text = metadata.fileNameView
+        cell.labelTitle.textColor = NCBrandColor.shared.label
+
+        cell.imageSelect.image = nil
+        cell.imageStatus.image = nil
+        cell.imageLocal.image = nil
+        cell.imageFavorite.image = nil
+        cell.imageShared.image = nil
+        cell.imageMore.image = nil
+        cell.imageItem.image = nil
+        cell.imageItem.backgroundColor = nil
+
+        cell.progressView.progress = 0.0
+
+        if metadata.directory {
+            setupDirectoryCell(cell, with: metadata)
+        }
+
+        // image Favorite
+        if metadata.favorite {
+            cell.imageFavorite.image = NCBrandColor.cacheImages.favorite
+        }
+
+        cell.imageSelect.isHidden = true
+        cell.backgroundView = nil
+        cell.hideButtonMore(true)
+        cell.hideButtonShare(true)
+        cell.selectMode(false)
+
+        // Live Photo
+        if metadata.livePhoto {
+            cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto
+        }
+
+        // Remove last separator
+        cell.separator.isHidden = collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1
+
+        return cell
+    }
+
+    func setupDirectoryCell(_ cell: NCListCell, with metadata: tableMetadata) {
+        var isShare = false
+        var isMounted = false
+        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)
+        }
+
+        var tableShare: tableShare?
+        if dataSource.metadataShare[metadata.ocId] != nil {
+            tableShare = dataSource.metadataShare[metadata.ocId]
+        }
+
+        if metadata.e2eEncrypted {
+            cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted
+        } else if isShare {
+            cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe
+        } else if tableShare != nil && tableShare?.shareType != 3 {
+            cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe
+        } else if tableShare != nil && tableShare?.shareType == 3 {
+            cell.imageItem.image = NCBrandColor.cacheImages.folderPublic
+        } else if metadata.mountType == "group" {
+            cell.imageItem.image = NCBrandColor.cacheImages.folderGroup
+        } else if isMounted {
+            cell.imageItem.image = NCBrandColor.cacheImages.folderExternal
+        } else if metadata.fileName == autoUploadFileName && metadata.serverUrl == autoUploadDirectory {
+            cell.imageItem.image = NCBrandColor.cacheImages.folderAutomaticUpload
+        } else {
+            cell.imageItem.image = NCBrandColor.cacheImages.folder
+        }
+
+        cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date)
+
+        let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)!
+        let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account, lockServerUrl))
+
+        // Local image: offline
+        if tableDirectory != nil && tableDirectory!.offline {
+            cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag
+        }
+    }
+}
+
+// MARK: - Table View (uploading files)
+
+extension NCShareExtension: UITableViewDelegate {
+
+    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        return heightRowTableView
+    }
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        guard !uploadStarted else { return }
+        let fileName = filesName[indexPath.row]
+        renameFile(named: fileName)
+    }
+}
+
+extension NCShareExtension: UITableViewDataSource {
+
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        filesName.count
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? NCShareCell else { return UITableViewCell() }
+        let fileName = filesName[indexPath.row]
+        cell.setup(fileName: fileName)
+        cell.delegate = self
+        return cell
+    }
+}

+ 215 - 0
Share/NCShareExtension+Files.swift

@@ -0,0 +1,215 @@
+//
+//  NCShareExtension+Files.swift
+//  Share
+//
+//  Created by Henrik Storch on 29.12.21.
+//  Copyright © 2021 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import Foundation
+
+extension NCShareExtension {
+
+    @objc func reloadDatasource(withLoadFolder: Bool) {
+
+        layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl)
+
+        let metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND directory == true", activeAccount.account, serverUrl))
+        self.dataSource = NCDataSource(
+            metadatasSource: metadatasSource,
+            sort: layoutForView?.sort,
+            ascending: layoutForView?.ascending,
+            directoryOnTop: layoutForView?.directoryOnTop,
+            favoriteOnTop: true,
+            filterLivePhoto: true)
+
+        if withLoadFolder {
+            loadFolder()
+        } else {
+            self.refreshControl.endRefreshing()
+        }
+
+        collectionView.reloadData()
+    }
+
+    func createFolder(with fileName: String) {
+
+        NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { errorCode, errorDescription in
+
+            DispatchQueue.main.async {
+                if errorCode == 0 {
+
+                    self.serverUrl += "/" + fileName
+                    self.reloadDatasource(withLoadFolder: true)
+                    self.setNavigationBar(navigationTitle: fileName)
+
+                } else {
+                    self.showAlert(title: "_error_createsubfolders_upload_", description: errorDescription)
+                }
+            }
+        }
+    }
+
+    func loadFolder() {
+
+        networkInProgress = true
+        collectionView.reloadData()
+
+        NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { _, metadataFolder, _, _, _, _, errorCode, errorDescription in
+
+            DispatchQueue.main.async {
+                if errorCode != 0 {
+                    self.showAlert(description: errorDescription)
+                }
+                self.networkInProgress = false
+                self.metadataFolder = metadataFolder
+                self.reloadDatasource(withLoadFolder: false)
+            }
+        }
+    }
+}
+
+class NCFilesExtensionHandler {
+    var itemsProvider: [NSItemProvider] = []
+    lazy var filesName: [String] = []
+    let dateFormatter: DateFormatter = {
+        let formatter = DateFormatter()
+        formatter.dateFormat = "yyyy-MM-dd HH-mm-ss-"
+        return formatter
+    }()
+
+    @discardableResult
+    init(items: [NSExtensionItem], completion: @escaping ([String]) -> Void) {
+        CCUtility.emptyTemporaryDirectory()
+        var counter = 0
+
+        self.itemsProvider = items.compactMap({ $0.attachments }).flatMap { $0.filter({
+            $0.hasItemConformingToTypeIdentifier(kUTTypeItem as String) || $0.hasItemConformingToTypeIdentifier("public.url")
+        }) }
+
+        for (ix, provider) in itemsProvider.enumerated() {
+            provider.loadItem(forTypeIdentifier: provider.typeIdentifier) { [self] item, error in
+                defer {
+                    counter += 1
+                    if counter == itemsProvider.count { completion(self.filesName) }
+                }
+                guard error == nil else { return }
+                var originalName = (dateFormatter.string(from: Date())) + String(ix)
+
+                if let url = item as? URL, url.isFileURL, !url.lastPathComponent.isEmpty {
+                    originalName = url.lastPathComponent
+                }
+
+                var fileName: String?
+                switch item {
+                case let image as UIImage:
+                    fileName = getItem(image: image, fileName: originalName)
+                case let url as URL:
+                    fileName = getItem(url: url, fileName: originalName)
+                case let data as Data:
+                    fileName = getItem(data: data, fileName: originalName, provider: provider)
+                case let text as String:
+                    fileName = getItem(string: text, fileName: originalName)
+                default: return
+                }
+
+                if let fileName = fileName, !filesName.contains(fileName) { filesName.append(fileName) }
+            }
+        }
+    }
+
+    // Image
+    func getItem(image: UIImage, fileName: String) -> String? {
+        var fileUrl = URL(fileURLWithPath: NSTemporaryDirectory() + fileName)
+        if fileUrl.pathExtension.isEmpty { fileUrl.appendPathExtension("png") }
+        guard let pngImageData = image.pngData(),
+              (try? pngImageData.write(to: fileUrl, options: [.atomic])) != nil
+        else { return nil }
+        return fileUrl.lastPathComponent
+    }
+
+    // URL
+    // Does not work for directories
+    func getItem(url: URL, fileName: String) -> String? {
+        var fileName = fileName
+        guard url.isFileURL else {
+            guard !filesName.contains(url.lastPathComponent) else { return nil }
+            if !url.deletingPathExtension().lastPathComponent.isEmpty { fileName = url.deletingPathExtension().lastPathComponent }
+            fileName += "." + (url.pathExtension.isEmpty ? "html" : url.pathExtension)
+            let filenamePath = NSTemporaryDirectory() + fileName
+
+            do {
+                let downloadedContent = try Data(contentsOf: url)
+                guard !FileManager.default.fileExists(atPath: filenamePath) else { return nil }
+                try downloadedContent.write(to: URL(fileURLWithPath: filenamePath))
+            } catch { print(error); return nil }
+            return fileName
+        }
+
+        let filenamePath = NSTemporaryDirectory() + fileName
+
+        try? FileManager.default.removeItem(atPath: filenamePath)
+
+        do {
+            try FileManager.default.copyItem(atPath: url.path, toPath: filenamePath)
+
+            let attr = try FileManager.default.attributesOfItem(atPath: filenamePath)
+            guard !attr.isEmpty else { return nil }
+            return fileName
+        } catch { return nil }
+    }
+
+    // Data
+    func getItem(data: Data, fileName: String, provider: NSItemProvider) -> String? {
+        guard !data.isEmpty else { return nil }
+        var fileName = fileName
+
+        if let url = URL(string: fileName), !url.pathExtension.isEmpty {
+            fileName = url.lastPathComponent
+        } else if let name = provider.suggestedName {
+            fileName = name
+        } else if let ext = provider.registeredTypeIdentifiers.last?.split(separator: ".").last {
+            fileName += "." + ext
+        } // else: no file information, use default name without ext
+
+        // when sharing images in safari only data is retuned.
+        // also, when sharing option "Automatic" is slected extension will return both raw data and a url, which will be downloaded, causing the image to appear twice with different names
+        if let image = UIImage(data: data) {
+            return getItem(image: image, fileName: fileName)
+        }
+
+        let filenamePath = NSTemporaryDirectory() + fileName
+        FileManager.default.createFile(atPath: filenamePath, contents: data, attributes: nil)
+        return fileName
+    }
+
+    // String
+    func getItem(string: String, fileName: String) -> String? {
+        guard !string.isEmpty else { return nil }
+        let filenamePath = NSTemporaryDirectory() + fileName + ".txt"
+        FileManager.default.createFile(atPath: filenamePath, contents: string.data(using: String.Encoding.utf8), attributes: nil)
+        return fileName
+    }
+}
+
+extension NSItemProvider {
+    var typeIdentifier: String {
+        if hasItemConformingToTypeIdentifier("public.url") { return "public.url" } else
+        if hasItemConformingToTypeIdentifier(kUTTypeItem as String) { return kUTTypeItem as String } else { return "" }
+    }
+}

+ 159 - 0
Share/NCShareExtension+NCDelegate.swift

@@ -0,0 +1,159 @@
+//
+//  NCShareExtension.swift
+//  Share
+//
+//  Created by Marino Faggiana on 04.01.2022.
+//  Copyright © 2022 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import NCCommunication
+import UIKit
+
+extension NCShareExtension: NCEmptyDataSetDelegate, NCAccountRequestDelegate {
+    // MARK: - Empty
+
+    func emptyDataSetView(_ view: NCEmptyView) {
+
+        if networkInProgress {
+            view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
+            view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
+            view.emptyDescription.text = ""
+        } else {
+            view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
+            view.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "")
+            view.emptyDescription.text = ""
+        }
+    }
+
+    // MARK: - Account
+
+    func showAccountPicker() {
+        let accounts = NCManageDatabase.shared.getAllAccountOrderAlias()
+        guard accounts.count > 1,
+              let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest else { return }
+
+        // Only here change the active account
+        for account in accounts {
+            account.active = account.account == self.activeAccount.account
+        }
+
+        vcAccountRequest.activeAccount = self.activeAccount
+        vcAccountRequest.accounts = accounts.sorted { sorg, dest -> Bool in
+            return sorg.active && !dest.active
+        }
+        vcAccountRequest.enableTimerProgress = false
+        vcAccountRequest.enableAddAccount = false
+        vcAccountRequest.delegate = self
+        vcAccountRequest.dismissDidEnterBackground = true
+
+        let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height / 5)
+        let height = min(CGFloat(accounts.count * Int(vcAccountRequest.heightCell) + 45), screenHeighMax)
+
+        let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height + 20)
+
+        self.present(popup, animated: true)
+    }
+
+    func accountRequestChangeAccount(account: String) {
+        guard let activeAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else {
+            cancel(with: NCShareExtensionError.noAccount)
+            return
+        }
+        self.activeAccount = activeAccount
+
+        // NETWORKING
+        NCCommunicationCommon.shared.setup(
+            account: activeAccount.account,
+            user: activeAccount.user,
+            userId: activeAccount.userId,
+            password: CCUtility.getPassword(activeAccount.account),
+            urlBase: activeAccount.urlBase,
+            userAgent: CCUtility.getUserAgent(),
+            webDav: NCUtilityFileSystem.shared.getWebDAV(account: activeAccount.account),
+            nextcloudVersion: 0,
+            delegate: NCNetworking.shared)
+
+        // get auto upload folder
+        autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName()
+        autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: activeAccount.urlBase, account: activeAccount.account)
+
+        serverUrl = NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account)
+
+        layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl)
+
+        reloadDatasource(withLoadFolder: true)
+        setNavigationBar(navigationTitle: NCBrandOptions.shared.brand)
+    }
+}
+
+extension NCShareExtension: NCShareCellDelegate, NCRenameFileDelegate, NCListCellDelegate {
+
+    func removeFile(named fileName: String) {
+        guard let index = self.filesName.firstIndex(of: fileName) else {
+            return showAlert(title: "_file_not_found_", description: fileName)
+        }
+        self.filesName.remove(at: index)
+        if self.filesName.isEmpty {
+            cancel(with: NCShareExtensionError.noFiles)
+        } else {
+            self.setCommandView()
+        }
+    }
+
+    func renameFile(named fileName: String) {
+        guard let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile else { return }
+
+        let resultInternalType = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: "", directory: false)
+        vcRename.delegate = self
+        vcRename.fileName = fileName
+        if let previewImage = UIImage.downsample(imageAt: URL(fileURLWithPath: NSTemporaryDirectory() + fileName), to: CGSize(width: 140, height: 140)) {
+            vcRename.imagePreview = previewImage
+        } else {
+            vcRename.imagePreview = UIImage(named: resultInternalType.iconName) ?? NCBrandColor.cacheImages.file
+        }
+
+        let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
+
+        self.present(popup, animated: true)
+    }
+
+    func rename(fileName: String, fileNameNew: String) {
+        guard fileName != fileNameNew else { return }
+        guard let fileIx = self.filesName.firstIndex(of: fileName),
+              !self.filesName.contains(fileNameNew),
+              NCUtilityFileSystem.shared.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: (NSTemporaryDirectory() + fileNameNew)) else {
+                  return showAlert(title: "_single_file_conflict_title_", description: "'\(fileName)' -> '\(fileNameNew)'")
+              }
+
+        filesName[fileIx] = fileNameNew
+        tableView.reloadData()
+    }
+}
+
+extension NCShareExtension: NCCreateFormUploadConflictDelegate {
+    func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
+        guard let metadatas = metadatas else {
+            uploadStarted = false
+            uploadMetadata.removeAll()
+            return
+        }
+
+        self.uploadMetadata.append(contentsOf: metadatas)
+        self.upload()
+    }
+}

+ 157 - 766
Share/NCShareExtension.swift

@@ -1,11 +1,13 @@
 //
 //  NCShareExtension.swift
-//  Nextcloud
+//  Share
 //
 //  Created by Marino Faggiana on 20/04/2021.
 //  Copyright © 2021 Marino Faggiana. All rights reserved.
+//  Copyright © 2021 Henrik Storch. All rights reserved.
 //
 //  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//  Author Henrik Storch <henrik.storch@nextcloud.com>
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -23,9 +25,13 @@
 
 import UIKit
 import NCCommunication
-import IHProgressHUD
+import JGProgressHUD
 
-class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDelegate, NCRenameFileDelegate, NCAccountRequestDelegate {
+enum NCShareExtensionError: Error {
+    case cancel, fileUpload, noAccount, noFiles
+}
+
+class NCShareExtension: UIViewController {
 
     @IBOutlet weak var collectionView: UICollectionView!
     @IBOutlet weak var tableView: UITableView!
@@ -38,7 +44,6 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
     @IBOutlet weak var createFolderView: UIView!
     @IBOutlet weak var createFolderImage: UIImageView!
     @IBOutlet weak var createFolderLabel: UILabel!
-
     @IBOutlet weak var uploadView: UIView!
     @IBOutlet weak var uploadImage: UIImageView!
     @IBOutlet weak var uploadLabel: UILabel!
@@ -48,26 +53,25 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
     var filesName: [String] = []
     // -------------------------------------------------------------
 
-    private var emptyDataSet: NCEmptyDataSet?
-    private let keyLayout = NCGlobal.shared.layoutViewShareExtension
-    private var metadataFolder: tableMetadata?
-    private var networkInProgress = false
-    private var dataSource = NCDataSource()
-
-    private var layoutForView: NCGlobal.layoutForViewType?
-
-    private var heightRowTableView: CGFloat = 50
-    private var heightCommandView: CGFloat = 170
-
-    private var autoUploadFileName = ""
-    private var autoUploadDirectory = ""
-
-    private let refreshControl = UIRefreshControl()
-    private var activeAccount: tableAccount!
-    private let chunckSize = CCUtility.getChunkSize() * 1000000
-
-    private var numberFilesName: Int = 0
-    private var counterUpload: Int = 0
+    var emptyDataSet: NCEmptyDataSet?
+    let keyLayout = NCGlobal.shared.layoutViewShareExtension
+    var metadataFolder: tableMetadata?
+    var networkInProgress = false
+    var dataSource = NCDataSource()
+    var layoutForView: NCGlobal.layoutForViewType?
+    let heightRowTableView: CGFloat = 50
+    let heightCommandView: CGFloat = 170
+    var autoUploadFileName = ""
+    var autoUploadDirectory = ""
+    let refreshControl = UIRefreshControl()
+    var activeAccount: tableAccount!
+    let chunckSize = CCUtility.getChunkSize() * 1000000
+    var progress: CGFloat = 0
+    var counterUploaded: Int = 0
+    var uploadErrors: [tableMetadata] = []
+    var uploadMetadata: [tableMetadata] = []
+    var uploadStarted = false
+    let hud = JGProgressHUD()
 
     // MARK: - View Life Cycle
 
@@ -76,36 +80,31 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
 
         self.navigationController?.navigationBar.prefersLargeTitles = false
 
-        // Cell
         collectionView.register(UINib(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell")
         collectionView.collectionViewLayout = NCListLayout()
 
-        // Add Refresh Control
         collectionView.addSubview(refreshControl)
         refreshControl.tintColor = NCBrandColor.shared.brandText
         refreshControl.backgroundColor = NCBrandColor.shared.systemBackground
         refreshControl.addTarget(self, action: #selector(reloadDatasource), for: .valueChanged)
 
-        // Command view
         commandView.backgroundColor = NCBrandColor.shared.secondarySystemBackground
         separatorView.backgroundColor = NCBrandColor.shared.separator
         separatorHeightConstraint.constant = 0.5
 
-        // Table view
         tableView.separatorColor = NCBrandColor.shared.separator
         tableView.layer.cornerRadius = 10
         tableView.tableFooterView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 0, height: 1)))
         commandViewHeightConstraint.constant = heightCommandView
 
-        // Create folder
         createFolderView.layer.cornerRadius = 10
         createFolderImage.image = NCUtility.shared.loadImage(named: "folder.badge.plus", color: NCBrandColor.shared.label)
         createFolderLabel.text = NSLocalizedString("_create_folder_", comment: "")
         let createFolderGesture = UITapGestureRecognizer(target: self, action: #selector(actionCreateFolder))
         createFolderView.addGestureRecognizer(createFolderGesture)
 
-        // Upload
         uploadView.layer.cornerRadius = 10
+        
         // uploadImage.image = NCUtility.shared.loadImage(named: "square.and.arrow.up", color: NCBrandColor.shared.label)
         uploadLabel.text = NSLocalizedString("_upload_", comment: "")
         uploadLabel.textColor = .systemBlue
@@ -127,62 +126,37 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
             NCCommunicationCommon.shared.writeLog("Start session with level \(levelLog) " + versionNextcloudiOS)
         }
 
-        // HUD
-        IHProgressHUD.set(viewForExtension: self.view)
-        IHProgressHUD.set(defaultMaskType: .clear)
-        IHProgressHUD.set(minimumDismiss: 0)
-
+        hud.indicatorView = JGProgressHUDRingIndicatorView()
+        if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
+            indicatorView.ringWidth = 1.5
+        }
+        
         NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil)
     }
 
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
+        guard serverUrl.isEmpty else { return }
 
-        if serverUrl == "" {
-
-            if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
-
-                setAccount(account: activeAccount.account)
-                getFilesExtensionContext { filesName in
-
-                    self.filesName = filesName
-                    DispatchQueue.main.async {
-
-                        var saveHtml: [String] = []
-                        var saveOther: [String] = []
-
-                        for fileName in self.filesName {
-                            if (fileName as NSString).pathExtension.lowercased() == "html" {
-                                saveHtml.append(fileName)
-                            } else {
-                                saveOther.append(fileName)
-                            }
-                        }
-
-                        if saveOther.count > 0 && saveHtml.count > 0 {
-                            for file in saveHtml {
-                                self.filesName = self.filesName.filter {$0 != file}
-                            }
-                        }
-
-                        self.setCommandView()
-                    }
-                }
-
-            } else {
-
-                let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_no_active_account_", comment: ""), preferredStyle: .alert)
-                alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
-                    self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
-                }))
-                self.present(alertController, animated: true)
+        guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else {
+            return showAlert(description: "_no_active_account_") {
+                self.cancel(with: .noAccount)
             }
         }
+
+        accountRequestChangeAccount(account: activeAccount.account)
+        guard let inputItems = extensionContext?.inputItems as? [NSExtensionItem] else {
+            cancel(with: .noFiles)
+            return
+        }
+        NCFilesExtensionHandler(items: inputItems) { fileNames in
+            self.filesName = fileNames
+            DispatchQueue.main.async { self.setCommandView() }
+        }
     }
 
     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
         super.viewWillTransition(to: size, with: coordinator)
-
         coordinator.animate(alongsideTransition: nil) { _ in
             self.collectionView?.collectionViewLayout.invalidateLayout()
         }
@@ -190,84 +164,62 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
 
     override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
         super.traitCollectionDidChange(previousTraitCollection)
-
         collectionView.reloadData()
         tableView.reloadData()
     }
 
     // MARK: -
 
-    @objc func triggerProgressTask(_ notification: NSNotification) {
-
-        if let userInfo = notification.userInfo as NSDictionary?, let progressNumber = userInfo["progress"] as? NSNumber {
-
-            let progress = CGFloat(progressNumber.floatValue)
-            let status =  NSLocalizedString("_upload_file_", comment: "") + " \(self.counterUpload) " + NSLocalizedString("_of_", comment: "") + " \(self.numberFilesName)"
-            IHProgressHUD.show(progress: progress, status: status)
-        }
+    func cancel(with error: NCShareExtensionError) {
+        // make sure no uploads are continued
+        uploadStarted = false
+        extensionContext?.cancelRequest(withError: error)
     }
 
-    // MARK: -
-
-    func setAccount(account: String) {
-
-        guard let activeAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else {
-            extensionContext?.completeRequest(returningItems: extensionContext?.inputItems, completionHandler: nil)
-            return
-        }
-        self.activeAccount = activeAccount
-
-        // NETWORKING
-        NCCommunicationCommon.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), webDav: NCUtilityFileSystem.shared.getWebDAV(account: activeAccount.account), nextcloudVersion: 0, delegate: NCNetworking.shared)
-
-        // get auto upload folder
-        autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName()
-        autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: activeAccount.urlBase, account: activeAccount.account)
-
-        serverUrl = NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account)
-
-        layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl)
-
-        reloadDatasource(withLoadFolder: true)
-        setNavigationBar(navigationTitle: NCBrandOptions.shared.brand)
+    func showAlert(title: String = "_error_", description: String, onDismiss: (() -> Void)? = nil) {
+        let alertController = UIAlertController(title: NSLocalizedString(title, comment: ""), message: NSLocalizedString(description, comment: ""), preferredStyle: .alert)
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
+            onDismiss?()
+        }))
+        self.present(alertController, animated: true)
     }
 
+    @objc func triggerProgressTask(_ notification: NSNotification) {
+        guard let progress = notification.userInfo?["progress"] as? Float else { return }
+        hud.progress = progress
+    }
+    
     func setNavigationBar(navigationTitle: String) {
 
         navigationItem.title = navigationTitle
         cancelButton.title = NSLocalizedString("_cancel_", comment: "")
 
         // BACK BUTTON
-
         let backButton = UIButton(type: .custom)
         backButton.setImage(UIImage(named: "back"), for: .normal)
         backButton.tintColor = .systemBlue
         backButton.semanticContentAttribute = .forceLeftToRight
-        backButton.setTitle(" "+NSLocalizedString("_back_", comment: ""), for: .normal)
+        backButton.setTitle(" " + NSLocalizedString("_back_", comment: ""), for: .normal)
         backButton.setTitleColor(.systemBlue, for: .normal)
         backButton.action(for: .touchUpInside) { _ in
-
-            while self.serverUrl.last != "/" {
+            if !self.uploadStarted {
+                while self.serverUrl.last != "/" { self.serverUrl.removeLast() }
                 self.serverUrl.removeLast()
-            }
-            self.serverUrl.removeLast()
 
-            self.reloadDatasource(withLoadFolder: true)
+                self.reloadDatasource(withLoadFolder: true)
 
-            var navigationTitle = (self.serverUrl as NSString).lastPathComponent
-            if NCUtilityFileSystem.shared.getHomeServer(account: self.activeAccount.account) == self.serverUrl {
-                navigationTitle = NCBrandOptions.shared.brand
+                var navigationTitle = (self.serverUrl as NSString).lastPathComponent
+                if NCUtilityFileSystem.shared.getHomeServer(account: self.activeAccount.account) == self.serverUrl {
+                    navigationTitle = NCBrandOptions.shared.brand
+                }
+                self.setNavigationBar(navigationTitle: navigationTitle)
             }
-            self.setNavigationBar(navigationTitle: navigationTitle)
         }
 
-        // PROFILE BUTTON
-
         let image = NCUtility.shared.loadUserImage(
             for: activeAccount.user,
                displayName: activeAccount.displayName,
                userBaseUrl: activeAccount)
-
         let profileButton = UIButton(type: .custom)
         profileButton.setImage(image, for: .normal)
 
@@ -287,100 +239,41 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
         profileButton.semanticContentAttribute = .forceLeftToRight
         profileButton.sizeToFit()
         profileButton.action(for: .touchUpInside) { _ in
-
-            let accounts = NCManageDatabase.shared.getAllAccountOrderAlias()
-            if accounts.count > 1 {
-
-                if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest {
-
-                    // Only here change the active account
-                    for account in accounts {
-                        if account.account == self.activeAccount.account {
-                            account.active = true
-                        } else {
-                            account.active = false
-                        }
-                    }
-
-                    vcAccountRequest.activeAccount = self.activeAccount
-                    vcAccountRequest.accounts = accounts.sorted { sorg, dest -> Bool in
-                        return sorg.active && !dest.active
-                    }
-                    vcAccountRequest.enableTimerProgress = false
-                    vcAccountRequest.enableAddAccount = false
-                    vcAccountRequest.delegate = self
-                    vcAccountRequest.dismissDidEnterBackground = true
-
-                    let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/5)
-                    let numberCell = accounts.count
-                    let height = min(CGFloat(numberCell * Int(vcAccountRequest.heightCell) + 45), screenHeighMax)
-
-                    let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height+20)
-
-                    self.present(popup, animated: true)
-                }
+            if !self.uploadStarted {
+                self.showAccountPicker()
             }
         }
-
-        if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) {
-
-            navigationItem.setLeftBarButtonItems([UIBarButtonItem(customView: profileButton)], animated: true)
-
-        } else {
-
+        var navItems = [UIBarButtonItem(customView: profileButton)]
+        if serverUrl != NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) {
             let space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
             space.width = 20
-
-            navigationItem.setLeftBarButtonItems([UIBarButtonItem(customView: backButton), space, UIBarButtonItem(customView: profileButton)], animated: true)
+            navItems.append(contentsOf: [UIBarButtonItem(customView: backButton), space])
         }
+        navigationItem.setLeftBarButtonItems(navItems, animated: true)
     }
 
     func setCommandView() {
-
-        var counter: CGFloat = 0
-
-        if filesName.count == 0 {
-            self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
+        guard !filesName.isEmpty else {
+            cancel(with: .noFiles)
             return
-        } else {
-            if filesName.count < 3 {
-                counter = CGFloat(filesName.count)
-                self.commandViewHeightConstraint.constant = heightCommandView + (self.heightRowTableView * counter)
-            } else {
-                counter = 3
-                self.commandViewHeightConstraint.constant = heightCommandView + (self.heightRowTableView * counter)
-            }
-            if filesName.count <= 3 {
-                self.tableView.isScrollEnabled = false
-            }
-            // Label upload button
-            numberFilesName = filesName.count
-            uploadLabel.text = NSLocalizedString("_upload_", comment: "") + " \(numberFilesName) " + NSLocalizedString("_files_", comment: "")
-            // Empty
-            emptyDataSet = NCEmptyDataSet(view: collectionView, offset: -50*counter, delegate: self)
-            self.tableView.reloadData()
         }
-    }
-
-    // MARK: - Empty
-
-    func emptyDataSetView(_ view: NCEmptyView) {
+        let counter = min(CGFloat(filesName.count), 3)
+        self.commandViewHeightConstraint.constant = heightCommandView + (self.heightRowTableView * counter)
 
-        if networkInProgress {
-            view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
-            view.emptyDescription.text = ""
-        } else {
-            view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "")
-            view.emptyDescription.text = ""
+        if filesName.count <= 3 {
+            self.tableView.isScrollEnabled = false
         }
+        // Label upload button
+        uploadLabel.text = NSLocalizedString("_upload_", comment: "") + " \(filesName.count) " + NSLocalizedString("_files_", comment: "")
+        // Empty
+        emptyDataSet = NCEmptyDataSet(view: collectionView, offset: -50 * counter, delegate: self)
+        self.tableView.reloadData()
     }
 
     // MARK: ACTION
 
     @IBAction func actionCancel(_ sender: UIBarButtonItem) {
-        extensionContext?.completeRequest(returningItems: extensionContext?.inputItems, completionHandler: nil)
+        cancel(with: .cancel)
     }
 
     @objc func actionCreateFolder() {
@@ -391,609 +284,107 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
             textField.autocapitalizationType = UITextAutocapitalizationType.words
         }
 
-        let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { (_: UIAlertAction) in
+        let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { _ in
             if let fileName = alertController.textFields?.first?.text {
                 self.createFolder(with: fileName)
             }
         }
 
-        let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (_: UIAlertAction) in
-            print("You've pressed cancel button")
-        }
+        let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel)
 
         alertController.addAction(actionSave)
         alertController.addAction(actionCancel)
 
         self.present(alertController, animated: true, completion: nil)
     }
+}
 
+// MARK: - Upload
+extension NCShareExtension {
     @objc func actionUpload() {
+        guard !uploadStarted else { return }
+        guard !filesName.isEmpty else { return showAlert(description: "_files_no_files_") }
 
-        if let fileName = filesName.first {
+        counterUploaded = 0
+        uploadStarted = true
+        uploadErrors = []
 
-            counterUpload += 1
-            filesName.removeFirst()
+        var conflicts: [tableMetadata] = []
+        for fileName in filesName {
             let ocId = NSUUID().uuidString
-            let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!
-
-            if NCUtilityFileSystem.shared.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: filePath) {
-
-                let metadata = NCManageDatabase.shared.createMetadata(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: activeAccount.urlBase, url: "", contentType: "", livePhoto: false)
-
-                metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload
-                metadata.sessionSelector = NCGlobal.shared.selectorUploadFile
-                metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: filePath)
-                metadata.status = NCGlobal.shared.metadataStatusWaitUpload
-
-                // E2EE
-                if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) {
-                    metadata.e2eEncrypted = true
-                }
-
-                // CHUNCK
-                if chunckSize != 0 && metadata.size > chunckSize {
-                    metadata.chunk = true
-                }
-
-                NCNetworking.shared.upload(metadata: metadata) {
-
-                } completion: { errorCode, errorDescription in
-
-                    if errorCode == 0 {
-
-                        self.actionUpload()
-
-                    } else {
-
-                        IHProgressHUD.dismiss()
-
-                        NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocId))
-                        NCManageDatabase.shared.deleteChunks(account: self.activeAccount.account, ocId: ocId)
-
-                        let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert)
-                        alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
-                            self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
-                        }))
-                        self.present(alertController, animated: true)
-                    }
-                }
-            }
-        } else {
-
-            IHProgressHUD.showSuccesswithStatus(NSLocalizedString("_success_", comment: ""))
-
-            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
-                self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
-            }
-        }
-    }
-
-    func rename(fileName: String, fileNameNew: String) {
-
-        if let row = self.filesName.firstIndex(where: {$0 == fileName}) {
-
-            if NCUtilityFileSystem.shared.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: (NSTemporaryDirectory() + fileNameNew)) {
-                filesName[row] = fileNameNew
-                tableView.reloadData()
-            }
-        }
-    }
-
-    func accountRequestChangeAccount(account: String) {
-        setAccount(account: account)
-    }
-}
-
-// MARK: - Collection View
-
-extension NCShareExtension: UICollectionViewDelegate {
-
-    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
-
-        if let metadata = dataSource.cellForItemAt(indexPath: indexPath) {
-            if let serverUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName) {
-
-                if metadata.e2eEncrypted && !CCUtility.isEnd(toEndEnabled: activeAccount.account) {
-                    let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: NSLocalizedString("_e2e_goto_settings_for_enable_", comment: ""), preferredStyle: .alert)
-                    alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
-                    self.present(alertController, animated: true)
-                    return
-                }
-
-                self.serverUrl = serverUrl
-                reloadDatasource(withLoadFolder: true)
-                setNavigationBar(navigationTitle: metadata.fileNameView)
-            }
-        }
-    }
-}
-
-extension NCShareExtension: UICollectionViewDataSource {
-
-    func numberOfSections(in collectionView: UICollectionView) -> Int {
-        return 1
-    }
-
-    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        let numberOfItems = dataSource.numberOfItems()
-        emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section)
-        return numberOfItems
-    }
-
-    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-
-        guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else {
-            return collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell
-        }
-
-        var tableShare: tableShare?
-        var isShare = false
-        var isMounted = false
-
-        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)
-        }
-
-        if dataSource.metadataShare[metadata.ocId] != nil {
-            tableShare = dataSource.metadataShare[metadata.ocId]
-        }
-
-        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell
-        cell.delegate = self
-
-        cell.fileObjectId = metadata.ocId
-        cell.fileUser = metadata.ownerId
-        cell.labelTitle.text = metadata.fileNameView
-        cell.labelTitle.textColor = NCBrandColor.shared.label
-
-        cell.imageSelect.image = nil
-        cell.imageStatus.image = nil
-        cell.imageLocal.image = nil
-        cell.imageFavorite.image = nil
-        cell.imageShared.image = nil
-        cell.imageMore.image = nil
-
-        cell.imageItem.image = nil
-        cell.imageItem.backgroundColor = nil
-
-        cell.progressView.progress = 0.0
-
-        if metadata.directory {
-
-            if metadata.e2eEncrypted {
-                cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted
-            } else if isShare {
-                cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe
-            } else if tableShare != nil && tableShare?.shareType != 3 {
-                cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe
-            } else if tableShare != nil && tableShare?.shareType == 3 {
-                cell.imageItem.image = NCBrandColor.cacheImages.folderPublic
-            } else if metadata.mountType == "group" {
-                cell.imageItem.image = NCBrandColor.cacheImages.folderGroup
-            } else if isMounted {
-                cell.imageItem.image = NCBrandColor.cacheImages.folderExternal
-            } else if metadata.fileName == autoUploadFileName && metadata.serverUrl == autoUploadDirectory {
-                cell.imageItem.image = NCBrandColor.cacheImages.folderAutomaticUpload
+            let toPath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!
+            guard NCUtilityFileSystem.shared.copyFile(atPath: (NSTemporaryDirectory() + fileName), toPath: toPath) else { continue }
+            let metadata = NCManageDatabase.shared.createMetadata(
+                account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId,
+                fileName: fileName, fileNameView: fileName,
+                ocId: ocId,
+                serverUrl: serverUrl, urlBase: activeAccount.urlBase, url: "",
+                contentType: "",
+                livePhoto: false)
+            metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload
+            metadata.sessionSelector = NCGlobal.shared.selectorUploadFileShareExtension
+            metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: toPath)
+            metadata.status = NCGlobal.shared.metadataStatusWaitUpload
+            if NCManageDatabase.shared.getMetadataConflict(account: activeAccount.account, serverUrl: serverUrl, fileName: fileName) != nil {
+                conflicts.append(metadata)
             } else {
-                cell.imageItem.image = NCBrandColor.cacheImages.folder
+                uploadMetadata.append(metadata)
             }
-
-            cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date)
-
-            let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)!
-            let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account, lockServerUrl))
-
-            // Local image: offline
-            if tableDirectory != nil && tableDirectory!.offline {
-                cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag
-            }
-
-        }
-
-        // image Favorite
-        if metadata.favorite {
-            cell.imageFavorite.image = NCBrandColor.cacheImages.favorite
         }
 
-        cell.imageSelect.isHidden = true
-        cell.backgroundView = nil
-        cell.hideButtonMore(true)
-        cell.hideButtonShare(true)
-        cell.selectMode(false)
-
-        // Live Photo
-        if metadata.livePhoto {
-            cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto
-        }
-
-        // Remove last separator
-        if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 {
-            cell.separator.isHidden = true
+        if !conflicts.isEmpty {
+            guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict
+            else { return }
+            conflict.serverUrl = self.serverUrl
+            conflict.metadatasUploadInConflict = conflicts
+            conflict.delegate = self
+            self.present(conflict, animated: true, completion: nil)
         } else {
-            cell.separator.isHidden = false
+            upload()
         }
-
-        return cell
-    }
-}
-
-// MARK: - Table View
-
-extension NCShareExtension: UITableViewDelegate {
-
-    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-        return heightRowTableView
     }
 
-    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-    }
-}
-
-extension NCShareExtension: UITableViewDataSource {
-
-    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-        filesName.count
-    }
-
-    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
-
-        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
-        cell.backgroundColor = NCBrandColor.shared.systemBackground
-
-        let imageCell = cell.viewWithTag(10) as? UIImageView
-        let fileNameCell = cell.viewWithTag(20) as? UILabel
-        let moreButton = cell.viewWithTag(30) as? NCShareExtensionButtonWithIndexPath
-        let sizeCell = cell.viewWithTag(40) as? UILabel
-
-        imageCell?.layer.cornerRadius = 6
-        imageCell?.layer.masksToBounds = true
+    func upload() {
+        guard uploadStarted else { return }
+        guard uploadMetadata.count > counterUploaded else { return finishedUploading() }
+        let metadata = uploadMetadata[counterUploaded]
 
-        let fileName = filesName[indexPath.row]
-        let resultInternalType = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: "", directory: false)
+        // E2EE
+        metadata.e2eEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase)
+        // CHUNCK
+        metadata.chunk = chunckSize != 0 && metadata.size > chunckSize
 
-        if let image = UIImage(contentsOfFile: (NSTemporaryDirectory() + fileName)) {
-            imageCell?.image = image.resizeImage(size: CGSize(width: 80, height: 80), isAspectRation: true)
-        } else {
-            if resultInternalType.iconName.count > 0 {
-                imageCell?.image = UIImage(named: resultInternalType.iconName)
+        hud.textLabel.text = NSLocalizedString("_upload_file_", comment: "") + " \(counterUploaded + 1) " + NSLocalizedString("_of_", comment: "") + " \(filesName.count)"
+        hud.progress = 0
+        hud.show(in: self.view)
+        
+        NCNetworking.shared.upload(metadata: metadata) { } completion: { errorCode, _ in
+            if errorCode == 0 {
+                self.counterUploaded += 1
+                self.upload()
             } else {
-                imageCell?.image = NCBrandColor.cacheImages.file
+                let path = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)!
+                NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
+                NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
+                NCUtilityFileSystem.shared.deleteFile(filePath: path)
+                self.uploadErrors.append(metadata)
             }
         }
-
-        fileNameCell?.text = fileName
-
-        let fileSize = NCUtilityFileSystem.shared.getFileSize(filePath: (NSTemporaryDirectory() + fileName))
-        sizeCell?.text = CCUtility.transformedSize(fileSize)
-
-        moreButton?.setImage(NCUtility.shared.loadImage(named: "more").image(color: NCBrandColor.shared.label, size: 15), for: .normal)
-        moreButton?.indexPath = indexPath
-        moreButton?.fileName = fileName
-        moreButton?.image = imageCell?.image
-        moreButton?.action(for: .touchUpInside, { sender in
-
-            if let fileName = (sender as! NCShareExtensionButtonWithIndexPath).fileName {
-                let alertController = UIAlertController(title: "", message: fileName, preferredStyle: .alert)
-
-                alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .default) { (_: UIAlertAction) in
-                    if let index = self.filesName.firstIndex(of: fileName) {
-
-                        self.filesName.remove(at: index)
-                        if self.filesName.count == 0 {
-                            self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
-                        } else {
-                            self.setCommandView()
-                        }
-                    }
-                })
-
-                alertController.addAction(UIAlertAction(title: NSLocalizedString("_rename_file_", comment: ""), style: .default) { (_: UIAlertAction) in
-
-                    if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile {
-
-                        vcRename.delegate = self
-                        vcRename.fileName = fileName
-                        vcRename.imagePreview = (sender as! NCShareExtensionButtonWithIndexPath).image
-
-                        let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
-
-                        self.present(popup, animated: true)
-                    }
-                })
-
-                alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (_: UIAlertAction) in })
-
-                self.present(alertController, animated: true, completion: nil)
-            }
-        })
-
-        return cell
     }
-}
 
-// MARK: - NC API & Algorithm
-
-extension NCShareExtension {
-
-    @objc func reloadDatasource(withLoadFolder: Bool) {
-
-        layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl)
-
-        let metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND directory == true", activeAccount.account, serverUrl))
-        self.dataSource = NCDataSource(metadatasSource: metadatasSource, sort: layoutForView?.sort, ascending: layoutForView?.ascending, directoryOnTop: layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true)
-
-        if withLoadFolder {
-            loadFolder()
-        } else {
-            self.refreshControl.endRefreshing()
-        }
-
-        collectionView.reloadData()
-    }
-
-    func createFolder(with fileName: String) {
-
-        NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { errorCode, errorDescription in
-
-            DispatchQueue.main.async {
-                if errorCode == 0 {
-
-                    self.serverUrl += "/" + fileName
-                    self.reloadDatasource(withLoadFolder: true)
-                    self.setNavigationBar(navigationTitle: fileName)
-
-                } else {
-
-                    let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert)
-                    alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
-                    self.present(alertController, animated: true)
-                }
+    func finishedUploading() {
+        uploadStarted = false
+        if !uploadErrors.isEmpty {
+            let fileList = "- " + uploadErrors.map({ $0.fileName }).joined(separator: "\n  - ")
+            showAlert(title: "_error_files_upload_", description: fileList) {
+                self.extensionContext?.cancelRequest(withError: NCShareExtensionError.fileUpload)
             }
-        }
-    }
-
-    func loadFolder() {
-
-        networkInProgress = true
-        collectionView.reloadData()
-
-        NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { _, metadataFolder, _, _, _, _, errorCode, errorDescription in
-
-            DispatchQueue.main.async {
-                if errorCode != 0 {
-                    let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert)
-                    alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
-                    self.present(alertController, animated: true)
-                }
-                self.networkInProgress = false
-                self.metadataFolder = metadataFolder
-                self.reloadDatasource(withLoadFolder: false)
-            }
-        }
-    }
-
-    func getFilesExtensionContext(completion: @escaping (_ filesName: [String]) -> Void) {
-
-        var itemsProvider: [NSItemProvider] = []
-        var filesName: [String] = []
-        var conuter = 0
-        let dateFormatter = DateFormatter()
-
-        // ----------------------------------------------------------------------------------------
-
-        // Image
-        func getItem(image: UIImage, fileNameOriginal: String?) {
-
-            var fileName: String = ""
-
-            if let pngImageData = image.pngData() {
-
-                if fileNameOriginal != nil {
-                    fileName =  fileNameOriginal!
-                } else {
-                    fileName = "\(dateFormatter.string(from: Date()))\(conuter).png"
-                }
-
-                let filenamePath = NSTemporaryDirectory() + fileName
-
-                if (try? pngImageData.write(to: URL(fileURLWithPath: filenamePath), options: [.atomic])) != nil {
-                    filesName.append(fileName)
-                }
-            }
-        }
-
-        // URL
-        func getItem(url: NSURL, fileNameOriginal: String?) {
-
-            guard let path = url.path else { return }
-
-            var fileName: String = ""
-
-            if fileNameOriginal != nil {
-                fileName =  fileNameOriginal!
-            } else {
-                if let ext = url.pathExtension {
-                    fileName = "\(dateFormatter.string(from: Date()))\(conuter)." + ext
-                }
-            }
-
-            let filenamePath = NSTemporaryDirectory() + fileName
-
-            do {
-                try FileManager.default.removeItem(atPath: filenamePath)
-            } catch { }
-
-            do {
-                try FileManager.default.copyItem(atPath: path, toPath: filenamePath)
-
-                do {
-                    let attr: NSDictionary? = try FileManager.default.attributesOfItem(atPath: filenamePath) as NSDictionary?
-
-                    if let _attr = attr {
-                        if _attr.fileSize() > 0 {
-                            filesName.append(fileName)
-                        }
-                    }
-
-                } catch { }
-            } catch { }
-        }
-
-        // Data
-        func getItem(data: Data, fileNameOriginal: String?, description: String) {
-
-            var fileName: String = ""
-
-            if data.count > 0 {
-
-                if fileNameOriginal != nil {
-                    fileName =  fileNameOriginal!
-                } else {
-                    let fullNameArr = description.components(separatedBy: "\"")
-                    let fileExtArr = fullNameArr[1].components(separatedBy: ".")
-                    let pathExtention = (fileExtArr[fileExtArr.count-1]).uppercased()
-                    fileName = "\(dateFormatter.string(from: Date()))\(conuter).\(pathExtention)"
-                }
-
-                let filenamePath = NSTemporaryDirectory() + fileName
-                FileManager.default.createFile(atPath: filenamePath, contents: data, attributes: nil)
-                filesName.append(fileName)
-            }
-        }
-
-        // String
-        func getItem(string: NSString, fileNameOriginal: String?) {
-
-            var fileName: String = ""
-
-            if string.length > 0 {
-
-                fileName = "\(dateFormatter.string(from: Date()))\(conuter).txt"
-                let filenamePath = NSTemporaryDirectory() + "\(dateFormatter.string(from: Date()))\(conuter).txt"
-                FileManager.default.createFile(atPath: filenamePath, contents: string.data(using: String.Encoding.utf8.rawValue), attributes: nil)
-                filesName.append(fileName)
-            }
-        }
-
-        // ----------------------------------------------------------------------------------------
-
-        guard let inputItems: [NSExtensionItem] = extensionContext?.inputItems as? [NSExtensionItem] else {
-            return completion(filesName)
-        }
-
-        for item: NSExtensionItem in inputItems {
-            if let attachments = item.attachments {
-                if attachments.isEmpty { continue }
-                for (_, itemProvider) in (attachments.enumerated()) {
-                    if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeItem as String) || itemProvider.hasItemConformingToTypeIdentifier("public.url") {
-                        itemsProvider.append(itemProvider)
-                    }
-                }
-            }
-        }
-
-        CCUtility.emptyTemporaryDirectory()
-        dateFormatter.dateFormat = "yyyy-MM-dd HH-mm-ss-"
-
-        for itemProvider in itemsProvider {
-
-            var typeIdentifier = ""
-            if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeItem as String) { typeIdentifier = kUTTypeItem as String }
-            if itemProvider.hasItemConformingToTypeIdentifier("public.url") { typeIdentifier = "public.url" }
-
-            itemProvider.loadItem(forTypeIdentifier: typeIdentifier, options: nil, completionHandler: {item, error -> Void in
-
-                if error == nil {
-
-                    var fileNameOriginal: String?
-
-                    if let url = item as? NSURL {
-                        if FileManager.default.fileExists(atPath: url.path ?? "") {
-                            fileNameOriginal = url.lastPathComponent!
-                        } else if url.scheme?.lowercased().contains("http") == true {
-                            fileNameOriginal = "\(dateFormatter.string(from: Date()))\(conuter).html"
-                        } else {
-                            fileNameOriginal = "\(dateFormatter.string(from: Date()))\(conuter)"
-                        }
-                    }
-
-                    if let image = item as? UIImage {
-                       getItem(image: image, fileNameOriginal: fileNameOriginal)
-                    }
-
-                    if let url = item as? URL {
-                        getItem(url: url as NSURL, fileNameOriginal: fileNameOriginal)
-                    }
-
-                    if let data = item as? Data {
-                        getItem(data: data, fileNameOriginal: fileNameOriginal, description: itemProvider.description)
-                    }
-
-                    if let string = item as? NSString {
-                        getItem(string: string, fileNameOriginal: fileNameOriginal)
-                    }
-                }
-
-                conuter += 1
-                if conuter == itemsProvider.count {
-                    completion(filesName)
-                }
-            })
-        }
-    }
-}
-
-/*
-let task = URLSession.shared.downloadTask(with: urlitem) { localURL, urlResponse, error in
-    
-    if let localURL = localURL {
-        
-        if fileNameOriginal != nil {
-            fileName =  fileNameOriginal!
         } else {
-            let ext = url.pathExtension
-            fileName = "\(dateFormatter.string(from: Date()))\(conuter)." + ext
-        }
-        
-        let filenamePath = NSTemporaryDirectory() + fileName
-      
-        do {
-            try FileManager.default.removeItem(atPath: filenamePath)
-        }
-        catch { }
-        
-        do {
-            try FileManager.default.copyItem(atPath: localURL.path, toPath:filenamePath)
-            
-            do {
-                let attr : NSDictionary? = try FileManager.default.attributesOfItem(atPath: filenamePath) as NSDictionary?
-                
-                if let _attr = attr {
-                    if _attr.fileSize() > 0 {
-                        
-                        filesName.append(fileName)
-                    }
-                }
-                
-            } catch let error {
-                outError = error
+            hud.indicatorView = JGProgressHUDSuccessIndicatorView()
+            hud.textLabel.text = NSLocalizedString("_success_", comment: "")
+            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
             }
-            
-        } catch let error {
-            outError = error
         }
     }
-    
-    if index + 1 == attachments.count {
-        completion(filesName, outError)
-    }
-}
-task.resume()
-*/
-
-class NCShareExtensionButtonWithIndexPath: UIButton {
-    var indexPath: IndexPath?
-    var fileName: String?
-    var image: UIImage?
 }

+ 7 - 4
iOSClient/AppDelegate.swift

@@ -27,7 +27,6 @@ import NCCommunication
 import TOPasscodeViewController
 import LocalAuthentication
 import Firebase
-import IHProgressHUD
 
 @UIApplicationMain
 class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, TOPasscodeViewControllerDelegate, NCAccountRequestDelegate, NCViewCertificateDetailsDelegate, NCUserBaseUrl {
@@ -211,9 +210,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         if account == "" { return }
         guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return }
 
-        // close HUD
-        IHProgressHUD.dismiss()
-
         // Account changed ??
         if activeAccount.account != account {
             settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account))
@@ -890,3 +886,10 @@ extension AppDelegate: NCAudioRecorderViewControllerDelegate {
     func didFinishWithoutRecording(_ viewController: NCAudioRecorderViewController, fileName: String) {
     }
 }
+
+extension AppDelegate: NCCreateFormUploadConflictDelegate {
+    func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
+        guard let metadatas = metadatas, !metadatas.isEmpty else { return }
+        networkingProcessUpload?.createProcessUploads(metadatas: metadatas)
+    }
+}

+ 0 - 1
iOSClient/Brand/NCBrand.swift

@@ -92,7 +92,6 @@ import UIKit
 
     @objc public var disable_background_color:          Bool = true
     @objc public var disable_background_image:          Bool = true
-    @objc public var disable_ff:                        Bool = true
 
     override init() {
 

+ 7 - 0
iOSClient/Data/NCDatabase.swift

@@ -526,6 +526,13 @@ class tableVideo: Object {
     @objc dynamic var duration: Int64 = 0
     @objc dynamic var ocId = ""
     @objc dynamic var time: Int64 = 0
+    @objc dynamic var codecNameVideo: String?
+    @objc dynamic var codecNameAudio: String?
+    @objc dynamic var codecAudioChannelLayout: String?
+    @objc dynamic var codecAudioLanguage: String?
+    @objc dynamic var codecSubtitleLanguage: String?
+    @objc dynamic var codecMaxCompatibility: Bool = false
+    @objc dynamic var codecQuality: String?
 
     override static func primaryKey() -> String {
         return "ocId"

+ 45 - 0
iOSClient/Data/NCManageDatabase.swift

@@ -1721,6 +1721,51 @@ class NCManageDatabase: NSObject {
             NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
         }
     }
+    
+    func addVideoCodec(metadata: tableMetadata, codecNameVideo: String?, codecNameAudio: String?, codecAudioChannelLayout: String?, codecAudioLanguage: String?, codecSubtitleLanguage: String?, codecMaxCompatibility: Bool, codecQuality: String?) {
+
+        let realm = try! Realm()
+
+        do {
+            try realm.safeWrite {
+                if let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first {
+                    if let codecNameVideo = codecNameVideo { result.codecNameVideo = codecNameVideo }
+                    if let codecNameAudio = codecNameAudio { result.codecNameAudio = codecNameAudio }
+                    if let codecAudioChannelLayout = codecAudioChannelLayout { result.codecAudioChannelLayout = codecAudioChannelLayout }
+                    if let codecAudioLanguage = codecAudioLanguage { result.codecAudioLanguage = codecAudioLanguage }
+                    if let codecSubtitleLanguage = codecSubtitleLanguage { result.codecSubtitleLanguage = codecSubtitleLanguage }
+                    result.codecMaxCompatibility = codecMaxCompatibility
+                    if let codecQuality = codecQuality { result.codecQuality = codecQuality }
+                    realm.add(result, update: .all)
+                } else {
+                    let addObject = tableVideo()
+                    addObject.account = metadata.account
+                    addObject.ocId = metadata.ocId
+                    addObject.codecNameVideo = codecNameVideo
+                    addObject.codecNameAudio = codecNameAudio
+                    addObject.codecAudioChannelLayout = codecAudioChannelLayout
+                    addObject.codecAudioLanguage = codecAudioLanguage
+                    addObject.codecSubtitleLanguage = codecSubtitleLanguage
+                    addObject.codecMaxCompatibility = codecMaxCompatibility
+                    addObject.codecQuality = codecQuality
+                    realm.add(addObject, update: .all)
+                }
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+    
+    func getVideo(metadata: tableMetadata?) -> tableVideo? {
+        guard let metadata = metadata else { return nil }
+        
+        let realm = try! Realm()
+        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
+            return nil
+        }
+        
+        return tableVideo.init(value: result)
+    }
 
     func getVideoDurationTime(metadata: tableMetadata?) -> CMTime? {
         guard let metadata = metadata else { return nil }

+ 31 - 0
iOSClient/Extensions/UIImage+Extensions.swift

@@ -173,4 +173,35 @@ extension UIImage {
         UIGraphicsEndImageContext()
         return newImage
     }
+
+    /// Downsamles a image using ImageIO. Has better memory perfomance than redrawing using UIKit
+    ///
+    /// - [Source](https://swiftsenpai.com/development/reduce-uiimage-memory-footprint/)
+    /// - [Original Source, WWDC18](https://developer.apple.com/videos/play/wwdc2018/416/?time=1352)
+    /// - Parameters:
+    ///   - imageURL: The URL path of the image
+    ///   - pointSize: The target point size
+    ///   - scale: The point to pixel scale (Pixeld per point)
+    /// - Returns: The downsampled image, if successful
+    static func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat = UIScreen.main.scale) -> UIImage? {
+
+        // Create an CGImageSource that represent an image
+        let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
+        guard let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions) else { return nil }
+
+        // Calculate the desired dimension
+        let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
+
+        // Perform downsampling
+        let downsampleOptions = [
+            kCGImageSourceCreateThumbnailFromImageAlways: true,
+            kCGImageSourceShouldCacheImmediately: true,
+            kCGImageSourceCreateThumbnailWithTransform: true,
+            kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels
+        ] as CFDictionary
+        guard let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions) else { return nil }
+
+        // Return the downsampled image as UIImage
+        return UIImage(cgImage: downsampledImage)
+    }
 }

+ 1 - 0
iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift

@@ -463,6 +463,7 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate {
                         conflict.metadatasNOConflict = metadatasNOConflict
                         conflict.metadatasMOV = metadatasMOV
                         conflict.metadatasUploadInConflict = metadatasUploadInConflict
+                        conflict.delegate = self.appDelegate
 
                         self.appDelegate.window?.rootViewController?.present(conflict, animated: true, completion: nil)
                     }

+ 11 - 14
iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift

@@ -58,7 +58,6 @@ extension NCCreateFormUploadConflictDelegate {
     @objc var alwaysNewFileNameNumber: Bool = false
     @objc var textLabelDetailNewFile: String?
 
-    let appDelegate = UIApplication.shared.delegate as! AppDelegate
     var metadatasConflictNewFiles: [String] = []
     var metadatasConflictAlreadyExistingFiles: [String] = []
     var fileNamesPath: [String: String] = [:]
@@ -179,7 +178,9 @@ extension NCCreateFormUploadConflictDelegate {
         }))
 
         conflictAlert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_keep_existing_action_title_", comment: ""), style: .cancel, handler: { _ in
-            self.dismiss(animated: true, completion: nil)
+            self.dismiss(animated: true) {
+                self.delegate?.dismissCreateFormUploadConflict(metadatas: nil)
+            }
         }))
 
         conflictAlert.addAction(UIAlertAction(title: NSLocalizedString("_more_action_title_", comment: ""), style: .default, handler: { _ in
@@ -237,9 +238,9 @@ extension NCCreateFormUploadConflictDelegate {
     }
 
     @IBAction func buttonCancelTouch(_ sender: Any) {
-
-        delegate?.dismissCreateFormUploadConflict(metadatas: nil)
-        dismiss(animated: true)
+        dismiss(animated: true) {
+            self.delegate?.dismissCreateFormUploadConflict(metadatas: nil)
+        }
     }
 
     @IBAction func buttonContinueTouch(_ sender: Any) {
@@ -305,19 +306,15 @@ extension NCCreateFormUploadConflictDelegate {
                 }
 
             } else {
-                print("error")
+                // used UIAlert (replace all)
             }
         }
 
         metadatasNOConflict.append(contentsOf: metadatasMOV)
 
-        if delegate != nil {
-            delegate?.dismissCreateFormUploadConflict(metadatas: metadatasNOConflict)
-        } else {
-            appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatasNOConflict)
+        dismiss(animated: true) {
+            self.delegate?.dismissCreateFormUploadConflict(metadatas: self.metadatasNOConflict)
         }
-
-        dismiss(animated: true)
     }
 }
 
@@ -458,8 +455,8 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
 
                 do {
                     if metadataNewFile.classFile ==  NCCommunicationCommon.typeClassFile.image.rawValue {
-                        let data = try Data(contentsOf: URL(fileURLWithPath: filePathNewFile))
-                        if let image = UIImage(data: data) {
+                        // preserver memory especially for very large files in Share extension
+                        if let image = UIImage.downsample(imageAt: URL(fileURLWithPath: filePathNewFile), to: cell.imageNewFile.frame.size) {
                             cell.imageNewFile.image = image
                         }
                     }

+ 38 - 20
iOSClient/Main/NCFunctionCenter.swift

@@ -24,7 +24,7 @@
 import UIKit
 import NCCommunication
 import Queuer
-import IHProgressHUD
+import JGProgressHUD
 
 @objc class NCFunctionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelectDelegate {
     @objc public static let shared: NCFunctionCenter = {
@@ -361,26 +361,38 @@ import IHProgressHUD
 
         let fileNameImage = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!)
         let fileNameMov = URL(fileURLWithPath: CCUtility.getDirectoryProviderStorageOcId(metadataMov.ocId, fileNameView: metadataMov.fileNameView)!)
-
-        IHProgressHUD.set(defaultMaskType: .clear)
-        IHProgressHUD.set(minimumDismiss: 2)
-
+        let hud = JGProgressHUD()
+        
+        hud.indicatorView = JGProgressHUDRingIndicatorView()
+        if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
+            indicatorView.ringWidth = 1.5
+        }
+        hud.show(in: (appDelegate.window?.rootViewController?.view)!)
+        hud.textLabel.text = NSLocalizedString("_saving_", comment: "")
+        
         NCLivePhoto.generate(from: fileNameImage, videoURL: fileNameMov, progress: { progress in
-
-            IHProgressHUD.show(progress: CGFloat(progress))
+            
+            hud.progress = Float(progress)
 
         }, completion: { _, resources in
 
             if resources != nil {
                 NCLivePhoto.saveToLibrary(resources!) { result in
-                    if !result {
-                        IHProgressHUD.showError(withStatus: NSLocalizedString("_livephoto_save_error_", comment: ""))
-                    } else {
-                        IHProgressHUD.showSuccesswithStatus(NSLocalizedString("_success_", comment: ""))
+                    DispatchQueue.main.async {
+                        if !result {
+                            hud.indicatorView = JGProgressHUDErrorIndicatorView()
+                            hud.textLabel.text = NSLocalizedString("_livephoto_save_error_", comment: "")
+                        } else {
+                            hud.indicatorView = JGProgressHUDSuccessIndicatorView()
+                            hud.textLabel.text = NSLocalizedString("_success_", comment: "")
+                        }
+                        hud.dismiss(afterDelay: 1)
                     }
                 }
             } else {
-                IHProgressHUD.showError(withStatus: NSLocalizedString("_livephoto_save_error_", comment: ""))
+                hud.indicatorView = JGProgressHUDErrorIndicatorView()
+                hud.textLabel.text = NSLocalizedString("_livephoto_save_error_", comment: "")
+                hud.dismiss(afterDelay: 1)
             }
         })
     }
@@ -457,25 +469,31 @@ import IHProgressHUD
                 let ocIdUpload = UUID().uuidString
                 let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(ocIdUpload, fileNameView: fileName)!
                 try data.write(to: URL(fileURLWithPath: fileNameLocalPath))
-
-                IHProgressHUD.set(defaultMaskType: .clear)
-                IHProgressHUD.set(minimumDismiss: 2)
+                let hud = JGProgressHUD()
+                
+                hud.indicatorView = JGProgressHUDRingIndicatorView()
+                if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
+                    indicatorView.ringWidth = 1.5
+                }
+                hud.show(in: (appDelegate.window?.rootViewController?.view)!)
+                hud.textLabel.text = fileName
 
                 NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath) { _ in
                 } progressHandler: { progress in
-
-                    IHProgressHUD.show(progress: CGFloat(progress.fractionCompleted), status: fileName)
-
+                    hud.progress = Float(progress.fractionCompleted)
                 } completionHandler: { account, ocId, etag, _, _, _, errorCode, errorDescription in
                     if errorCode == 0 && etag != nil && ocId != nil {
                         let toPath = CCUtility.getDirectoryProviderStorageOcId(ocId!, fileNameView: fileName)!
                         NCUtilityFileSystem.shared.moveFile(atPath: fileNameLocalPath, toPath: toPath)
                         NCManageDatabase.shared.addLocalFile(account: account, etag: etag!, ocId: ocId!, fileName: fileName)
                         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": serverUrl])
-                        IHProgressHUD.showSuccesswithStatus(NSLocalizedString("_success_", comment: ""))
+                        hud.indicatorView = JGProgressHUDSuccessIndicatorView()
+                        hud.textLabel.text = NSLocalizedString("_success_", comment: "")
                     } else {
-                        IHProgressHUD.showError(withStatus: NSLocalizedString(errorDescription, comment: ""))
+                        hud.indicatorView = JGProgressHUDErrorIndicatorView()
+                        hud.textLabel.text = NSLocalizedString(errorDescription, comment: "")
                     }
+                    hud.dismiss(afterDelay: 1)
                 }
             } catch {
                 return false

+ 1 - 1
iOSClient/Main/NCPickerViewController.swift

@@ -160,7 +160,7 @@ class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
                 if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileName: fileName) != nil {
 
                     if let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict {
-
+                        conflict.delegate = appDelegate
                         conflict.serverUrl = serverUrl
                         conflict.metadatasUploadInConflict = [metadataForUpload]
 

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

@@ -133,7 +133,27 @@ extension NCViewer {
                 )
             )
         }
-
+        
+        //
+        // CONVERSION VIDEO TO MPEG4 (MFFF Lib)
+        //
+        #if MFFFLIB
+        if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue {
+            
+            actions.append(
+                NCMenuAction(
+                    title: NSLocalizedString("_video_conversion_", comment: ""),
+                    icon: NCUtility.shared.loadImage(named: "film"),
+                    action: { menuAction in
+                        if let ncplayer = (viewController as? NCViewerMediaPage)?.currentViewController.ncplayer {
+                            ncplayer.convertVideo()
+                        }
+                    }
+                )
+            )
+        }
+        #endif
+        
         //
         // SAVE IMAGE / VIDEO
         //

+ 2 - 1
iOSClient/NCGlobal.swift

@@ -112,7 +112,7 @@ class NCGlobal: NSObject {
     // Database Realm
     //
     let databaseDefault                             = "nextcloud.realm"
-    let databaseSchemaVersion: UInt64               = 213
+    let databaseSchemaVersion: UInt64               = 215
 
     // Intro selector
     //
@@ -279,6 +279,7 @@ class NCGlobal: NSObject {
     let selectorUploadAutoUpload                    = "uploadAutoUpload"
     let selectorUploadAutoUploadAll                 = "uploadAutoUploadAll"
     let selectorUploadFile                          = "uploadFile"
+    let selectorUploadFileShareExtension            = "uploadFileShareExtension"
     let selectorSaveAlbum                           = "saveAlbum"
     let selectorSaveBackground                      = "saveBackground"
     let selectorSaveAlbumLivePhotoIMG               = "saveAlbumLivePhotoIMG"

+ 41 - 33
iOSClient/Networking/NCNetworking.swift

@@ -411,12 +411,46 @@ import Queuer
     // MARK: - Upload
 
     @objc func upload(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) {
-
-        var metadata = tableMetadata.init(value: metadata)
-        var fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
+        
+        func uploadMetadata(_ metadata: tableMetadata) {
+            
+            NCManageDatabase.shared.addMetadata(metadata)
+            let metadata = tableMetadata.init(value: metadata)
+            
+            if metadata.e2eEncrypted {
+#if !EXTENSION_FILE_PROVIDER_EXTENSION
+                NCNetworkingE2EE.shared.upload(metadata: metadata, start: start) { errorCode, errorDescription in
+                    DispatchQueue.main.async {
+                        completion(errorCode, errorDescription)
+                    }
+                }
+#endif
+            } else if metadata.chunk {
+                uploadChunkedFile(metadata: metadata, start: start) { errorCode, errorDescription in
+                    DispatchQueue.main.async {
+                        completion(errorCode, errorDescription)
+                    }
+                }
+            } else if metadata.session == NCCommunicationCommon.shared.sessionIdentifierUpload {
+                uploadFile(metadata: metadata, start: start) { errorCode, errorDescription in
+                    DispatchQueue.main.async {
+                        completion(errorCode, errorDescription)
+                    }
+                }
+            } else {
+                uploadFileInBackground(metadata: metadata, start: start) { errorCode, errorDescription in
+                    DispatchQueue.main.async {
+                        completion(errorCode, errorDescription)
+                    }
+                }
+            }
+        }
+        
+        let metadata = tableMetadata.init(value: metadata)
 
         if CCUtility.fileProviderStorageExists(metadata.ocId, fileNameView: metadata.fileNameView) {
 
+            let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
             let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: metadata.contentType, directory: false)
             metadata.contentType = results.mimeType
             metadata.iconName = results.iconName
@@ -429,47 +463,21 @@ import Queuer
             }
             metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: fileNameLocalPath)
 
-            NCManageDatabase.shared.addMetadata(metadata)
-            metadata = tableMetadata.init(value: metadata)
-
-            if metadata.e2eEncrypted {
-#if !EXTENSION_FILE_PROVIDER_EXTENSION
-                NCNetworkingE2EE.shared.upload(metadata: tableMetadata.init(value: metadata), start: { start() }, completion: completion)
-#endif
-            } else if metadata.chunk {
-                uploadChunkedFile(metadata: metadata, start: { start() }, completion: completion)
-            } else if metadata.session == NCCommunicationCommon.shared.sessionIdentifierUpload {
-                uploadFile(metadata: metadata, start: { start() }, completion: completion)
-            } else {
-                uploadFileInBackground(metadata: metadata, start: { start() }, completion: completion)
-            }
+            uploadMetadata(metadata)
 
         } else {
 
             CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadata, notification: true) { extractMetadata, fileNamePath in
 
-                guard let extractMetadata = extractMetadata else {
+                guard let metadata = extractMetadata else {
                     NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
                     return completion(NCGlobal.shared.errorInternalError, "Internal error")
                 }
 
-                let metadata = tableMetadata.init(value: extractMetadata)
-                fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(extractMetadata.ocId, fileNameView: extractMetadata.fileNameView)
+                let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
                 NCUtilityFileSystem.shared.moveFileInBackground(atPath: fileNamePath!, toPath: fileNameLocalPath)
 
-                NCManageDatabase.shared.addMetadata(extractMetadata)
-
-                if metadata.e2eEncrypted {
-                    #if !EXTENSION_FILE_PROVIDER_EXTENSION
-                    NCNetworkingE2EE.shared.upload(metadata: extractMetadata, start: { start() }, completion: completion)
-                    #endif
-                } else if metadata.chunk {
-                    self.uploadChunkedFile(metadata: metadata, start: { start() }, completion: completion)
-                } else if metadata.session == NCCommunicationCommon.shared.sessionIdentifierUpload {
-                    self.uploadFile(metadata: metadata, start: { start() }, completion: completion)
-                } else {
-                    self.uploadFileInBackground(metadata: metadata, start: { start() }, completion: completion)
-                }
+                uploadMetadata(metadata)
             }
         }
     }

+ 1 - 1
iOSClient/Networking/NCNetworkingE2EE.swift

@@ -86,7 +86,7 @@ import Alamofire
                                 object.serverUrl = serverUrl
                                 object.version = 1
 
-                                _ = NCManageDatabase.shared.addE2eEncryption(object)
+                                NCManageDatabase.shared.addE2eEncryption(object)
 
                                 self.sendE2EMetadata(account: account, serverUrl: serverUrl, fileNameRename: nil, fileNameNewRename: nil, deleteE2eEncryption: nil, urlBase: urlBase) { e2eToken, errorCode, errorDescription in
                                     // unlock

+ 9 - 0
iOSClient/Networking/NCNetworkingProcessUpload.swift

@@ -242,6 +242,15 @@ class NCNetworkingProcessUpload: NSObject {
 
         var session: URLSession?
 
+        // remove leaning upload share extension
+        let metadatasUploadShareExtension = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "session == %@ AND sessionSelector == %@", NCCommunicationCommon.shared.sessionIdentifierUpload, NCGlobal.shared.selectorUploadFileShareExtension))
+        for metadata in metadatasUploadShareExtension {
+            let path = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)!
+            NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
+            NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
+            NCUtilityFileSystem.shared.deleteFile(filePath: path)
+        }
+        
         // verify metadataStatusInUpload (BACKGROUND)
         let metadatasInUploadBackground = NCManageDatabase.shared.getMetadatas(
             predicate: NSPredicate(

+ 3 - 2
iOSClient/Rename file/NCRenameFile.swift

@@ -219,8 +219,9 @@ class NCRenameFile: UIViewController, UITextFieldDelegate {
             }
 
             fileNameNew = (fileNameWithoutExt.text ?? "") + "." + (ext.text ?? "")
-            self.delegate?.rename(fileName: fileName, fileNameNew: fileNameNew)
-            self.dismiss(animated: true)
+            self.dismiss(animated: true) {
+                self.delegate?.rename(fileName: fileName, fileNameNew: fileNameNew)
+            }
         }
     }
 

+ 14 - 11
iOSClient/Security/NCEndToEndEncryption.m

@@ -78,16 +78,21 @@
 {
     OPENSSL_init();
     
+    int ret;
     EVP_PKEY * pkey;
     pkey = EVP_PKEY_new();
-    
     RSA * rsa;
-    rsa = RSA_generate_key(
-                           2048, /* number of bits for the key - 2048 is a sensible value */
-                           RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */
-                           NULL, /* callback - can be NULL if we aren't displaying progress */
-                           NULL /* callback argument - not needed in this case */
-                           );
+    BIGNUM *bignum = BN_new();
+    ret = BN_set_word(bignum, RSA_F4);
+    if (ret != 1) {
+        return NO;
+    }
+
+    rsa = RSA_new();
+    ret = RSA_generate_key_ex(rsa, 2048, bignum, NULL);
+    if (ret != 1) {
+        return NO;
+    }
     
     EVP_PKEY_assign_RSA(pkey, rsa);
     
@@ -581,7 +586,6 @@
 
 - (NSData *)encryptAsymmetricString:(NSString *)plain publicKey:(NSString *)publicKey privateKey:(NSString *)privateKey
 {
-    ENGINE *eng = ENGINE_get_default_RSA();
     EVP_PKEY *key = NULL;
     int status = 0;
     
@@ -616,7 +620,7 @@
             return nil;
     }
     
-    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, eng);
+    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
     if (!ctx)
         return nil;
     
@@ -658,7 +662,6 @@
 - (NSString *)decryptAsymmetricData:(NSData *)cipherData privateKey:(NSString *)privateKey
 {
     unsigned char *pKey = (unsigned char *)[privateKey UTF8String];
-    ENGINE *eng = ENGINE_get_default_RSA();
     int status = 0;
     
     BIO *bio = BIO_new_mem_buf(pKey, -1);
@@ -669,7 +672,7 @@
     if (!key)
         return nil;
     
-    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, eng);
+    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
     if (!ctx)
         return nil;
     

+ 4 - 4
iOSClient/Settings/Acknowledgements.rtf

@@ -1,8 +1,8 @@
-{\rtf1\ansi\ansicpg1252\cocoartf2580
+{\rtf1\ansi\ansicpg1252\cocoartf2636
 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;}
 {\colortbl;\red255\green255\blue255;}
 {\*\expandedcolortbl;;}
-\paperw12240\paperh15840\margl1440\margr1440\vieww34680\viewh19260\viewkind0
+\margl1440\margr1440\vieww34680\viewh19260\viewkind0
 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
 
 \f0\fs24 \cf0 \
@@ -199,11 +199,11 @@ Copyright (c)  Tim Oliver\
 ____________________________________________\
 \
 
-\f1\b IHProgressHUD
+\f1\b JGProgressHUD
 \f0\b0 \
 \
 MIT License\
 \
-Copyright (c)  Md Ibrahim Hassan\
+Copyright (c)  Jonas Gessner\
 ____________________________________________\
 }

+ 1 - 1
iOSClient/Settings/CCAdvanced.h

@@ -22,7 +22,7 @@
 //
 
 #import <MessageUI/MFMailComposeViewController.h>
-#import <XLForm/XLForm.h>
+#import <XLForm.h>
 
 @interface CCAdvanced : XLFormViewController <MFMailComposeViewControllerDelegate>
 

+ 1 - 1
iOSClient/Settings/CCManageAccount.h

@@ -21,7 +21,7 @@
 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //
 
-#import <XLForm/XLForm.h>
+#import <XLForm.h>
 
 @interface CCManageAccount : XLFormViewController
 

+ 1 - 1
iOSClient/Settings/CCManageAutoUpload.h

@@ -21,7 +21,7 @@
 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //
 
-#import <XLForm/XLForm.h>
+#import <XLForm.h>
 
 @interface CCManageAutoUpload : XLFormViewController
 

+ 1 - 1
iOSClient/Settings/NCManageEndToEndEncryption.h

@@ -21,7 +21,7 @@
 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //
 
-#import <XLForm/XLForm.h>
+#import <XLForm.h>
 
 @class NCEndToEndInitialize;
 

+ 1 - 1
iOSClient/Settings/NCSettings.h

@@ -23,7 +23,7 @@
 
 #import <UIKit/UIKit.h>
 #import <MessageUI/MessageUI.h>
-#import <XLForm/XLForm.h>
+#import <XLForm.h>
 #import "CCUtility.h"
 
 @interface NCSettings : XLFormViewController

二进制
iOSClient/Supporting Files/af.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ar.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ast.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/az.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/br.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/bs.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ca.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/da.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/de.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/el.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/en-GB.lproj/Localizable.strings


+ 36 - 18
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -25,7 +25,7 @@
 "_accessibility_add_upload_" = "Add and upload";
 "_download_file_"           = "Download file";
 "_loading_"                 = "Loading";
-"_loading_with_points_"     = "Loading…";
+"_loading_with_points_"     = "Loading …";
 "_loading_num_"             = "Loading file %i";
 "_loading_autoupload_"      = "Auto uploading";
 "_uploading_"               = "Uploading";
@@ -71,7 +71,7 @@
 "_save_exit_"               = "Do you want to exit without saving?";
 "_video_"                   = "Video";
 "_overwrite_"               = "Overwrite";
-"_transfers_in_queue_"      = "Tranfers in progress, please wait…";
+"_transfers_in_queue_"      = "Transfers in progress, please wait …";
 "_too_errors_upload_"       = "Too many errors, please verify the problem";
 "_create_folder_"           = "Create folder";
 "_create_folder_on_"        = "Create folder on";
@@ -115,7 +115,7 @@
 "_dark_mode_detect_"        = "Detect iOS dark mode";
 "_screen_"                  = "Screen";
 "_wipe_account_"            = "Account wiped from server";
-"_appconfig_view_title_"    = "Account configuration in progress…";
+"_appconfig_view_title_"    = "Account configuration in progress …";
 "_no_permission_add_file_"  = "You don't have permission to add files";
 "_no_permission_delete_file_" = "You don't have permission to delete files";
 "_no_permission_modify_file_" = "You don't have permission to modify files";
@@ -143,6 +143,11 @@
 "_recent_"                  = "Recent";
 "_view_in_folder_"          = "View in folder";
 "_leave_share_"             = "Leave this share";
+
+/* Remove a file from a list, don't delete it entirely */
+"_remove_file_"             = "Remove file";
+
+/* Delete file and put it into the trash */
 "_delete_file_"             = "Delete file";
 "_delete_folder_"           = "Delete folder";
 "_delete_photo_"            = "Delete photo";
@@ -298,7 +303,7 @@
 "_want_delete_"                 = "Do you really want to delete?";
 "_no_delete_"                   = "No, do not delete";
 "_yes_delete_"                  = "Yes, delete";
-"_remove_cache_"                = "Please wait, deleting cache…";
+"_remove_cache_"                = "Deleting cache, please wait …";
 "_optimizations_"               = "Optimizations";
 "_synchronizations_"            = "Synchronized folders";
 "_version_server_"              = "Server version";
@@ -386,7 +391,7 @@
 "_connection_error_"            = "Connection error";
 "_serverstatus_error_"          = "Connection to server failure, verify your server address or network status";
 "_add_your_nextcloud_"          = "Add your Nextcloud account";
-"_login_url_"                   = "Server address https://…";
+"_login_url_"                   = "Server address https:// …";
 "_login_bottom_label_"          = "Don't have a server yet?\nChoose one of the providers.";
 "_error_multidomain_"           = "Address not allowed, only the following domains are valid:";
 "_account_already_exists_"      = "The account %@ already exists";
@@ -417,7 +422,7 @@
 "_access_photo_location_not_enabled_"       = "Access to Photos and Location not enabled";
 "_access_photo_location_not_enabled_msg_"   = "Please go to \"Settings\" and turn on \"Photo Access\" and \"Location Services\"";
 "_tutorial_photo_view_"                     = "No photos or videos uploaded yet";
-"_create_full_upload_"                      = "Creating archive… May take a long time. During this process, keep the application active during the transfer as well.";
+"_create_full_upload_"                      = "Creating archive … May take a long time. During this process, keep the application active during the transfer as well.";
 "_error_createsubfolders_upload_"           = "Error creating subfolders";
 "_activate_autoupload_"                     = "Enable auto upload";
 "_remove_photo_CameraRoll_"                 = "Remove from camera roll";
@@ -433,13 +438,13 @@
 "_over_30_days_"                = "over 30 days";
 "_connection_internet_offline_" = "The internet connection appears to be offline or Wi-Fi is required";
 "_insert_password_"             = "Enter password";
-"_update_in_progress_"          = "Version upgrade, please wait…";
+"_update_in_progress_"          = "Version upgrade, please wait …";
 "_forbidden_characters_"        = "The file or folder name contains invalid characters";
 "_cannot_send_mail_error_"      = "No account set up, or wrong email address entered";
 "_open_url_error_"              = "Cannot open the URL for this action";
 "_photo_camera_"                = "Photos";
 "_media_"                       = "Media";
-"_unzip_in_progress_"           = "Extraction in progress on local storage…";
+"_unzip_in_progress_"           = "Extraction in progress on local storage …";
 "_file_unpacked_"               = "File unpacked on local storage";
 "_file_saved_local_"            = "File saved on local storage.";
 "_file_not_present_"            = "Error: File not present, please reload.";
@@ -473,8 +478,8 @@
 "_protect_passcode_"            = "Protect with password";
 "_share_"                       = "Share";
 "_reload_"                      = "Reload";
-"_open_in_"                     = "Open in…";
-"_open_"                        = "Open…";
+"_open_in_"                     = "Open in …";
+"_open_"                        = "Open …";
 "_remove_local_file_"           = "Remove from cache";
 "_add_local_"                   = "Add to local storage";
 "_comm_erro_pull_down_"         = "Attention: Communication error with the server. Pull down to refresh.";
@@ -485,7 +490,7 @@
 "_files_"                       = "files";
 "_file_"                        = "file";
 "_folder_blocked_"              = "Folder blocked";
-"_downloading_progress_"        = "Initiating download of files…";
+"_downloading_progress_"        = "Initiating download of files …";
 "_no_file_pull_down_"           = "Upload a file or pull down to refresh";
 "_browse_images_"               = "Browse images";
 "_synchronized_folder_"         = "Keep the folder synchronized";
@@ -515,11 +520,11 @@
 "_directory_on_top_no_"         = "Folders on top";
 "_folder_automatic_upload_"     = "Folder for \"Auto upload\"";
 "_search_no_record_found_"      = "No result";
-"_search_in_progress_"          = "Search in progress…";
+"_search_in_progress_"          = "Search in progress …";
 "_search_instruction_"          = "Search for file (minimum 2 characters)";
 "_files_no_files_"              = "No files in here";
 "_files_no_folders_"            = "No folders in here";
-"_request_in_progress_"         = "Request to server in progress…";
+"_request_in_progress_"         = "Request to server in progress …";
 
 "audio"                         = "AUDIO";
 "compress"                      = "COMPRESS";
@@ -558,7 +563,7 @@
 "_password_pdf_error_"          = "Wrong password";
 "_error_download_photobrowser_" = "Error: Unable to download photo";
 "_share_link_"                  = "Share link";
-"_share_link_button_"           = "Send link to…";
+"_share_link_button_"           = "Send link to …";
 "_Link_name_"                   = "Link name";
 "_password_"                    = "Password";
 "_share_password_"              = "Password protected link";
@@ -568,12 +573,12 @@
 "_add_sharee_"                  = "Add users or groups";
 "_add_sharee_footer_"           = "You can share this resource by adding users or groups. To remove a share, remove all users and groups";
 "_find_sharee_title_"           = "Search";
-"_find_sharee_"                 = "Search for user or group…";
+"_find_sharee_"                 = "Search for user or group …";
 "_find_sharee_footer_"          = "Enter part of the name of the user or group to search for (at least 2 characters) followed by \"Return\", select the users that should be allowed to access the share followed by \"Done\" to confirm";
 "_user_is_group_"               = "(Group)";
 "_direct_sharee_title_"         = "Share";
 "_direct_sharee_footer_"        = "If you already know the name, enter it, then select the share type and press \"Done\" to confirm";
-"_direct_sharee_"               = "Enter the username…";
+"_direct_sharee_"               = "Enter the username …";
 "_user_sharee_footer_"          = "Tap to change permissions";
 "_share_type_title_"            = "Type of share";
 "_share_type_user_"             = "User";
@@ -583,7 +588,7 @@
 "_password_obligatory_"         = "Enforce password protection enabled, password obligatory";
 "_shared_with_you_by_"          = "Shared with you by";
 "_shareLinksearch_placeholder_" = "Type a name and press Enter";
-"_new_comment_"                 = "New comment…";
+"_new_comment_"                 = "New comment …";
 "_edit_comment_"                = "Edit comment";
 "_delete_comment_"              = "Delete comment";
 "_share_allow_editing_"         = "Allow editing";
@@ -763,6 +768,7 @@
 "_request_entity_too_large_"            = "The file is too large";
 "_not_possible_download_"               = "It is not possible to download the file";
 "_not_possible_upload_"                 = "It is not possible to upload the file";
+"_error_files_upload_"                  = "Error uploading files";
 "_method_not_allowed_"                  = "The requested method is not supported";
 "_invalid_url_"                         = "Invalid server URL";
 "_invalid_literal_"                     = "Invalid search string";
@@ -822,4 +828,16 @@
 "_copy_path_"               = "Copy path";
 "_certificates_"            = "Certificates";
 "_privacy_screen_"          = "Splash screen when app inactive";
-
+"_saving_"                  = "Saving …";
+// Video
+"_video_processing_"        = "Video processing";
+"_video_being_processed_"   = "Video being processed …";
+"_downloading_"             = "Downloading";
+"_download_error_"          = "Download error";
+"_subtitle_"                = "Subtitle";
+"_dts_to_ac3_"              = "The DTS is not supported, it requires a conversion to Dolby Digital";
+"_reuired_conversion_"      = "This video takes a long time to convert.";
+"_stay_app_foreground_"     = "Keep the app in the foreground …";
+"_conversion_available_"    = "The conversion is always available on menu";
+"_video_format_not_recognized_"     = "This video needs to be processed to be played, do you want to do it now?";
+"_conversion_max_compatibility_"    = "Max compatibility, the conversion can take much longer";

二进制
iOSClient/Supporting Files/eo.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-419.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-AR.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-CL.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-CO.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-CR.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-DO.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-EC.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-GT.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-HN.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-MX.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-NI.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PA.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PE.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PR.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PY.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-SV.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-UY.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/et_EE.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/eu.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/fa.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/fr.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/gl.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/he.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/hr.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/hu.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ia.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/id.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/is.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/it.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ko.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/lb.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/lo.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/lv.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/mk.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/mn.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/nl.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/nn_NO.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/oc.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/pl.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/pt-PT.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ro.lproj/Localizable.strings


部分文件因为文件数量过多而无法显示