diff --git a/Tests/NextcloudUnitTests/RenameFileTests.swift b/Tests/NextcloudUnitTests/RenameFileTests.swift
new file mode 100644
index 0000000000..c0aa06f029
--- /dev/null
+++ b/Tests/NextcloudUnitTests/RenameFileTests.swift
@@ -0,0 +1,108 @@
+//
+// RenameFileTests.swift
+// NextcloudTests
+//
+// Created by A200073704 on 14/06/23.
+// Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+@testable import Nextcloud
+import XCTest
+import NextcloudKit
+
+class RenameFileTests: XCTestCase {
+
+
+ override func setUpWithError() throws {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDownWithError() throws {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ }
+
+
+ func testStoryboardPresence() {
+
+ let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil)
+ XCTAssertNotNil(storyboard, "Storyboard 'NCRenameFile' should be present")
+
+ }
+
+ func testRenameButtonPresence() {
+ let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil)
+ guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else {
+ XCTFail("Failed to instantiate view controller from storyboard")
+ return
+ }
+
+ _ = viewController.view // Load the view
+
+ let renameButton = viewController.renameButton
+ XCTAssertNotNil(renameButton, "Rename button should be present")
+ }
+
+ func testRenameButtonBackgroundColor() {
+
+ let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil)
+ guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else {
+ XCTFail("Failed to instantiate view controller from storyboard")
+ return
+ }
+
+ _ = viewController.view // Load the view
+
+ let color = NCBrandColor.shared.brand.cgColor
+ let renameButton = viewController.renameButton.layer.backgroundColor
+
+ XCTAssertEqual(renameButton,color, "Rename Button Bcakground Color should be brand")
+ }
+
+ func testCancelButtonPresence() {
+ let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil)
+ guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else {
+ XCTFail("Failed to instantiate view controller from storyboard")
+ return
+ }
+
+ _ = viewController.view // Load the view
+
+ let cancelButton = viewController.cancelButton
+ XCTAssertNotNil(cancelButton, "Cancel button should be present")
+ }
+
+ func testImageViewPresence() {
+
+ let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil)
+ guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else {
+ XCTFail("Failed to instantiate view controller from storyboard")
+ return
+ }
+
+ _ = viewController.view // Load the view
+
+ let imageView = viewController.previewFile
+ XCTAssertNotNil(imageView, "UIImageView should be present on the storyboard")
+ }
+
+ func testTextFiledPresence() {
+
+ let storyboard = UIStoryboard(name: "NCRenameFile", bundle: nil)
+ guard let viewController = storyboard.instantiateInitialViewController() as? NCRenameFile else {
+ XCTFail("Failed to instantiate view controller from storyboard")
+ return
+ }
+
+ _ = viewController.view // Load the view
+
+ let textField = viewController.fileNameNoExtension
+ let textFieldExt = viewController.ext
+
+ XCTAssertNotNil(textField, "FileNameNoExtention TextFiled should be present on the storyboard")
+ XCTAssertNotNil(textFieldExt, "Extension TextFiled should be present on the storyboard")
+
+ }
+
+
+
+}
diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
index 16ca2ab50d..4c8a10b987 100644
--- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
+++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
@@ -333,6 +333,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDeleteFile), object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCopyMoveFile), object: nil)
+ NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCopyFile), object: nil)
+ NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterMoveFile), object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterRenameFile), object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCreateFolder), object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterFavoriteFile), object: nil)
diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift
index b8738d0c6a..6ac8ce99c4 100644
--- a/iOSClient/NCGlobal.swift
+++ b/iOSClient/NCGlobal.swift
@@ -318,6 +318,8 @@ class NCGlobal: NSObject {
let notificationCenterCreateFolder = "createFolder" // userInfo: ocId, serverUrl, account, withPush, sceneIdentifier
let notificationCenterDeleteFile = "deleteFile" // userInfo: [ocId], error
let notificationCenterCopyMoveFile = "copyMoveFile" // userInfo: [ocId] serverUrl, account, dragdrop, type (copy, move)
+ let notificationCenterMoveFile = "moveFile" // userInfo: [ocId], [indexPath], error
+ let notificationCenterCopyFile = "copyFile" // userInfo: [ocId], [indexPath], error
let notificationCenterRenameFile = "renameFile" // userInfo: serverUrl, account, error
let notificationCenterFavoriteFile = "favoriteFile" // userInfo: ocId, serverUrl
let notificationCenterFileExists = "fileExists" // userInfo: ocId, fileExists
diff --git a/iOSClient/Rename file/NCRenameFile.storyboard b/iOSClient/Rename file/NCRenameFile.storyboard
new file mode 100644
index 0000000000..6e98f850cc
--- /dev/null
+++ b/iOSClient/Rename file/NCRenameFile.storyboard
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Rename file/NCRenameFile.swift b/iOSClient/Rename file/NCRenameFile.swift
new file mode 100644
index 0000000000..723e02ed3f
--- /dev/null
+++ b/iOSClient/Rename file/NCRenameFile.swift
@@ -0,0 +1,263 @@
+//
+// NCRenameFile.swift
+// Nextcloud
+//
+// Created by Marino Faggiana on 26/02/21.
+// Copyright © 2021 Marino Faggiana. All rights reserved.
+//
+// Author Marino Faggiana
+//
+// 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 .
+//
+
+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 separatorHeightContraint: NSLayoutConstraint!
+ @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!
+ @IBOutlet weak var seperator: UIView!
+
+ let width: CGFloat = 300
+ let height: CGFloat = 350
+
+ 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: "")
+ }
+ separatorHeightContraint.constant = 0.3
+ seperator.backgroundColor = NCBrandColor.shared.seperatorRename
+ fileNameNoExtension.backgroundColor = .secondarySystemGroupedBackground
+ 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.iconColor, for: .normal)
+ cancelButton.layer.cornerRadius = 5
+ cancelButton.layer.masksToBounds = true
+ cancelButton.layer.borderWidth = 0.3
+ cancelButton.layer.borderColor = NCBrandColor.shared.iconColor.cgColor
+
+ renameButton.setTitle(NSLocalizedString("_rename_", comment: ""), for: .normal)
+ renameButton.setTitleColor(NCBrandColor.shared.brandText, for: .normal)
+ renameButton.layer.cornerRadius = 5
+ renameButton.layer.masksToBounds = true
+ renameButton.layer.backgroundColor = NCBrandColor.shared.brand.cgColor
+ }
+
+ 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)
+ }
+ }
+ }
+}