Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; };
F310B1EF2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */; };
F314F1142A30E2DE00BC7FAB /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E8A390295DC5E0006CB2D0 /* View+Extension.swift */; };
F317C82E2E844C5300761AEA /* DeclarativeUIViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F317C82D2E844C5300761AEA /* DeclarativeUIViewer.swift */; };
F321DA8A2B71205A00DDA0E6 /* NCTrashSelectTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321DA892B71205A00DDA0E6 /* NCTrashSelectTabBar.swift */; };
F32FADA92D1176E3007035E2 /* UIButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F32FADA82D1176DE007035E2 /* UIButton+Extension.swift */; };
F3374A812D64AB9F002A38F9 /* StatusInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3374A802D64AB9E002A38F9 /* StatusInfo.swift */; };
Expand Down Expand Up @@ -1369,6 +1370,8 @@
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 = "<group>"; };
F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCViewerMedia+VisionKit.swift"; sourceTree = "<group>"; };
F317C82B2E82E5C200761AEA /* NextcloudKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = NextcloudKit; path = ../NextcloudKit; sourceTree = SOURCE_ROOT; };
F317C82D2E844C5300761AEA /* DeclarativeUIViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclarativeUIViewer.swift; sourceTree = "<group>"; };
F321DA892B71205A00DDA0E6 /* NCTrashSelectTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTrashSelectTabBar.swift; sourceTree = "<group>"; };
F32FADA82D1176DE007035E2 /* UIButton+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Extension.swift"; sourceTree = "<group>"; };
F3374A802D64AB9E002A38F9 /* StatusInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusInfo.swift; sourceTree = "<group>"; };
Expand All @@ -1382,6 +1385,7 @@
F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = "<group>"; };
F351D1A52D0AF24A00930F94 /* PHAssetCollection+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAssetCollection+Extension.swift"; sourceTree = "<group>"; };
F359D8662A7D03420023F405 /* NCUtility+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCUtility+Exif.swift"; sourceTree = "<group>"; };
F35FAC252E7C5FD70077994E /* NextcloudKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = NextcloudKit; path = ../NextcloudKit; sourceTree = SOURCE_ROOT; };
F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+SelectTabBarDelegate.swift"; sourceTree = "<group>"; };
F37208742BAB4AB0006B5430 /* TestConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestConstants.swift; sourceTree = "<group>"; };
F3754A7C2CF87D600009312E /* SetupPasscodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPasscodeView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2240,6 +2244,14 @@
path = Tests;
sourceTree = "<group>";
};
F317C82C2E844C3C00761AEA /* DeclarativeUI */ = {
isa = PBXGroup;
children = (
F317C82D2E844C5300761AEA /* DeclarativeUIViewer.swift */,
);
path = DeclarativeUI;
sourceTree = "<group>";
};
F3374A7F2D64AB40002A38F9 /* Components */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3343,6 +3355,8 @@
C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */,
C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */,
F7F1FBA62E27D13700C79E20 /* Frameworks */,
F35FAC252E7C5FD70077994E /* NextcloudKit */,
F317C82B2E82E5C200761AEA /* NextcloudKit */,
);
sourceTree = "<group>";
};
Expand All @@ -3361,6 +3375,7 @@
F70F96AF2874394B006C8379 /* Nextcloud-Bridging-Header.h */,
F7F67BB81A24D27800EE80DA /* Images.xcassets */,
F769CA1B2966EF4F00039397 /* GUI */,
F317C82C2E844C3C00761AEA /* DeclarativeUI */,
F70211F31BAC56E9003FC03E /* Main */,
F7FDFF5A2E437E55000D7688 /* Account */,
F7A321621E9E37960069AD1B /* Activity */,
Expand Down Expand Up @@ -4752,6 +4767,7 @@
F76882362C0DD1E7001CF441 /* NCAcknowledgementsView.swift in Sources */,
F785EE9D246196DF00B3F945 /* NCNetworkingE2EE.swift in Sources */,
F724377B2C10B83E00C7C68D /* NCSharePermissions.swift in Sources */,
F317C82E2E844C5300761AEA /* DeclarativeUIViewer.swift in Sources */,
F794E13D2BBBFF2E003693D7 /* NCMainTabBarController.swift in Sources */,
F753DBDF2E5D99C300A1AF91 /* NCFiles+SyncMetadata.swift in Sources */,
F7CBC1252BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.swift in Sources */,
Expand Down
83 changes: 83 additions & 0 deletions iOSClient/DeclarativeUI/DeclarativeUIViewer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2025 Milen Pivchev
// SPDX-License-Identifier: GPL-3.0-or-later

