Răsfoiți Sursa

Version 5.5.5 (#3033)

Filename validator Nextcloud 30
Marino Faggiana 7 luni în urmă
părinte
comite
6d1744a85c
100 a modificat fișierele cu 337 adăugiri și 540 ștergeri
  1. 2 2
      File Provider Extension/FileProviderData.swift
  2. 6 2
      File Provider Extension/FileProviderExtension+Actions.swift
  3. 5 25
      Nextcloud.xcodeproj/project.pbxproj
  4. 5 2
      Share/NCShareExtension+DataSource.swift
  5. 1 0
      Share/NCShareExtension+Files.swift
  6. 31 48
      Share/NCShareExtension+NCDelegate.swift
  7. 7 0
      Share/NCShareExtension.swift
  8. 18 4
      iOSClient/AppDelegate.swift
  9. 13 0
      iOSClient/Data/NCManageDatabase+Capabilities.swift
  10. 11 0
      iOSClient/DeepLink/NCDeepLinkHandler.swift
  11. 123 1
      iOSClient/Extensions/UIAlertController+Extension.swift
  12. 1 0
      iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift
  13. 24 6
      iOSClient/Main/Create cloud/Upload Assets/NCUploadAssetsView.swift
  14. 6 0
      iOSClient/Main/NCActionCenter.swift
  15. 11 1
      iOSClient/Main/NCMainTabBar.swift
  16. 12 2
      iOSClient/Main/NCPickerViewController.swift
  17. 1 11
      iOSClient/Menu/NCCollectionViewCommon+Menu.swift
  18. 16 3
      iOSClient/Menu/NCMenuAction.swift
  19. 1 12
      iOSClient/Menu/NCViewer+Menu.swift
  20. 6 0
      iOSClient/NCGlobal.swift
  21. 0 1
      iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift
  22. 1 1
      iOSClient/Networking/NCNetworking+WebDAV.swift
  23. 0 153
      iOSClient/Rename file/NCRenameFile.storyboard
  24. 0 251
      iOSClient/Rename file/NCRenameFile.swift
  25. 13 2
      iOSClient/Scan document/NCUploadScanDocument.swift
  26. 10 7
      iOSClient/Select/NCSelect.swift
  27. BIN
      iOSClient/Supporting Files/af.lproj/Localizable.strings
  28. BIN
      iOSClient/Supporting Files/an.lproj/Localizable.strings
  29. BIN
      iOSClient/Supporting Files/ar.lproj/Localizable.strings
  30. BIN
      iOSClient/Supporting Files/ast.lproj/Localizable.strings
  31. BIN
      iOSClient/Supporting Files/az.lproj/Localizable.strings
  32. BIN
      iOSClient/Supporting Files/be.lproj/Localizable.strings
  33. BIN
      iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings
  34. BIN
      iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings
  35. BIN
      iOSClient/Supporting Files/br.lproj/Localizable.strings
  36. BIN
      iOSClient/Supporting Files/bs.lproj/Localizable.strings
  37. BIN
      iOSClient/Supporting Files/ca.lproj/Localizable.strings
  38. BIN
      iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings
  39. BIN
      iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings
  40. BIN
      iOSClient/Supporting Files/da.lproj/Localizable.strings
  41. BIN
      iOSClient/Supporting Files/de.lproj/Localizable.strings
  42. BIN
      iOSClient/Supporting Files/el.lproj/Localizable.strings
  43. BIN
      iOSClient/Supporting Files/en-GB.lproj/Localizable.strings
  44. 13 6
      iOSClient/Supporting Files/en.lproj/Localizable.strings
  45. BIN
      iOSClient/Supporting Files/eo.lproj/Localizable.strings
  46. BIN
      iOSClient/Supporting Files/es-419.lproj/Localizable.strings
  47. BIN
      iOSClient/Supporting Files/es-AR.lproj/Localizable.strings
  48. BIN
      iOSClient/Supporting Files/es-CL.lproj/Localizable.strings
  49. BIN
      iOSClient/Supporting Files/es-CO.lproj/Localizable.strings
  50. BIN
      iOSClient/Supporting Files/es-CR.lproj/Localizable.strings
  51. BIN
      iOSClient/Supporting Files/es-DO.lproj/Localizable.strings
  52. BIN
      iOSClient/Supporting Files/es-EC.lproj/Localizable.strings
  53. BIN
      iOSClient/Supporting Files/es-GT.lproj/Localizable.strings
  54. BIN
      iOSClient/Supporting Files/es-HN.lproj/Localizable.strings
  55. BIN
      iOSClient/Supporting Files/es-MX.lproj/Localizable.strings
  56. BIN
      iOSClient/Supporting Files/es-NI.lproj/Localizable.strings
  57. BIN
      iOSClient/Supporting Files/es-PA.lproj/Localizable.strings
  58. BIN
      iOSClient/Supporting Files/es-PE.lproj/Localizable.strings
  59. BIN
      iOSClient/Supporting Files/es-PR.lproj/Localizable.strings
  60. BIN
      iOSClient/Supporting Files/es-PY.lproj/Localizable.strings
  61. BIN
      iOSClient/Supporting Files/es-SV.lproj/Localizable.strings
  62. BIN
      iOSClient/Supporting Files/es-UY.lproj/Localizable.strings
  63. BIN
      iOSClient/Supporting Files/es.lproj/Localizable.strings
  64. BIN
      iOSClient/Supporting Files/et_EE.lproj/Localizable.strings
  65. BIN
      iOSClient/Supporting Files/eu.lproj/Localizable.strings
  66. BIN
      iOSClient/Supporting Files/fa.lproj/Localizable.strings
  67. BIN
      iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings
  68. BIN
      iOSClient/Supporting Files/fo.lproj/Localizable.strings
  69. BIN
      iOSClient/Supporting Files/fr.lproj/Localizable.strings
  70. BIN
      iOSClient/Supporting Files/ga.lproj/Localizable.strings
  71. BIN
      iOSClient/Supporting Files/gd.lproj/Localizable.strings
  72. BIN
      iOSClient/Supporting Files/gl.lproj/Localizable.strings
  73. BIN
      iOSClient/Supporting Files/he.lproj/Localizable.strings
  74. BIN
      iOSClient/Supporting Files/hi_IN.lproj/Localizable.strings
  75. BIN
      iOSClient/Supporting Files/hr.lproj/Localizable.strings
  76. BIN
      iOSClient/Supporting Files/hsb.lproj/Localizable.strings
  77. BIN
      iOSClient/Supporting Files/hu.lproj/Localizable.strings
  78. BIN
      iOSClient/Supporting Files/hy.lproj/Localizable.strings
  79. BIN
      iOSClient/Supporting Files/ia.lproj/Localizable.strings
  80. BIN
      iOSClient/Supporting Files/id.lproj/Localizable.strings
  81. BIN
      iOSClient/Supporting Files/ig.lproj/Localizable.strings
  82. BIN
      iOSClient/Supporting Files/is.lproj/Localizable.strings
  83. BIN
      iOSClient/Supporting Files/it.lproj/Localizable.strings
  84. BIN
      iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings
  85. BIN
      iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings
  86. BIN
      iOSClient/Supporting Files/ka.lproj/Localizable.strings
  87. BIN
      iOSClient/Supporting Files/kab.lproj/Localizable.strings
  88. BIN
      iOSClient/Supporting Files/km.lproj/Localizable.strings
  89. BIN
      iOSClient/Supporting Files/kn.lproj/Localizable.strings
  90. BIN
      iOSClient/Supporting Files/ko.lproj/Localizable.strings
  91. BIN
      iOSClient/Supporting Files/la.lproj/Localizable.strings
  92. BIN
      iOSClient/Supporting Files/lb.lproj/Localizable.strings
  93. BIN
      iOSClient/Supporting Files/lo.lproj/Localizable.strings
  94. BIN
      iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings
  95. BIN
      iOSClient/Supporting Files/lv.lproj/Localizable.strings
  96. BIN
      iOSClient/Supporting Files/mk.lproj/Localizable.strings
  97. BIN
      iOSClient/Supporting Files/mn.lproj/Localizable.strings
  98. BIN
      iOSClient/Supporting Files/mr.lproj/Localizable.strings
  99. BIN
      iOSClient/Supporting Files/ms_MY.lproj/Localizable.strings
  100. BIN
      iOSClient/Supporting Files/my.lproj/Localizable.strings

+ 2 - 2
File Provider Extension/FileProviderData.swift

@@ -91,7 +91,7 @@ class fileProviderData: NSObject {
             homeServerUrl = utilityFileSystem.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId)
 
             NCManageDatabase.shared.setCapabilities(account: account)
-            NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: NCKeychain().getPassword(account: activeAccount.account), urlBase: activeAccount.urlBase, userAgent: userAgent, nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup, delegate: NCNetworking.shared)
+            NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: NCKeychain().getPassword(account: activeAccount.account), urlBase: activeAccount.urlBase, userAgent: userAgent, nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
             NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
 
             return tableAccount.init(value: activeAccount)
