Skip to content
Merged
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
8 changes: 6 additions & 2 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@
F769454022E9F077000A798A /* NCSharePaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769453F22E9F077000A798A /* NCSharePaging.swift */; };
F769454622E9F1B0000A798A /* NCShareCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454522E9F1B0000A798A /* NCShareCommon.swift */; };
F769454822E9F20D000A798A /* NCShareNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454722E9F20D000A798A /* NCShareNetworking.swift */; };
F76995F42F9A4AC400291FA7 /* NCCollectionViewCommon+UIEditMenuInteractionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76995F32F9A4AC000291FA7 /* NCCollectionViewCommon+UIEditMenuInteractionDelegate.swift */; };
F769CA192966EA3C00039397 /* ComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769CA182966EA3C00039397 /* ComponentView.swift */; };
F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; };
F76B3CCF1EAE01BD00921AC9 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; };
Expand Down Expand Up @@ -1493,6 +1494,7 @@
F769453F22E9F077000A798A /* NCSharePaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSharePaging.swift; sourceTree = "<group>"; };
F769454522E9F1B0000A798A /* NCShareCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCommon.swift; sourceTree = "<group>"; };
F769454722E9F20D000A798A /* NCShareNetworking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareNetworking.swift; sourceTree = "<group>"; };
F76995F32F9A4AC000291FA7 /* NCCollectionViewCommon+UIEditMenuInteractionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+UIEditMenuInteractionDelegate.swift"; sourceTree = "<group>"; };
F769CA182966EA3C00039397 /* ComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentView.swift; sourceTree = "<group>"; };
F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCBrand.swift; sourceTree = "<group>"; };
F76B649B2ADFFAED00014640 /* NCImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCImageCache.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2525,6 +2527,7 @@
children = (
F75FE06B2BB01D0D00A0EFEF /* Cell */,
F70D7C3525FFBF81002B9E34 /* NCCollectionViewCommon.swift */,
F76995F32F9A4AC000291FA7 /* NCCollectionViewCommon+UIEditMenuInteractionDelegate.swift */,
F7CAFE172F164B9200DB35A5 /* NCCollectionViewCommon+CellDelegate.swift */,
F7743A132C33F13A0034F670 /* NCCollectionViewCommon+CollectionViewDataSource.swift */,
F74D50342C9855A000BBBF4C /* NCCollectionViewCommon+CollectionViewDataSourcePrefetching.swift */,
Expand Down Expand Up @@ -4761,6 +4764,7 @@
F70968A424212C4E00ED60E5 /* NCLivePhoto.swift in Sources */,
F7C30DFA291BCF790017149B /* NCNetworkingE2EECreateFolder.swift in Sources */,
F72CA05C2F5051DB002E2F06 /* AlertActionBannerView.swift in Sources */,
F76995F42F9A4AC400291FA7 /* NCCollectionViewCommon+UIEditMenuInteractionDelegate.swift in Sources */,
F722133B2D40EF9D002F7438 /* NCFilesNavigationController.swift in Sources */,
F7BC288026663F85004D46C5 /* NCViewCertificateDetails.swift in Sources */,
F78B87E92B62550800C65ADC /* NCMediaDownloadThumbnail.swift in Sources */,
Expand Down Expand Up @@ -5822,7 +5826,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = NKUJUXUJ3B;
Expand Down Expand Up @@ -5889,7 +5893,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = NKUJUXUJ3B;
Expand Down
17 changes: 10 additions & 7 deletions Share/NCShareExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ class NCShareExtension: UIViewController {

NCBrandColor.shared.createUserColors()

registerForTraitChanges([UITraitUserInterfaceStyle.self]) { (self: Self, _) in
guard !self.maintenanceMode else {
return
}
self.updateAppearance()
}

NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in
if NCPreferences().presentPasscode {
NCPasscode.shared.presentPasscode(viewController: self, delegate: self) {
Expand Down Expand Up @@ -167,13 +174,9 @@ class NCShareExtension: UIViewController {
}
}

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)

if !maintenanceMode {
collectionView.reloadData()
tableView.reloadData()
}
private func updateAppearance() {
collectionView.visibleCells.forEach { $0.setNeedsLayout() }
tableView.visibleCells.forEach { $0.setNeedsLayout() }
}

// MARK: -
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2026 Marino Faggiana
// SPDX-License-Identifier: GPL-3.0-or-later

extension NCCollectionViewCommon: NCListCellDelegate, NCGridCellDelegate {
func openContextMenu(with metadata: tableMetadata?, button: UIButton, sender: Any) {
Task {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ extension NCCollectionViewCommon: UICollectionViewDropDelegate {
}
} else {
DragDropHover.shared.sourceMetadatas = metadatas
openMenu(collectionView: collectionView, location: coordinator.session.location(in: collectionView))
openDragDropMenuItems(location: coordinator.session.location(in: collectionView))
}
}
}
Expand All @@ -116,41 +116,6 @@ extension NCCollectionViewCommon: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView, dropSessionDidEnd session: UIDropSession) {
DragDropHover.shared.cleanPushDragDropHover()
}

// MARK: -