import SwiftUI

struct DeclarativeUIViewer: View {
@Environment(\.openURL) private var openURL

struct Row: Identifiable {
let id = UUID()
let element: String
let title: String?
let urlString: String
}

// Configurable inputs
let rows: [Row]
let baseURL: String

var body: some View {
ScrollView {
LazyVStack(alignment: .leading, spacing: 12) {
ForEach(rows) { row in
VStack(alignment: .leading, spacing: 8) {
HStack {
Text(row.element)
.font(.subheadline)
.fontWeight(.semibold)
.foregroundStyle(.secondary)
Spacer()
}

if let title = row.title {
Text(title).font(.headline)
}

let finalUrl = baseURL + row.urlString

Text(finalUrl)
.font(.footnote)
.foregroundStyle(.secondary)
.textSelection(.enabled)

HStack(spacing: 12) {
Button {
openURL(URL(string: finalUrl)!)
} label: {
Label("Open", systemImage: "safari")
}

Button {
UIPasteboard.general.string = row.urlString
} label: {
Label("Copy", systemImage: "doc.on.doc")
}
}
.buttonStyle(.borderedProminent)
}
.padding()
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 12))
}
}
.padding()
}
}

// private func resolvedURL(for row: Row) -> URL? {
// // If the string is already an absolute URL with a scheme, use it.
// if let absolute = URL(string: row.urlString), absolute.scheme != nil {
// return absolute
// }
// // Otherwise, resolve relative to the provided base URL if available.
// if let baseURL {
// return URL(string: row.urlString, relativeTo: baseURL)?.absoluteURL
// }
// return nil
// }
}

#Preview {
DeclarativeUIViewer(rows: [.init(element: "URL", title: "Test", urlString: "/test")], baseURL: "test.com")
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegate {
}

return UIContextMenuConfiguration(identifier: identifier, previewProvider: {
return NCViewerProviderContextMenu(metadata: metadata, image: image, sceneIdentifier: self.sceneIdentifier)
return nil
}, actionProvider: { _ in
let contextMenu = NCContextMenu(metadata: metadata.detachedCopy(), viewController: self, sceneIdentifier: self.sceneIdentifier, image: image)
return contextMenu.viewMenu()
Expand Down
50 changes: 50 additions & 0 deletions iOSClient/Menu/NCCollectionViewCommon+Menu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import UIKit
import FloatingPanel
import NextcloudKit
import Queuer
import SVGKit

extension NCCollectionViewCommon {
func toggleMenu(metadata: tableMetadata, image: UIImage?, sender: Any?) {
Expand Down Expand Up @@ -407,6 +408,54 @@ extension NCCollectionViewCommon {
actions.append(.deleteOrUnshareAction(selectedMetadatas: [metadata], metadataFolder: metadataFolder, controller: self.controller, order: 170, sender: sender))
}

if let apps = capabilities.declarativeUI?.apps {
for (appName, context) in apps {
for item in context.contextMenu {
if item.mimetypeFilters == nil || (item.mimetypeFilters?.contains(metadata.contentType) == true) {
let iconImage: UIImage
if let iconUrl = item.icon, let source = SVGKSourceURL.source(from: URL(string: metadata.urlBase + iconUrl)) {
iconImage = SVGKImage(source: source)?.uiImage ?? UIImage()
} else {
iconImage = utility.loadImage(named: "testtube.2", colors: [NCBrandColor.shared.presentationIconColor])
}

actions.append(
NCMenuAction(
title: item.name,
icon: iconImage,
order: Int.max,
sender: sender,
action: { _ in
Task {
await NextcloudKit.shared.sendRequestAsync(account: metadata.account,
fileId: metadata.fileId,
filePath: metadata.path,
url: item.url,
method: item.method,
params: item.params)
}
}
)
)
}
}
}
}

// capabilities.declarativeUI?.contextMenu.forEach { item in
// actions.append(
// NCMenuAction(
// title: item.title,
// icon: utility.loadImage(named: "testtube.2", colors: [NCBrandColor.shared.presentationIconColor]),
// order: Int.max,
// sender: sender,
// action: { _ in
//
// }
// )
// )
// }

applicationHandle.addCollectionViewCommonMenu(metadata: metadata, image: image, actions: &actions)

presentMenu(with: actions, controller: controller, sender: sender)
Expand All @@ -422,3 +471,4 @@ extension TimeInterval {
return formatter.string(from: self)
}
}

Loading