From bcc5bdd5fd4002660f530de8c3619a41eb8d3009 Mon Sep 17 00:00:00 2001 From: Shweta Waikar Date: Tue, 13 Jun 2023 14:33:11 +0530 Subject: [PATCH 1/6] NMC 2267 Rename file/folder customisation --- iOSClient/Rename file/NCRenameFile.storyboard | 135 +++++++++ iOSClient/Rename file/NCRenameFile.swift | 263 ++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 iOSClient/Rename file/NCRenameFile.storyboard create mode 100644 iOSClient/Rename file/NCRenameFile.swift 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) + } + } + } +} From 328193d794b4e8799059f20d0e7d671970126d7d Mon Sep 17 00:00:00 2001 From: Shweta Waikar Date: Wed, 14 Jun 2023 12:42:25 +0530 Subject: [PATCH 2/6] NMC 2267 - Unit test cases added for rename file --- .../NextcloudUnitTests/RenameFileTests.swift | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Tests/NextcloudUnitTests/RenameFileTests.swift 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") + + } + + + +} From d0ee4acbd0ae08ca43832d94d6b1669aad7bf1d4 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:18:04 +0530 Subject: [PATCH 3/6] NMC 2267 - NMC 2880 File- Renaming file from its preview doesn't change filename --- .../NCCollectionViewCommon.swift | 21 +++++++++++++++ iOSClient/NCGlobal.swift | 27 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 7db4928ad4..c0dceb9ea2 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -374,6 +374,27 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCloseRichWorkspaceWebView), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterChangeStatusFolderE2EE), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterChangeLayout), object: nil) + + 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) + + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDownloadStartFile), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDownloadedFile), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDownloadCancelFile), object: nil) + + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadStartFile), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadedFile), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadedLivePhoto), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadCancelFile), object: nil) + + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUpdateShare), object: nil) removeImageCache(metadatas: self.dataSource.getMetadatas()) } diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 81f58bb5f2..683890eb2f 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -252,6 +252,33 @@ final class NCGlobal: Sendable { let notificationCenterCheckUserDelaultErrorDone = "checkUserDelaultErrorDone" // userInfo: account, controller let notificationCenterServerDidUpdate = "serverDidUpdate" // userInfo: account let notificationCenterNetworkReachability = "networkReachability" + let notificationCenterUpdateNotification = "updateNotification" + let notificationCenterReloadDataSource = "reloadDataSource" // userInfo: serverUrl?, clearDataSource + let notificationCenterGetServerData = "getServerData" // userInfo: serverUrl? + + let notificationCenterChangeStatusFolderE2EE = "changeStatusFolderE2EE" // userInfo: serverUrl + + let notificationCenterDownloadStartFile = "downloadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account + let notificationCenterDownloadedFile = "downloadedFile" // userInfo: ocId, ocIdTransfer, session, session, serverUrl, account, selector, error + let notificationCenterDownloadCancelFile = "downloadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account + + let notificationCenterUploadStartFile = "uploadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, sessionSelector + let notificationCenterUploadedFile = "uploadedFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error + let notificationCenterUploadedLivePhoto = "uploadedLivePhoto" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error + let notificationCenterUploadCancelFile = "uploadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account + + let notificationCenterProgressTask = "progressTask" // userInfo: account, ocId, ocIdTransfer, session, serverUrl, status, chunk, e2eEncrypted, progress, totalBytes, totalBytesExpected + + let notificationCenterUpdateBadgeNumber = "updateBadgeNumber" // userInfo: counterDownload, counterUpload + + 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 let notificationCenterMenuSearchTextPDF = "menuSearchTextPDF" let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF" From edc98a6e38673ef7d245a3e78978f14e2dff44a6 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Tue, 8 Apr 2025 13:42:47 +0530 Subject: [PATCH 4/6] NMC 2267 - Rename file/folder customisation --- Nextcloud.xcodeproj/project.pbxproj | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index a3788d3efc..863672c3d3 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -84,7 +84,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 */; }; - CB3666201AF7550816B5CD6A /* NCContextMenuComment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8932E90EC4278026D86CCCC9 /* NCContextMenuComment.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 */; }; F31165022F9674A1009A1E37 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = F31165012F9674A1009A1E37 /* AppIcon.icon */; }; @@ -1268,8 +1273,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 = ""; }; - B4C7A5B36D1ED178FB6B76CB /* NCContextMenuPlayerTracks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCContextMenuPlayerTracks.swift; sourceTree = ""; }; - BB7697C94BA14450A0867940 /* NCContextMenuProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCContextMenuProfile.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 = ""; }; @@ -2094,6 +2101,8 @@ children = ( F34BDB3B2F574A58007A222C /* BidiSafeFilenameTests.swift */, AA52EB452D42AC5A0089C348 /* Placeholder.swift */, + B5D45E6F2DA5119A00773929 /* RenameFileTests.swift */, + AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */, ); path = NextcloudUnitTests; sourceTree = ""; @@ -2132,6 +2141,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 = ( @@ -3366,6 +3384,7 @@ F7381ED9218218A4000B1560 /* Offline */, F713418B2597513800768D21 /* PushNotification */, F765F72E25237E3F00391DBE /* Recent */, + B5D45E6C2DA510E000773929 /* Rename file */, F7CADB3D23CCDDA1000EEC78 /* RichWorkspace */, F76882042C0DD1E7001CF441 /* Settings */, F758B41E212C516300515F55 /* Scan document */, @@ -4059,6 +4078,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 */, @@ -4227,6 +4248,7 @@ AA52EB472D42AC9E0089C348 /* Placeholder.swift in Sources */, F34BDB3C2F574A58007A222C /* BidiSafeFilenameTests.swift in Sources */, F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */, + B5D45E702DA5119A00773929 /* RenameFileTests.swift in Sources */, F78E2D6C29AF02DB0024D4F3 /* Database.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4883,6 +4905,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 */, From 50d80ebf36deb6fdf2ccc547ba3c72b0ab656af8 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Tue, 30 Sep 2025 18:30:21 +0530 Subject: [PATCH 5/6] NMC 2267 - Rename file/folder customisation changes --- .../NCCollectionViewCommon.swift | 758 +++++++++++++++++- iOSClient/NCGlobal.swift | 280 +++++-- 2 files changed, 953 insertions(+), 85 deletions(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index c0dceb9ea2..b5dd38d4ce 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -4,10 +4,12 @@ import UIKit import SwiftUI +import Realm import RealmSwift import NextcloudKit import EasyTipView import LucidBanner +import MoEngageInApps class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, UIAdaptivePresentationControllerDelegate, UIContextMenuInteractionDelegate { @@ -101,6 +103,11 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, internal let heightHeaderRecommendations: CGFloat = 160 internal let heightHeaderSection: CGFloat = 30 + var isTransitioning: Bool = false + var selectableDataSource: [RealmSwiftObject] { dataSource.getMetadataSourceForAllSections() } + var pushed: Bool = false + var emptyDataSet: NCEmptyDataSet? + internal var isLayoutPhoto: Bool { layoutForView?.layout == global.layoutPhotoRatio || layoutForView?.layout == global.layoutPhotoSquare @@ -152,7 +159,17 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, SceneManager.shared.getWindowScene(controller: self.tabBarController as? NCMainTabBarController) } - internal var isNumberOfItemsInAllSectionsNull: Bool { + var defaultPredicate: NSPredicate { + let predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND NOT (status IN %@) AND NOT (livePhotoFile != '' AND classFile == %@)", session.account, self.serverUrl, NCGlobal.shared.metadataStatusHideInView, NKCommon.TypeClassFile.video.rawValue) + return predicate + } + + var personalFilesOnlyPredicate: NSPredicate { + let predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND (ownerId == %@ || ownerId == '') AND mountType == '' AND NOT (status IN %@) AND NOT (livePhotoFile != '' AND classFile == %@)", session.account, self.serverUrl, session.userId, global.metadataStatusHideInView, NKCommon.TypeClassFile.video.rawValue) + return predicate + } + + var isNumberOfItemsInAllSectionsNull: Bool { var totalItems = 0 for section in 0.. 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) + } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) @@ -463,6 +568,413 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, self.present(alertController, animated: true) } } + + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + + if let frame = tabBarController?.tabBar.frame { + tabBarSelect?.hostingController?.view.frame = frame + } + } + + // MARK: - NotificationCenter + +// @objc func applicationWillResignActive(_ notification: NSNotification) { +// self.resetPlusButtonAlpha() +// self.refreshControl.endRefreshing() +// } + + @objc func reloadAvatar(_ notification: NSNotification) { + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + self.showTipAccounts() + } + guard let userInfo = notification.userInfo as NSDictionary?, + let error = userInfo["error"] as? NKError, + error.errorCode != global.errorNotModified else { return } + /// Magentacloud branding changes hide user account button on left navigation bar + setNavigationLeftItems() + } + + @objc func changeTheming(_ notification: NSNotification) { + self.reloadDataSource() + } + + @objc func changeLayout(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let account = userInfo["account"] as? String, + let serverUrl = userInfo["serverUrl"] as? String, + let layoutForView = userInfo["layoutForView"] as? NCDBLayoutForView, + account == session.account, + serverUrl == self.serverUrl + else { return } + + if self.layoutForView?.layout == layoutForView.layout { + self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView) + self.reloadDataSource() + return + } + + self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView) + layoutForView.layout = layoutForView.layout + self.layoutType = layoutForView.layout + + collectionView.reloadData() + + switch layoutForView.layout { + case global.layoutList: + self.collectionView.setCollectionViewLayout(self.listLayout, animated: true) + case global.layoutGrid: + self.collectionView.setCollectionViewLayout(self.gridLayout, animated: true) + case global.layoutPhotoSquare, global.layoutPhotoRatio: + self.collectionView.setCollectionViewLayout(self.mediaLayout, animated: true) + default: + break + } + + self.collectionView.collectionViewLayout.invalidateLayout() + +// (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() + } + + @objc func reloadDataSource(_ notification: NSNotification) { + if let userInfo = notification.userInfo as? NSDictionary { + if let serverUrl = userInfo["serverUrl"] as? String { + if serverUrl != self.serverUrl { + return + } + } + + if let clearDataSource = userInfo["clearDataSource"] as? Bool, clearDataSource { + self.dataSource.removeAll() + } + } + + reloadDataSource() + } + + @objc func getServerData(_ notification: NSNotification) { + if let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String { + if serverUrl != self.serverUrl { + return + } + } + + getServerData() + } + + @objc func reloadHeader(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let account = userInfo["account"] as? String, + account == session.account + else { return } + + self.collectionView.reloadData() + } + + @objc func changeStatusFolderE2EE(_ notification: NSNotification) { + reloadDataSource() + } + + @objc func closeRichWorkspaceWebView() { + reloadDataSource() + } + + @objc func deleteFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let error = userInfo["error"] as? NKError else { return } + + if error == .success { + if isSearchingMode { + return networkSearch() + } + + if isRecommendationActived { + Task.detached { + await NCNetworking.shared.createRecommendations(session: self.session) + } + } + } else { + NCContentPresenter().showError(error: error) + } + + reloadDataSource() + } + + @objc func copyMoveFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String, + account == session.account else { return } + + if isSearchingMode { + return networkSearch() + } + + if isRecommendationActived { + Task.detached { + await NCNetworking.shared.createRecommendations(session: self.session) + } + } + + if serverUrl == self.serverUrl { + reloadDataSource() + } + } + + @objc func renameFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let account = userInfo["account"] as? String, + let serverUrl = userInfo["serverUrl"] as? String, + let error = userInfo["error"] as? NKError, + account == session.account + else { return } + + if error == .success { + if isSearchingMode { + return networkSearch() + } + + if isRecommendationActived { + Task.detached { + await NCNetworking.shared.createRecommendations(session: self.session) + } + } + } + + if serverUrl == self.serverUrl { + if error != .success { + NCContentPresenter().showError(error: error) + } + reloadDataSource() + } else { + collectionView.reloadData() + } + } + + @objc func createFolder(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let ocId = userInfo["ocId"] as? String, + let account = userInfo["account"] as? String, + account == session.account, + let withPush = userInfo["withPush"] as? Bool, + let metadata = database.getMetadataFromOcId(ocId) + else { return } + + if isSearchingMode { + return networkSearch() + } + + if metadata.serverUrl + "/" + metadata.fileName == self.serverUrl { + reloadDataSource() + } else if withPush, metadata.serverUrl == self.serverUrl { + reloadDataSource() + if let sceneIdentifier = userInfo["sceneIdentifier"] as? String { + if sceneIdentifier == controller?.sceneIdentifier { + pushMetadata(metadata) + } + } else { + pushMetadata(metadata) + } + } + } + + @objc func favoriteFile(_ notification: NSNotification) { + if isSearchingMode { + return networkSearch() + } + + if self is NCFavorite { + return reloadDataSource() + } + + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + serverUrl == self.serverUrl + else { return } + + reloadDataSource() + } + + @objc func downloadStartFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String + else { return } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } + } + + @objc func downloadedFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String + else { return } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } + } + + @objc func downloadCancelFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String + else { return } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } + } + + @objc func uploadStartFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let ocId = userInfo["ocId"] as? String, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String, + !isSearchingMode, + let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) + else { return } + + // Header view trasfer + if metadata.isTransferInForeground { + NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: 0) + DispatchQueue.main.async { self.collectionView?.reloadData() } + } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } + } + + @objc func uploadedFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String + else { return } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } + } + + @objc func uploadedLivePhoto(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String + else { return } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } + } + + @objc func uploadCancelFile(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String + else { return } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } + } + + @objc func triggerProgressTask(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let progressNumber = userInfo["progress"] as? NSNumber, + let totalBytes = userInfo["totalBytes"] as? Int64, + let totalBytesExpected = userInfo["totalBytesExpected"] as? Int64, + let ocId = userInfo["ocId"] as? String, + let ocIdTransfer = userInfo["ocIdTransfer"] as? String, + let session = userInfo["session"] as? String + else { return } + + let chunk: Int = userInfo["chunk"] as? Int ?? 0 + let e2eEncrypted: Bool = userInfo["e2eEncrypted"] as? Bool ?? false + + let transfer = NCTransferProgress.shared.append(NCTransferProgress.Transfer(ocId: ocId, ocIdTransfer: ocIdTransfer, session: session, chunk: chunk, e2eEncrypted: e2eEncrypted, progressNumber: progressNumber, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected)) + +// DispatchQueue.main.async { + if self.headerMenuTransferView && (chunk > 0 || e2eEncrypted) { + if NCNetworking.shared.transferInForegorund?.ocId == ocId { + NCNetworking.shared.transferInForegorund?.progress = progressNumber.floatValue + } else { + NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: progressNumber.floatValue) + self.collectionView.reloadData() + } + self.headerMenu?.progressTransfer.progress = transfer.progressNumber.floatValue + } else { + guard let indexPath = self.dataSource.getIndexPathMetadata(ocId: ocId), + let cell = self.collectionView?.cellForItem(at: indexPath), + let cell = cell as? NCCellProtocol else { return } + if progressNumber.floatValue == 1 && !(cell is NCTransferCell) { + cell.fileProgressView?.isHidden = true + cell.fileProgressView?.progress = .zero + cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCImageCache.images.buttonMore) + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { + cell.writeInfoDateSize(date: metadata.date, size: metadata.size) + } else { + cell.fileInfoLabel?.text = "" + cell.fileSubinfoLabel?.text = "" + } + } else { + cell.fileProgressView?.isHidden = false + cell.fileProgressView?.progress = progressNumber.floatValue + cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCImageCache.images.buttonStop) + let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal + if status == NCGlobal.shared.metadataStatusDownloading { + cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↓ " + self.utilityFileSystem.transformedSize(totalBytes) + } else if status == NCGlobal.shared.metadataStatusUploading { + if totalBytes > 0 { + cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↑ " + self.utilityFileSystem.transformedSize(totalBytes) + } else { + cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↑ …" + } + } + } + } +// } + } + + @objc func updateShare(_ notification: NSNotification) { + if isSearchingMode { + networkSearch() + } else { +// self.dataSource.removeAll() + getServerData() + } + } + + @objc func updateIcons() { + collectionView.reloadData() +// reloadDataSource() + } + + // MARK: - Layout + + func setNavigationLeftItems() { + navigationItem.title = titleCurrentFolder + } internal func setLayout(layoutForView: NCDBLayoutForView, withSubFolders: Bool = false) async { self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView, withSubFolders: withSubFolders) @@ -526,6 +1038,42 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, self.navigationItem.titleView = nil self.navigationItem.title = self.titleCurrentFolder } + + func accountSettingsDidDismiss(tableAccount: tableAccount?, controller: NCMainTabBarController?) { } + + func resetPlusButtonAlpha(animated: Bool = true) { } + + func isHiddenPlusButton(_ isHidden: Bool) { } + + // MARK: - Empty + + func emptyDataSetView(_ view: NCEmptyView) { + + self.emptyDataSet?.setOffset(getHeaderHeight()) + if isSearchingMode { + view.emptyImage.image = UIImage(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width) + if self.dataSourceTask?.state == .running { + view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "") + } else { + view.emptyTitle.text = NSLocalizedString("_search_no_record_found_", comment: "") + } + view.emptyDescription.text = NSLocalizedString("_search_instruction_", comment: "") + } else if self.dataSourceTask?.state == .running { + view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") + view.emptyDescription.text = "" + } else { + if serverUrl.isEmpty { + view.emptyImage.image = emptyImage + view.emptyTitle.text = NSLocalizedString(emptyTitle, comment: "") + view.emptyDescription.text = NSLocalizedString(emptyDescription, comment: "") + } else { + view.emptyImage.image = UIImage(named: "folder_nmcloud") + view.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "") + view.emptyDescription.text = NSLocalizedString("_no_file_pull_down_", comment: "") + } + } + } // MARK: - SEARCH @@ -610,7 +1158,48 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } } - // MARK: - TAP EVENT + + func tapRecommendations(with metadata: tableMetadata) { + didSelectMetadata(metadata, withOcIds: false) + } + + func tapButtonSwitch(_ sender: Any) { + guard !isTransitioning else { return } + isTransitioning = true + + guard let layoutForView = NCManageDatabase.shared.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) else { return } + + if layoutForView.layout == NCGlobal.shared.layoutGrid { + layoutForView.layout = NCGlobal.shared.layoutList + } else { + layoutForView.layout = NCGlobal.shared.layoutGrid + } + self.layoutForView = NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView) + self.collectionView.reloadData() + self.collectionView.collectionViewLayout.invalidateLayout() + self.collectionView.setCollectionViewLayout(layoutForView.layout == NCGlobal.shared.layoutList ? self.listLayout : self.gridLayout, animated: true) {_ in self.isTransitioning = false } + } + + func tapButtonOrder(_ sender: Any) { + let sortMenu = NCSortMenu() + sortMenu.toggleMenu(viewController: self, account: session.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) + } + + func tapButtonTransfer(_ sender: Any) { } + + func longPressListItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) { + } + func longPressListItem(with ocId: String, ocIdTransfer: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + 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) @@ -624,6 +1213,121 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, }) } + func openMenuItems(with objectId: String?, gestureRecognizer: UILongPressGestureRecognizer) { + if gestureRecognizer.state != .began { return } + + var listMenuItems: [UIMenuItem] = [] + let touchPoint = gestureRecognizer.location(in: collectionView) + + becomeFirstResponder() + + if !serverUrl.isEmpty { + listMenuItems.append(UIMenuItem(title: NSLocalizedString("_paste_file_", comment: ""), action: #selector(pasteFilesMenu(_:)))) + } + + if !listMenuItems.isEmpty { + UIMenuController.shared.menuItems = listMenuItems + UIMenuController.shared.showMenu(from: collectionView, rect: CGRect(x: touchPoint.x, y: touchPoint.y, width: 0, height: 0)) + } + } + + // MARK: - Transfer Delegate + + func transferProgressDidUpdate(progress: Float, totalBytes: Int64, totalBytesExpected: Int64, fileName: String, serverUrl: String) { } + + func tranferChange(status: String, metadata: tableMetadata, error: NKError) { } + + // MARK: - Menu Item + + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + if #selector(pasteFilesMenu(_:)) == action { + if !UIPasteboard.general.items.isEmpty, !(metadataFolder?.e2eEncrypted ?? false) { + return true + } + } else if #selector(copyMenuFile(_:)) == action { + return true + } else if #selector(moveMenuFile(_:)) == action { + return true + } + + return false + } + + @objc func pasteFilesMenu(_ sender: Any?) { + Task {@MainActor in + guard let tblAccount = await NCManageDatabase.shared.getTableAccountAsync(account: session.account) else { + return + } + let scene = SceneManager.shared.getWindow(controller: controller)?.windowScene + let token = showHudBanner( + scene: scene, + title: NSLocalizedString("_upload_in_progress_", comment: "")) + + for (index, items) in UIPasteboard.general.items.enumerated() { + for item in items { + let capabilities = await NKCapabilities.shared.getCapabilities(for: session.account) + let results = NKFilePropertyResolver().resolve(inUTI: item.key, capabilities: capabilities) + guard let data = UIPasteboard.general.data(forPasteboardType: item.key, + inItemSet: IndexSet([index]))?.first + else { + continue + } + let fileName = results.name + "_" + NCPreferences().incrementalNumber + "." + results.ext + let serverUrlFileName = utilityFileSystem.createServerUrl(serverUrl: serverUrl, fileName: fileName) + let ocIdUpload = UUID().uuidString + let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId( + ocIdUpload, + fileName: fileName, + userId: tblAccount.userId, + urlBase: tblAccount.urlBase + ) + do { + try data.write(to: URL(fileURLWithPath: fileNameLocalPath)) + } catch { + continue + } + + let resultsUpload = await NCNetworking.shared.uploadFile(account: session.account, + fileNameLocalPath: fileNameLocalPath, + serverUrlFileName: serverUrlFileName) { _ in + } progressHandler: { _, _, fractionCompleted in + Task {@MainActor in + LucidBanner.shared.update(progress: fractionCompleted, for: token) + } + } + + if resultsUpload.error == .success, + let etag = resultsUpload.etag, + let ocId = resultsUpload.ocId { + let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId( + ocId, + fileName: fileName, + userId: tblAccount.userId, + urlBase: tblAccount.urlBase) + self.utilityFileSystem.moveFile(atPath: fileNameLocalPath, toPath: toPath) + NCManageDatabase.shared.addLocalFile( + account: session.account, + etag: etag, + ocId: ocId, + fileName: fileName) + Task { + await NCNetworking.shared.transferDispatcher.notifyAllDelegates { delegate in + delegate.transferReloadData(serverUrl: serverUrl, requestData: true, status: nil) + } + } + } else { + Task {@MainActor in + await showErrorBanner(scene: scene, + errorDescription: resultsUpload.error.errorDescription, + errorCode: resultsUpload.error.errorCode) + } + } + } + } + LucidBanner.shared.dismiss() + } + } + // MARK: - DataSource @MainActor @@ -749,18 +1453,28 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } } + func isHeaderMenuTransferViewEnabled() -> [tableMetadata]? { + if headerMenuTransferView, + NCNetworking.shared.isOnline, + let results = database.getResultsMetadatas(predicate: NSPredicate(format: "status IN %@", [global.metadataStatusWaitUpload, global.metadataStatusUploading])), + !results.isEmpty { + return Array(results) + } + return nil + } + func sizeForHeaderInSection(section: Int) -> CGSize { var height: CGFloat = 0 let isLandscape = view.bounds.width > view.bounds.height let isIphone = UIDevice.current.userInterfaceIdiom == .phone if self.dataSource.isEmpty() { - height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: emptyDataPortaitOffset, landscapeOffset: emptyDataLandscapeOffset) + height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: emptyDataPortaitOffset, landscapeOffset: emptyDataLandscapeOffset, isHeaderMenuTransferViewEnabled: isHeaderMenuTransferViewEnabled() != nil) } else if isEditMode || (isLandscape && isIphone) { return CGSize.zero } else { - let (heightHeaderRichWorkspace, heightHeaderRecommendations, heightHeaderSection) = getHeaderHeight(section: section) - height = heightHeaderRichWorkspace + heightHeaderRecommendations + heightHeaderSection + let (heightHeaderCommands, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: section) + height = heightHeaderCommands + heightHeaderRichWorkspace + heightHeaderSection } return CGSize(width: collectionView.frame.width, height: height) @@ -769,26 +1483,22 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, // MARK: - Footer size func sizeForFooterInSection(section: Int) -> CGSize { - guard let controller else { - return CGSize.zero - } let sections = dataSource.numberOfSections() - let bottomAreaInsets: CGFloat = controller.tabBar.safeAreaInsets.bottom == 0 ? 34 : 0 - let height = controller.tabBar.frame.height + bottomAreaInsets - - if isEditMode { - return CGSize(width: collectionView.frame.width, height: 90 + height) - } - - if isSearchingMode { - return CGSize(width: collectionView.frame.width, height: 50) - } + let metadataForSection = self.dataSource.getMetadataForSection(section) + let isPaginated = metadataForSection?.lastSearchResult?.isPaginated ?? false + let metadatasCount: Int = metadataForSection?.lastSearchResult?.entries.count ?? 0 + var size = CGSize(width: collectionView.frame.width, height: 0) if section == sections - 1 { - return CGSize(width: collectionView.frame.width, height: height) + size.height += 85 } else { - return CGSize(width: collectionView.frame.width, height: 0) + size.height += 1 + } + + if isSearchingMode && isPaginated && metadatasCount > 0 { + size.height += 30 } + return size } func accountSettingsDidDismiss(tblAccount: tableAccount?, controller: NCMainTabBarController?) { } diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 683890eb2f..554b3dab6f 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -4,18 +4,34 @@ import UIKit -final class NCGlobal: Sendable { - static let shared = NCGlobal() - - init() { } - +/// Used for read/write in Realm +var isAppSuspending: Bool = false +/// Used for know if the app in in Background mode +var isAppInBackground: Bool = false + +class NCGlobal: NSObject, @unchecked Sendable { + @objc static let shared = NCGlobal() + + override init() { + super.init() + NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in + isAppSuspending = true + isAppInBackground = true + } + + NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { _ in + isAppSuspending = false + isAppInBackground = false + } + } + // ENUM // public enum TypeFilterScanDocument: String { case document = "document" case original = "original" } - + // Directory on Group // let directoryProviderStorage = "File Provider Storage" @@ -24,13 +40,13 @@ final class NCGlobal: Sendable { let appDatabaseNextcloud = "Library/Application Support/Nextcloud" let appScan = "Library/Application Support/Scan" let appUserData = "Library/Application Support/UserData" - + // Service // let metadataKeyedUnarchiver = "it.twsweb.nextcloud.metadata" let refreshTask = "com.nextcloud.refreshTask" let processingTask = "com.nextcloud.processingTask" - + // App // let appName = "files" @@ -39,17 +55,42 @@ final class NCGlobal: Sendable { let spreedName = "spreed" let twoFactorNotificatioName = "twofactor_nextcloud_notification" let termsOfServiceName = "terms_of_service" - + + // Nextcloud version + // + let nextcloudVersion12: Int = 12 + let nextcloudVersion18: Int = 18 + let nextcloudVersion20: Int = 20 + let nextcloudVersion23: Int = 23 + let nextcloudVersion24: Int = 24 + let nextcloudVersion25: Int = 25 + let nextcloudVersion26: Int = 26 + let nextcloudVersion27: Int = 27 + let nextcloudVersion28: Int = 28 + let nextcloudVersion30: Int = 30 + let nextcloudVersion31: Int = 31 + + // Nextcloud unsupported + // + let nextcloud_unsupported_version: Int = 20 + +// let nextcloud_unsupported_version: Int = 17 + // Intro selector // - let introLogin: Int = 0 - let introSignUpWithProvider: Int = 1 - + @objc let introLogin: Int = 0 + let introSignup: Int = 1 + // let introSignUpWithProvider: Int = 1 + + // Varie size GUI + // + @objc let heightCellSettings: CGFloat = 50 + // Avatar // let avatarSize: Int = 128 * Int(UIScreen.main.scale) let avatarSizeRounded: Int = 128 - + // Preview size // let size1024: CGSize = CGSize(width: 1024, height: 1024) @@ -59,46 +100,51 @@ final class NCGlobal: Sendable { let previewExt1024 = ".1024.preview.jpg" let previewExt512 = ".512.preview.jpg" let previewExt256 = ".256.preview.jpg" - + func getSizeExtension(column: Int) -> String { if column == 0 { return previewExt256 } let width = UIScreen.main.bounds.width / CGFloat(column) - - switch (width * 4) { - case 0...384: - return previewExt256 - case 385...768: - return previewExt512 - default: - return previewExt1024 - } + + switch (width * 4) { + case 0...384: + return previewExt256 + case 385...768: + return previewExt512 + default: + return previewExt1024 + } } - + // E2EE // let e2eePassphraseTest = "more over television factory tendency independence international intellectual impress interest sentence pony" + @objc let e2eeVersions = ["1.1", "1.2", "2.0"] + let e2eeVersionV11 = "1.1" + let e2eeVersionV12 = "1.2" + let e2eeVersionV20 = "2.0" + // CHUNK let chunkSizeMBCellular = 10000000 let chunkSizeMBEthernetOrWiFi = 100000000 - + // Video // let maxHTTPCache: Int64 = 10000000000 // 10 GB let fileNameVideoEncoded: String = "video_encoded.mp4" - + // NCViewerProviderContextMenu // let maxAutoDownload: UInt64 = 50000000 // 50MB let maxAutoDownloadCellular: UInt64 = 10000000 // 10MB - + // Layout // let layoutList = "typeLayoutList" let layoutGrid = "typeLayoutGrid" let layoutPhotoRatio = "typeLayoutPhotoRatio" let layoutPhotoSquare = "typeLayoutPhotoSquare" - + let layoutViewTrash = "LayoutTrash" let layoutViewOffline = "LayoutOffline" let layoutViewFavorite = "LayoutFavorite" @@ -108,16 +154,47 @@ final class NCGlobal: Sendable { let layoutViewShareExtension = "LayoutShareExtension" let layoutViewGroupfolders = "LayoutGroupfolders" let layoutViewMedia = "LayoutMedia" + let layoutViewMove = "LayoutMove" + // Button Type in Cell list/grid // 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" - + // ContentPresenter // let dismissAfterSecond: TimeInterval = 5 @@ -135,6 +212,7 @@ final class NCGlobal: Sendable { let errorPreconditionFailed: Int = 412 let errorUnsupportedMediaType: Int = 415 let errorExpectationFailed: Int = 417 + let errorWebDAVLocked: Int = 423 let errorInternalServerError: Int = 500 let errorMaintenance: Int = 503 let errorQuota: Int = 507 @@ -164,6 +242,7 @@ final class NCGlobal: Sendable { let errorE2EEKeyChecksums: Int = -98002 let errorE2EEKeyEncodeMetadata: Int = -98003 let errorE2EEKeyDecodeMetadataV12: Int = -98004 + let errorE2EEKeyDecodeMetadata: Int = -98004 let errorE2EEKeyVerifySignature: Int = -98005 let errorE2EEKeyCiphertext: Int = -98006 let errorE2EEKeyFiledropCiphertext: Int = -98007 @@ -190,6 +269,7 @@ final class NCGlobal: Sendable { let selectorDownloadFile = "downloadFile" let selectorUploadAutoUpload = "uploadAutoUpload" + let selectorUploadAutoUploadAll = "uploadAutoUploadAll" let selectorUploadFile = "uploadFile" let selectorUploadFileNODelete = "UploadFileNODelete" let selectorUploadFileShareExtension = "uploadFileShareExtension" @@ -198,7 +278,9 @@ final class NCGlobal: Sendable { let selectorSaveAsScan = "saveAsScan" let selectorOpenDetail = "openDetail" let selectorSynchronizationOffline = "synchronizationOffline" - + let selectorPrint = "print" + let selectorDeleteFile = "deleteFile" + // Metadata : Status // // 0 normal @@ -207,70 +289,92 @@ final class NCGlobal: Sendable { // ± 3 error // let metadataStatusNormal: Int = 0 - + let metadataStatusWaitDownload: Int = -1 let metadataStatusDownloading: Int = -2 let metadataStatusDownloadError: Int = -3 - + let metadataStatusWaitUpload: Int = 1 let metadataStatusUploading: Int = 2 let metadataStatusUploadError: Int = 3 - + let metadataStatusWaitCreateFolder: Int = 10 let metadataStatusWaitDelete: Int = 11 let metadataStatusWaitRename: Int = 12 let metadataStatusWaitFavorite: Int = 13 let metadataStatusWaitCopy: Int = 14 let metadataStatusWaitMove: Int = 15 - + let metadataStatusUploadingAllMode = [1,2,3] let metadataStatusDownloadingAllMode = [-1, -2, -3] let metadataStatusForScreenAwake = [-1, -2, 1, 2] + let metadataStatusInTransfer = [-1, -2, 1, 2] + let metadataStatusFileDown = [-1, -2, -3] let metadataStatusHideInView = [1, 2, 3, 11] + let metadataStatusHideInFileExtension = [1, 2, 3, 10, 11] let metadataStatusWaitWebDav = [10, 11, 12, 13, 14, 15] let metadataStatusTransfers = [-2, -3, 2, 3, 10, 11, 12, 13, 14, 15] + let metadataStatusObserveNetworkingProcess = [-1, 1, 10, 11, 12, 13, 14, 15] + let metadataStatusObserveTrasfers = [-2, 2, 10, 11, 12, 13, 14, 15] let metadatasStatusInWaiting = [-1, 1, 10, 11, 12, 13, 14, 15] let metadatasStatusInWaitingDownloadUpload = [-1, 1] let metadatasStatusDownloadingUploading = [-2, 2] + // Hidden files included in the read + // + let includeHiddenFiles: [String] = [".LivePhoto"] + // Auto upload subfolder granularity // - let subfolderGranularityDaily = 2 - let subfolderGranularityMonthly = 1 - let subfolderGranularityYearly = 0 - + @objc let subfolderGranularityDaily = 2 + @objc let subfolderGranularityMonthly = 1 + @objc let subfolderGranularityYearly = 0 + // Notification Center // - let notificationCenterChangeUser = "changeUser" // userInfo: account, controller - let notificationCenterChangeTheming = "changeTheming" // userInfo: account + @objc let notificationCenterChangeUser = "changeUser" + let notificationCenterChangeTheming = "changeTheming" + @objc let notificationCenterApplicationDidEnterBackground = "applicationDidEnterBackground" + @objc let notificationCenterApplicationDidBecomeActive = "applicationDidBecomeActive" + @objc let notificationCenterApplicationWillResignActive = "applicationWillResignActive" + @objc let notificationCenterApplicationWillEnterForeground = "applicationWillEnterForeground" + + + @objc let notificationCenterInitialize = "initialize" let notificationCenterRichdocumentGrabFocus = "richdocumentGrabFocus" let notificationCenterReloadDataNCShare = "reloadDataNCShare" + let notificationCenterDidCreateShareLink = "didCreateShareLink" + let notificationCenterCloseRichWorkspaceWebView = "closeRichWorkspaceWebView" let notificationCenterReloadAvatar = "reloadAvatar" + let notificationCenterReloadHeader = "reloadHeader" let notificationCenterClearCache = "clearCache" + let notificationCenterChangeLayout = "changeLayout" // userInfo: account, serverUrl, layoutForView let notificationCenterCheckUserDelaultErrorDone = "checkUserDelaultErrorDone" // userInfo: account, controller let notificationCenterServerDidUpdate = "serverDidUpdate" // userInfo: account let notificationCenterNetworkReachability = "networkReachability" + let notificationCenterCreateMediaCacheEnded = "createMediaCacheEnded" let notificationCenterUpdateNotification = "updateNotification" + let notificationCenterReloadDataSource = "reloadDataSource" // userInfo: serverUrl?, clearDataSource let notificationCenterGetServerData = "getServerData" // userInfo: serverUrl? - + let notificationCenterChangeStatusFolderE2EE = "changeStatusFolderE2EE" // userInfo: serverUrl - + let notificationCenterDownloadStartFile = "downloadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account let notificationCenterDownloadedFile = "downloadedFile" // userInfo: ocId, ocIdTransfer, session, session, serverUrl, account, selector, error let notificationCenterDownloadCancelFile = "downloadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account - + let notificationCenterUploadStartFile = "uploadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, sessionSelector let notificationCenterUploadedFile = "uploadedFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error let notificationCenterUploadedLivePhoto = "uploadedLivePhoto" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error let notificationCenterUploadCancelFile = "uploadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account - + let notificationCenterProgressTask = "progressTask" // userInfo: account, ocId, ocIdTransfer, session, serverUrl, status, chunk, e2eEncrypted, progress, totalBytes, totalBytesExpected - + let notificationCenterUpdateBadgeNumber = "updateBadgeNumber" // userInfo: counterDownload, counterUpload - + 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) @@ -279,19 +383,32 @@ final class NCGlobal: Sendable { let notificationCenterRenameFile = "renameFile" // userInfo: serverUrl, account, error let notificationCenterFavoriteFile = "favoriteFile" // userInfo: ocId, serverUrl let notificationCenterFileExists = "fileExists" // userInfo: ocId, fileExists - + let notificationCenterMenuSearchTextPDF = "menuSearchTextPDF" let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF" - + let notificationCenterOpenMediaDetail = "openMediaDetail" // userInfo: ocId - + let notificationCenterDismissScanDocument = "dismissScanDocument" - + let notificationCenterDismissUploadAssets = "dismissUploadAssets" + let notificationCenterEnableSwipeGesture = "enableSwipeGesture" let notificationCenterDisableSwipeGesture = "disableSwipeGesture" - + + let notificationCenterShareViewIn = "ShareViewIn" + let notificationCenterShareAdvancePermission = "ShareAdvancePermission" + let notificationCenterShareSendEmail = "ShareSendEmail" + let notificationCenterShareUnshare = "ShareUnshare" + let notificationCenterStatusReadOnly = "statusReadOnly" + let notificationCenterStatusEditing = "statusEditing" + let notificationCenterStatusFileDrop = "statusFileDrop" + let notificationCenterPlayerIsPlaying = "playerIsPlaying" let notificationCenterPlayerStoppedPlaying = "playerStoppedPlaying" + + let notificationCenterUpdateShare = "updateShare" + let notificationCenterShareCountsUpdated = "shareCountsUpdated" + let notificationCenterUpdateIcons = "updateIcons" let notificationCenterUserInteractionMonitor = "serInteractionMonitor" @@ -320,6 +437,7 @@ final class NCGlobal: Sendable { let tipScanAddImage = "tipScanAddImage" let tipMediaDetailView = "tipMediaDetailView" let tipAutoUploadButton = "tipAutoUploadButton" + let tipAutoUpload = "tipAutoUpload" // ACTION // @@ -350,10 +468,31 @@ final class NCGlobal: Sendable { let configuration_disable_multiaccount = "disable_multiaccount" let configuration_disable_crash_service = "disable_crash_service" let configuration_disable_log = "disable_log" + let configuration_disable_manage_account = "disable_manage_account" let configuration_disable_more_external_site = "disable_more_external_site" let configuration_disable_openin_file = "disable_openin_file" let configuration_enforce_passcode_lock = "enforce_passcode_lock" - + + // CAPABILITIES + // + var capabilityServerVersionMajor: Int = 0 + @objc var capabilityServerVersion: String = "" + @objc var capabilityThemingName: String = "" + @objc var capabilityThemingSlogan: String = "" + + @objc var capabilityE2EEEnabled: Bool = false + @objc var capabilityE2EEApiVersion: String = "" + + var capabilityRichdocumentsEnabled: Bool = false + var capabilityRichdocumentsMimetypes: [String] = [] + var capabilityActivity: [String] = [] + var capabilityNotification: [String] = [] + + @objc var capabilityUserStatusEnabled: Bool = false + var isLivePhotoServerAvailable: Bool { // NC28 + return capabilityServerVersionMajor >= nextcloudVersion28 + } + // MORE NEXTCLOUD APPS // let talkSchemeUrl = "nextcloudtalk://" @@ -361,40 +500,59 @@ final class NCGlobal: Sendable { let talkAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-talk/id1296825574" let notesAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-notes/id813973264" let moreAppsUrl = "itms-apps://search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&term=nextcloud" - + // SNAPSHOT PREVIEW // let defaultSnapshotConfiguration = "DefaultPreviewConfiguration" - + +// // FORBIDDEN CHARACTERS +// // +// // TODO: Remove this +// let forbiddenCharacters = ["/", "\\", ":", "\"", "|", "?", "*", "<", ">"] + // DIAGNOSTICS CLIENTS // let diagnosticIssueSyncConflicts = "sync_conflicts" let diagnosticIssueProblems = "problems" let diagnosticIssueVirusDetected = "virus_detected" let diagnosticIssueE2eeErrors = "e2ee_errors" - + let diagnosticProblemsForbidden = "CHARACTERS_FORBIDDEN" let diagnosticProblemsBadResponse = "BAD_SERVER_RESPONSE" let diagnosticProblemsUploadServerError = "UploadError.SERVER_ERROR" - + // MEDIA LAYOUT // let mediaLayoutRatio = "mediaLayoutRatio" let mediaLayoutSquare = "mediaLayoutSquare" - + // DRAG & DROP // let metadataOcIdDataRepresentation = "text/com.nextcloud.ocId" - + // GROUP AMIN // let groupAdmin = "admin" - // TASK DESCRIPTION + // DATA TASK DESCRIPTION // 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" From 70ae71eca85667232ec29beafaf00c6558dac447 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Mon, 15 Dec 2025 12:37:14 +0530 Subject: [PATCH 6/6] NMC 2267 - Rename file/folder customisation changes --- .../NCCollectionViewCommon.swift | 657 ++---------------- iOSClient/NCGlobal.swift | 223 ++---- iOSClient/Rename file/NCRenameFile.swift | 16 +- 3 files changed, 117 insertions(+), 779 deletions(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index b5dd38d4ce..05cc3016f8 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -108,7 +108,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, var pushed: Bool = false var emptyDataSet: NCEmptyDataSet? - internal var isLayoutPhoto: Bool { layoutForView?.layout == global.layoutPhotoRatio || layoutForView?.layout == global.layoutPhotoSquare } @@ -204,7 +203,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, override func viewDidLoad() { super.viewDidLoad() - tabBarSelect = NCCollectionViewCommonSelectTabBar(controller: self.controller, delegate: self) self.navigationController?.presentationController?.delegate = self collectionView.alwaysBounceVertical = true collectionView.accessibilityIdentifier = "NCCollectionViewCommon" @@ -241,8 +239,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, collectionView.register(UINib(nibName: "NCTransferCell", bundle: nil), forCellWithReuseIdentifier: "transferCell") // Header - collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") -// collectionView.register(UINib(nibName: "NCSectionFirstHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeader") + collectionView.register(UINib(nibName: "NCSectionFirstHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeader") collectionView.register(UINib(nibName: "NCSectionFirstHeader", bundle: nil), forSupplementaryViewOfKind: mediaSectionHeader, withReuseIdentifier: "sectionFirstHeader") collectionView.register(UINib(nibName: "NCSectionHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeader") collectionView.register(UINib(nibName: "NCSectionHeader", bundle: nil), forSupplementaryViewOfKind: mediaSectionHeader, withReuseIdentifier: "sectionHeader") @@ -255,9 +252,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, collectionView.refreshControl = refreshControl refreshControl.action(for: .valueChanged) { _ in - self.dataSource.removeAll() - self.getServerData() - Task { @MainActor in // Perform async server forced await self.getServerData(forced: true) @@ -269,16 +263,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, try? await Task.sleep(for: .seconds(1.5)) self.mainNavigationController?.menuPlus?.resetPlusButtonAlpha() } - - // if self.isRecommendationActived { -// Task.detached { -// await NCNetworking.shared.createRecommendations(session: self.session) -// } -// } } - - // Empty - emptyDataSet = NCEmptyDataSet(view: collectionView, offset: getHeaderHeight(), delegate: self) let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressCollecationView(_:))) longPressedGesture.minimumPressDuration = 0.5 @@ -297,6 +282,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 } sectionFirstHeader?.setRichWorkspaceColor(style: view.traitCollection.userInterfaceStyle) @@ -316,11 +309,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, await self.debouncerReloadData.resume() } } - - NotificationCenter.default.addObserver(self, selector: #selector(changeTheming(_:)), name: NSNotification.Name(rawValue: global.notificationCenterChangeTheming), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource(_:)), name: NSNotification.Name(rawValue: global.notificationCenterReloadDataSource), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(getServerData(_:)), name: NSNotification.Name(rawValue: global.notificationCenterGetServerData), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(reloadHeader(_:)), name: NSNotification.Name(rawValue: global.notificationCenterReloadHeader), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(updateIcons), name: NSNotification.Name(rawValue: global.notificationCenterUpdateIcons), object: nil) DispatchQueue.main.async { @@ -349,23 +338,11 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - AnalyticsHelper.shared.displayInAppNotification() - if titlePreviusFolder != nil { navigationController?.navigationBar.topItem?.title = titlePreviusFolder } navigationItem.title = titleCurrentFolder - navigationController?.setNavigationBarAppearance() - navigationController?.navigationBar.prefersLargeTitles = true - navigationController?.setNavigationBarHidden(false, animated: true) - - appDelegate.activeViewController = self - appDelegate.account = session.account - appDelegate.urlBase = session.urlBase - appDelegate.userId = session.userId - appDelegate.user = session.user - NCKeychain().setAccountName(account: session.account) if tabBarSelect == nil { tabBarSelect = NCCollectionViewCommonSelectTabBar(controller: self.controller, viewController: self, delegate: self) } @@ -379,12 +356,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, await (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() } - /// Magentacloud branding changes hide user account button on left navigation bar - // setNavigationLeftItems() - setNavigationRightItems() - layoutForView = database.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) - gridLayout.column = CGFloat(layoutForView?.columnGrid ?? 3) if isLayoutList { collectionView?.collectionViewLayout = listLayout self.layoutType = global.layoutList @@ -398,6 +370,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, collectionView?.collectionViewLayout = mediaLayout self.layoutType = global.layoutPhotoSquare } + collectionView.reloadData() } @@ -410,38 +383,12 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, 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) - NotificationCenter.default.addObserver(self, selector: #selector(changeStatusFolderE2EE(_:)), name: NSNotification.Name(rawValue: global.notificationCenterChangeStatusFolderE2EE), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(changeLayout(_:)), name: NSNotification.Name(rawValue: global.notificationCenterChangeLayout), object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(deleteFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterDeleteFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(copyMoveFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterCopyMoveFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(renameFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterRenameFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(createFolder(_:)), name: NSNotification.Name(rawValue: global.notificationCenterCreateFolder), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(favoriteFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterFavoriteFile), object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(downloadStartFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterDownloadStartFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(downloadedFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterDownloadedFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(downloadCancelFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterDownloadCancelFile), object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(uploadStartFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUploadStartFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUploadedFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(uploadedLivePhoto(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUploadedLivePhoto), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(uploadCancelFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUploadCancelFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(updateShare(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUpdateShare), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: global.notificationCenterProgressTask), object: nil) - - // FIXME: iPAD PDF landscape mode iOS 16 - DispatchQueue.main.async { - self.collectionView?.collectionViewLayout.invalidateLayout() - } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) dismissTip() - pushed = false - toggleSelect(isOn: false) - + // Cancel Queue & Retrieves Properties self.networking.downloadThumbnailQueue.cancelAll() Task { @@ -456,52 +403,10 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, await NCNetworking.shared.transferDispatcher.removeDelegate(self) } - NCNetworking.shared.transferDelegate = nil - NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCloseRichWorkspaceWebView), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterChangeStatusFolderE2EE), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterChangeLayout), object: nil) - - 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) - - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDeleteFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterMoveFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCopyFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCreateFolder), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterFavoriteFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDownloadStartFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDownloadedFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDownloadCancelFile), object: nil) - - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadStartFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadedFile), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadedLivePhoto), object: nil) - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUploadCancelFile), object: nil) - - NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterUpdateShare), object: nil) - - dataSource.removeImageCache() - removeImageCache(metadatas: self.dataSource.getMetadatas()) - } - - 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) + removeImageCache(metadatas: self.dataSource.getMetadatas()) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { @@ -517,6 +422,23 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, override var canBecomeFirstResponder: Bool { return true } + + @objc func updateIcons() { + collectionView.reloadData() + } + + 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) + } func presentationControllerDidDismiss( _ presentationController: UIPresentationController) { let viewController = presentationController.presentedViewController @@ -568,413 +490,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, self.present(alertController, animated: true) } } - - override func viewWillLayoutSubviews() { - super.viewWillLayoutSubviews() - - if let frame = tabBarController?.tabBar.frame { - tabBarSelect?.hostingController?.view.frame = frame - } - } - - // MARK: - NotificationCenter - -// @objc func applicationWillResignActive(_ notification: NSNotification) { -// self.resetPlusButtonAlpha() -// self.refreshControl.endRefreshing() -// } - - @objc func reloadAvatar(_ notification: NSNotification) { - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { - self.showTipAccounts() - } - guard let userInfo = notification.userInfo as NSDictionary?, - let error = userInfo["error"] as? NKError, - error.errorCode != global.errorNotModified else { return } - /// Magentacloud branding changes hide user account button on left navigation bar - setNavigationLeftItems() - } - - @objc func changeTheming(_ notification: NSNotification) { - self.reloadDataSource() - } - - @objc func changeLayout(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let account = userInfo["account"] as? String, - let serverUrl = userInfo["serverUrl"] as? String, - let layoutForView = userInfo["layoutForView"] as? NCDBLayoutForView, - account == session.account, - serverUrl == self.serverUrl - else { return } - - if self.layoutForView?.layout == layoutForView.layout { - self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView) - self.reloadDataSource() - return - } - - self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView) - layoutForView.layout = layoutForView.layout - self.layoutType = layoutForView.layout - - collectionView.reloadData() - - switch layoutForView.layout { - case global.layoutList: - self.collectionView.setCollectionViewLayout(self.listLayout, animated: true) - case global.layoutGrid: - self.collectionView.setCollectionViewLayout(self.gridLayout, animated: true) - case global.layoutPhotoSquare, global.layoutPhotoRatio: - self.collectionView.setCollectionViewLayout(self.mediaLayout, animated: true) - default: - break - } - - self.collectionView.collectionViewLayout.invalidateLayout() - -// (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() - } - - @objc func reloadDataSource(_ notification: NSNotification) { - if let userInfo = notification.userInfo as? NSDictionary { - if let serverUrl = userInfo["serverUrl"] as? String { - if serverUrl != self.serverUrl { - return - } - } - - if let clearDataSource = userInfo["clearDataSource"] as? Bool, clearDataSource { - self.dataSource.removeAll() - } - } - - reloadDataSource() - } - - @objc func getServerData(_ notification: NSNotification) { - if let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String { - if serverUrl != self.serverUrl { - return - } - } - - getServerData() - } - - @objc func reloadHeader(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let account = userInfo["account"] as? String, - account == session.account - else { return } - - self.collectionView.reloadData() - } - - @objc func changeStatusFolderE2EE(_ notification: NSNotification) { - reloadDataSource() - } - - @objc func closeRichWorkspaceWebView() { - reloadDataSource() - } - - @objc func deleteFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let error = userInfo["error"] as? NKError else { return } - - if error == .success { - if isSearchingMode { - return networkSearch() - } - - if isRecommendationActived { - Task.detached { - await NCNetworking.shared.createRecommendations(session: self.session) - } - } - } else { - NCContentPresenter().showError(error: error) - } - - reloadDataSource() - } - - @objc func copyMoveFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String, - account == session.account else { return } - - if isSearchingMode { - return networkSearch() - } - - if isRecommendationActived { - Task.detached { - await NCNetworking.shared.createRecommendations(session: self.session) - } - } - - if serverUrl == self.serverUrl { - reloadDataSource() - } - } - - @objc func renameFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let account = userInfo["account"] as? String, - let serverUrl = userInfo["serverUrl"] as? String, - let error = userInfo["error"] as? NKError, - account == session.account - else { return } - - if error == .success { - if isSearchingMode { - return networkSearch() - } - - if isRecommendationActived { - Task.detached { - await NCNetworking.shared.createRecommendations(session: self.session) - } - } - } - - if serverUrl == self.serverUrl { - if error != .success { - NCContentPresenter().showError(error: error) - } - reloadDataSource() - } else { - collectionView.reloadData() - } - } - - @objc func createFolder(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let ocId = userInfo["ocId"] as? String, - let account = userInfo["account"] as? String, - account == session.account, - let withPush = userInfo["withPush"] as? Bool, - let metadata = database.getMetadataFromOcId(ocId) - else { return } - - if isSearchingMode { - return networkSearch() - } - - if metadata.serverUrl + "/" + metadata.fileName == self.serverUrl { - reloadDataSource() - } else if withPush, metadata.serverUrl == self.serverUrl { - reloadDataSource() - if let sceneIdentifier = userInfo["sceneIdentifier"] as? String { - if sceneIdentifier == controller?.sceneIdentifier { - pushMetadata(metadata) - } - } else { - pushMetadata(metadata) - } - } - } - - @objc func favoriteFile(_ notification: NSNotification) { - if isSearchingMode { - return networkSearch() - } - - if self is NCFavorite { - return reloadDataSource() - } - - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - serverUrl == self.serverUrl - else { return } - - reloadDataSource() - } - - @objc func downloadStartFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String - else { return } - - if account == self.session.account, serverUrl == self.serverUrl { - reloadDataSource() - } else { - collectionView?.reloadData() - } - } - - @objc func downloadedFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String - else { return } - - if account == self.session.account, serverUrl == self.serverUrl { - reloadDataSource() - } else { - collectionView?.reloadData() - } - } - - @objc func downloadCancelFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String - else { return } - - if account == self.session.account, serverUrl == self.serverUrl { - reloadDataSource() - } else { - collectionView?.reloadData() - } - } - - @objc func uploadStartFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let ocId = userInfo["ocId"] as? String, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String, - !isSearchingMode, - let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) - else { return } - - // Header view trasfer - if metadata.isTransferInForeground { - NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: 0) - DispatchQueue.main.async { self.collectionView?.reloadData() } - } - - if account == self.session.account, serverUrl == self.serverUrl { - reloadDataSource() - } else { - collectionView?.reloadData() - } - } - - @objc func uploadedFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String - else { return } - - if account == self.session.account, serverUrl == self.serverUrl { - reloadDataSource() - } else { - collectionView?.reloadData() - } - } - - @objc func uploadedLivePhoto(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String - else { return } - - if account == self.session.account, serverUrl == self.serverUrl { - reloadDataSource() - } else { - collectionView?.reloadData() - } - } - - @objc func uploadCancelFile(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let serverUrl = userInfo["serverUrl"] as? String, - let account = userInfo["account"] as? String - else { return } - - if account == self.session.account, serverUrl == self.serverUrl { - reloadDataSource() - } else { - collectionView?.reloadData() - } - } - - @objc func triggerProgressTask(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let progressNumber = userInfo["progress"] as? NSNumber, - let totalBytes = userInfo["totalBytes"] as? Int64, - let totalBytesExpected = userInfo["totalBytesExpected"] as? Int64, - let ocId = userInfo["ocId"] as? String, - let ocIdTransfer = userInfo["ocIdTransfer"] as? String, - let session = userInfo["session"] as? String - else { return } - - let chunk: Int = userInfo["chunk"] as? Int ?? 0 - let e2eEncrypted: Bool = userInfo["e2eEncrypted"] as? Bool ?? false - - let transfer = NCTransferProgress.shared.append(NCTransferProgress.Transfer(ocId: ocId, ocIdTransfer: ocIdTransfer, session: session, chunk: chunk, e2eEncrypted: e2eEncrypted, progressNumber: progressNumber, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected)) - -// DispatchQueue.main.async { - if self.headerMenuTransferView && (chunk > 0 || e2eEncrypted) { - if NCNetworking.shared.transferInForegorund?.ocId == ocId { - NCNetworking.shared.transferInForegorund?.progress = progressNumber.floatValue - } else { - NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: progressNumber.floatValue) - self.collectionView.reloadData() - } - self.headerMenu?.progressTransfer.progress = transfer.progressNumber.floatValue - } else { - guard let indexPath = self.dataSource.getIndexPathMetadata(ocId: ocId), - let cell = self.collectionView?.cellForItem(at: indexPath), - let cell = cell as? NCCellProtocol else { return } - if progressNumber.floatValue == 1 && !(cell is NCTransferCell) { - cell.fileProgressView?.isHidden = true - cell.fileProgressView?.progress = .zero - cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCImageCache.images.buttonMore) - if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { - cell.writeInfoDateSize(date: metadata.date, size: metadata.size) - } else { - cell.fileInfoLabel?.text = "" - cell.fileSubinfoLabel?.text = "" - } - } else { - cell.fileProgressView?.isHidden = false - cell.fileProgressView?.progress = progressNumber.floatValue - cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCImageCache.images.buttonStop) - let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal - if status == NCGlobal.shared.metadataStatusDownloading { - cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) - cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↓ " + self.utilityFileSystem.transformedSize(totalBytes) - } else if status == NCGlobal.shared.metadataStatusUploading { - if totalBytes > 0 { - cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) - cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↑ " + self.utilityFileSystem.transformedSize(totalBytes) - } else { - cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) - cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↑ …" - } - } - } - } -// } - } - - @objc func updateShare(_ notification: NSNotification) { - if isSearchingMode { - networkSearch() - } else { -// self.dataSource.removeAll() - getServerData() - } - } - - @objc func updateIcons() { - collectionView.reloadData() -// reloadDataSource() - } - - // MARK: - Layout - - func setNavigationLeftItems() { - navigationItem.title = titleCurrentFolder - } internal func setLayout(layoutForView: NCDBLayoutForView, withSubFolders: Bool = false) async { self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView, withSubFolders: withSubFolders) @@ -1038,42 +553,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, self.navigationItem.titleView = nil self.navigationItem.title = self.titleCurrentFolder } - - func accountSettingsDidDismiss(tableAccount: tableAccount?, controller: NCMainTabBarController?) { } - - func resetPlusButtonAlpha(animated: Bool = true) { } - - func isHiddenPlusButton(_ isHidden: Bool) { } - - // MARK: - Empty - - func emptyDataSetView(_ view: NCEmptyView) { - - self.emptyDataSet?.setOffset(getHeaderHeight()) - if isSearchingMode { - view.emptyImage.image = UIImage(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width) - if self.dataSourceTask?.state == .running { - view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "") - } else { - view.emptyTitle.text = NSLocalizedString("_search_no_record_found_", comment: "") - } - view.emptyDescription.text = NSLocalizedString("_search_instruction_", comment: "") - } else if self.dataSourceTask?.state == .running { - view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) - view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") - view.emptyDescription.text = "" - } else { - if serverUrl.isEmpty { - view.emptyImage.image = emptyImage - view.emptyTitle.text = NSLocalizedString(emptyTitle, comment: "") - view.emptyDescription.text = NSLocalizedString(emptyDescription, comment: "") - } else { - view.emptyImage.image = UIImage(named: "folder_nmcloud") - view.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "") - view.emptyDescription.text = NSLocalizedString("_no_file_pull_down_", comment: "") - } - } - } // MARK: - SEARCH @@ -1162,34 +641,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, func tapRecommendations(with metadata: tableMetadata) { didSelectMetadata(metadata, withOcIds: false) } - - func tapButtonSwitch(_ sender: Any) { - guard !isTransitioning else { return } - isTransitioning = true - - guard let layoutForView = NCManageDatabase.shared.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) else { return } - - if layoutForView.layout == NCGlobal.shared.layoutGrid { - layoutForView.layout = NCGlobal.shared.layoutList - } else { - layoutForView.layout = NCGlobal.shared.layoutGrid - } - self.layoutForView = NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView) - self.collectionView.reloadData() - self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionView.setCollectionViewLayout(layoutForView.layout == NCGlobal.shared.layoutList ? self.listLayout : self.gridLayout, animated: true) {_ in self.isTransitioning = false } - } - - func tapButtonOrder(_ sender: Any) { - let sortMenu = NCSortMenu() - sortMenu.toggleMenu(viewController: self, account: session.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) - } - - func tapButtonTransfer(_ sender: Any) { } - - func longPressListItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) { - } - func longPressListItem(with ocId: String, ocIdTransfer: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } func longPressListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } @@ -1231,12 +682,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } } - // MARK: - Transfer Delegate - - func transferProgressDidUpdate(progress: Float, totalBytes: Int64, totalBytesExpected: Int64, fileName: String, serverUrl: String) { } - - func tranferChange(status: String, metadata: tableMetadata, error: NKError) { } - // MARK: - Menu Item override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { @@ -1453,28 +898,18 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } } - func isHeaderMenuTransferViewEnabled() -> [tableMetadata]? { - if headerMenuTransferView, - NCNetworking.shared.isOnline, - let results = database.getResultsMetadatas(predicate: NSPredicate(format: "status IN %@", [global.metadataStatusWaitUpload, global.metadataStatusUploading])), - !results.isEmpty { - return Array(results) - } - return nil - } - func sizeForHeaderInSection(section: Int) -> CGSize { var height: CGFloat = 0 let isLandscape = view.bounds.width > view.bounds.height let isIphone = UIDevice.current.userInterfaceIdiom == .phone if self.dataSource.isEmpty() { - height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: emptyDataPortaitOffset, landscapeOffset: emptyDataLandscapeOffset, isHeaderMenuTransferViewEnabled: isHeaderMenuTransferViewEnabled() != nil) + height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: emptyDataPortaitOffset, landscapeOffset: emptyDataLandscapeOffset) } else if isEditMode || (isLandscape && isIphone) { return CGSize.zero } else { - let (heightHeaderCommands, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: section) - height = heightHeaderCommands + heightHeaderRichWorkspace + heightHeaderSection + let (heightHeaderRichWorkspace, heightHeaderRecommendations, heightHeaderSection) = getHeaderHeight(section: section) + height = heightHeaderRichWorkspace + heightHeaderRecommendations + heightHeaderSection } return CGSize(width: collectionView.frame.width, height: height) @@ -1483,22 +918,26 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, // MARK: - Footer size func sizeForFooterInSection(section: Int) -> CGSize { + guard let controller else { + return CGSize.zero + } let sections = dataSource.numberOfSections() - let metadataForSection = self.dataSource.getMetadataForSection(section) - let isPaginated = metadataForSection?.lastSearchResult?.isPaginated ?? false - let metadatasCount: Int = metadataForSection?.lastSearchResult?.entries.count ?? 0 - var size = CGSize(width: collectionView.frame.width, height: 0) + let bottomAreaInsets: CGFloat = controller.tabBar.safeAreaInsets.bottom == 0 ? 34 : 0 + let height = controller.tabBar.frame.height + bottomAreaInsets - if section == sections - 1 { - size.height += 85 - } else { - size.height += 1 + if isEditMode { + return CGSize(width: collectionView.frame.width, height: 90 + height) } - if isSearchingMode && isPaginated && metadatasCount > 0 { - size.height += 30 + if isSearchingMode { + return CGSize(width: collectionView.frame.width, height: 50) + } + + if section == sections - 1 { + return CGSize(width: collectionView.frame.width, height: height) + } else { + return CGSize(width: collectionView.frame.width, height: 0) } - return size } func accountSettingsDidDismiss(tblAccount: tableAccount?, controller: NCMainTabBarController?) { } diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 554b3dab6f..c008f46fed 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -4,34 +4,18 @@ import UIKit -/// Used for read/write in Realm -var isAppSuspending: Bool = false -/// Used for know if the app in in Background mode -var isAppInBackground: Bool = false +final class NCGlobal: Sendable { + static let shared = NCGlobal() + + init() { } -class NCGlobal: NSObject, @unchecked Sendable { - @objc static let shared = NCGlobal() - - override init() { - super.init() - NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in - isAppSuspending = true - isAppInBackground = true - } - - NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { _ in - isAppSuspending = false - isAppInBackground = false - } - } - // ENUM // public enum TypeFilterScanDocument: String { case document = "document" case original = "original" } - + // Directory on Group // let directoryProviderStorage = "File Provider Storage" @@ -40,13 +24,13 @@ class NCGlobal: NSObject, @unchecked Sendable { let appDatabaseNextcloud = "Library/Application Support/Nextcloud" let appScan = "Library/Application Support/Scan" let appUserData = "Library/Application Support/UserData" - + // Service // let metadataKeyedUnarchiver = "it.twsweb.nextcloud.metadata" let refreshTask = "com.nextcloud.refreshTask" let processingTask = "com.nextcloud.processingTask" - + // App // let appName = "files" @@ -55,10 +39,9 @@ class NCGlobal: NSObject, @unchecked Sendable { let spreedName = "spreed" let twoFactorNotificatioName = "twofactor_nextcloud_notification" let termsOfServiceName = "terms_of_service" - + // Nextcloud version // - let nextcloudVersion12: Int = 12 let nextcloudVersion18: Int = 18 let nextcloudVersion20: Int = 20 let nextcloudVersion23: Int = 23 @@ -69,7 +52,7 @@ class NCGlobal: NSObject, @unchecked Sendable { let nextcloudVersion28: Int = 28 let nextcloudVersion30: Int = 30 let nextcloudVersion31: Int = 31 - + // Nextcloud unsupported // let nextcloud_unsupported_version: Int = 20 @@ -78,14 +61,10 @@ class NCGlobal: NSObject, @unchecked Sendable { // Intro selector // - @objc let introLogin: Int = 0 + let introLogin: Int = 0 let introSignup: Int = 1 - // let introSignUpWithProvider: Int = 1 - - // Varie size GUI - // - @objc let heightCellSettings: CGFloat = 50 - + let introSignUpWithProvider: Int = 1 + // Avatar // let avatarSize: Int = 128 * Int(UIScreen.main.scale) @@ -100,51 +79,50 @@ class NCGlobal: NSObject, @unchecked Sendable { let previewExt1024 = ".1024.preview.jpg" let previewExt512 = ".512.preview.jpg" let previewExt256 = ".256.preview.jpg" - + func getSizeExtension(column: Int) -> String { if column == 0 { return previewExt256 } let width = UIScreen.main.bounds.width / CGFloat(column) - - switch (width * 4) { - case 0...384: - return previewExt256 - case 385...768: - return previewExt512 - default: - return previewExt1024 - } + + switch (width * 4) { + case 0...384: + return previewExt256 + case 385...768: + return previewExt512 + default: + return previewExt1024 + } } - + // E2EE // let e2eePassphraseTest = "more over television factory tendency independence international intellectual impress interest sentence pony" - - @objc let e2eeVersions = ["1.1", "1.2", "2.0"] + let e2eeVersions = ["1.1", "1.2", "2.0"] let e2eeVersionV11 = "1.1" let e2eeVersionV12 = "1.2" let e2eeVersionV20 = "2.0" - + // CHUNK let chunkSizeMBCellular = 10000000 let chunkSizeMBEthernetOrWiFi = 100000000 - + // Video // let maxHTTPCache: Int64 = 10000000000 // 10 GB let fileNameVideoEncoded: String = "video_encoded.mp4" - + // NCViewerProviderContextMenu // let maxAutoDownload: UInt64 = 50000000 // 50MB let maxAutoDownloadCellular: UInt64 = 10000000 // 10MB - + // Layout // let layoutList = "typeLayoutList" let layoutGrid = "typeLayoutGrid" let layoutPhotoRatio = "typeLayoutPhotoRatio" let layoutPhotoSquare = "typeLayoutPhotoSquare" - + let layoutViewTrash = "LayoutTrash" let layoutViewOffline = "LayoutOffline" let layoutViewFavorite = "LayoutFavorite" @@ -154,16 +132,13 @@ class NCGlobal: NSObject, @unchecked Sendable { let layoutViewShareExtension = "LayoutShareExtension" let layoutViewGroupfolders = "LayoutGroupfolders" let layoutViewMedia = "LayoutMedia" - let layoutViewMove = "LayoutMove" - // Button Type in Cell list/grid // let buttonMoreMore = "more" let buttonMoreLock = "moreLock" let buttonMoreStop = "stop" - // Standard height sections header/footer // let heightButtonsView: CGFloat = 50 @@ -194,7 +169,7 @@ class NCGlobal: NSObject, @unchecked Sendable { // Rich Workspace // let fileNameRichWorkspace = "Readme.md" - + // ContentPresenter // let dismissAfterSecond: TimeInterval = 5 @@ -242,7 +217,6 @@ class NCGlobal: NSObject, @unchecked Sendable { let errorE2EEKeyChecksums: Int = -98002 let errorE2EEKeyEncodeMetadata: Int = -98003 let errorE2EEKeyDecodeMetadataV12: Int = -98004 - let errorE2EEKeyDecodeMetadata: Int = -98004 let errorE2EEKeyVerifySignature: Int = -98005 let errorE2EEKeyCiphertext: Int = -98006 let errorE2EEKeyFiledropCiphertext: Int = -98007 @@ -269,7 +243,6 @@ class NCGlobal: NSObject, @unchecked Sendable { let selectorDownloadFile = "downloadFile" let selectorUploadAutoUpload = "uploadAutoUpload" - let selectorUploadAutoUploadAll = "uploadAutoUploadAll" let selectorUploadFile = "uploadFile" let selectorUploadFileNODelete = "UploadFileNODelete" let selectorUploadFileShareExtension = "uploadFileShareExtension" @@ -280,7 +253,7 @@ class NCGlobal: NSObject, @unchecked Sendable { let selectorSynchronizationOffline = "synchronizationOffline" let selectorPrint = "print" let selectorDeleteFile = "deleteFile" - + // Metadata : Status // // 0 normal @@ -289,33 +262,27 @@ class NCGlobal: NSObject, @unchecked Sendable { // ± 3 error // let metadataStatusNormal: Int = 0 - + let metadataStatusWaitDownload: Int = -1 let metadataStatusDownloading: Int = -2 let metadataStatusDownloadError: Int = -3 - + let metadataStatusWaitUpload: Int = 1 let metadataStatusUploading: Int = 2 let metadataStatusUploadError: Int = 3 - + let metadataStatusWaitCreateFolder: Int = 10 let metadataStatusWaitDelete: Int = 11 let metadataStatusWaitRename: Int = 12 let metadataStatusWaitFavorite: Int = 13 let metadataStatusWaitCopy: Int = 14 let metadataStatusWaitMove: Int = 15 - + let metadataStatusUploadingAllMode = [1,2,3] let metadataStatusDownloadingAllMode = [-1, -2, -3] let metadataStatusForScreenAwake = [-1, -2, 1, 2] - let metadataStatusInTransfer = [-1, -2, 1, 2] - let metadataStatusFileDown = [-1, -2, -3] let metadataStatusHideInView = [1, 2, 3, 11] - let metadataStatusHideInFileExtension = [1, 2, 3, 10, 11] let metadataStatusWaitWebDav = [10, 11, 12, 13, 14, 15] - let metadataStatusTransfers = [-2, -3, 2, 3, 10, 11, 12, 13, 14, 15] - let metadataStatusObserveNetworkingProcess = [-1, 1, 10, 11, 12, 13, 14, 15] - let metadataStatusObserveTrasfers = [-2, 2, 10, 11, 12, 13, 14, 15] let metadatasStatusInWaiting = [-1, 1, 10, 11, 12, 13, 14, 15] let metadatasStatusInWaitingDownloadUpload = [-1, 1] @@ -327,88 +294,42 @@ class NCGlobal: NSObject, @unchecked Sendable { // Auto upload subfolder granularity // - @objc let subfolderGranularityDaily = 2 - @objc let subfolderGranularityMonthly = 1 - @objc let subfolderGranularityYearly = 0 - + let subfolderGranularityDaily = 2 + let subfolderGranularityMonthly = 1 + let subfolderGranularityYearly = 0 + // Notification Center // - @objc let notificationCenterChangeUser = "changeUser" - let notificationCenterChangeTheming = "changeTheming" - @objc let notificationCenterApplicationDidEnterBackground = "applicationDidEnterBackground" - @objc let notificationCenterApplicationDidBecomeActive = "applicationDidBecomeActive" - @objc let notificationCenterApplicationWillResignActive = "applicationWillResignActive" - @objc let notificationCenterApplicationWillEnterForeground = "applicationWillEnterForeground" - - - @objc let notificationCenterInitialize = "initialize" + let notificationCenterChangeUser = "changeUser" // userInfo: account, controller + let notificationCenterChangeTheming = "changeTheming" // userInfo: account let notificationCenterRichdocumentGrabFocus = "richdocumentGrabFocus" let notificationCenterReloadDataNCShare = "reloadDataNCShare" let notificationCenterDidCreateShareLink = "didCreateShareLink" - + let notificationCenterCloseRichWorkspaceWebView = "closeRichWorkspaceWebView" let notificationCenterReloadAvatar = "reloadAvatar" - let notificationCenterReloadHeader = "reloadHeader" let notificationCenterClearCache = "clearCache" - let notificationCenterChangeLayout = "changeLayout" // userInfo: account, serverUrl, layoutForView let notificationCenterCheckUserDelaultErrorDone = "checkUserDelaultErrorDone" // userInfo: account, controller let notificationCenterServerDidUpdate = "serverDidUpdate" // userInfo: account let notificationCenterNetworkReachability = "networkReachability" - let notificationCenterCreateMediaCacheEnded = "createMediaCacheEnded" - let notificationCenterUpdateNotification = "updateNotification" - let notificationCenterReloadDataSource = "reloadDataSource" // userInfo: serverUrl?, clearDataSource - let notificationCenterGetServerData = "getServerData" // userInfo: serverUrl? - - let notificationCenterChangeStatusFolderE2EE = "changeStatusFolderE2EE" // userInfo: serverUrl - - let notificationCenterDownloadStartFile = "downloadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account - let notificationCenterDownloadedFile = "downloadedFile" // userInfo: ocId, ocIdTransfer, session, session, serverUrl, account, selector, error - let notificationCenterDownloadCancelFile = "downloadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account - - let notificationCenterUploadStartFile = "uploadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, sessionSelector - let notificationCenterUploadedFile = "uploadedFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error - let notificationCenterUploadedLivePhoto = "uploadedLivePhoto" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error - let notificationCenterUploadCancelFile = "uploadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account - - let notificationCenterProgressTask = "progressTask" // userInfo: account, ocId, ocIdTransfer, session, serverUrl, status, chunk, e2eEncrypted, progress, totalBytes, totalBytesExpected - - let notificationCenterUpdateBadgeNumber = "updateBadgeNumber" // userInfo: counterDownload, counterUpload - - 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 - + let notificationCenterMenuSearchTextPDF = "menuSearchTextPDF" let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF" - + let notificationCenterOpenMediaDetail = "openMediaDetail" // userInfo: ocId - + let notificationCenterDismissScanDocument = "dismissScanDocument" let notificationCenterDismissUploadAssets = "dismissUploadAssets" - + let notificationCenterEnableSwipeGesture = "enableSwipeGesture" let notificationCenterDisableSwipeGesture = "disableSwipeGesture" - - let notificationCenterShareViewIn = "ShareViewIn" - let notificationCenterShareAdvancePermission = "ShareAdvancePermission" - let notificationCenterShareSendEmail = "ShareSendEmail" - let notificationCenterShareUnshare = "ShareUnshare" - let notificationCenterStatusReadOnly = "statusReadOnly" - let notificationCenterStatusEditing = "statusEditing" - let notificationCenterStatusFileDrop = "statusFileDrop" - + let notificationCenterPlayerIsPlaying = "playerIsPlaying" let notificationCenterPlayerStoppedPlaying = "playerStoppedPlaying" - - let notificationCenterUpdateShare = "updateShare" - let notificationCenterShareCountsUpdated = "shareCountsUpdated" - let notificationCenterUpdateIcons = "updateIcons" + + let notificationCenterFavoriteStatusChanged = "favoriteStatusChanged" let notificationCenterUserInteractionMonitor = "serInteractionMonitor" @@ -429,6 +350,7 @@ class NCGlobal: NSObject, @unchecked Sendable { let networkingStatusUploaded = "statusUploaded" let networkingStatusReloadAvatar = "statusReloadAvatar" + let notificationCenterUpdateIcons = "updateIcons" // TIP // @@ -437,7 +359,6 @@ class NCGlobal: NSObject, @unchecked Sendable { let tipScanAddImage = "tipScanAddImage" let tipMediaDetailView = "tipMediaDetailView" let tipAutoUploadButton = "tipAutoUploadButton" - let tipAutoUpload = "tipAutoUpload" // ACTION // @@ -468,31 +389,10 @@ class NCGlobal: NSObject, @unchecked Sendable { let configuration_disable_multiaccount = "disable_multiaccount" let configuration_disable_crash_service = "disable_crash_service" let configuration_disable_log = "disable_log" - let configuration_disable_manage_account = "disable_manage_account" let configuration_disable_more_external_site = "disable_more_external_site" let configuration_disable_openin_file = "disable_openin_file" let configuration_enforce_passcode_lock = "enforce_passcode_lock" - - // CAPABILITIES - // - var capabilityServerVersionMajor: Int = 0 - @objc var capabilityServerVersion: String = "" - @objc var capabilityThemingName: String = "" - @objc var capabilityThemingSlogan: String = "" - - @objc var capabilityE2EEEnabled: Bool = false - @objc var capabilityE2EEApiVersion: String = "" - - var capabilityRichdocumentsEnabled: Bool = false - var capabilityRichdocumentsMimetypes: [String] = [] - var capabilityActivity: [String] = [] - var capabilityNotification: [String] = [] - - @objc var capabilityUserStatusEnabled: Bool = false - var isLivePhotoServerAvailable: Bool { // NC28 - return capabilityServerVersionMajor >= nextcloudVersion28 - } - + // MORE NEXTCLOUD APPS // let talkSchemeUrl = "nextcloudtalk://" @@ -500,41 +400,36 @@ class NCGlobal: NSObject, @unchecked Sendable { let talkAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-talk/id1296825574" let notesAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-notes/id813973264" let moreAppsUrl = "itms-apps://search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&term=nextcloud" - + // SNAPSHOT PREVIEW // let defaultSnapshotConfiguration = "DefaultPreviewConfiguration" - -// // FORBIDDEN CHARACTERS -// // -// // TODO: Remove this -// let forbiddenCharacters = ["/", "\\", ":", "\"", "|", "?", "*", "<", ">"] - + // DIAGNOSTICS CLIENTS // let diagnosticIssueSyncConflicts = "sync_conflicts" let diagnosticIssueProblems = "problems" let diagnosticIssueVirusDetected = "virus_detected" let diagnosticIssueE2eeErrors = "e2ee_errors" - + let diagnosticProblemsForbidden = "CHARACTERS_FORBIDDEN" let diagnosticProblemsBadResponse = "BAD_SERVER_RESPONSE" let diagnosticProblemsUploadServerError = "UploadError.SERVER_ERROR" - + // MEDIA LAYOUT // let mediaLayoutRatio = "mediaLayoutRatio" let mediaLayoutSquare = "mediaLayoutSquare" - + // DRAG & DROP // let metadataOcIdDataRepresentation = "text/com.nextcloud.ocId" - + // GROUP AMIN // let groupAdmin = "admin" - // DATA TASK DESCRIPTION + // TASK DESCRIPTION // let taskDescriptionRetrievesProperties = "retrievesProperties" let taskDescriptionSynchronization = "synchronization" @@ -552,7 +447,7 @@ class NCGlobal: NSObject, @unchecked Sendable { let keyFileNameAutoUploadType = "fileNameAutoUploadType" let keyFileNameOriginal = "fileNameOriginal" let keyFileNameOriginalAutoUpload = "fileNameOriginalAutoUpload" - + // LOG TAG // let logTagTask = "BGT" diff --git a/iOSClient/Rename file/NCRenameFile.swift b/iOSClient/Rename file/NCRenameFile.swift index 723e02ed3f..d27b86dc9a 100644 --- a/iOSClient/Rename file/NCRenameFile.swift +++ b/iOSClient/Rename file/NCRenameFile.swift @@ -45,6 +45,7 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { @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 @@ -89,7 +90,7 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { if metadata.directory { if imagePreview == nil { - previewFile.image = NCImageCache.images.folder + previewFile.image = imageCache.getFolder(account: metadata.account) } ext.isHidden = true @@ -99,7 +100,7 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { } else { if imagePreview == nil { - previewFile.image = NCImageCache.images.file + previewFile.image = imageCache.getImageFile() } fileNameNoExtensionTrailingContraint.constant = 90 @@ -118,7 +119,7 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { ext.delegate = self if imagePreview == nil { - previewFile.image = NCImageCache.images.file + previewFile.image = imageCache.getImageFile() } else { previewFile.image = imagePreview } @@ -127,11 +128,11 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { } cancelButton.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal) - cancelButton.setTitleColor(NCBrandColor.shared.iconColor, 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.iconColor.cgColor + cancelButton.layer.borderColor = NCBrandColor.shared.iconImageColor.cgColor renameButton.setTitle(NSLocalizedString("_rename_", comment: ""), for: .normal) renameButton.setTitleColor(NCBrandColor.shared.brandText, for: .normal) @@ -246,13 +247,16 @@ class NCRenameFile: UIViewController, UITextFieldDelegate { 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 { - self.dismiss(animated: true) + DispatchQueue.main.async { + self.dismiss(animated: true) + } } else {