@@ -114,7 +114,7 @@ class fileProviderData: NSObject {
 
                 NCManageDatabase.shared.setCapabilities(account: account)
 
-                NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: NCKeychain().getPassword(account: activeAccount.account), urlBase: activeAccount.urlBase, userAgent: userAgent, nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup, delegate: NCNetworking.shared)
+                NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: NCKeychain().getPassword(account: activeAccount.account), urlBase: activeAccount.urlBase, userAgent: userAgent, nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
                 NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
 
                 return tableAccount.init(value: activeAccount)

+ 6 - 2
File Provider Extension/FileProviderExtension+Actions.swift

@@ -54,7 +54,7 @@ extension FileProviderExtension {
                     }
                 }
             } else {
-                completionHandler(nil, NSFileProviderError(.serverUnreachable))
+                completionHandler(nil, NSFileProviderError(.filenameCollision))
             }
         }
     }
@@ -70,7 +70,7 @@ extension FileProviderExtension {
         let fileName = metadata.fileName
 
         NextcloudKit.shared.deleteFileOrFolder(serverUrlFileName: serverUrlFileName, account: metadata.account) { account, error in
-            if error == .success { // || error == kOCErrorServerPathNotFound {
+            if error == .success {
                 let fileNamePath = self.utilityFileSystem.getDirectoryProviderStorageOcId(itemIdentifier.rawValue)
 
                 do {
@@ -122,6 +122,8 @@ extension FileProviderExtension {
                 let item = FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier)
 
                 completionHandler(item, nil)
+            } else if error.errorCode == NCGlobal.shared.errorBadRequest {
+                completionHandler(nil, NSFileProviderError(.noSuchItem, userInfo: [NSLocalizedDescriptionKey: error.errorDescription, NSLocalizedFailureReasonErrorKey: ""]))
             } else {
                 completionHandler(nil, NSFileProviderError(.serverUnreachable))
             }
@@ -161,6 +163,8 @@ extension FileProviderExtension {
                 }
                 let item = FileProviderItem(metadata: tableMetadata.init(value: metadata), parentItemIdentifier: parentItemIdentifier)
                 completionHandler(item, nil)
+            } else if error.errorCode == NCGlobal.shared.errorBadRequest  {
+                completionHandler(nil, NSFileProviderError(.noSuchItem, userInfo: [NSLocalizedDescriptionKey: error.errorDescription, NSLocalizedFailureReasonErrorKey: ""]))
             } else {
                 completionHandler(nil, NSFileProviderError(.serverUnreachable))
             }

+ 5 - 25
Nextcloud.xcodeproj/project.pbxproj

@@ -197,8 +197,6 @@
 		F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */; };
 		F70CEF5623E9C7E50007035B /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
 		F70D7C3725FFBF82002B9E34 /* NCCollectionViewCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D7C3525FFBF81002B9E34 /* NCCollectionViewCommon.swift */; };
-		F70D87CF25EE6E58008CBBBD /* NCRenameFile.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F70D87CD25EE6E58008CBBBD /* NCRenameFile.storyboard */; };
-		F70D87D025EE6E58008CBBBD /* NCRenameFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D87CE25EE6E58008CBBBD /* NCRenameFile.swift */; };
 		F70D8D8124A4A9BF000A5756 /* NCNetworkingProcess.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D8D8024A4A9BF000A5756 /* NCNetworkingProcess.swift */; };
 		F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = F710D1F42405770F00A6033D /* NCViewerPDF.swift */; };
 		F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F710D2012405826100A6033D /* NCViewer+Menu.swift */; };
@@ -712,8 +710,6 @@
 		F79B646226CA661600838ACA /* UIControl+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79B645F26CA661600838ACA /* UIControl+Extension.swift */; };
 		F79B646326CA661600838ACA /* UIControl+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79B645F26CA661600838ACA /* UIControl+Extension.swift */; };
 		F79B869B265E19D40085C0E0 /* NSMutableAttributedString+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79B869A265E19D40085C0E0 /* NSMutableAttributedString+Extension.swift */; };
-		F79EC77F26316193004E59D6 /* NCRenameFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D87CE25EE6E58008CBBBD /* NCRenameFile.swift */; };
-		F79EC784263161BA004E59D6 /* NCRenameFile.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F70D87CD25EE6E58008CBBBD /* NCRenameFile.storyboard */; };
 		F79EC78926316AC4004E59D6 /* NCPopupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F702F30725EE5D47008F8E80 /* NCPopupViewController.swift */; };
 		F79EDAA326B004980007D134 /* NCPlayerToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79EDA9F26B004980007D134 /* NCPlayerToolBar.swift */; };
 		F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79EDAA126B004980007D134 /* NCPlayer.swift */; };
