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