diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 4c951b95c0..cae6b48575 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -85,6 +85,12 @@ AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; }; AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; }; AFCE353927E5DE0500FEA6C2 /* Shareable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* Shareable.swift */; }; + AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; }; + B5D45E6D2DA510E000773929 /* NCRenameFile.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5D45E6A2DA510E000773929 /* NCRenameFile.storyboard */; }; + B5D45E6E2DA510E000773929 /* NCRenameFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D45E6B2DA510E000773929 /* NCRenameFile.swift */; }; + B5D45E702DA5119A00773929 /* RenameFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D45E6F2DA5119A00773929 /* RenameFileTests.swift */; }; + C04E2F232A17BB4D001BAD85 /* FilesIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */; }; + D575039F27146F93008DC9DC /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; }; F310B1EF2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */; }; F317C82E2E844C5300761AEA /* ClientIntegrationUIViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F317C82D2E844C5300761AEA /* ClientIntegrationUIViewer.swift */; }; @@ -1235,6 +1241,10 @@ AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = ""; }; AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = ""; }; AFCE353827E5DE0400FEA6C2 /* Shareable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shareable.swift; sourceTree = ""; }; + AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = ""; }; + B5D45E6A2DA510E000773929 /* NCRenameFile.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCRenameFile.storyboard; sourceTree = ""; }; + B5D45E6B2DA510E000773929 /* NCRenameFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCRenameFile.swift; sourceTree = ""; }; + B5D45E6F2DA5119A00773929 /* RenameFileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameFileTests.swift; sourceTree = ""; }; C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = ""; }; @@ -2042,6 +2052,8 @@ isa = PBXGroup; children = ( AA52EB452D42AC5A0089C348 /* Placeholder.swift */, + B5D45E6F2DA5119A00773929 /* RenameFileTests.swift */, + AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */, ); path = NextcloudUnitTests; sourceTree = ""; @@ -2080,6 +2092,15 @@ path = Advanced; sourceTree = ""; }; + B5D45E6C2DA510E000773929 /* Rename file */ = { + isa = PBXGroup; + children = ( + B5D45E6A2DA510E000773929 /* NCRenameFile.storyboard */, + B5D45E6B2DA510E000773929 /* NCRenameFile.swift */, + ); + path = "Rename file"; + sourceTree = ""; + }; C0046CDB2A17B98400D87C9D /* NextcloudUITests */ = { isa = PBXGroup; children = ( @@ -3292,6 +3313,7 @@ F7381ED9218218A4000B1560 /* Offline */, F713418B2597513800768D21 /* PushNotification */, F765F72E25237E3F00391DBE /* Recent */, + B5D45E6C2DA510E000773929 /* Rename file */, F7CADB3D23CCDDA1000EEC78 /* RichWorkspace */, F76882042C0DD1E7001CF441 /* Settings */, F758B41E212C516300515F55 /* Scan document */, @@ -3981,6 +4003,8 @@ F7381EE5218218C9000B1560 /* NCOffline.storyboard in Resources */, F768822D2C0DD1E7001CF441 /* Acknowledgements.rtf in Resources */, F76D3CF32428B94E005DFA87 /* NCViewerPDFSearchCell.xib in Resources */, + F7CA212E25F1333300826ABB /* NCAccountRequest.storyboard in Resources */, + B5D45E6D2DA510E000773929 /* NCRenameFile.storyboard in Resources */, F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */, F723B3DD22FC6D1D00301EFE /* NCShareCommentsCell.xib in Resources */, F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */, @@ -4116,6 +4140,7 @@ files = ( AA52EB472D42AC9E0089C348 /* Placeholder.swift in Sources */, F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */, + B5D45E702DA5119A00773929 /* RenameFileTests.swift in Sources */, F78E2D6C29AF02DB0024D4F3 /* Database.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4745,6 +4770,7 @@ F763D29D2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */, F76882252C0DD1E7001CF441 /* NCSettingsAdvancedModel.swift in Sources */, F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */, + B5D45E6E2DA510E000773929 /* NCRenameFile.swift in Sources */, F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */, F78B87E72B62527100C65ADC /* NCMediaDataSource.swift in Sources */, F76882272C0DD1E7001CF441 /* NCManageE2EEView.swift in Sources */, 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 37b71d071c..f8d9b7cefe 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -230,6 +230,14 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, let dropInteraction = UIDropInteraction(delegate: self) self.navigationController?.navigationItem.leftBarButtonItems?.first?.customView?.addInteraction(dropInteraction) + if(!UserDefaults.standard.bool(forKey: "isInitialPrivacySettingsShowed") || isApplicationUpdated()){ + redirectToPrivacyViewController() + + //set current app version + let appVersion = Bundle.main.infoDictionary?["CFBundleInfoDictionaryVersion"] as? String + UserDefaults.standard.set(appVersion, forKey: "CurrentAppVersion") + } + registerForTraitChanges([UITraitUserInterfaceStyle.self]) { [weak self] (view: NCCollectionViewCommon, _) in guard let self else { return } @@ -251,6 +259,8 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } } + NotificationCenter.default.addObserver(self, selector: #selector(updateIcons), name: NSNotification.Name(rawValue: global.notificationCenterUpdateIcons), object: nil) + DispatchQueue.main.async { self.collectionView?.collectionViewLayout.invalidateLayout() } @@ -259,6 +269,8 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) +// AnalyticsHelper.shared.displayInAppNotification() + if titlePreviusFolder != nil { navigationController?.navigationBar.topItem?.title = titlePreviusFolder } @@ -298,6 +310,9 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) + // Re-evaluate in-app messages after viewDidAppear + MoEngageAnalytics.shared.displayInAppNotificationSafely(reason: "viewDidAppear") + NotificationCenter.default.addObserver(self, selector: #selector(applicationWillResignActive(_:)), name: UIApplication.willResignActiveNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(closeRichWorkspaceWebView), name: NSNotification.Name(rawValue: global.notificationCenterCloseRichWorkspaceWebView), object: nil) } @@ -351,6 +366,26 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, override var canBecomeFirstResponder: Bool { return true } + + @objc func updateIcons() { +// collectionView.reloadData() + Task { + await self.reloadDataSource() + } + } + + func isApplicationUpdated() -> Bool { + let appVersion = Bundle.main.infoDictionary?["CFBundleInfoDictionaryVersion"] as? String ?? "" + let currentVersion = UserDefaults.standard.string(forKey: "CurrentAppVersion") + return currentVersion != appVersion + } + + func redirectToPrivacyViewController() { + let storyBoard: UIStoryboard = UIStoryboard(name: "NCSettings", bundle: nil) + let newViewController = storyBoard.instantiateViewController(withIdentifier: "privacySettingsNavigation") as? UINavigationController + newViewController?.modalPresentationStyle = .fullScreen + self.present(newViewController!, animated: true, completion: nil) + } // MARK: - NotificationCenter @@ -470,7 +505,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, searchController?.searchBar.alpha = 1 } else { searchController?.searchBar.alpha = 0.3 - } } @@ -514,6 +548,62 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, // MARK: - TAP EVENT + func tapMoreListItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { + tapMoreGridItem(with: ocId, ocIdTransfer: ocIdTransfer, image: image, sender: sender) + } + + func tapMorePhotoItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { + tapMoreGridItem(with: ocId, ocIdTransfer: ocIdTransfer, image: image, sender: sender) + } + + func tapShareListItem(with ocId: String, ocIdTransfer: String, sender: Any) { + guard let metadata = self.database.getMetadataFromOcId(ocId) else { return } + TealiumHelper.shared.trackEvent(title: "magentacloud-app.filebrowser.sharing", data: ["": ""]) + appDelegate.adjust.trackEvent(TriggerEvent(Sharing.rawValue)) + + NCCreate().createShare(viewController: self, metadata: metadata, page: .sharing) + } + + func tapMoreGridItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { + guard let metadata = self.database.getMetadataFromOcId(ocId) else { return } + toggleMenu(metadata: metadata, image: image, sender: sender) + } + +// func tapRichWorkspace(_ sender: Any) { +// if let navigationController = UIStoryboard(name: "NCViewerRichWorkspace", bundle: nil).instantiateInitialViewController() as? UINavigationController { +// if let viewerRichWorkspace = navigationController.topViewController as? NCViewerRichWorkspace { +// viewerRichWorkspace.richWorkspaceText = richWorkspaceText ?? "" +// viewerRichWorkspace.serverUrl = serverUrl +// viewerRichWorkspace.delegate = self +// +// navigationController.modalPresentationStyle = .fullScreen +// self.present(navigationController, animated: true, completion: nil) +// } +// } +// } + +// func tapRecommendationsButtonMenu(with metadata: tableMetadata, image: UIImage?, sender: Any?) { +// toggleMenu(metadata: metadata, image: image, sender: sender) +// } + +// func tapButtonSection(_ sender: Any, metadataForSection: NCMetadataForSection?) { +// unifiedSearchMore(metadataForSection: metadataForSection) +// } + +// func tapRecommendations(with metadata: tableMetadata) { +// didSelectMetadata(metadata, withOcIds: false) +// } + + func longPressListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func longPressGridItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func longPressMoreListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func longPressPhotoItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func longPressMoreGridItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + @objc func longPressCollecationView(_ gestureRecognizer: UILongPressGestureRecognizer) { openMenuItems(with: nil, gestureRecognizer: gestureRecognizer) } diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 1b84d949ed..10b53cfbe2 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -52,6 +52,8 @@ final class NCGlobal: Sendable { let nextcloudVersion28: Int = 28 let nextcloudVersion30: Int = 30 let nextcloudVersion31: Int = 31 + let nextcloudVersionFuture: Int = 99999 + // Nextcloud unsupported // @@ -60,6 +62,7 @@ final class NCGlobal: Sendable { // Intro selector // let introLogin: Int = 0 + let introSignup: Int = 1 let introSignUpWithProvider: Int = 1 // Avatar @@ -128,6 +131,7 @@ final class NCGlobal: Sendable { let layoutViewOffline = "LayoutOffline" let layoutViewFavorite = "LayoutFavorite" let layoutViewFiles = "LayoutFiles" + let layoutViewTransfers = "LayoutTransfers" let layoutViewRecent = "LayoutRecent" let layoutViewShares = "LayoutShares" let layoutViewShareExtension = "LayoutShareExtension" @@ -138,7 +142,34 @@ final class NCGlobal: Sendable { // let buttonMoreMore = "more" let buttonMoreLock = "moreLock" - + let buttonMoreStop = "stop" + + // Standard height sections header/footer + // + let heightButtonsView: CGFloat = 50 + let heightHeaderTransfer: CGFloat = 50 + let heightSection: CGFloat = 30 + let heightFooter: CGFloat = 1 + let heightFooterButton: CGFloat = 30 + let endHeightFooter: CGFloat = 85 + + // Text - OnlyOffice - Collabora - QuickLook + // + let editorText = "text" + let editorOnlyoffice = "onlyoffice" + let editorCollabora = "collabora" + let editorQuickLook = "quicklook" + + let onlyofficeDocx = "onlyoffice_docx" + let onlyofficeXlsx = "onlyoffice_xlsx" + let onlyofficePptx = "onlyoffice_pptx" + + // Template + // + let templateDocument = "document" + let templateSpreadsheet = "spreadsheet" + let templatePresentation = "presentation" + // Rich Workspace // let fileNameRichWorkspace = "Readme.md" @@ -221,7 +252,9 @@ final class NCGlobal: Sendable { let selectorSaveAsScan = "saveAsScan" let selectorOpenDetail = "openDetail" let selectorSynchronizationOffline = "synchronizationOffline" - + let selectorPrint = "print" + let selectorDeleteFile = "deleteFile" + // Metadata : Status // // 0 normal @@ -274,6 +307,16 @@ final class NCGlobal: Sendable { let notificationCenterCheckUserDelaultErrorDone = "checkUserDelaultErrorDone" // userInfo: account, controller let notificationCenterServerDidUpdate = "serverDidUpdate" // userInfo: account let notificationCenterNetworkReachability = "networkReachability" + let notificationCenterDidCreateShareLink = "didCreateShareLink" + + 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 + let notificationCenterReloadDataSource = "reloadDataSource" // userInfo: serverUrl?, clearDataSource let notificationCenterMenuSearchTextPDF = "menuSearchTextPDF" let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF" @@ -281,6 +324,7 @@ final class NCGlobal: Sendable { let notificationCenterOpenMediaDetail = "openMediaDetail" // userInfo: ocId let notificationCenterDismissScanDocument = "dismissScanDocument" + let notificationCenterDismissUploadAssets = "dismissUploadAssets" let notificationCenterEnableSwipeGesture = "enableSwipeGesture" let notificationCenterDisableSwipeGesture = "disableSwipeGesture" @@ -305,7 +349,7 @@ final class NCGlobal: Sendable { let networkingStatusUploaded = "statusUploaded" let networkingStatusReloadAvatar = "statusReloadAvatar" - + let notificationCenterUpdateIcons = "updateIcons" // TIP // @@ -388,7 +432,21 @@ final class NCGlobal: Sendable { // let taskDescriptionRetrievesProperties = "retrievesProperties" let taskDescriptionSynchronization = "synchronization" - + let taskDescriptionDeleteFileOrFolder = "deleteFileOrFolder" + + // MoEngage App Version + // + let moEngageAppVersion = 854 + + // Filename Mask and Type + // + let keyFileNameMask = "fileNameMask" + let keyFileNameType = "fileNameType" + let keyFileNameAutoUploadMask = "fileNameAutoUploadMask" + let keyFileNameAutoUploadType = "fileNameAutoUploadType" + let keyFileNameOriginal = "fileNameOriginal" + let keyFileNameOriginalAutoUpload = "fileNameOriginalAutoUpload" + // LOG TAG // let logTagTask = "BGT" @@ -407,6 +465,10 @@ final class NCGlobal: Sendable { // let udMigrationMultiDomains = "migrationMultiDomains" let udLastVersion = "lastVersion" + + // Album + // + let selectedTabIndexAlbum: Int = 3 } /** 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..404afeedba --- /dev/null +++ b/iOSClient/Rename file/NCRenameFile.swift @@ -0,0 +1,275 @@ +// +// 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 imageCache = NCImageCache.shared + + 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 + } + NCUtility().createImageFileFrom(metadata: metadata) + if let image = NCUtility().getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt512, userId: metadata.userId, urlBase: metadata.urlBase) { + Task { @MainActor in + previewFile.image = image + } + } + + previewFile.layer.cornerRadius = 10 + previewFile.layer.masksToBounds = true + + if metadata.directory { + + if imagePreview == nil { + previewFile.image = imageCache.getFolder() + } + + ext.isHidden = true + point.isHidden = true + fileNameNoExtensionTrailingContraint.constant = 20 + + } else { + + if imagePreview == nil { + previewFile.image = imageCache.getImageFile() + } + + 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 = imageCache.getImageFile() + } else { + previewFile.image = imagePreview + } + previewFile.layer.cornerRadius = 10 + previewFile.layer.masksToBounds = true + } + + cancelButton.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal) + cancelButton.setTitleColor(NCBrandColor.shared.iconImageColor, for: .normal) + cancelButton.layer.cornerRadius = 5 + cancelButton.layer.masksToBounds = true + cancelButton.layer.borderWidth = 0.3 + cancelButton.layer.borderColor = NCBrandColor.shared.iconImageColor.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) + + // Re-evaluate in-app messages after viewDidAppear + MoEngageAnalytics.shared.displayInAppNotificationSafely(reason: "viewDidAppear") + + 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) + NCNetworking.shared.renameMetadata(metadata, fileNameNew: fileNameNew, indexPath: indexPath, viewController: self) { error in + + NCActivityIndicator.shared.stop() + + if error == .success { + + DispatchQueue.main.async { + self.dismiss(animated: true) + } + + } else { + + NCContentPresenter().showError(error: error) + } + } + } +}