@@ -1217,8 +1213,6 @@
 		F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NCEndToEndEncryption.m; sourceTree = "<group>"; };
 		F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; };
 		F70D7C3525FFBF81002B9E34 /* NCCollectionViewCommon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCCollectionViewCommon.swift; sourceTree = "<group>"; };
-		F70D87CD25EE6E58008CBBBD /* NCRenameFile.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCRenameFile.storyboard; sourceTree = "<group>"; };
-		F70D87CE25EE6E58008CBBBD /* NCRenameFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCRenameFile.swift; sourceTree = "<group>"; };
 		F70D8D8024A4A9BF000A5756 /* NCNetworkingProcess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingProcess.swift; sourceTree = "<group>"; };
 		F70F2BA4225F2D8900EBB73E /* ZIPFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ZIPFoundation.framework; path = Carthage/Build/iOS/ZIPFoundation.framework; sourceTree = "<group>"; };
 		F70F96AF2874394B006C8379 /* Nextcloud-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Nextcloud-Bridging-Header.h"; sourceTree = "<group>"; };
@@ -2082,15 +2076,6 @@
 			path = Color;
 			sourceTree = "<group>";
 		};
-		F70D87CC25EE6E58008CBBBD /* Rename file */ = {
-			isa = PBXGroup;
-			children = (
-				F70D87CD25EE6E58008CBBBD /* NCRenameFile.storyboard */,
-				F70D87CE25EE6E58008CBBBD /* NCRenameFile.swift */,
-			);
-			path = "Rename file";
-			sourceTree = "<group>";
-		};
 		F713418B2597513800768D21 /* PushNotification */ = {
 			isa = PBXGroup;
 			children = (
@@ -2980,7 +2965,6 @@
 				F7381ED9218218A4000B1560 /* Offline */,
 				F713418B2597513800768D21 /* PushNotification */,
 				F765F72E25237E3F00391DBE /* Recent */,
-				F70D87CC25EE6E58008CBBBD /* Rename file */,
 				F7CADB3D23CCDDA1000EEC78 /* RichWorkspace */,
 				F76882042C0DD1E7001CF441 /* Settings */,
 				F758B41E212C516300515F55 /* Scan document */,
@@ -3668,7 +3652,6 @@
 				F7145A231D12E3B700CAFEEC /* Localizable.strings in Resources */,
 				F746EC51273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */,
 				F76C26A62850D3A500E42BDF /* Images.xcassets in Resources */,
-				F79EC784263161BA004E59D6 /* NCRenameFile.storyboard in Resources */,
 				F714805E262ED52900693E51 /* NCSectionFooter.xib in Resources */,
 				F700222D1EC479840080073F /* Custom.xcassets in Resources */,
 			);
@@ -3714,7 +3697,6 @@
 				F702F2F125EE5CDB008F8E80 /* NCLogin.storyboard in Resources */,
 				F723985C253C95CE00257F49 /* NCViewerRichdocument.storyboard in Resources */,
 				F758B45A212C564000515F55 /* NCScan.storyboard in Resources */,
-				F70D87CF25EE6E58008CBBBD /* NCRenameFile.storyboard in Resources */,
 				F765F73225237E3F00391DBE /* NCRecent.storyboard in Resources */,
 				F78F74342163757000C2ADAD /* NCTrash.storyboard in Resources */,
 				F702F30225EE5D2C008F8E80 /* english.txt in Resources */,
@@ -4046,7 +4028,6 @@
 				F76D364728A4F8BF00214537 /* NCActivityIndicator.swift in Sources */,
 				F73EF7CA2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */,
 				F749B654297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
-				F79EC77F26316193004E59D6 /* NCRenameFile.swift in Sources */,
 				AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */,
 				F74C86382AEFBE64009A1D4A /* NCImageCache.swift in Sources */,
 				F73EF7C22B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */,
@@ -4234,7 +4215,6 @@
 				F702F30825EE5D47008F8E80 /* NCPopupViewController.swift in Sources */,
 				F733598125C1C188002ABA72 /* NCAskAuthorization.swift in Sources */,
 				370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */,
-				F70D87D025EE6E58008CBBBD /* NCRenameFile.swift in Sources */,
 				F768822C2C0DD1E7001CF441 /* NCKeychain.swift in Sources */,
 				F71CD6CA2930D7B1006C95C1 /* NCApplicationHandle.swift in Sources */,
 				F73EF7D72B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */,
@@ -5414,7 +5394,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 13;
+				CURRENT_PROJECT_VERSION = 1;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -5441,7 +5421,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 5.5.4;
+				MARKETING_VERSION = 5.5.5;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_CFLAGS = "-v";
 				OTHER_LDFLAGS = "";
@@ -5480,7 +5460,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 13;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -5504,7 +5484,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 5.5.4;
+				MARKETING_VERSION = 5.5.5;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_CFLAGS = "-v";
 				OTHER_LDFLAGS = "";
@@ -5779,7 +5759,7 @@
 			repositoryURL = "https://github.com/nextcloud/NextcloudKit";
 			requirement = {
 				kind = exactVersion;
-				version = 4.0.6;
+				version = 4.0.8;
 			};
 		};
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {

+ 5 - 2
Share/NCShareExtension+DataSource.swift

@@ -35,6 +35,11 @@ extension NCShareExtension: UICollectionViewDelegate {
             showAlert(title: "_info_", description: "_e2e_goto_settings_for_enable_")
         }
 
+        if let fileNameError = FileNameValidator.shared.checkFileName(metadata.fileNameView) {
+            present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+            return
+        }
+
         self.serverUrl = serverUrl
         reloadDatasource(withLoadFolder: true)
         setNavigationBar(navigationTitle: metadata.fileNameView)
@@ -84,8 +89,6 @@ extension NCShareExtension: UICollectionViewDataSource {
             return UICollectionViewCell()
         }
 
-        cell.listCellDelegate = self
-
         cell.fileObjectId = metadata.ocId
         cell.indexPath = indexPath
         cell.fileUser = metadata.ownerId

+ 1 - 0
Share/NCShareExtension+Files.swift

@@ -23,6 +23,7 @@
 
 import Foundation
 import UniformTypeIdentifiers
+import NextcloudKit
 
 extension NCShareExtension {
     @objc func reloadDatasource(withLoadFolder: Bool) {

+ 31 - 48
Share/NCShareExtension+NCDelegate.swift

@@ -93,10 +93,30 @@ extension NCShareExtension: NCAccountRequestDelegate {
 
         reloadDatasource(withLoadFolder: true)
         setNavigationBar(navigationTitle: NCBrandOptions.shared.brand)
+
+        FileNameValidator.shared.setup(
+            forbiddenFileNames: NCGlobal.shared.capabilityForbiddenFileNames,
+            forbiddenFileNameBasenames: NCGlobal.shared.capabilityForbiddenFileNameBasenames,
+            forbiddenFileNameCharacters: NCGlobal.shared.capabilityForbiddenFileNameCharacters,
+            forbiddenFileNameExtensions: NCGlobal.shared.capabilityForbiddenFileNameExtensions
+        )
+    }
+}
+
+extension NCShareExtension: NCCreateFormUploadConflictDelegate {
+    func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
+        guard let metadatas = metadatas else {
+            uploadStarted = false
+            uploadMetadata.removeAll()
+            return
+        }
+
+        self.uploadMetadata.append(contentsOf: metadatas)
+        self.upload()
     }
 }
 
-extension NCShareExtension: NCShareCellDelegate, NCRenameFileDelegate, NCListCellDelegate {
+extension NCShareExtension: NCShareCellDelegate {
     func removeFile(named fileName: String) {
         guard let index = self.filesName.firstIndex(of: fileName) else {
             return showAlert(title: "_file_not_found_", description: fileName)
@@ -110,54 +130,17 @@ extension NCShareExtension: NCShareCellDelegate, NCRenameFileDelegate, NCListCel
     }
 
     func renameFile(named fileName: String) {
-        guard let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile else { return }
-
-        let resultInternalType = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: fileName, mimeType: "", directory: false)
-        vcRename.delegate = self
-        vcRename.fileName = fileName
-        vcRename.indexPath = IndexPath()
-        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) ?? NCImageCache.images.file
+        let alert = UIAlertController.renameFile(fileName: fileName) { [self] newFileName in
+            guard let fileIx = self.filesName.firstIndex(of: fileName),
+                  !self.filesName.contains(newFileName),
+                  utilityFileSystem.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: (NSTemporaryDirectory() + newFileName)) else {
+                      return showAlert(title: "_single_file_conflict_title_", description: "'\(fileName)' -> '\(newFileName)'")
+                  }
+
+            filesName[fileIx] = newFileName
+            tableView.reloadData()
         }
 
-        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),
-              utilityFileSystem.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: (NSTemporaryDirectory() + fileNameNew)) else {
-                  return showAlert(title: "_single_file_conflict_title_", description: "'\(fileName)' -> '\(fileNameNew)'")
-              }
-
-        filesName[fileIx] = fileNameNew
-        tableView.reloadData()
-    }
-
-    func tapShareListItem(with objectId: String, indexPath: IndexPath, sender: Any) {
-    }
-
-    func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any) {
-    }
-
-    func longPressListItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {
-    }
-}
-
-extension NCShareExtension: NCCreateFormUploadConflictDelegate {
-    func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
-        guard let metadatas = metadatas else {
-            uploadStarted = false
-            uploadMetadata.removeAll()
-            return
-        }
-
-        self.uploadMetadata.append(contentsOf: metadatas)
-        self.upload()
+        present(alert, animated: true)
     }
 }

+ 7 - 0
Share/NCShareExtension.swift

@@ -298,6 +298,12 @@ extension NCShareExtension {
 
         var conflicts: [tableMetadata] = []
         for fileName in filesName {
+            if let fileNameError = FileNameValidator.shared.checkFileName(fileName) {
+                present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+
+                continue
+            }
+
             let ocId = NSUUID().uuidString
             let toPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)
             guard utilityFileSystem.copyFile(atPath: (NSTemporaryDirectory() + fileName), toPath: toPath) else { continue }
@@ -335,6 +341,7 @@ extension NCShareExtension {
         guard uploadStarted else { return }
         guard uploadMetadata.count > counterUploaded else { return DispatchQueue.main.async { self.finishedUploading() } }
         let metadata = uploadMetadata[counterUploaded]
+
         let results = NextcloudKit.shared.nkCommonInstance.getInternalType(fileName: metadata.fileNameView, mimeType: metadata.contentType, directory: false)
         metadata.contentType = results.mimeType
         metadata.iconName = results.iconName

+ 18 - 4
iOSClient/AppDelegate.swift

@@ -109,7 +109,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             userId = activeAccount.userId
             password = NCKeychain().getPassword(account: account)
 
-            NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
+            NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase)
             NCManageDatabase.shared.setCapabilities(account: account)
 
             NCBrandColor.shared.settingThemingColor(account: activeAccount.account)
@@ -148,6 +148,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             self.handleProcessingTask(task)
         }
 
+        FileNameValidator.shared.setup(
+            forbiddenFileNames: NCGlobal.shared.capabilityForbiddenFileNames,
+            forbiddenFileNameBasenames: NCGlobal.shared.capabilityForbiddenFileNameBasenames,
+            forbiddenFileNameCharacters: NCGlobal.shared.capabilityForbiddenFileNameCharacters,
+            forbiddenFileNameExtensions: NCGlobal.shared.capabilityForbiddenFileNameExtensions
+        )
+
         return true
     }
 
@@ -462,7 +469,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         if urlBase.last == "/" { urlBase = String(urlBase.dropLast()) }
         let account: String = "\(user) \(urlBase)"
 
-        NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
+        NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase)
         NextcloudKit.shared.getUserProfile(account: account) { account, userProfile, _, error in
             if error == .success, let userProfile {
                 NCManageDatabase.shared.deleteAccount(account)
@@ -472,7 +479,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
                     completion(error)
                 }
             } else {
-                NextcloudKit.shared.setup(account: self.account, user: self.user, userId: self.userId, password: self.password, urlBase: self.urlBase, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
+                NextcloudKit.shared.setup(account: self.account, user: self.user, userId: self.userId, password: self.password, urlBase: self.urlBase)
                 let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert)
                 alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
                 UIApplication.shared.firstWindow?.rootViewController?.present(alertController, animated: true)
@@ -509,7 +516,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         self.userId = tableAccount.userId
         self.password = NCKeychain().getPassword(account: tableAccount.account)
 
-        NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
+        NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase)
         NCManageDatabase.shared.setCapabilities(account: account)
 
         if let userProfile {
@@ -523,6 +530,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Initialize Auto upload with \(items) uploads")
         }
 
+        FileNameValidator.shared.setup(
+            forbiddenFileNames: NCGlobal.shared.capabilityForbiddenFileNames,
+            forbiddenFileNameBasenames: NCGlobal.shared.capabilityForbiddenFileNameBasenames,
+            forbiddenFileNameCharacters: NCGlobal.shared.capabilityForbiddenFileNameCharacters,
+            forbiddenFileNameExtensions: NCGlobal.shared.capabilityForbiddenFileNameExtensions
+        )
+
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeUser)
         completion()
     }

+ 13 - 0
iOSClient/Data/NCManageDatabase+Capabilities.swift