private func openMenu(collectionView: UICollectionView, location: CGPoint) {
var listMenuItems: [UIMenuItem] = []

listMenuItems.append(UIMenuItem(title: NSLocalizedString("_copy_", comment: ""), action: #selector(copyMenuFile(_:))))
listMenuItems.append(UIMenuItem(title: NSLocalizedString("_move_", comment: ""), action: #selector(moveMenuFile(_:))))
UIMenuController.shared.menuItems = listMenuItems
UIMenuController.shared.showMenu(from: collectionView, rect: CGRect(x: location.x, y: location.y, width: 0, height: 0))
}

@objc func copyMenuFile(_ sender: Any?) {
guard let sourceMetadatas = DragDropHover.shared.sourceMetadatas else { return }
var destination: String = self.serverUrl

if let destinationMetadata = DragDropHover.shared.destinationMetadata, destinationMetadata.directory {
destination = utilityFileSystem.createServerUrl(serverUrl: destinationMetadata.serverUrl, fileName: destinationMetadata.fileName)
}
Task {
await NCDragDrop().copyFile(metadatas: sourceMetadatas, destination: destination, controller: self.controller)
}
}

@objc func moveMenuFile(_ sender: Any?) {
guard let sourceMetadatas = DragDropHover.shared.sourceMetadatas else { return }
var destination: String = self.serverUrl

if let destinationMetadata = DragDropHover.shared.destinationMetadata, destinationMetadata.directory {
destination = utilityFileSystem.createServerUrl(serverUrl: destinationMetadata.serverUrl, fileName: destinationMetadata.fileName)
}
Task {
await NCDragDrop().moveFile(metadatas: sourceMetadatas, destination: destination, controller: self.controller)
}
}
}

// MARK: - Drop Interaction Delegate
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2026 Marino Faggiana
// SPDX-License-Identifier: GPL-3.0-or-later

import UIKit
import NextcloudKit
import RealmSwift
import LucidBanner

extension NCCollectionViewCommon: UIEditMenuInteractionDelegate {
func editMenuInteraction(_ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement]) -> UIMenu? {
var actions: [UIMenuElement] = []

if configuration.identifier as? String == dragDropMenuIdentifier {
let copyAction = UIAction(title: NSLocalizedString("_copy_", comment: "")) { [weak self] _ in
self?.performCopyDragDropMenuAction()
}

let moveAction = UIAction(title: NSLocalizedString("_move_", comment: "")) { [weak self] _ in
self?.performMoveDragDropMenuAction()
}

actions.append(copyAction)
actions.append(moveAction)
return UIMenu(children: actions)
}

if !UIPasteboard.general.items.isEmpty,
!(metadataFolder?.e2eEncrypted ?? false) {
let pasteAction = UIAction(
title: NSLocalizedString("_paste_file_", comment: "")
) { [weak self] _ in
self?.performPasteMenuAction()
}
actions.append(pasteAction)
}

return actions.isEmpty ? nil : UIMenu(children: actions)
}

func editMenuInteraction(_ interaction: UIEditMenuInteraction, targetRectFor configuration: UIEditMenuConfiguration) -> CGRect {
CGRect(x: currentMenuPoint.x, y: currentMenuPoint.y, width: 1, height: 1)
}

// MARK: Paste Menu

func openMenuItems(with objectId: String?, gestureRecognizer: UILongPressGestureRecognizer) {
guard gestureRecognizer.state == .began else { return }
guard !serverUrl.isEmpty else { return }
guard let editMenuInteraction else { return }

let touchPoint = gestureRecognizer.location(in: collectionView)

currentMenuObjectId = objectId
currentMenuPoint = touchPoint

let configuration = UIEditMenuConfiguration(identifier: objectId as NSString?, sourcePoint: touchPoint)
editMenuInteraction.presentEditMenu(with: configuration)
}

private func performPasteMenuAction() {
Task {@MainActor in
guard let tblAccount = await NCManageDatabase.shared.getTableAccountAsync(account: session.account) else {
return
}
let bannerResults = showHudBanner(
windowScene: windowScene,
title: "_upload_in_progress_")

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
bannerResults.banner?.update(
payload: LucidBannerPayload.Update(progress: fractionCompleted),
for: bannerResults.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.transferReloadDataSource(serverUrl: self.serverUrl, requestData: true, status: nil)
}
}
} else {
Task {
await showErrorBanner(windowScene: windowScene,
text: resultsUpload.error.errorDescription,
errorCode: resultsUpload.error.errorCode)
}
}
}
}

if let banner = bannerResults.banner {
banner.dismiss()
}
}
}

// MARK: Drag&Drop Menu

func openDragDropMenuItems(location: CGPoint) {
guard let editMenuInteraction else { return }

currentMenuPoint = location
currentMenuObjectId = nil

let configuration = UIEditMenuConfiguration(
identifier: dragDropMenuIdentifier as NSString,
sourcePoint: location
)

editMenuInteraction.presentEditMenu(with: configuration)
}

private func performCopyDragDropMenuAction() {
guard let sourceMetadatas = DragDropHover.shared.sourceMetadatas else { return }
var destination: String = self.serverUrl

if let destinationMetadata = DragDropHover.shared.destinationMetadata, destinationMetadata.directory {
destination = utilityFileSystem.createServerUrl(
serverUrl: destinationMetadata.serverUrl,
fileName: destinationMetadata.fileName
)
}

Task {
await NCDragDrop().copyFile(
metadatas: sourceMetadatas,
destination: destination,
controller: self.controller
)
}
}

private func performMoveDragDropMenuAction() {
guard let sourceMetadatas = DragDropHover.shared.sourceMetadatas else { return }
var destination: String = self.serverUrl

if let destinationMetadata = DragDropHover.shared.destinationMetadata, destinationMetadata.directory {
destination = utilityFileSystem.createServerUrl(
serverUrl: destinationMetadata.serverUrl,
fileName: destinationMetadata.fileName
)
}

Task {
await NCDragDrop().moveFile(
metadatas: sourceMetadatas,
destination: destination,
controller: self.controller
)
}
}
}
Loading
Loading