From d583705d1c931685f1d640a09afd5a46d30b0a4d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Aug 2026 09:09:21 +0200 Subject: [PATCH 1/7] feat: add document editor coordinator Select the highest-priority available editor and open Collabora documents using generated rich-document URLs. Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 4 + iOSClient/NCGlobal.swift | 8 ++ .../Viewer/NCDocumentEditorCoordinator.swift | 114 ++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 iOSClient/Viewer/NCDocumentEditorCoordinator.swift diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index d9bb4f9321..511dbd9a7d 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -814,6 +814,7 @@ F7C7B25028B8AD4500E7115D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F7E70DE91A24DE4100E1B66A /* Localizable.strings */; }; F7C7B25128B8B0C400E7115D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7F67BB81A24D27800EE80DA /* Images.xcassets */; }; F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C7B488245EBA4100D93E60 /* NCViewerQuickLook.swift */; }; + F7C8A93A3025B757004E3A10 /* NCDocumentEditorCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C8A9393025B74B004E3A10 /* NCDocumentEditorCoordinator.swift */; }; F7C9555321F0C4CA0024296E /* NCActivity.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7C9555221F0C4CA0024296E /* NCActivity.storyboard */; }; F7C9555521F0C5470024296E /* NCActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9555421F0C5470024296E /* NCActivity.swift */; }; F7C9739528F17131002C43E2 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C9739428F17131002C43E2 /* IntentHandler.swift */; }; @@ -1840,6 +1841,7 @@ F7C630832FFF6DDF00257EEB /* NCMetadataDownloadTranfersSuccess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMetadataDownloadTranfersSuccess.swift; sourceTree = ""; }; F7C687E82D22BD46004757BC /* NCManageDatabase+RecommendedFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+RecommendedFiles.swift"; sourceTree = ""; }; F7C7B488245EBA4100D93E60 /* NCViewerQuickLook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewerQuickLook.swift; sourceTree = ""; }; + F7C8A9393025B74B004E3A10 /* NCDocumentEditorCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCDocumentEditorCoordinator.swift; sourceTree = ""; }; F7C9555221F0C4CA0024296E /* NCActivity.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCActivity.storyboard; sourceTree = ""; }; F7C9555421F0C5470024296E /* NCActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivity.swift; sourceTree = ""; }; F7C9739028F17131002C43E2 /* WidgetDashboardIntentHandler.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetDashboardIntentHandler.appex; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -3023,6 +3025,7 @@ isa = PBXGroup; children = ( F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */, + F7C8A9393025B74B004E3A10 /* NCDocumentEditorCoordinator.swift */, F7EFA47725ADBA500083159A /* NCViewerProviderContextMenu.swift */, F7CDB5C12FA33CA300F72306 /* NCViewerMedia */, F723986A253C9C0E00257F49 /* NCViewerQuickLook */, @@ -4807,6 +4810,7 @@ files = ( F77444F522281649000D5EB0 /* NCMediaCell.swift in Sources */, F78C6FDE296D677300C952C3 /* NCContextMenuMain.swift in Sources */, + F7C8A93A3025B757004E3A10 /* NCDocumentEditorCoordinator.swift in Sources */, A5A87F9E4B0E4441A6A4BC20 /* NCContextMenuProfile.swift in Sources */, CB3666201AF7550816B5CD6A /* NCContextMenuComment.swift in Sources */, F7E402332BA89551007E5609 /* NCTrash+Networking.swift in Sources */, diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index f9626c0147..9eded6458e 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -40,6 +40,14 @@ final class NCGlobal: Sendable { let twoFactorNotificatioName = "twofactor_nextcloud_notification" let termsOfServiceName = "terms_of_service" + // OFFICE + // + let editorText: String = "text" + let editorEuroOffice: String = "eurooffice" + let editorCollabora: String = "richdocuments" + let editorOnlyOffice: String = "onlyoffice" + var priorityEditors: [String] {[editorText, editorEuroOffice, editorCollabora, editorOnlyOffice]} + // Intro selector // let introLogin: Int = 0 diff --git a/iOSClient/Viewer/NCDocumentEditorCoordinator.swift b/iOSClient/Viewer/NCDocumentEditorCoordinator.swift new file mode 100644 index 0000000000..ff10931a37 --- /dev/null +++ b/iOSClient/Viewer/NCDocumentEditorCoordinator.swift @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2026 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + +import UIKit +import NextcloudKit +import QuickLook +import SwiftUI + +@MainActor +final class NCDocumentEditorCoordinator: NSObject { + let utilityFileSystem = NCUtilityFileSystem() + let utility = NCUtility() + let database = NCManageDatabase.shared + let global = NCGlobal.shared + private var viewerQuickLook: NCViewerQuickLook? + + let metadata: tableMetadata + let image: UIImage? + let delegate: UIViewController? + + init(metadata: tableMetadata, image: UIImage?, delegate: UIViewController?) { + self.metadata = metadata + self.image = image + self.delegate = delegate + + super.init() + } + + func selectOffice() async -> UIViewController? { + let availableEditors = Set( + utility.editorsDirectEditing( + account: metadata.account, + contentType: metadata.contentType + ) + .map { $0.lowercased() } + ) + + guard let selectedEditor = global.priorityEditors + .lazy + .map({ $0.lowercased() }) + .first(where: availableEditors.contains) else { + return nil + } + + if selectedEditor == global.editorText.lowercased() { + // return await editorText() + return nil + } else if selectedEditor == global.editorEuroOffice.lowercased() { + // return await editorEuroOffice() + return nil + } else if selectedEditor == global.editorCollabora.lowercased() { + return await editorCollabora() + } + + return nil + } + + // COLLABORA + // + private func editorCollabora() async -> UIViewController? { + let link: String + + if metadata.url.isEmpty { + NCActivityIndicator.shared.start(backgroundView: delegate?.view) + + let results = await NextcloudKit.shared.createUrlRichdocumentsAsync(fileID: metadata.fileId, account: metadata.account) { task in + Task { + let identifier = await NCNetworking.shared.networkingTasks.createIdentifier( + account: self.metadata.account, + path: self.metadata.fileId, + name: "createUrlRichdocuments" + ) + + await NCNetworking.shared.networkingTasks.track( + identifier: identifier, + task: task + ) + } + } + + NCActivityIndicator.shared.stop() + + guard results.error == .success, let generatedURL = results.url else { + let windowScene = SceneManager.shared.getWindowScene( + controller: delegate?.tabBarController as? NCMainTabBarController + ) + + await showErrorBanner( + windowScene: windowScene, + text: results.error.errorDescription, + errorCode: results.error.errorCode + ) + + return nil + } + + link = generatedURL + } else { + link = metadata.url + } + + guard let viewController = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as? NCViewerRichDocument else { + return nil + } + + viewController.metadata = metadata + viewController.link = link + viewController.imageIcon = image + viewController.navigationItem.setBidiSafeTitle(metadata.fileNameView) + + return viewController + } +} From 2c609a3fdde26569231e91ee7d752a127ae16f4e Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Aug 2026 09:25:03 +0200 Subject: [PATCH 2/7] feat: support text and EuroOffice document editors Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 10 +- .../Viewer/NCDocumentEditorCoordinator.swift | 114 ---------- .../NCDocumentEditorCoordinator.swift | 200 ++++++++++++++++++ 3 files changed, 209 insertions(+), 115 deletions(-) delete mode 100644 iOSClient/Viewer/NCDocumentEditorCoordinator.swift create mode 100644 iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 511dbd9a7d..a04e5d7452 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -3025,8 +3025,8 @@ isa = PBXGroup; children = ( F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */, - F7C8A9393025B74B004E3A10 /* NCDocumentEditorCoordinator.swift */, F7EFA47725ADBA500083159A /* NCViewerProviderContextMenu.swift */, + F7C8A93B3025BCBC004E3A10 /* NCViewerDocument */, F7CDB5C12FA33CA300F72306 /* NCViewerMedia */, F723986A253C9C0E00257F49 /* NCViewerQuickLook */, F76D3CEF2428B3DD005DFA87 /* NCViewerPDF */, @@ -3288,6 +3288,14 @@ path = "Action Assistant"; sourceTree = ""; }; + F7C8A93B3025BCBC004E3A10 /* NCViewerDocument */ = { + isa = PBXGroup; + children = ( + F7C8A9393025B74B004E3A10 /* NCDocumentEditorCoordinator.swift */, + ); + path = NCViewerDocument; + sourceTree = ""; + }; F7C9739328F17131002C43E2 /* WidgetDashboardIntentHandler */ = { isa = PBXGroup; children = ( diff --git a/iOSClient/Viewer/NCDocumentEditorCoordinator.swift b/iOSClient/Viewer/NCDocumentEditorCoordinator.swift deleted file mode 100644 index ff10931a37..0000000000 --- a/iOSClient/Viewer/NCDocumentEditorCoordinator.swift +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-FileCopyrightText: Nextcloud GmbH -// SPDX-FileCopyrightText: 2026 Marino Faggiana -// SPDX-License-Identifier: GPL-3.0-or-later - -import UIKit -import NextcloudKit -import QuickLook -import SwiftUI - -@MainActor -final class NCDocumentEditorCoordinator: NSObject { - let utilityFileSystem = NCUtilityFileSystem() - let utility = NCUtility() - let database = NCManageDatabase.shared - let global = NCGlobal.shared - private var viewerQuickLook: NCViewerQuickLook? - - let metadata: tableMetadata - let image: UIImage? - let delegate: UIViewController? - - init(metadata: tableMetadata, image: UIImage?, delegate: UIViewController?) { - self.metadata = metadata - self.image = image - self.delegate = delegate - - super.init() - } - - func selectOffice() async -> UIViewController? { - let availableEditors = Set( - utility.editorsDirectEditing( - account: metadata.account, - contentType: metadata.contentType - ) - .map { $0.lowercased() } - ) - - guard let selectedEditor = global.priorityEditors - .lazy - .map({ $0.lowercased() }) - .first(where: availableEditors.contains) else { - return nil - } - - if selectedEditor == global.editorText.lowercased() { - // return await editorText() - return nil - } else if selectedEditor == global.editorEuroOffice.lowercased() { - // return await editorEuroOffice() - return nil - } else if selectedEditor == global.editorCollabora.lowercased() { - return await editorCollabora() - } - - return nil - } - - // COLLABORA - // - private func editorCollabora() async -> UIViewController? { - let link: String - - if metadata.url.isEmpty { - NCActivityIndicator.shared.start(backgroundView: delegate?.view) - - let results = await NextcloudKit.shared.createUrlRichdocumentsAsync(fileID: metadata.fileId, account: metadata.account) { task in - Task { - let identifier = await NCNetworking.shared.networkingTasks.createIdentifier( - account: self.metadata.account, - path: self.metadata.fileId, - name: "createUrlRichdocuments" - ) - - await NCNetworking.shared.networkingTasks.track( - identifier: identifier, - task: task - ) - } - } - - NCActivityIndicator.shared.stop() - - guard results.error == .success, let generatedURL = results.url else { - let windowScene = SceneManager.shared.getWindowScene( - controller: delegate?.tabBarController as? NCMainTabBarController - ) - - await showErrorBanner( - windowScene: windowScene, - text: results.error.errorDescription, - errorCode: results.error.errorCode - ) - - return nil - } - - link = generatedURL - } else { - link = metadata.url - } - - guard let viewController = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as? NCViewerRichDocument else { - return nil - } - - viewController.metadata = metadata - viewController.link = link - viewController.imageIcon = image - viewController.navigationItem.setBidiSafeTitle(metadata.fileNameView) - - return viewController - } -} diff --git a/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift new file mode 100644 index 0000000000..ef17e0a7f8 --- /dev/null +++ b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift @@ -0,0 +1,200 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2026 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + +import UIKit +import NextcloudKit +import QuickLook +import SwiftUI + +@MainActor +final class NCDocumentEditorCoordinator: NSObject { + let utilityFileSystem = NCUtilityFileSystem() + let utility = NCUtility() + let database = NCManageDatabase.shared + let global = NCGlobal.shared + private var viewerQuickLook: NCViewerQuickLook? + + let metadata: tableMetadata + let image: UIImage? + let selectedEditor: String? + let delegate: UIViewController? + + init(metadata: tableMetadata, image: UIImage?, selectedEditor: String? = nil, delegate: UIViewController?) { + self.metadata = metadata + self.image = image + self.selectedEditor = selectedEditor + self.delegate = delegate + + super.init() + } + + func selectOffice() async -> UIViewController? { + let availableEditors = Set( + utility.editorsDirectEditing( + account: metadata.account, + contentType: metadata.contentType + ) + .map { $0.lowercased() } + ) + + guard let selectedEditor = global.priorityEditors + .lazy + .map({ $0.lowercased() }) + .first(where: availableEditors.contains) else { + return nil + } + + if selectedEditor == global.editorText.lowercased() { + return await makeDirectEditingViewController(editor: global.editorText) + } else if selectedEditor == global.editorEuroOffice.lowercased() { + return await makeDirectEditingViewController(editor: global.editorEuroOffice) + } else if selectedEditor == global.editorCollabora.lowercased() { + return await makeCollaboraViewController() + } + + return nil + } + + // MARK: - Text editor + + private func makeDirectEditingViewController(editor: String) async -> UIViewController? { + guard let editorAdapter = NCDirectEditorAdapter.resolve( + from: [editor] + ) else { + return nil + } + + let account = metadata.account + let editorIdentifier = selectedEditor ?? editorAdapter.apiKey + let editorViewController = editorAdapter.viewControllerEditor + let options = NKRequestOptions( + customUserAgent: editorAdapter.userAgent(utility) + ) + + let link: String + + if metadata.url.isEmpty { + let session = NCSession.shared.getSession(account: account) + let fileNamePath = utilityFileSystem.getRelativeFilePath( + metadata.fileName, + serverUrl: metadata.serverUrl, + session: session + ) + + NCActivityIndicator.shared.start(backgroundView: delegate?.view) + + let results = await NextcloudKit.shared.textOpenFileAsync( + fileNamePath: fileNamePath, + editor: editorIdentifier, + account: account, + options: options + ) { task in + Task { + let identifier = await NCNetworking.shared.networkingTasks.createIdentifier( + account: account, + path: fileNamePath, + name: "textOpenFile" + ) + + await NCNetworking.shared.networkingTasks.track( + identifier: identifier, + task: task + ) + } + } + + NCActivityIndicator.shared.stop() + + guard results.error == .success, + let generatedURL = results.url else { + let windowScene = SceneManager.shared.getWindowScene( + controller: delegate?.tabBarController as? NCMainTabBarController + ) + + await showErrorBanner( + windowScene: windowScene, + text: results.error.errorDescription, + errorCode: results.error.errorCode + ) + + return nil + } + + link = generatedURL + } else { + link = metadata.url + } + + guard let viewController = UIStoryboard( + name: "NCViewerDirectEditing", + bundle: nil + ).instantiateInitialViewController() as? NCViewerDirectEditing else { + return nil + } + + viewController.metadata = metadata + viewController.editor = editorViewController + viewController.link = link + viewController.imageIcon = image + viewController.navigationItem.setBidiSafeTitle(metadata.fileNameView) + + return viewController + } + + // MARK: - Collabora + + private func makeCollaboraViewController() async -> UIViewController? { + let link: String + + if metadata.url.isEmpty { + NCActivityIndicator.shared.start(backgroundView: delegate?.view) + + let results = await NextcloudKit.shared.createUrlRichdocumentsAsync(fileID: metadata.fileId, account: metadata.account) { task in + Task { + let identifier = await NCNetworking.shared.networkingTasks.createIdentifier( + account: self.metadata.account, + path: self.metadata.fileId, + name: "createUrlRichdocuments" + ) + + await NCNetworking.shared.networkingTasks.track( + identifier: identifier, + task: task + ) + } + } + + NCActivityIndicator.shared.stop() + + guard results.error == .success, let generatedURL = results.url else { + let windowScene = SceneManager.shared.getWindowScene( + controller: delegate?.tabBarController as? NCMainTabBarController + ) + + await showErrorBanner( + windowScene: windowScene, + text: results.error.errorDescription, + errorCode: results.error.errorCode + ) + + return nil + } + + link = generatedURL + } else { + link = metadata.url + } + + guard let viewController = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as? NCViewerRichDocument else { + return nil + } + + viewController.metadata = metadata + viewController.link = link + viewController.imageIcon = image + viewController.navigationItem.setBidiSafeTitle(metadata.fileNameView) + + return viewController + } +} From ae560a0a85b7821b04e6210886dca3a0a55acec4 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Aug 2026 09:40:14 +0200 Subject: [PATCH 3/7] refactor: centralize document editor selection Signed-off-by: Marino Faggiana --- iOSClient/Viewer/NCViewer.swift | 108 ++---------------- .../NCDocumentEditorCoordinator.swift | 4 +- 2 files changed, 9 insertions(+), 103 deletions(-) diff --git a/iOSClient/Viewer/NCViewer.swift b/iOSClient/Viewer/NCViewer.swift index 31c95469c5..0533d35f00 100644 --- a/iOSClient/Viewer/NCViewer.swift +++ b/iOSClient/Viewer/NCViewer.swift @@ -78,109 +78,15 @@ class NCViewer: NSObject { return vc } - // DirectEditing - if metadata.isAvailableDirectEditingEditorView { - let availableEditors = utility.editorsDirectEditing( - account: metadata.account, - contentType: metadata.contentType - ).map { $0.lowercased() } - let editors: [String] - - if availableEditors.contains("text") { - editors = ["text"] - } else { - editors = availableEditors - } - - guard let editorAdapter = NCDirectEditorAdapter.resolve(from: editors) else { - self.QLPreview(metadata: metadata, delegate: delegate) - return nil - } - let editor = selectedEditor ?? editorAdapter.apiKey - let editorViewController = editorAdapter.viewControllerEditor - let options = NKRequestOptions(customUserAgent: editorAdapter.userAgent(utility)) - if metadata.url.isEmpty { - let fileNamePath = utilityFileSystem.getRelativeFilePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session) - - NCActivityIndicator.shared.start(backgroundView: delegate?.view) - let results = await NextcloudKit.shared.textOpenFileAsync(fileNamePath: fileNamePath, editor: editor, account: metadata.account, options: options) { task in - Task { - let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account, - path: fileNamePath, - name: "textOpenFile") - await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) - } - } - NCActivityIndicator.shared.stop() - - guard results.error == .success, let url = results.url else { - let windowScene = SceneManager.shared.getWindowScene(controller: delegate?.tabBarController as? NCMainTabBarController) - await showErrorBanner(windowScene: windowScene, text: results.error.errorDescription, errorCode: results.error.errorCode) - return nil - } - - let vc = UIStoryboard(name: "NCViewerDirectEditing", bundle: nil).instantiateInitialViewController() as? NCViewerDirectEditing - - vc?.metadata = metadata - vc?.editor = editorViewController - vc?.link = url - vc?.imageIcon = image - vc?.navigationItem.setBidiSafeTitle(metadata.fileNameView) - - return vc - } else { - let vc = UIStoryboard(name: "NCViewerDirectEditing", bundle: nil).instantiateInitialViewController() as? NCViewerDirectEditing - - vc?.metadata = metadata - vc?.editor = editorViewController - vc?.link = metadata.url - vc?.imageIcon = image - vc?.navigationItem.setBidiSafeTitle(metadata.fileNameView) - - return vc - } + // TEXT - OFFICE + let documentEditorCoordinator = NCDocumentEditorCoordinator(metadata: metadata, image: image, selectedEditor: selectedEditor, delegate: delegate) + if let viewController = await documentEditorCoordinator.selectEditor() { + return viewController } - // RichDocument: Collabora - if metadata.isAvailableRichDocumentEditorView { - if metadata.url.isEmpty { - NCActivityIndicator.shared.start(backgroundView: delegate?.view) - let results = await NextcloudKit.shared.createUrlRichdocumentsAsync(fileID: metadata.fileId, account: metadata.account) { task in - Task { - let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account, - path: metadata.fileId, - name: "createUrlRichdocuments") - await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) - } - } - NCActivityIndicator.shared.stop() - - guard results.error == .success, let url = results.url else { - let windowScene = SceneManager.shared.getWindowScene(controller: delegate?.tabBarController as? NCMainTabBarController) - await showErrorBanner(windowScene: windowScene, text: results.error.errorDescription, errorCode: results.error.errorCode) - return nil - } - - let vc = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as? NCViewerRichDocument - - vc?.metadata = metadata - vc?.link = url - vc?.imageIcon = image - vc?.navigationItem.setBidiSafeTitle(metadata.fileNameView) + self.QLPreview(metadata: metadata, delegate: delegate) - return vc - - } else { - let vc = UIStoryboard(name: "NCViewerRichdocument", bundle: nil).instantiateInitialViewController() as? NCViewerRichDocument - - vc?.metadata = metadata - vc?.link = metadata.url - vc?.imageIcon = image - vc?.navigationItem.setBidiSafeTitle(metadata.fileNameView) - - return vc - } - } + return nil } // iOS QL-Preview @@ -189,7 +95,7 @@ class NCViewer: NSObject { return nil } - func QLPreview(metadata: tableMetadata, delegate: UIViewController? = nil) { + private func QLPreview(metadata: tableMetadata, delegate: UIViewController? = nil) { let item = URL(fileURLWithPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileName: metadata.fileNameView, userId: metadata.userId, diff --git a/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift index ef17e0a7f8..2ef7813c81 100644 --- a/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift +++ b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift @@ -20,7 +20,7 @@ final class NCDocumentEditorCoordinator: NSObject { let selectedEditor: String? let delegate: UIViewController? - init(metadata: tableMetadata, image: UIImage?, selectedEditor: String? = nil, delegate: UIViewController?) { + init(metadata: tableMetadata, image: UIImage?, selectedEditor: String?, delegate: UIViewController?) { self.metadata = metadata self.image = image self.selectedEditor = selectedEditor @@ -29,7 +29,7 @@ final class NCDocumentEditorCoordinator: NSObject { super.init() } - func selectOffice() async -> UIViewController? { + func selectEditor() async -> UIViewController? { let availableEditors = Set( utility.editorsDirectEditing( account: metadata.account, From 2db766448d9e40fa32cef59e35e8625feda517bc Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Aug 2026 10:37:57 +0200 Subject: [PATCH 4/7] refactor: migrate to renamed editor capabilities API Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 4 ++-- .../Data/NCManageDatabase+Capabilities.swift | 4 ++-- iOSClient/Data/NCManageDatabase+Metadata.swift | 8 ++++---- iOSClient/Menu/NCContextMenuMain.swift | 2 +- iOSClient/Menu/NCContextMenuPlus.swift | 15 ++++++++------- .../RichWorkspace/NCRichWorkspaceCommon.swift | 5 +++-- iOSClient/SceneDelegate.swift | 4 ++-- .../Capabilities/NCCapabilitiesModel.swift | 5 +++-- iOSClient/Utility/NCUtility.swift | 4 ++-- .../NCDocumentEditorCoordinator.swift | 2 +- 10 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index a04e5d7452..dfbffbfd30 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -6660,8 +6660,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/nextcloud/NextcloudKit"; requirement = { - kind = exactVersion; - version = 7.4.1; + branch = "capabilities-editor"; + kind = branch; }; }; F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = { diff --git a/iOSClient/Data/NCManageDatabase+Capabilities.swift b/iOSClient/Data/NCManageDatabase+Capabilities.swift index 520204222a..b189519c1f 100644 --- a/iOSClient/Data/NCManageDatabase+Capabilities.swift +++ b/iOSClient/Data/NCManageDatabase+Capabilities.swift @@ -91,8 +91,8 @@ extension NCManageDatabase { capabilities = await NKCapabilities.shared.getCapabilities(for: account) } - capabilities?.directEditingEditors = editors - capabilities?.directEditingCreators = creators + capabilities?.editorEditors = editors + capabilities?.editorCreators = creators if let capabilities { await NKCapabilities.shared.setCapabilities(for: account, capabilities: capabilities) diff --git a/iOSClient/Data/NCManageDatabase+Metadata.swift b/iOSClient/Data/NCManageDatabase+Metadata.swift index 5b9bba5ac0..1d7c8e3307 100644 --- a/iOSClient/Data/NCManageDatabase+Metadata.swift +++ b/iOSClient/Data/NCManageDatabase+Metadata.swift @@ -248,17 +248,17 @@ extension tableMetadata { return false } let utility = NCUtility() - let directEditingEditors = utility.editorsDirectEditing(account: account, contentType: contentType).map { $0.lowercased() } + let editorsEditing = utility.editorsEditing(account: account, contentType: contentType).map { $0.lowercased() } let richDocumentEditor = utility.isTypeFileRichDocument(self) let capabilities = NCNetworking.shared.capabilities[account] if let capabilities, capabilities.richDocumentsEnabled, richDocumentEditor, - directEditingEditors.isEmpty { + editorsEditing.isEmpty { // RichDocument: Collabora return true - } else if !directEditingEditors.isEmpty { + } else if !editorsEditing.isEmpty { return true } return false @@ -280,7 +280,7 @@ extension tableMetadata { guard (classFile == NKTypeClassFile.document.rawValue) && NextcloudKit.shared.isNetworkReachable() else { return false } - let editors = NCUtility().editorsDirectEditing(account: account, contentType: contentType) + let editors = NCUtility().editorsEditing(account: account, contentType: contentType) return !editors.isEmpty } diff --git a/iOSClient/Menu/NCContextMenuMain.swift b/iOSClient/Menu/NCContextMenuMain.swift index 9bb7539d39..829a739609 100644 --- a/iOSClient/Menu/NCContextMenuMain.swift +++ b/iOSClient/Menu/NCContextMenuMain.swift @@ -110,7 +110,7 @@ class NCContextMenuMain: NSObject { } if metadata.isAvailableDirectEditingEditorView { - let availableEditors = utility.editorsDirectEditing( + let availableEditors = utility.editorsEditing( account: metadata.account, contentType: metadata.contentType ).map { $0.lowercased() } diff --git a/iOSClient/Menu/NCContextMenuPlus.swift b/iOSClient/Menu/NCContextMenuPlus.swift index e175e29dcd..20dc72e73d 100644 --- a/iOSClient/Menu/NCContextMenuPlus.swift +++ b/iOSClient/Menu/NCContextMenuPlus.swift @@ -48,6 +48,7 @@ class NCContextMenuPlus: NSObject { let capabilities = await NCManageDatabase.shared.getCapabilities(account: session.account) ?? NKCapabilities.Capabilities() let utilityFileSystem = NCUtilityFileSystem() let utility = NCUtility() + let global = NCGlobal.shared let serverUrl = controller.currentServerUrl() let isDirectoryE2EE = await NCUtilityFileSystem().isDirectoryE2EEAsync(serverUrl: serverUrl, urlBase: session.urlBase, userId: session.userId, account: session.account) @@ -55,8 +56,8 @@ class NCContextMenuPlus: NSObject { let isNetworkReachable = NextcloudKit.shared.isNetworkReachable() let titleCreateFolder = isDirectoryE2EE ? NSLocalizedString("_create_folder_e2ee_", comment: "") : NSLocalizedString("_create_folder_", comment: "") let imageCreateFolder = isDirectoryE2EE ? NCImageCache.shared.getFolderEncrypted(account: session.account) : NCImageCache.shared.getFolder(account: session.account) - let creatorsByEditor = Dictionary(grouping: capabilities.directEditingCreators, by: \.editor) - let directEditingSignature = capabilities.directEditingCreators + let creatorsByEditor = Dictionary(grouping: capabilities.editorCreators, by: \.editor) + let directEditingSignature = capabilities.editorCreators .sorted { $0.identifier < $1.identifier } .map { creator in "\(creator.identifier)|\(creator.editor)|\(creator.ext)|\(creator.mimetype)|\(creator.templates)" @@ -167,7 +168,7 @@ class NCContextMenuPlus: NSObject { // if NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v34) { // FOLDER INFO - if let textCreators = creatorsByEditor["text"], + if let textCreators = creatorsByEditor[global.editorText], !textCreators.isEmpty, directory?.richWorkspace == nil, !isDirectoryE2EE, @@ -188,7 +189,7 @@ class NCContextMenuPlus: NSObject { controller: controller, serverUrl: serverUrl, fileName: fileName, - editorId: "text", + editorId: global.editorText, creatorId: "textdocument", templateId: "", session: session) @@ -213,7 +214,7 @@ class NCContextMenuPlus: NSObject { } // TEXT if isNetworkReachable, - let creator = capabilities.directEditingCreators.first(where: { $0.editor == "text" }), + let creator = capabilities.editorCreators.first(where: { $0.editor == global.editorText }), !isDirectoryE2EE { menuTextElements.append(UIAction(title: NSLocalizedString("_create_nextcloudtext_document_", comment: ""), image: utility.loadImage(named: "doc.text", colors: [NCBrandColor.shared.iconImageColor])) { _ in @@ -223,7 +224,7 @@ class NCContextMenuPlus: NSObject { await NCCreate().createDocument(controller: controller, serverUrl: serverUrl, fileName: fileName, - editorId: "text", + editorId: global.editorText, creatorId: creator.identifier, templateId: "document", session: session) @@ -292,7 +293,7 @@ class NCContextMenuPlus: NSObject { // for editorId in creatorsByEditor.keys.sorted() { guard NCDirectEditorAdapter.resolve(from: [editorId]) != nil, - editorId != "text" else { + editorId != global.editorText else { continue } diff --git a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift index 557f2beb60..48d60c073e 100644 --- a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift +++ b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift @@ -7,6 +7,7 @@ import NextcloudKit class NCRichWorkspaceCommon: NSObject { let utilityFileSystem = NCUtilityFileSystem() + let global = NCGlobal.shared func createViewerNextcloudText(serverUrl: String, viewController: UIViewController, controller: NCMainTabBarController?, session: NCSession.Session) { if !NextcloudKit.shared.isNetworkReachable() { @@ -18,7 +19,7 @@ class NCRichWorkspaceCommon: NSObject { } guard let capabilities = NCNetworking.shared.capabilities[session.account], - let textCreators = capabilities.directEditingCreators.filter({ $0.editor == "text" }).first else { + let textCreators = capabilities.editorCreators.filter({ $0.editor == global.editorText }).first else { return } @@ -68,7 +69,7 @@ class NCRichWorkspaceCommon: NSObject { NCActivityIndicator.shared.start(backgroundView: viewController.view) let fileNamePath = utilityFileSystem.getRelativeFilePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session) - NextcloudKit.shared.textOpenFile(fileNamePath: fileNamePath, editor: "text", account: metadata.account) { task in + NextcloudKit.shared.textOpenFile(fileNamePath: fileNamePath, editor: global.editorText, account: metadata.account) { task in Task { let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account, path: fileNamePath, diff --git a/iOSClient/SceneDelegate.swift b/iOSClient/SceneDelegate.swift index 4b528c3d7c..7297f046b2 100644 --- a/iOSClient/SceneDelegate.swift +++ b/iOSClient/SceneDelegate.swift @@ -406,7 +406,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { case self.global.actionTextDocument: let session = SceneManager.shared.getSession(scene: scene) let capabilities = await NKCapabilities.shared.getCapabilities(for: session.account) - guard let creator = capabilities.directEditingCreators.first(where: { $0.editor == "text" }) else { + guard let creator = capabilities.editorCreators.first(where: { $0.editor == global.editorText }) else { return } let serverUrl = controller.currentServerUrl() @@ -415,7 +415,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { await NCCreate().createDocument(controller: controller, serverUrl: serverUrl, fileName: fileName, - editorId: "text", + editorId: global.editorText, creatorId: creator.identifier, templateId: "document", session: session) diff --git a/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift index 1218e3ce3f..bfab71c6b2 100644 --- a/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift +++ b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift @@ -34,6 +34,7 @@ class NCCapabilitiesModel: ObservableObject, ViewOnAppearHandling { } let utilityFileSystem = NCUtilityFileSystem() let utility = NCUtility() + let global = NCGlobal.shared init(controller: NCMainTabBarController?) { self.controller = controller @@ -69,9 +70,9 @@ class NCCapabilitiesModel: ObservableObject, ViewOnAppearHandling { image = utility.loadImage(named: "trash") capabililies.append(Capability(text: "Deleted files", image: image, resize: false, available: cap.filesUndelete)) - let editors = cap.directEditingCreators + let editors = cap.editorCreators for editor in editors { - if editor.editor.lowercased() == "text" { + if editor.editor.lowercased() == global.editorText { textEditor = true } else if editor.editor.lowercased() == "onlyoffice" { onlyofficeEditor = true diff --git a/iOSClient/Utility/NCUtility.swift b/iOSClient/Utility/NCUtility.swift index e64b90735c..cd8409939a 100644 --- a/iOSClient/Utility/NCUtility.swift +++ b/iOSClient/Utility/NCUtility.swift @@ -38,11 +38,11 @@ final class NCUtility: NSObject, Sendable { return false } - func editorsDirectEditing(account: String, contentType: String) -> [String] { + func editorsEditing(account: String, contentType: String) -> [String] { var identifiers: [String] = [] let capabilities = NCNetworking.shared.capabilities[account] - capabilities?.directEditingEditors.forEach { editor in + capabilities?.editorEditors.forEach { editor in editor.mimetypes.forEach { mimetype in if mimetype == contentType { identifiers.append(editor.identifier) diff --git a/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift index 2ef7813c81..a8c659492b 100644 --- a/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift +++ b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift @@ -31,7 +31,7 @@ final class NCDocumentEditorCoordinator: NSObject { func selectEditor() async -> UIViewController? { let availableEditors = Set( - utility.editorsDirectEditing( + utility.editorsEditing( account: metadata.account, contentType: metadata.contentType ) From 228e76e500b425799fffba84ee758f4e832e8d59 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Aug 2026 11:49:01 +0200 Subject: [PATCH 5/7] fix: support OnlyOffice in document editor flows Organize document creation actions by editor and use shared editor identifiers for capability detection. Signed-off-by: Marino Faggiana --- iOSClient/Menu/NCContextMenuPlus.swift | 163 +++++++++++------- .../Capabilities/NCCapabilitiesModel.swift | 4 +- .../NCDocumentEditorCoordinator.swift | 24 +-- 3 files changed, 105 insertions(+), 86 deletions(-) diff --git a/iOSClient/Menu/NCContextMenuPlus.swift b/iOSClient/Menu/NCContextMenuPlus.swift index 20dc72e73d..16a1c65af2 100644 --- a/iOSClient/Menu/NCContextMenuPlus.swift +++ b/iOSClient/Menu/NCContextMenuPlus.swift @@ -233,13 +233,13 @@ class NCContextMenuPlus: NSObject { } } - // OFFICE + // OFFICE - EDITOR // - if isNetworkReachable, - !isDirectoryE2EE { - if capabilities.richDocumentsEnabled { - // COLLABORA - // + if isNetworkReachable, !isDirectoryE2EE { + + // RICH DOCUMENTS - COLLABORA + // + if creatorsByEditor.keys.contains(global.editorCollabora) { menuRichDocumentElements.append(UIAction(title: NSLocalizedString("_create_new_document_", comment: ""), image: utility.loadImage(named: "doc.richtext", colors: [NCBrandColor.shared.documentIconColor])) { _ in Task { @MainActor in @@ -287,69 +287,73 @@ class NCContextMenuPlus: NSObject { session: session) } }) + } - // DIRECT EDITING (eurooffice, onlyoffice) + // EURO OFFICE - ONLY OFFICE // - for editorId in creatorsByEditor.keys.sorted() { - guard NCDirectEditorAdapter.resolve(from: [editorId]) != nil, - editorId != global.editorText else { - continue - } - - let sortedCreators = creatorsByEditor[editorId]! - .compactMap { creator -> (NKEditorDetailsCreator, CreatorMenuInfo)? in - guard let info = NCContextMenuPlus.menuInfo(for: creator.ext) else { return nil } - return (creator, info) + if creatorsByEditor.keys.contains(global.editorEuroOffice) || creatorsByEditor.keys.contains(global.editorOnlyOffice) { + for editorId in creatorsByEditor.keys.sorted() { + guard NCDirectEditorAdapter.resolve(from: [editorId]) != nil, + editorId != global.editorText else { + continue } - .sorted { $0.1.sortOrder < $1.1.sortOrder } - let editorActions: [UIMenuElement] = sortedCreators.map { creator, info in - UIAction( - title: NSLocalizedString(info.titleKey, comment: ""), - image: utility.loadImage(named: info.icon, colors: [info.iconColor]) - ) { _ in - Task { @MainActor in - let createDocument = NCCreate() - let fileExt: String - let templateIdentifier: String - if creator.templates { - let result = await createDocument.getTemplate(editorId: editorId, templateId: info.templateId, account: session.account) - fileExt = result.ext - templateIdentifier = result.selectedTemplate.identifier - } else { - fileExt = creator.ext - templateIdentifier = "" + let sortedCreators = creatorsByEditor[editorId]! + .compactMap { creator -> (NKEditorDetailsCreator, CreatorMenuInfo)? in + guard let info = NCContextMenuPlus.menuInfo(for: creator.ext) else { return nil } + return (creator, info) + } + .sorted { $0.1.sortOrder < $1.1.sortOrder } + + let editorActions: [UIMenuElement] = sortedCreators.map { creator, info in + UIAction( + title: NSLocalizedString(info.titleKey, comment: ""), + image: utility.loadImage(named: info.icon, colors: [info.iconColor]) + ) { _ in + Task { @MainActor in + let createDocument = NCCreate() + let fileExt: String + let templateIdentifier: String + if creator.templates { + let result = await createDocument.getTemplate(editorId: editorId, templateId: info.templateId, account: session.account) + fileExt = result.ext + templateIdentifier = result.selectedTemplate.identifier + } else { + fileExt = creator.ext + templateIdentifier = "" + } + let fileName = await NCNetworking.shared.createFileName(fileNameBase: NSLocalizedString("_untitled_", comment: "") + "." + fileExt, account: session.account, serverUrl: serverUrl) + + await createDocument.createDocument(controller: controller, + serverUrl: serverUrl, + fileName: fileName, + editorId: editorId, + creatorId: creator.identifier, + templateId: templateIdentifier, + session: session) } - let fileName = await NCNetworking.shared.createFileName(fileNameBase: NSLocalizedString("_untitled_", comment: "") + "." + fileExt, account: session.account, serverUrl: serverUrl) - - await createDocument.createDocument(controller: controller, - serverUrl: serverUrl, - fileName: fileName, - editorId: editorId, - creatorId: creator.identifier, - templateId: templateIdentifier, - session: session) } } - } - menuDirectEditingTextElements.append(contentsOf: editorActions) - } + menuDirectEditingTextElements.append(contentsOf: editorActions) + } - // DIRECT EDITING OTHERS - // - let filteredCreatorsByEditor = creatorsByEditor.filter { - $0.key != "eurooffice" - } - let creators = filteredCreatorsByEditor.values.flatMap { $0 } - let sortedCreators = creators.sorted { - $0.name < $1.name - } + // OTHERS + // + let filteredCreatorsByEditor = creatorsByEditor.filter { + $0.key != global.editorEuroOffice && + $0.key != global.editorText && + $0.key != global.editorOnlyOffice + } + let creators = filteredCreatorsByEditor.values.flatMap { $0 } + let sortedCreators = creators.sorted { + $0.name < $1.name + } - for creator in sortedCreators { - let image: UIImage? - switch creator.ext { + for creator in sortedCreators { + let image: UIImage? + switch creator.ext { case "md": image = UIImage(systemName: "text.document") case "whiteboard": @@ -358,19 +362,46 @@ class NCContextMenuPlus: NSObject { image = UIImage(systemName: "doc") } - let action = UIAction( - title: creator.name, - image: image - ) { _ in + let action = UIAction( + title: creator.name, + image: image + ) { _ in + Task { @MainActor in + let createDocument = NCCreate() + let fileName = await NCNetworking.shared.createFileName( + fileNameBase: NSLocalizedString("_untitled_", comment: "") + "." + creator.ext, + account: session.account, + serverUrl: serverUrl + ) + + await createDocument.createDocument( + controller: controller, + serverUrl: serverUrl, + fileName: fileName, + editorId: creator.editor, + creatorId: creator.identifier, + templateId: "", + session: session) + } + } + + menuDirectEditingOthersElements.append(action) + } + } + + // NEXTCLOUD TEXT + // + if creatorsByEditor.keys.contains(global.editorText), let creator = creatorsByEditor[global.editorText]?.first { + menuActionElements.append(UIAction(title: NSLocalizedString("_create_nextcloudtext_document_", comment: ""), + image: utility.loadImage(named: "text.document", colors: [NCBrandColor.shared.iconImageColor])) { _ in Task { @MainActor in - let createDocument = NCCreate() let fileName = await NCNetworking.shared.createFileName( fileNameBase: NSLocalizedString("_untitled_", comment: "") + "." + creator.ext, account: session.account, serverUrl: serverUrl ) - await createDocument.createDocument( + await NCCreate().createDocument( controller: controller, serverUrl: serverUrl, fileName: fileName, @@ -379,9 +410,7 @@ class NCContextMenuPlus: NSObject { templateId: "", session: session) } - } - - menuDirectEditingOthersElements.append(action) + }) } } diff --git a/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift index bfab71c6b2..d0b9056d35 100644 --- a/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift +++ b/iOSClient/Settings/Advanced/Capabilities/NCCapabilitiesModel.swift @@ -74,9 +74,9 @@ class NCCapabilitiesModel: ObservableObject, ViewOnAppearHandling { for editor in editors { if editor.editor.lowercased() == global.editorText { textEditor = true - } else if editor.editor.lowercased() == "onlyoffice" { + } else if editor.editor.lowercased() == global.editorOnlyOffice { onlyofficeEditor = true - } else if editor.editor.lowercased() == "eurooffice" { + } else if editor.editor.lowercased() == global.editorEuroOffice { euroOfficeEditor = true } } diff --git a/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift index a8c659492b..232128584a 100644 --- a/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift +++ b/iOSClient/Viewer/NCViewerDocument/NCDocumentEditorCoordinator.swift @@ -51,6 +51,8 @@ final class NCDocumentEditorCoordinator: NSObject { return await makeDirectEditingViewController(editor: global.editorEuroOffice) } else if selectedEditor == global.editorCollabora.lowercased() { return await makeCollaboraViewController() + } else if selectedEditor == global.editorOnlyOffice.lowercased() { + return await makeDirectEditingViewController(editor: global.editorOnlyOffice) } return nil @@ -59,19 +61,14 @@ final class NCDocumentEditorCoordinator: NSObject { // MARK: - Text editor private func makeDirectEditingViewController(editor: String) async -> UIViewController? { - guard let editorAdapter = NCDirectEditorAdapter.resolve( - from: [editor] - ) else { + guard let editorAdapter = NCDirectEditorAdapter.resolve(from: [editor]) else { return nil } let account = metadata.account let editorIdentifier = selectedEditor ?? editorAdapter.apiKey let editorViewController = editorAdapter.viewControllerEditor - let options = NKRequestOptions( - customUserAgent: editorAdapter.userAgent(utility) - ) - + let options = NKRequestOptions(customUserAgent: editorAdapter.userAgent(utility)) let link: String if metadata.url.isEmpty { @@ -106,12 +103,8 @@ final class NCDocumentEditorCoordinator: NSObject { NCActivityIndicator.shared.stop() - guard results.error == .success, - let generatedURL = results.url else { - let windowScene = SceneManager.shared.getWindowScene( - controller: delegate?.tabBarController as? NCMainTabBarController - ) - + guard results.error == .success, let generatedURL = results.url else { + let windowScene = SceneManager.shared.getWindowScene(controller: delegate?.tabBarController as? NCMainTabBarController) await showErrorBanner( windowScene: windowScene, text: results.error.errorDescription, @@ -168,10 +161,7 @@ final class NCDocumentEditorCoordinator: NSObject { NCActivityIndicator.shared.stop() guard results.error == .success, let generatedURL = results.url else { - let windowScene = SceneManager.shared.getWindowScene( - controller: delegate?.tabBarController as? NCMainTabBarController - ) - + let windowScene = SceneManager.shared.getWindowScene(controller: delegate?.tabBarController as? NCMainTabBarController) await showErrorBanner( windowScene: windowScene, text: results.error.errorDescription, From 1958102770500c6a9826ca780d2a77f572eeeee5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Aug 2026 11:53:54 +0200 Subject: [PATCH 6/7] chore: bump build number and pin NextcloudKit 7.4.2 Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index dfbffbfd30..99fa37b7e5 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -6323,7 +6323,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = NKUJUXUJ3B; @@ -6391,7 +6391,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = NKUJUXUJ3B; @@ -6660,8 +6660,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/nextcloud/NextcloudKit"; requirement = { - branch = "capabilities-editor"; - kind = branch; + kind = exactVersion; + version = 7.4.2; }; }; F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = { From cddf8dfd3028691f43c0804d98892c8f346fa08c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Aug 2026 12:21:06 +0200 Subject: [PATCH 7/7] chore: bump project build number to 3 Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 99fa37b7e5..41551bde3e 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -6323,7 +6323,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = NKUJUXUJ3B; @@ -6391,7 +6391,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = NKUJUXUJ3B;