@@ -229,11 +229,19 @@ extension NCManageDatabase {
                             let bigfilechunking: Bool?
                             let versiondeletion: Bool?
                             let versionlabeling: Bool?
+                            let forbiddenFileNames: [String]?
+                            let forbiddenFileNameBasenames: [String]?
+                            let forbiddenFileNameCharacters: [String]?
+                            let forbiddenFileNameExtensions: [String]?
 
                             enum CodingKeys: String, CodingKey {
                                 case undelete, locking, comments, versioning, directEditing, bigfilechunking
                                 case versiondeletion = "version_deletion"
                                 case versionlabeling = "version_labeling"
+                                case forbiddenFileNames = "forbidden_filenames"
+                                case forbiddenFileNameBasenames = "forbidden_filename_basenames"
+                                case forbiddenFileNameCharacters = "forbidden_filename_characters"
+                                case forbiddenFileNameExtensions = "forbidden_filename_extensions"
                             }
 
                             struct DirectEditing: Codable {
@@ -360,6 +368,11 @@ extension NCManageDatabase {
             }
             global.capabilityGroupfoldersEnabled = data.capabilities.groupfolders?.hasGroupFolders ?? false
             global.capabilitySecurityGuardDiagnostics = data.capabilities.securityguard?.diagnostics ?? false
+
+            global.capabilityForbiddenFileNames = data.capabilities.files?.forbiddenFileNames ?? []
+            global.capabilityForbiddenFileNameBasenames = data.capabilities.files?.forbiddenFileNameBasenames ?? []
+            global.capabilityForbiddenFileNameCharacters = data.capabilities.files?.forbiddenFileNameCharacters ?? []
+            global.capabilityForbiddenFileNameExtensions = data.capabilities.files?.forbiddenFileNameExtensions ?? []
         } catch let error as NSError {
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not access database: \(error)")
             return

+ 11 - 0
iOSClient/DeepLink/NCDeepLinkHandler.swift

@@ -22,6 +22,7 @@
 import Foundation
 import UIKit
 import SwiftUI
+import NextcloudKit
 
 enum DeepLink: String {
     case openFiles              // nextcloud://openFiles
@@ -109,6 +110,16 @@ class NCDeepLinkHandler {
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
         controller.selectedIndex = ControllerConstants.filesIndex
         DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
+            let serverUrl = controller.currentServerUrl()
+            let fileFolderPath = NCUtilityFileSystem().getFileNamePath("", serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId)
+            let fileFolderName = (serverUrl as NSString).lastPathComponent
+
+            if !FileNameValidator.shared.checkFolderPath(folderPath: fileFolderPath) {
+                controller.present(UIAlertController.warning(message: "\(String(format: NSLocalizedString("_file_name_validator_error_reserved_name_", comment: ""), fileFolderName)) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+
+                return
+            }
+
             appDelegate.toggleMenu(controller: controller)
         }
     }

+ 123 - 1
iOSClient/Extensions/UIAlertController+Extension.swift

@@ -75,7 +75,10 @@ extension UIAlertController {
             queue: .main) { _ in
                 guard let text = alertController.textFields?.first?.text else { return }
                 let folderName = text.trimmingCharacters(in: .whitespaces)
-                okAction.isEnabled = !folderName.isEmpty && folderName != "." && folderName != ".."
+
+                let textCheck = FileNameValidator.shared.checkFileName(folderName)
+                okAction.isEnabled = textCheck?.error == nil && !folderName.isEmpty
+                alertController.message = textCheck?.error.localizedDescription
             }
 
         alertController.addAction(cancelAction)
@@ -149,4 +152,123 @@ extension UIAlertController {
         })
         return alertController
     }
+
+    static func renameFile(fileName: String, completion: @escaping (_ newFileName: String) -> Void) -> UIAlertController {
+        let alertController = UIAlertController(title: NSLocalizedString("_rename_", comment: ""), message: nil, preferredStyle: .alert)
+
+        let okAction = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default, handler: { _ in
+            guard let newFileName = alertController.textFields?.first?.text else { return }
+
+            completion(newFileName)
+        })
+
+        // text field is initially empty, no action
+        okAction.isEnabled = false
+        let cancelAction = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel)
+
+        alertController.addTextField { textField in
+            textField.text = fileName
+            textField.autocapitalizationType = .words
+        }
+
+        // only allow saving if folder name exists
+        NotificationCenter.default.addObserver(
+            forName: UITextField.textDidBeginEditingNotification,
+            object: alertController.textFields?.first,
+            queue: .main) { _ in
+                guard let textField = alertController.textFields?.first else { return }
+
+                if let start = textField.position(from: textField.beginningOfDocument, offset: 0),
+                   let end = textField.position(from: start, offset: textField.text?.withRemovedFileExtension.count ?? 0) {
+                    textField.selectedTextRange = textField.textRange(from: start, to: end)
+                }
+            }
+
+        NotificationCenter.default.addObserver(
+            forName: UITextField.textDidChangeNotification,
+            object: alertController.textFields?.first,
+            queue: .main) { _ in
+                guard let text = alertController.textFields?.first?.text else { return }
+
+                let textCheck = FileNameValidator.shared.checkFileName(text)
+                okAction.isEnabled = textCheck?.error == nil && !text.isEmpty
+                alertController.message = textCheck?.error.localizedDescription
+            }
+
+        alertController.addAction(cancelAction)
+        alertController.addAction(okAction)
+        return alertController
+    }
+
+    static func renameFile(metadata: tableMetadata, indexPath: IndexPath) -> UIAlertController {
+        let alertController = UIAlertController(title: NSLocalizedString("_rename_", comment: ""), message: nil, preferredStyle: .alert)
+
+        let okAction = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default, handler: { _ in
+            guard let newFileName = alertController.textFields?.first?.text else { return }
+
+            // verify if already exists
+            if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, newFileName)) != nil {
+                NCContentPresenter().showError(error: NKError(errorCode: 0, errorDescription: "_rename_already_exists_"))
+                return
+            }
+
+            NCActivityIndicator.shared.start()
+
+            NCNetworking.shared.renameMetadata(metadata, fileNameNew: newFileName, indexPath: indexPath) { error in
+
+                NCActivityIndicator.shared.stop()
+
+                if error != .success {
+                    NCContentPresenter().showError(error: error)
+                }
+            }
+        })
+
+        // text field is initially empty, no action
+        okAction.isEnabled = false
+        let cancelAction = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel)
+
+        alertController.addTextField { textField in
+            textField.text = metadata.fileName
+            textField.autocapitalizationType = .words
+        }
+
+        // only allow saving if folder name exists
+        NotificationCenter.default.addObserver(
+            forName: UITextField.textDidBeginEditingNotification,
+            object: alertController.textFields?.first,
+            queue: .main) { _ in
+                guard let textField = alertController.textFields?.first else { return }
+
+                if let start = textField.position(from: textField.beginningOfDocument, offset: 0),
+                   let end = textField.position(from: start, offset: textField.text?.withRemovedFileExtension.count ?? 0) {
+                    textField.selectedTextRange = textField.textRange(from: start, to: end)
+                }
+            }
+
+        NotificationCenter.default.addObserver(
+            forName: UITextField.textDidChangeNotification,
+            object: alertController.textFields?.first,
+            queue: .main) { _ in
+                guard let text = alertController.textFields?.first?.text else { return }
+
+                let textCheck = FileNameValidator.shared.checkFileName(text)
+                okAction.isEnabled = textCheck?.error == nil && !text.isEmpty
+                alertController.message = textCheck?.error.localizedDescription
+            }
+
+        alertController.addAction(cancelAction)
+        alertController.addAction(okAction)
+        return alertController
+    }
+
+    static func warning(title: String? = nil, message: String? = nil) -> UIAlertController {
+        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
+
+        let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default)
+
+        alertController.addAction(okAction)
+
+        return alertController
+    }
 }

+ 1 - 0
iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift

