diff --git a/iOSClient/Menu/NCContextMenu.swift b/iOSClient/Menu/NCContextMenu.swift index c0f96047c7..efe9f95367 100644 --- a/iOSClient/Menu/NCContextMenu.swift +++ b/iOSClient/Menu/NCContextMenu.swift @@ -27,11 +27,15 @@ import NextcloudKit import JGProgressHUD class NCContextMenu: NSObject { + + // swiftlint:disable force_cast + let appDelegate = UIApplication.shared.delegate as! AppDelegate + // swiftlint:enable force_cast let utilityFileSystem = NCUtilityFileSystem() let utility = NCUtility() - func viewMenu(ocId: String, viewController: UIViewController, image: UIImage?) -> UIMenu { + func viewMenu(ocId: String, indexPath: IndexPath, viewController: UIViewController, image: UIImage?) -> UIMenu { guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return UIMenu() } var downloadRequest: DownloadRequest? @@ -50,6 +54,17 @@ class NCContextMenu: NSObject { request.cancel() } } + + var titleSave: String = NSLocalizedString("_save_selected_files_", comment: "") + if metadataMOV != nil { titleSave = NSLocalizedString("_livephoto_save_", comment: "") } + let serverUrl = metadata.serverUrl + "/" + metadata.fileName + var isOffline: Bool = false + + if metadata.directory, let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, serverUrl)) { + isOffline = directory.offline + } else if let localFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) { + isOffline = localFile.offline + } // MENU ITEMS @@ -58,10 +73,60 @@ class NCContextMenu: NSObject { NCActionCenter.shared.openShare(viewController: viewController, metadata: metadata, page: .activity) } + let titleOffline = isOffline ? NSLocalizedString("_remove_available_offline_", comment: "") : NSLocalizedString("_set_available_offline_", comment: "") + + let offline = UIAction(title: titleOffline, image: UIImage(systemName: "tray.and.arrow.down")) { _ in + NCActionCenter.shared.setMetadataAvalableOffline(metadata, isOffline: isOffline) + if let viewController = viewController as? NCCollectionViewCommon { + viewController.reloadDataSource() + } + } + + let print = UIAction(title: NSLocalizedString("_print_", comment: ""), image: UIImage(systemName: "printer") ) { _ in + NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorPrint)) + } + + let moveCopy = UIAction(title: NSLocalizedString("_move_or_copy_", comment: ""), image: UIImage(systemName: "arrow.up.right.square")) { action in + NCActionCenter.shared.openSelectView(items: [metadata], indexPath: [indexPath]) + } + + let rename = UIAction(title: NSLocalizedString("_rename_", comment: ""), image: UIImage(systemName: "pencil")) { action in + if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile { + vcRename.metadata = metadata + vcRename.imagePreview = image + vcRename.indexPath = indexPath + let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height) + viewController.present(popup, animated: true) + } + } + + let decrypt = UIAction(title: NSLocalizedString("_e2e_remove_folder_encrypted_", comment: ""), image: UIImage(systemName: "lock") ) { action in + NextcloudKit.shared.markE2EEFolder(fileId: metadata.fileId, delete: true) { _, error in + if error == .success { + NCManageDatabase.shared.deleteE2eEncryption(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, serverUrl)) + NCManageDatabase.shared.setDirectory(serverUrl: serverUrl, serverUrlTo: nil, etag: nil, ocId: nil, fileId: nil, encrypted: false, richWorkspace: nil, account: metadata.account) + NCManageDatabase.shared.setMetadataEncrypted(ocId: metadata.ocId, encrypted: false) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeStatusFolderE2EE, userInfo: ["serverUrl": metadata.serverUrl]) + } else { + NCContentPresenter().messageNotification(NSLocalizedString("_e2e_error_", comment: ""), error: error, delay: NCGlobal.shared.dismissAfterSecond, type: .error) + } + } + } + + let encrypt = UIAction(title: NSLocalizedString("_e2e_set_folder_encrypted_", comment: ""), image: UIImage(systemName: "lock") ) { action in + Task { + let error = await NCNetworkingE2EEMarkFolder().markFolderE2ee(account: metadata.account, fileName: metadata.fileName, serverUrl: metadata.serverUrl, userId: metadata.userId) + if error != .success { + NCContentPresenter().showError(error: error) + } + } + } + let favorite = UIAction(title: metadata.favorite ? NSLocalizedString("_remove_favorites_", comment: "") : NSLocalizedString("_add_favorites_", comment: ""), - image: utility.loadImage(named: metadata.favorite ? "star.slash" : "star", color: NCBrandColor.shared.yellowFavorite)) { _ in + image: utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite)) { _ in NCNetworking.shared.favoriteMetadata(metadata) { error in if error != .success { NCContentPresenter().showError(error: error) @@ -69,6 +134,76 @@ class NCContextMenu: NSObject { } } + let openIn = UIAction(title: NSLocalizedString("_open_in_", comment: ""), + image: UIImage(systemName: "square.and.arrow.up") ) { _ in + if self.utilityFileSystem.fileProviderStorageExists(metadata) { + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorOpenIn, "error": NKError(), "account": metadata.account]) + } else { + guard let metadata = NCManageDatabase.shared.setMetadatasSessionInWaitDownload(metadatas: [metadata], + session: NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, + selector: NCGlobal.shared.selectorOpenIn) else { return } + hud.show(in: viewController.view) + NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) { + } requestHandler: { request in + downloadRequest = request + } progressHandler: { progress in + hud.progress = Float(progress.fractionCompleted) + } completion: { afError, error in + DispatchQueue.main.async { + if error == .success || afError?.isExplicitlyCancelledError ?? false { + hud.dismiss() + } else { + hud.indicatorView = JGProgressHUDErrorIndicatorView() + hud.textLabel.text = error.description + hud.dismiss(afterDelay: NCGlobal.shared.dismissAfterSecond) + } + } + } + } + } + + let viewInFolder = UIAction(title: NSLocalizedString("_view_in_folder_", comment: ""), + image: UIImage(systemName: "arrow.forward.square")) { _ in + NCActionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileNameBlink: metadata.fileName, fileNameOpen: nil) + } + + let save = UIAction(title: titleSave, + image: UIImage(systemName: "square.and.arrow.down")) { _ in + if let metadataMOV = metadataMOV { + NCNetworking.shared.saveLivePhotoQueue.addOperation(NCOperationSaveLivePhoto(metadata: metadata, metadataMOV: metadataMOV)) + } else { + if self.utilityFileSystem.fileProviderStorageExists(metadata) { + NCActionCenter.shared.saveAlbum(metadata: metadata) + } else { + guard let metadata = NCManageDatabase.shared.setMetadatasSessionInWaitDownload(metadatas: [metadata], + session: NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, + selector: NCGlobal.shared.selectorSaveAlbum) else { return } + hud.show(in: viewController.view) + NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) { + } requestHandler: { request in + downloadRequest = request + } progressHandler: { progress in + hud.progress = Float(progress.fractionCompleted) + } completion: { afError, error in + DispatchQueue.main.async { + if error == .success || afError?.isExplicitlyCancelledError ?? false { + hud.dismiss() + } else { + hud.indicatorView = JGProgressHUDErrorIndicatorView() + hud.textLabel.text = error.description + hud.dismiss(afterDelay: NCGlobal.shared.dismissAfterSecond) + } + } + } + } + } + } + + let copy = UIAction(title: NSLocalizedString("_copy_file_", comment: ""), + image: UIImage(systemName: "doc.on.doc")) { _ in + NCActionCenter.shared.copyPasteboard(pasteboardOcIds: [metadata.ocId]) + } + let share = UIAction(title: NSLocalizedString("_share_", comment: ""), image: UIImage(systemName: "square.and.arrow.up") ) { _ in if self.utilityFileSystem.fileProviderStorageExists(metadata) { @@ -103,10 +238,6 @@ class NCContextMenu: NSObject { } } - let viewInFolder = UIAction(title: NSLocalizedString("_view_in_folder_", comment: ""), - image: UIImage(systemName: "questionmark.folder")) { _ in - NCActionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileNameBlink: metadata.fileName, fileNameOpen: nil) - } let livePhotoSave = UIAction(title: NSLocalizedString("_livephoto_save_", comment: ""), image: UIImage(systemName: "livephoto")) { _ in @@ -166,7 +297,7 @@ class NCContextMenu: NSObject { } else { NCContentPresenter().showError(error: error) } - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "onlyLocalCache": false, "error": error]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "indexPath": [indexPath], "onlyLocalCache": false, "error": error]) } }) alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { _ in }) @@ -183,7 +314,7 @@ class NCContextMenu: NSObject { } else { NCContentPresenter().showError(error: error) } - NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "onlyLocalCache": true, "error": error]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "indexPath": [indexPath], "onlyLocalCache": true, "error": error]) } } @@ -194,58 +325,53 @@ class NCContextMenu: NSObject { // ------ MENU ----- - var menu: [UIMenuElement] = [] - if metadata.directory { - - if metadata.isDirectoryE2EE || metadata.e2eEncrypted { - menu.append(favorite) - } else { - menu.append(favorite) - menu.append(deleteConfirmFile) - } - return UIMenu(title: "", children: [detail, UIMenu(title: "", options: .displayInline, children: menu)]) + let serverUrlHome = utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) + let isEncryptionDisabled = metadata.canUnsetDirectoryAsE2EE + let isEncrytptionEnabled = metadata.serverUrl == serverUrlHome && metadata.canSetDirectoryAsE2EE + let submenu = UIMenu(title: "", options: .displayInline, children: isEncrytptionEnabled ? [favorite, offline, rename, moveCopy, encrypt, deleteSubMenu] : [favorite, offline, rename, moveCopy, deleteSubMenu]) + let childrenArray = metadata.e2eEncrypted ? ( isEncryptionDisabled ? [offline, decrypt] : (metadata.serverUrl == serverUrlHome) ? [offline] : [offline, deleteSubMenu]) : [detail,submenu] + return UIMenu(title: "", children: childrenArray) } else { - if metadata.lock { - menu.append(favorite) - if metadata.isDocumentViewableOnly { - // - } else { - menu.append(share) - if NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) != nil { - menu.append(livePhotoSave) - } - } - } else { - menu.append(favorite) - if metadata.isDocumentViewableOnly { - if viewController is NCMedia { - menu.append(viewInFolder) - } - } else { - menu.append(share) - if NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) != nil { - menu.append(livePhotoSave) - } + var children: [UIMenuElement] = metadata.e2eEncrypted ? [openIn, copy, deleteSubMenu] : [offline, openIn, deleteSubMenu] - if viewController is NCMedia { - menu.append(viewInFolder) - } - - // MODIFY WITH QUICK LOOK - if metadata.isModifiableWithQuickLook { - menu.append(modify) - } + if !metadata.lock { + // Workaround: PROPPATCH doesn't work (favorite) + // https://github.com/nextcloud/files_lock/issues/68 + if !metadata.isDirectoryE2EE { + children.insert(favorite, at: 0) + children.insert(moveCopy, at: 2) + children.insert(rename, at: 3) + children.insert(copy, at: 3) } + } + + children.append(deleteSubMenu) + + if (metadata.contentType != "image/svg+xml") && (metadata.classFile == NKCommon.TypeClassFile.image.rawValue || metadata.classFile == NKCommon.TypeClassFile.video.rawValue) { + children.insert(save, at: 2) + } + + if !metadata.e2eEncrypted, (metadata.contentType != "image/svg+xml") && (metadata.classFile == NKCommon.TypeClassFile.image.rawValue || metadata.contentType == "application/pdf" || metadata.contentType == "com.adobe.pdf") { + children.insert(print, at: 2) + } + + if !metadata.e2eEncrypted { if viewController is NCMedia { - menu.append(deleteConfirmFile) - } else { - menu.append(deleteSubMenu) + children.insert(viewInFolder, at: children.count - 1) } } - return UIMenu(title: "", children: [detail, UIMenu(title: "", options: .displayInline, children: menu)]) + + if (!metadata.isDirectoryE2EE && metadata.contentType != "image/gif" && metadata.contentType != "image/svg+xml") && (metadata.contentType == "com.adobe.pdf" || metadata.contentType == "application/pdf" || metadata.classFile == NKCommon.TypeClassFile.image.rawValue) { + children.insert(modify, at: children.count - 1) + } + + let submenu = UIMenu(title: "", options: .displayInline, children: children) + guard appDelegate.disableSharesView == false else { return submenu } + let childrenArray = metadata.isDirectoryE2EE ? [submenu] : [detail, submenu] + return UIMenu(title: "", children: childrenArray) } } } diff --git a/iOSClient/Menu/NCViewer+Menu.swift b/iOSClient/Menu/NCViewer+Menu.swift index 42ffdfa179..e5d3abe79c 100644 --- a/iOSClient/Menu/NCViewer+Menu.swift +++ b/iOSClient/Menu/NCViewer+Menu.swift @@ -36,21 +36,6 @@ extension NCViewer { let localFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) let isOffline = localFile?.offline == true - // - // DETAIL - // - if !appDelegate.disableSharesView { - actions.append( - NCMenuAction( - title: NSLocalizedString("_details_", comment: ""), - icon: utility.loadImage(named: "info.circle"), - action: { _ in - NCActionCenter.shared.openShare(viewController: viewController, metadata: metadata, page: .activity) - } - ) - ) - } - // // VIEW IN FOLDER // @@ -58,7 +43,7 @@ extension NCViewer { actions.append( NCMenuAction( title: NSLocalizedString("_view_in_folder_", comment: ""), - icon: utility.loadImage(named: "questionmark.folder"), + icon: utility.loadImage(named: "arrow.forward.square", color: NCBrandColor.shared.iconColor), action: { _ in NCActionCenter.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, fileNameBlink: metadata.fileName, fileNameOpen: nil) } @@ -70,11 +55,11 @@ extension NCViewer { // FAVORITE // Workaround: PROPPATCH doesn't work // https://github.com/nextcloud/files_lock/issues/68 - if !metadata.lock { + if !metadata.lock, !metadata.isDirectoryE2EE{ actions.append( NCMenuAction( title: metadata.favorite ? NSLocalizedString("_remove_favorites_", comment: "") : NSLocalizedString("_add_favorites_", comment: ""), - icon: utility.loadImage(named: metadata.favorite ? "star.slash.fill" : "star.fill", color: NCBrandColor.shared.yellowFavorite), + icon: utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite), action: { _ in NCNetworking.shared.favoriteMetadata(metadata) { error in if error != .success { @@ -99,58 +84,42 @@ extension NCViewer { if !webView, metadata.canShare { actions.append(.share(selectedMetadatas: [metadata], viewController: viewController)) } - - // - // SAVE LIVE PHOTO - // - if let metadataMOV = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) { - actions.append( - NCMenuAction( - title: NSLocalizedString("_livephoto_save_", comment: ""), - icon: NCUtility().loadImage(named: "livephoto"), - action: { _ in - NCNetworking.shared.saveLivePhotoQueue.addOperation(NCOperationSaveLivePhoto(metadata: metadata, metadataMOV: metadataMOV)) - } - ) - ) - } - + // - // SAVE AS SCAN + // PRINT // - if !webView, metadata.isSavebleAsImage { + if !webView, metadata.isPrintable { actions.append( NCMenuAction( - title: NSLocalizedString("_save_as_scan_", comment: ""), - icon: utility.loadImage(named: "doc.viewfinder"), + title: NSLocalizedString("_print_", comment: ""), + icon: utility.loadImage(named: "printer", color: NCBrandColor.shared.iconColor), action: { _ in if self.utilityFileSystem.fileProviderStorageExists(metadata) { - NotificationCenter.default.post( - name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), - object: nil, - userInfo: ["ocId": metadata.ocId, - "selector": NCGlobal.shared.selectorSaveAsScan, - "error": NKError(), - "account": metadata.account]) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadedFile, userInfo: ["ocId": metadata.ocId, "selector": NCGlobal.shared.selectorPrint, "error": NKError(), "account": metadata.account]) } else { - guard let metadata = NCManageDatabase.shared.setMetadatasSessionInWaitDownload(metadatas: [metadata], - session: NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, - selector: NCGlobal.shared.selectorSaveAsScan) else { return } - NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true) + NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorPrint)) } } ) ) } + + // + // SAVE CAMERA ROLL + // + if !webView, metadata.isSavebleInCameraRoll { + actions.append(.saveMediaAction(selectedMediaMetadatas: [metadata])) + } + // // RENAME // - if !webView, metadata.isRenameable { + if !webView, metadata.isRenameable, !metadata.isDirectoryE2EE { actions.append( NCMenuAction( title: NSLocalizedString("_rename_", comment: ""), - icon: utility.loadImage(named: "text.cursor"), + icon: utility.loadImage(named: "rename", color: NCBrandColor.shared.iconColor), action: { _ in if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile { @@ -177,21 +146,10 @@ extension NCViewer { } // - // DOWNLOAD FULL RESOLUTION + // COPY IN PASTEBOARD // - if !webView, metadata.session.isEmpty, !self.utilityFileSystem.fileProviderStorageExists(metadata) { - actions.append( - NCMenuAction( - title: NSLocalizedString("_try_download_full_resolution_", comment: ""), - icon: utility.loadImage(named: "photo"), - action: { _ in - guard let metadata = NCManageDatabase.shared.setMetadatasSessionInWaitDownload(metadatas: [metadata], - session: NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, - selector: "") else { return } - NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: true) - } - ) - ) + if !webView, metadata.isCopyableInPasteboard, !metadata.isDirectoryE2EE { + actions.append(.copyAction(selectOcId: [metadata.ocId])) } // @@ -201,7 +159,7 @@ extension NCViewer { actions.append( NCMenuAction( title: NSLocalizedString("_search_", comment: ""), - icon: UIImage(named: "search")!.image(color: UIColor.systemGray, size: 50), + icon: UIImage(named: "search")!.image(color: NCBrandColor.shared.iconColor, size: 50), action: { _ in NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMenuSearchTextPDF) } @@ -211,7 +169,7 @@ extension NCViewer { actions.append( NCMenuAction( title: NSLocalizedString("_go_to_page_", comment: ""), - icon: utility.loadImage(named: "repeat"), + icon: utility.loadImage(named: "go-to-page", color: NCBrandColor.shared.iconColor), action: { _ in NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterMenuGotToPageInPDF) } @@ -226,7 +184,7 @@ extension NCViewer { actions.append( NCMenuAction( title: NSLocalizedString("_modify_", comment: ""), - icon: utility.loadImage(named: "pencil.tip.crop.circle"), + icon: utility.loadImage(named: "pencil.tip.crop.circle", color: NCBrandColor.shared.iconColor), action: { _ in if self.utilityFileSystem.fileProviderStorageExists(metadata) { NotificationCenter.default.post( @@ -251,7 +209,7 @@ extension NCViewer { // DELETE // if !webView, metadata.isDeletable { - actions.append(.deleteAction(selectedMetadatas: [metadata], indexPaths: [], metadataFolder: nil, viewController: viewController)) + actions.append(.deleteAction(selectedMetadatas: [metadata], indexPath: [], metadataFolder: nil, viewController: viewController)) } viewController.presentMenu(with: actions)