@@ -87,6 +87,7 @@ extension NCCollectionViewCommon: NCCollectionViewCommonSelectTabBarDelegate {
 
     func move() {
         let metadatas = getSelectedMetadatas()
+
         NCActionCenter.shared.openSelectView(items: metadatas, controller: self.tabBarController as? NCMainTabBarController)
         setEditMode(false)
     }

+ 24 - 6
iOSClient/Main/Create cloud/Upload Assets/NCUploadAssetsView.swift

@@ -7,13 +7,15 @@
 //
 
 import SwiftUI
+import NextcloudKit
 
 struct NCUploadAssetsView: View {
     @ObservedObject var model: NCUploadAssetsModel
     @State private var showSelect = false
     @State private var showUploadConflict = false
     @State private var showQuickLook = false
-    @State private var shorRenameAlert = false
+    @State private var showRenameAlert = false
+    @State private var renameError = ""
     @State private var renameFileName: String = ""
     @State private var renameIndex: Int = 0
     @State private var index: Int = 0
@@ -39,7 +41,7 @@ struct NCUploadAssetsView: View {
                                         Button(action: {
                                             renameFileName = model.previewStore[index].fileName
                                             renameIndex = index
-                                            shorRenameAlert = true
+                                            showRenameAlert = true
                                         }) {
                                             Label(NSLocalizedString("_rename_", comment: ""), systemImage: "pencil")
                                         }
@@ -84,21 +86,37 @@ struct NCUploadAssetsView: View {
                                         }
                                     } label: {
                                         ImageAsset(model: model, index: index)
-                                            .alert(NSLocalizedString("_rename_file_", comment: ""), isPresented: $shorRenameAlert) {
-                                                TextField(NSLocalizedString("_enter_filename_", comment: ""), text: $renameFileName)
+                                            .alert(NSLocalizedString("_rename_", comment: ""), isPresented: $showRenameAlert) {
+                                                TextField("", text: $renameFileName)
                                                     .autocapitalization(.none)
                                                     .autocorrectionDisabled()
+
                                                 Button(NSLocalizedString("_rename_", comment: ""), action: {
-                                                    model.previewStore[renameIndex].fileName = renameFileName.trimmingCharacters(in: .whitespacesAndNewlines)
+                                                    if !renameError.isEmpty {
+                                                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
+                                                            showRenameAlert = true
+                                                        }
+                                                    } else {
+                                                        model.previewStore[renameIndex].fileName = renameFileName.trimmingCharacters(in: .whitespacesAndNewlines)
+                                                    }
                                                 })
+
                                                 Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel, action: {})
+                                            } message: {
+                                                Text(renameError)
                                             }
                                     }
+                                    .onChange(of: renameFileName) { newValue in
+                                        if let error = FileNameValidator.shared.checkFileName(newValue) {
+                                            renameError = error.errorDescription
+                                        } else {
+                                            renameError = ""
+                                        }
+                                    }
                                 }
                             }
                         }
                     }
-                    // .redacted(reason: uploadAssets.previewStore.isEmpty ? .placeholder : [])
 
                     Section {
                         Toggle(isOn: $model.useAutoUploadFolder, label: {

+ 6 - 0
iOSClient/Main/NCActionCenter.swift

@@ -575,6 +575,12 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
 
         var copyItems: [tableMetadata] = []
         for item in items {
+            if let fileNameError = FileNameValidator.shared.checkFileName(item.fileNameView) {
+                controller?.present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+
+                return
+            }
+
             copyItems.append(item)
         }
 

+ 11 - 1
iOSClient/Main/NCMainTabBar.swift

@@ -180,7 +180,7 @@ class NCMainTabBar: UITabBar {
         centerButton.layer.shadowOffset = CGSize(width: 0, height: 0)
         centerButton.layer.shadowRadius = 3.0
         centerButton.layer.shadowOpacity = 0.5
-        centerButton.action(for: .touchUpInside) { _ in
+        centerButton.action(for: .touchUpInside) { [self] _ in
 
             if let controller = self.window?.rootViewController as? NCMainTabBarController {
                 let serverUrl = controller.currentServerUrl()
@@ -191,6 +191,16 @@ class NCMainTabBar: UITabBar {
                         return
                     }
                 }
+
+                let fileFolderPath = NCUtilityFileSystem().getFileNamePath("", serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId)
+                let fileFolderName = (serverUrl as NSString).lastPathComponent
+
+                if !FileNameValidator.shared.checkFolderPath(folderPath: fileFolderPath) {
+                    controller.present(UIAlertController.warning(message: "\(String(format: NSLocalizedString("_file_name_validator_error_reserved_name_", comment: ""), fileFolderName)) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+
+                    return
+                }
+
                 self.appDelegate.toggleMenu(controller: controller)
             }
         }

+ 12 - 2
iOSClient/Main/NCPickerViewController.swift

@@ -142,8 +142,13 @@ class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
             if metadata.classFile == NKCommon.TypeClassFile.unknow.rawValue {
                 metadata.classFile = NKCommon.TypeClassFile.video.rawValue
             }
-            NCManageDatabase.shared.addMetadata(metadata)
-            NCViewer().view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: nil)
+
+            if let fileNameError = FileNameValidator.shared.checkFileName(metadata.fileNameView) {
+                mainTabBarController.present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+            } else {
+                NCManageDatabase.shared.addMetadata(metadata)
+                NCViewer().view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: nil)
+            }
 
         } else {
             let serverUrl = mainTabBarController.currentServerUrl()
@@ -161,6 +166,11 @@ class NCDocumentPickerViewController: NSObject, UIDocumentPickerDelegate {
 
                 let metadataForUpload = NCManageDatabase.shared.createMetadata(account: appDelegate.account, user: appDelegate.user, userId: appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: appDelegate.urlBase, url: "", contentType: "")
 
+                if let fileNameError = FileNameValidator.shared.checkFileName(metadataForUpload.fileNameView) {
+                    mainTabBarController.present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+                    continue
+                }
+
                 metadataForUpload.session = NCNetworking.shared.sessionUploadBackground
                 metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile
                 metadataForUpload.size = utilityFileSystem.getFileSize(filePath: toPath)

+ 1 - 11
iOSClient/Menu/NCCollectionViewCommon+Menu.swift

@@ -281,17 +281,7 @@ extension NCCollectionViewCommon {
                     icon: utility.loadImage(named: "text.cursor", colors: [NCBrandColor.shared.iconImageColor]),
                     order: 120,
                     action: { _ in
-
-                        if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile {
-
-                            vcRename.metadata = metadata
-                            vcRename.imagePreview = imageIcon
-                            vcRename.indexPath = indexPath
-
-                            let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
-
-                            self.present(popup, animated: true)
-                        }
+                        self.present(UIAlertController.renameFile(metadata: metadata, indexPath: indexPath), animated: true)
                     }
                 )
             )

+ 16 - 3
iOSClient/Menu/NCMenuAction.swift

@@ -201,9 +201,22 @@ extension NCMenuAction {
             icon: NCUtility().loadImage(named: "rectangle.portrait.and.arrow.right", colors: [NCBrandColor.shared.iconImageColor]),
             order: order,
             action: { _ in
-                let controller = viewController.tabBarController as? NCMainTabBarController
-                NCActionCenter.shared.openSelectView(items: selectedMetadatas, controller: controller)
-                completion?()
+                var fileNameError: NKError?
+
+                for metadata in selectedMetadatas {
+                    if let checkError = FileNameValidator.shared.checkFileName(metadata.fileNameView) {
+                        fileNameError = checkError
+                        break
+                    }
+                }
+
+                if let fileNameError {
+                    viewController.present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true, completion: nil)
+                } else {
+                    let controller = viewController.tabBarController as? NCMainTabBarController
+                    NCActionCenter.shared.openSelectView(items: selectedMetadatas, controller: controller)
+                    completion?()
+                }
             }
         )
     }

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

@@ -152,18 +152,7 @@ extension NCViewer {
                     title: NSLocalizedString("_rename_", comment: ""),
                     icon: utility.loadImage(named: "text.cursor", colors: [NCBrandColor.shared.iconImageColor]),
                     action: { _ in
-
-                        if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile {
-
-                            vcRename.metadata = metadata
-                            vcRename.disableChangeExt = true
-                            vcRename.imagePreview = imageIcon
-                            vcRename.indexPath = indexPath
-
-                            let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
-
-                            viewController.present(popup, animated: true)
-                        }
+                        viewController.present(UIAlertController.renameFile(metadata: metadata, indexPath: indexPath), animated: true)
                     }
                 )
             )

+ 6 - 0
iOSClient/NCGlobal.swift

@@ -451,6 +451,11 @@ class NCGlobal: NSObject {
 
     var capabilitySecurityGuardDiagnostics                      = false
 
+    var capabilityForbiddenFileNames: [String]                    = []
+    var capabilityForbiddenFileNameBasenames: [String]            = []
+    var capabilityForbiddenFileNameCharacters: [String]           = []
+    var capabilityForbiddenFileNameExtensions: [String]           = []
+
     // MORE NEXTCLOUD APPS
     let talkSchemeUrl                                           = "nextcloudtalk://"
     let notesSchemeUrl                                          = "nextcloudnotes://"
@@ -464,6 +469,7 @@ class NCGlobal: NSObject {
 
     // FORBIDDEN CHARACTERS
     //
+    // TODO: Remove this
     let forbiddenCharacters = ["/", "\\", ":", "\"", "|", "?", "*", "<", ">"]
 
     // DIAGNOSTICS CLIENTS

+ 0 - 1
iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift

@@ -44,7 +44,6 @@ class NCNetworkingE2EEUpload: NSObject {
     var numChunks: Int = 0
 
     func upload(metadata: tableMetadata, uploadE2EEDelegate: uploadE2EEDelegate? = nil, hudView: UIView?, hud: JGProgressHUD?) async -> NKError {
-
         var metadata = metadata
         let ocIdTemp = metadata.ocId
 

+ 1 - 1
iOSClient/Networking/NCNetworking+WebDAV.swift

@@ -220,6 +220,7 @@ extension NCNetworking {
         if fileNameFolder.isEmpty {
             return completion(NKError())
         }
+
         let fileNameFolderUrl = serverUrl + "/" + fileNameFolder
 
         NextcloudKit.shared.createFolder(serverUrlFileName: fileNameFolderUrl, account: account) { account, _, _, error in
@@ -411,7 +412,6 @@ extension NCNetworking {
     func renameMetadata(_ metadata: tableMetadata,
                         fileNameNew: String,
                         indexPath: IndexPath,
-                        viewController: UIViewController?,
                         completion: @escaping (_ error: NKError) -> Void) {
         let metadataLive = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata)
         let fileNameNew = fileNameNew.trimmingCharacters(in: .whitespacesAndNewlines)

+ 0 - 153
iOSClient/Rename file/NCRenameFile.storyboard

@@ -1,153 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V0q-CP-xMJ">
-    <device id="retina6_0" orientation="portrait" appearance="light"/>
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
-        <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"/>
-    </dependencies>
-    <scenes>
-        <!--Rename File-->
-        <scene sceneID="L90-uG-f4z">
-            <objects>
-                <viewController id="V0q-CP-xMJ" customClass="NCRenameFile" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
-                    <view key="view" contentMode="scaleToFill" id="gzh-6E-hc4">
-                        <rect key="frame" x="0.0" y="0.0" width="300" height="310"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <subviews>
-                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Rename" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nZr-nE-ths">
-                                <rect key="frame" x="20" y="62" width="260" height="18"/>
-                                <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
-                                <nil key="textColor"/>
-                                <nil key="highlightedColor"/>
-                            </label>
-                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="t26-3S-4T4">
-                                <rect key="frame" x="80" y="95" width="140" height="83.666666666666686"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="140" id="PaU-P7-coi"/>
-                                    <constraint firstAttribute="height" constant="140" id="s6R-ay-3Ui"/>
-                                </constraints>
-                            </imageView>
-                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FOZ-fs-k7i">
-                                <rect key="frame" x="210" y="203" width="10" height="21"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="10" id="T5K-dj-AdT"/>
-                                </constraints>
-                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
-                                <nil key="textColor"/>
-                                <nil key="highlightedColor"/>
-                            </label>
-                            <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Q9G-gl-Fkc">
-                                <rect key="frame" x="220" y="196.66666666666666" width="60" height="34"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="60" id="6ga-cj-dYT"/>
-                                </constraints>
-                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                <textInputTraits key="textInputTraits"/>
-                            </textField>
-                            <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Ny2-wR-rxo">
-                                <rect key="frame" x="20" y="198.66666666666666" width="190" height="30"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="30" id="dBg-ka-5gB"/>
-                                </constraints>
-                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                <textInputTraits key="textInputTraits"/>
-                            </textField>
-                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7CJ-Q0-ABH" userLabel="SeparatorV">
-                                <rect key="frame" x="149.66666666666666" y="244" width="0.66666666666665719" height="32"/>
-                                <color key="backgroundColor" systemColor="systemGray4Color"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="0.5" id="wU1-tA-NZk"/>
-                                </constraints>
-                            </view>
-                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ouH-gK-Guv" userLabel="SeparatorH">
-                                <rect key="frame" x="0.0" y="243.66666666666666" width="300" height="0.33333333333334281"/>
-                                <color key="backgroundColor" systemColor="systemGray4Color"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="0.5" id="2OQ-Mt-Gnh"/>
-                                </constraints>
-                            </view>
-                            <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="249" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="W5y-aT-UlI">
-                                <rect key="frame" x="0.0" y="244" width="150" height="32"/>
-                                <fontDescription key="fontDescription" type="system" pointSize="16"/>
-                                <state key="normal" title="Cancel">
-                                    <color key="titleColor" systemColor="systemBlueColor"/>
-                                </state>
-                                <connections>
-                                    <action selector="cancel:" destination="V0q-CP-xMJ" eventType="touchUpInside" id="2u6-re-dJy"/>
-                                </connections>
-                            </button>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hcV-V0-eZB">
-                                <rect key="frame" x="150" y="244" width="150" height="32"/>
-                                <fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
-                                <state key="normal" title="Rename">
-                                    <color key="titleColor" systemColor="systemBlueColor"/>
-                                </state>
-                                <connections>
-                                    <action selector="renameFile:" destination="V0q-CP-xMJ" eventType="touchUpInside" id="m9a-mj-q7P"/>
-                                </connections>
-                            </button>
-                        </subviews>
-                        <viewLayoutGuide key="safeArea" id="1c1-7Q-WMG"/>
-                        <color key="backgroundColor" systemColor="systemGray6Color"/>
-                        <constraints>
-                            <constraint firstItem="Ny2-wR-rxo" firstAttribute="leading" secondItem="1c1-7Q-WMG" secondAttribute="leading" constant="20" id="0xL-8c-oLT"/>
-                            <constraint firstItem="hcV-V0-eZB" firstAttribute="top" secondItem="ouH-gK-Guv" secondAttribute="bottom" id="1MZ-1P-Ej1"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="bottom" secondItem="hcV-V0-eZB" secondAttribute="bottom" id="2Wh-Y6-n8F"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="bottom" secondItem="7CJ-Q0-ABH" secondAttribute="bottom" id="8HO-F9-tfD"/>
-                            <constraint firstItem="Q9G-gl-Fkc" firstAttribute="leading" secondItem="FOZ-fs-k7i" secondAttribute="trailing" id="9XT-FO-xYu"/>
-                            <constraint firstItem="ouH-gK-Guv" firstAttribute="leading" secondItem="1c1-7Q-WMG" secondAttribute="leading" id="A6T-ed-97T"/>
-                            <constraint firstItem="hcV-V0-eZB" firstAttribute="leading" secondItem="W5y-aT-UlI" secondAttribute="trailing" id="Aa4-Pg-Ioh"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="trailing" secondItem="Ny2-wR-rxo" secondAttribute="trailing" constant="90" id="BZO-yF-B1w"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="trailing" secondItem="nZr-nE-ths" secondAttribute="trailing" constant="20" id="DPW-MV-oKc"/>
-                            <constraint firstItem="7CJ-Q0-ABH" firstAttribute="centerX" secondItem="1c1-7Q-WMG" secondAttribute="centerX" id="EVx-ob-2bn"/>
-                            <constraint firstItem="Ny2-wR-rxo" firstAttribute="top" secondItem="t26-3S-4T4" secondAttribute="bottom" constant="20" id="Ggg-Yg-PBS"/>
-                            <constraint firstItem="nZr-nE-ths" firstAttribute="leading" secondItem="1c1-7Q-WMG" secondAttribute="leading" constant="20" id="SI9-xL-6s8"/>
-                            <constraint firstItem="Q9G-gl-Fkc" firstAttribute="centerY" secondItem="Ny2-wR-rxo" secondAttribute="centerY" id="ZYX-EF-MUc"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="bottom" secondItem="W5y-aT-UlI" secondAttribute="bottom" id="ai8-AR-XYe"/>
-                            <constraint firstItem="7CJ-Q0-ABH" firstAttribute="top" secondItem="ouH-gK-Guv" secondAttribute="bottom" id="an1-EN-YiB"/>
-                            <constraint firstItem="t26-3S-4T4" firstAttribute="top" secondItem="nZr-nE-ths" secondAttribute="bottom" constant="15" id="and-de-reg"/>
-                            <constraint firstItem="FOZ-fs-k7i" firstAttribute="centerY" secondItem="Ny2-wR-rxo" secondAttribute="centerY" id="bRG-fN-OJB"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="trailing" secondItem="W5y-aT-UlI" secondAttribute="trailing" multiplier="2" id="g0h-1g-A3R"/>
-                            <constraint firstItem="t26-3S-4T4" firstAttribute="centerX" secondItem="1c1-7Q-WMG" secondAttribute="centerX" id="gjy-i8-K5B"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="trailing" secondItem="hcV-V0-eZB" secondAttribute="trailing" id="heW-2p-hLJ"/>
-                            <constraint firstItem="ouH-gK-Guv" firstAttribute="top" secondItem="Ny2-wR-rxo" secondAttribute="bottom" constant="15" id="ilX-ml-Dce"/>
-                            <constraint firstItem="W5y-aT-UlI" firstAttribute="leading" secondItem="1c1-7Q-WMG" secondAttribute="leading" id="kw6-l5-CAR"/>
-                            <constraint firstItem="nZr-nE-ths" firstAttribute="top" secondItem="1c1-7Q-WMG" secondAttribute="top" constant="15" id="oyJ-sj-j5N"/>
-                            <constraint firstItem="1c1-7Q-WMG" firstAttribute="trailing" secondItem="ouH-gK-Guv" secondAttribute="trailing" id="r1N-R6-iZg"/>
-                            <constraint firstItem="W5y-aT-UlI" firstAttribute="top" secondItem="ouH-gK-Guv" secondAttribute="bottom" id="ywb-oW-pJe"/>
-                            <constraint firstItem="FOZ-fs-k7i" firstAttribute="leading" secondItem="Ny2-wR-rxo" secondAttribute="trailing" id="zTq-r2-mRv"/>
-                        </constraints>
-                    </view>
-                    <navigationItem key="navigationItem" id="Zon-2j-rsc"/>
-                    <size key="freeformSize" width="300" height="310"/>
-                    <connections>
-                        <outlet property="cancelButton" destination="W5y-aT-UlI" id="P9l-o1-miU"/>
-                        <outlet property="ext" destination="Q9G-gl-Fkc" id="YeW-bU-cMx"/>
-                        <outlet property="fileNameNoExtension" destination="Ny2-wR-rxo" id="gQX-c7-EMv"/>
-                        <outlet property="fileNameNoExtensionTrailingContraint" destination="BZO-yF-B1w" id="VWV-as-Wa7"/>
-                        <outlet property="point" destination="FOZ-fs-k7i" id="InG-ZA-GpE"/>
-                        <outlet property="previewFile" destination="t26-3S-4T4" id="aOo-XG-pom"/>
-                        <outlet property="renameButton" destination="hcV-V0-eZB" id="YGX-pw-OGW"/>
-                        <outlet property="titleLabel" destination="nZr-nE-ths" id="UbA-Dl-0Ad"/>
-                    </connections>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="qdm-Cl-C5l" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="1453.125" y="133.75"/>
-        </scene>
-    </scenes>
-    <resources>
-        <systemColor name="systemBlueColor">
-            <color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-        </systemColor>
-        <systemColor name="systemGray4Color">
-            <color red="0.81960784313725488" green="0.81960784313725488" blue="0.83921568627450982" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-        </systemColor>
-        <systemColor name="systemGray6Color">
-            <color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-        </systemColor>
-    </resources>
-</document>

+ 0 - 251
iOSClient/Rename file/NCRenameFile.swift

@@ -1,251 +0,0 @@
-//
-//  NCRenameFile.swift
-//  Nextcloud
-//
-//  Created by Marino Faggiana on 26/02/21.
-//  Copyright © 2021 Marino Faggiana. All rights reserved.
-//
-//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-import UIKit
-import NextcloudKit
-
-public protocol NCRenameFileDelegate: AnyObject {
-    func rename(fileName: String, fileNameNew: String)
-}
-
-// optional func
-public extension NCRenameFileDelegate {
-    func rename(fileName: String, fileNameNew: String) {}
-}
-
-class NCRenameFile: UIViewController, UITextFieldDelegate {
-
-    @IBOutlet weak var titleLabel: UILabel!
-    @IBOutlet weak var previewFile: UIImageView!
-    @IBOutlet weak var fileNameNoExtension: UITextField!
-    @IBOutlet weak var point: UILabel!
-    @IBOutlet weak var ext: UITextField!
-    @IBOutlet weak var fileNameNoExtensionTrailingContraint: NSLayoutConstraint!
-    @IBOutlet weak var cancelButton: UIButton!
-    @IBOutlet weak var renameButton: UIButton!
-
-    let width: CGFloat = 300
-    let height: CGFloat = 310
-
-    var metadata: tableMetadata?
-    var indexPath: IndexPath = IndexPath()
-    var fileName: String?
-    var imagePreview: UIImage?
-    var disableChangeExt: Bool = false
-    weak var delegate: NCRenameFileDelegate?
-
-    // MARK: - View Life Cycle
-
-    override func viewDidLoad() {
-        super.viewDidLoad()
-
-        if let metadata = self.metadata {
-
-            if metadata.directory {
-                titleLabel.text = NSLocalizedString("_rename_folder_", comment: "")
-            } else {
-                titleLabel.text = NSLocalizedString("_rename_file_", comment: "")
-            }
-
-            fileNameNoExtension.text = (metadata.fileNameView as NSString).deletingPathExtension
-            fileNameNoExtension.delegate = self
-            fileNameNoExtension.becomeFirstResponder()
-
-            ext.text = metadata.fileExtension
-            ext.delegate = self
-            if disableChangeExt {
-                ext.isEnabled = false
-                ext.textColor = .lightGray
-            }
-
-            previewFile.image = imagePreview
-            previewFile.layer.cornerRadius = 10
-            previewFile.layer.masksToBounds = true
-
-            if metadata.directory {
-
-                if imagePreview == nil {
-                    previewFile.image = NCImageCache.images.folder
-                }
-
-                ext.isHidden = true
-                point.isHidden = true
-                fileNameNoExtensionTrailingContraint.constant = 20
-
-            } else {
-
-                if imagePreview == nil {
-                    previewFile.image = NCImageCache.images.file
-                }
-
-                fileNameNoExtensionTrailingContraint.constant = 90
-            }
-
-        } else if let fileName = self.fileName {
-
-            titleLabel.text = NSLocalizedString("_rename_file_", comment: "")
-
-            fileNameNoExtension.text = (fileName as NSString).deletingPathExtension
-            fileNameNoExtension.delegate = self
-            fileNameNoExtension.becomeFirstResponder()
-            fileNameNoExtensionTrailingContraint.constant = 90
-
-            ext.text = (fileName as NSString).pathExtension
-            ext.delegate = self
-
-            if imagePreview == nil {
-                previewFile.image = NCImageCache.images.file
-            } else {
-                previewFile.image = imagePreview
-            }
-            previewFile.layer.cornerRadius = 10
-            previewFile.layer.masksToBounds = true
-        }
-
-        cancelButton.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal)
-        cancelButton.setTitleColor(NCBrandColor.shared.brandElement, for: .normal)
-        renameButton.setTitle(NSLocalizedString("_rename_", comment: ""), for: .normal)
-        renameButton.setTitleColor(NCBrandColor.shared.brandElement, for: .normal)
-    }
-
-    override func viewDidAppear(_ animated: Bool) {
-        super.viewDidAppear(animated)
-
-        if metadata == nil && fileName == nil {
-            dismiss(animated: true)
-        }
-
-        fileNameNoExtension.selectAll(nil)
-    }
-
-    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
-
-        textField.resignFirstResponder()
-        renameFile(textField)
-        return true
-    }
-
-    // MARK: - Action
-
-    @IBAction func cancel(_ sender: Any) {
-
-        dismiss(animated: true)
-    }
-
-    @IBAction func renameFile(_ sender: Any) {
-
-        var fileNameNoExtensionNew = ""
-        var extNew = ""
-        var fileNameNew = ""
-
-        if let metadata = self.metadata {
-
-            let extCurrent = (metadata.fileNameView as NSString).pathExtension
-
-            if fileNameNoExtension.text == nil || fileNameNoExtension.text?.count == 0 {
-                return self.fileNameNoExtension.text = (metadata.fileNameView as NSString).deletingPathExtension
-            } else {
-                fileNameNoExtensionNew = fileNameNoExtension.text!
-            }
-
-            if metadata.directory {
-
-                fileNameNew = fileNameNoExtensionNew
-                renameMetadata(metadata, fileNameNew: fileNameNew, indexPath: indexPath)
-
-            } else {
-
-                if ext.text == nil || ext.text?.count == 0 {
-                    return self.ext.text = metadata.fileExtension
-                } else {
-                    extNew = ext.text!
-                }
-
-                if extNew != extCurrent {
-
-                    let message = String(format: NSLocalizedString("_rename_ext_message_", comment: ""), extNew, extCurrent)
-                    let alertController = UIAlertController(title: NSLocalizedString("_rename_ext_title_", comment: ""), message: message, preferredStyle: .alert)
-
-                    var title = NSLocalizedString("_use_", comment: "") + " ." + extNew
-                    alertController.addAction(UIAlertAction(title: title, style: .default, handler: { _ in
-
-                        fileNameNew = fileNameNoExtensionNew + "." + extNew
-                        self.renameMetadata(metadata, fileNameNew: fileNameNew, indexPath: self.indexPath)
-                    }))
-
-                    title = NSLocalizedString("_keep_", comment: "") + " ." + extCurrent
-                    alertController.addAction(UIAlertAction(title: title, style: .default, handler: { _ in
-                        self.ext.text = metadata.fileExtension
-                    }))
-
-                    self.present(alertController, animated: true)
-
-                } else {
-
-                    fileNameNew = fileNameNoExtensionNew + "." + extNew
-                    renameMetadata(metadata, fileNameNew: fileNameNew, indexPath: indexPath)
-                }
-            }
-
-        } else if let fileName = self.fileName {
-
-            if fileNameNoExtension.text == nil || fileNameNoExtension.text?.count == 0 {
-                return fileNameNoExtension.text = (fileName as NSString).deletingPathExtension
-            } else if ext.text == nil || ext.text?.count == 0 {
-                return ext.text = (fileName as NSString).pathExtension
-            }
-
-            fileNameNew = (fileNameNoExtension.text ?? "") + "." + (ext.text ?? "")
-            self.dismiss(animated: true) {
-                self.delegate?.rename(fileName: fileName, fileNameNew: fileNameNew)
-            }
-        }
-    }
-
-    // MARK: - Networking
-
-    func renameMetadata(_ metadata: tableMetadata, fileNameNew: String, indexPath: IndexPath) {
-
-        // verify if already exists
-        if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", metadata.account, metadata.serverUrl, fileNameNew)) != nil {
-            NCContentPresenter().showError(error: NKError(errorCode: 0, errorDescription: "_rename_already_exists_"))
-            return
-        }
-
-        NCActivityIndicator.shared.start()
-
-        NCNetworking.shared.renameMetadata(metadata, fileNameNew: fileNameNew, indexPath: indexPath, viewController: self) { error in
-
-            NCActivityIndicator.shared.stop()
-
-            if error == .success {
-
-                self.dismiss(animated: true)
-
-            } else {
-
-                NCContentPresenter().showError(error: error)
-            }
-        }
-    }
-}

+ 13 - 2
iOSClient/Scan document/NCUploadScanDocument.swift

@@ -321,6 +321,7 @@ extension NCUploadScanDocument: NCCreateFormUploadConflictDelegate {
 
 struct UploadScanDocumentView: View {
     @State var fileName = NCUtilityFileSystem().createFileNameDate("scan", ext: "")
+    @State var footer = ""
     @State var password: String = ""
     @State var isSecuredPassword: Bool = true
     @State var isTextRecognition: Bool = NCKeychain().textRecognitionStatus
@@ -349,7 +350,7 @@ struct UploadScanDocumentView: View {
         GeometryReader { geo in
             ZStack(alignment: .top) {
                 List {
-                    Section(header: Text(NSLocalizedString("_file_creation_", comment: ""))) {
+                    Section(header: Text(NSLocalizedString("_file_creation_", comment: "")), footer: Text(footer)) {
                         HStack {
                             Label {
                                 if NCUtilityFileSystem().getHomeServer(urlBase: uploadScanDocument.userBaseUrl.urlBase, userId: uploadScanDocument.userBaseUrl.userId) == uploadScanDocument.serverUrl {
@@ -383,6 +384,14 @@ struct UploadScanDocumentView: View {
                             TextField(NSLocalizedString("_enter_filename_", comment: ""), text: $fileName)
                                 .modifier(TextFieldClearButton(text: $fileName))
                                 .multilineTextAlignment(.trailing)
+                                .onChange(of: fileName) { _ in
+                                    if let fileNameError = FileNameValidator.shared.checkFileName(fileName) {
+                                        footer = fileNameError.errorDescription
+                                    } else {
+                                        footer = ""
+
+                                    }
+                                }
                         }
                         HStack {
                             Group {
@@ -414,6 +423,7 @@ struct UploadScanDocumentView: View {
                     .complexModifier { view in
                         view.listRowSeparator(.hidden)
                     }
+
                     VStack(spacing: 20) {
                         Toggle(NSLocalizedString("_delete_all_scanned_images_", comment: ""), isOn: $removeAllFiles)
                             .toggleStyle(SwitchToggleStyle(tint: Color(NCBrandColor.shared.brandElement)))
@@ -436,7 +446,8 @@ struct UploadScanDocumentView: View {
                                 }
                             }
                         }
-                        .buttonStyle(ButtonRounded(disabled: fileName.isEmpty))
+                        .buttonStyle(ButtonRounded(disabled: fileName.isEmpty || !footer.isEmpty))
+                        .disabled(fileName.isEmpty || !footer.isEmpty)
                     }
 
                     Section(header: Text(NSLocalizedString("_quality_image_title_", comment: ""))) {

+ 10 - 7
iOSClient/Select/NCSelect.swift

@@ -147,11 +147,11 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
     override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
 
-        self.navigationItem.title = titleCurrentFolder
+        let folderPath = utilityFileSystem.getFileNamePath("", serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId)
 
-        // set the serverUrl
-        if serverUrl.isEmpty {
+        if serverUrl.isEmpty || !FileNameValidator.shared.checkFolderPath(folderPath: folderPath) {
             serverUrl = utilityFileSystem.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId)
+            titleCurrentFolder = NCBrandOptions.shared.brand
         }
 
         // get auto upload folder
@@ -159,6 +159,8 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
         autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: activeAccount.urlBase, userId: activeAccount.userId, account: activeAccount.account)
 
         loadDatasource(withLoadFolder: true)
+
+        self.navigationItem.title = titleCurrentFolder
     }
 
     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
@@ -252,7 +254,11 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
         viewController.titleCurrentFolder = metadata.fileNameView
         viewController.serverUrl = serverUrlPush
 
-        self.navigationController?.pushViewController(viewController, animated: true)
+        if let fileNameError = FileNameValidator.shared.checkFileName(metadata.fileNameView) {
+            present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+        } else {
+            navigationController?.pushViewController(viewController, animated: true)
+        }
     }
 }
 
@@ -265,11 +271,8 @@ extension NCSelect: UICollectionViewDelegate {
         guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return }
 
         if metadata.directory {
-
             pushMetadata(metadata)
-
         } else {
-
             delegate?.dismissSelect(serverUrl: serverUrl, metadata: metadata, type: type, items: items, overwrite: overwrite, copy: false, move: false)
             self.dismiss(animated: true, completion: nil)
         }

BIN
iOSClient/Supporting Files/af.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/an.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ar.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ast.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/az.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/be.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/br.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/bs.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ca.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/da.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/de.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/el.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/en-GB.lproj/Localizable.strings


+ 13 - 6
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -944,13 +944,13 @@
 "_calendar_contacts_footer_"    = "After downloading the profile you can install it from Settings.";
 "_preview_"                 = "Preview";
 "_crop_"                    = "Crop";
-"_modify_image_desc_"       = "Tap the image for modify";
-"_message_disable_livephoto_" = "This image is a Live Photo, changing it will lose the Live effect";
+"_modify_image_desc_"       = "Tap on a file to modify or rename.";
+"_message_disable_livephoto_" = "This image is a Live Photo, changing it will lose the Live Photo effect";
 "_enable_livephoto_"        = "Enable Live Photo";
 "_disable_livephoto_"       = "Disable Live Photo";
-"_undo_modify_"             = "Undo the modify";
-"_unauthorizedFilesPasscode_" = "Files cannot be used with an activated passcode";
-"_disableFilesApp_"         = "Files cannot be used because it is disabled";
+"_undo_modify_"             = "Undo modifying";
+"_unauthorizedFilesPasscode_" = "Files app cannot be used with an activated passcode";
+"_disableFilesApp_"         = "Files app cannot be used because it is disabled";
 "_reset_application_done_"  = "Reset application, done.";
 "_rename_already_exists_"   = "A file with this name already exists";
 "_created_"                 = "Created";
@@ -985,7 +985,7 @@
 "_delete_selected_photos_"  = "Delete selected photos";
 "_media_square_"            = "Square grid";
 "_media_ratio_"             = "Aspect ratio grid";
-"_autoupload_notice_"       = "To ensure the proper functioning of the application, it is necessary to enable Background App Refresh. Otherwise, new photos or videos will not be detected when the application is in the background.\n\nAdditionally, please note that the application will not be able to detect new photos and videos if it is manually terminated. When the app is in the background, data transfer may be slower, and new photos and/or videos will generally be detected every 10 minutes, depending on the device’s battery level.\n\nTo verify that the app is functioning correctly, you can use the log file available in Advanced.";
+"_autoupload_notice_"       = "To ensure the proper functioning of the application, it is necessary to enable Background App Refresh. Otherwise, new photos or videos will not be detected when the application is in the background.\n\nAdditionally, please note that the application will not be able to detect new photos and videos if it is manually terminated. When the app is in the background, data transfer may be slower, and new photos and/or videos will generally be detected every 10 minutes, depending on the device’s battery level.\n\nTo verify that the app is functioning correctly, you can use the log file available in Advanced settings.";
 "_display_"                 = "Display";
 "_appearance_"              = "Appearance";
 "_light_"                   = "Light";
@@ -1090,3 +1090,10 @@
 
 // MARK: Login poll
 "_poll_desc_"                    = "Please complete the log in process in your browser";
+
+// MARK: File name validator
+"_file_name_validator_error_ends_with_space_period_" = "Name ends with a space or a period.";
+"_file_name_validator_error_reserved_name_" = "\"%@\" is a forbidden name.";
+"_file_name_validator_error_forbidden_file_extension_" = "\".%@\" is a forbidden file extension.";
+"_file_name_validator_error_invalid_character_" = "Name contains an invalid character: \"%@\".";
+"_please_rename_file_"      = "Please rename the file or folder.";

BIN
iOSClient/Supporting Files/eo.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-419.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-AR.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-CL.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-CO.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-CR.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-DO.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-EC.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-GT.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-HN.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-MX.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-NI.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PA.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PE.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PR.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PY.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-SV.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-UY.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/et_EE.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/eu.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fa.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fo.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fr.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ga.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/gd.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/gl.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/he.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hi_IN.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hr.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hsb.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hu.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hy.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ia.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/id.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ig.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/is.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/it.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ka.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/kab.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/km.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/kn.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ko.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/la.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lb.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lo.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lv.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/mk.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/mn.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/mr.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ms_MY.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/my.lproj/Localizable.strings


Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff