NCCollectionViewCommon+DragDrop.swift 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //
  2. // NCCollectionViewCommon+DragDrop.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 19/04/24.
  6. // Copyright © 2024 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. import Foundation
  24. import UIKit
  25. import NextcloudKit
  26. // MARK: - Drag
  27. extension NCCollectionViewCommon: UICollectionViewDragDelegate {
  28. func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
  29. if isEditMode {
  30. return NCDragDrop().performDrag(fileSelect: fileSelect)
  31. } else if let metadata = self.dataSource.getMetadata(indexPath: indexPath) {
  32. return NCDragDrop().performDrag(metadata: metadata)
  33. }
  34. return []
  35. }
  36. func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters? {
  37. let previewParameters = UIDragPreviewParameters()
  38. if isLayoutList,
  39. let cell = collectionView.cellForItem(at: indexPath) as? NCListCell {
  40. let width = (collectionView.frame.width / 3) * 2
  41. previewParameters.visiblePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: width, height: cell.frame.height), cornerRadius: 10)
  42. return previewParameters
  43. } else if let cell = collectionView.cellForItem(at: indexPath) as? NCGridCell {
  44. previewParameters.visiblePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height - 40), cornerRadius: 10)
  45. return previewParameters
  46. } else if let cell = collectionView.cellForItem(at: indexPath) as? NCPhotoCell {
  47. previewParameters.visiblePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height), cornerRadius: 10)
  48. return previewParameters
  49. }
  50. return nil
  51. }
  52. }
  53. // MARK: - Drop
  54. extension NCCollectionViewCommon: UICollectionViewDropDelegate {
  55. func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool {
  56. return true
  57. }
  58. func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
  59. var destinationMetadata: tableMetadata?
  60. if let destinationIndexPath, let metadata = self.dataSource.getMetadata(indexPath: destinationIndexPath) {
  61. destinationMetadata = metadata
  62. }
  63. DragDropHover.shared.destinationMetadata = destinationMetadata
  64. if let destinationMetadata {
  65. if destinationMetadata.e2eEncrypted || destinationMetadata.isDirectoryE2EE {
  66. DragDropHover.shared.cleanPushDragDropHover()
  67. return UICollectionViewDropProposal(operation: .forbidden)
  68. }
  69. if !destinationMetadata.directory && serverUrl.isEmpty {
  70. DragDropHover.shared.cleanPushDragDropHover()
  71. return UICollectionViewDropProposal(operation: .forbidden)
  72. }
  73. } else {
  74. if serverUrl.isEmpty || NCUtilityFileSystem().isDirectoryE2EE(serverUrl: serverUrl, account: self.session.account) {
  75. DragDropHover.shared.cleanPushDragDropHover()
  76. return UICollectionViewDropProposal(operation: .forbidden)
  77. }
  78. }
  79. // DIRECTORY - Push Metadata
  80. if DragDropHover.shared.pushIndexPath != destinationIndexPath || DragDropHover.shared.pushCollectionView != collectionView {
  81. DragDropHover.shared.pushIndexPath = destinationIndexPath
  82. DragDropHover.shared.pushCollectionView = collectionView
  83. DragDropHover.shared.pushTimerIndexPath?.invalidate()
  84. DragDropHover.shared.pushTimerIndexPath = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { [weak self] _ in
  85. guard let self else { return }
  86. if let destinationIndexPath,
  87. DragDropHover.shared.pushIndexPath == destinationIndexPath,
  88. DragDropHover.shared.pushCollectionView == collectionView,
  89. let metadata = self.dataSource.getMetadata(indexPath: destinationIndexPath),
  90. metadata.directory {
  91. DragDropHover.shared.cleanPushDragDropHover()
  92. self.pushMetadata(metadata)
  93. }
  94. }
  95. }
  96. return UICollectionViewDropProposal(operation: .copy)
  97. }
  98. func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
  99. DragDropHover.shared.cleanPushDragDropHover()
  100. DragDropHover.shared.sourceMetadatas = nil
  101. if let metadatas = NCDragDrop().performDrop(collectionView, performDropWith: coordinator, serverUrl: self.serverUrl, isImageVideo: false, controller: self.controller) {
  102. // TODO: NOT POSSIBLE DRAG DROP DIFFERENT ACCOUNT
  103. if let metadata = metadatas.first,
  104. metadata.account != self.session.account {
  105. return
  106. }
  107. DragDropHover.shared.sourceMetadatas = metadatas
  108. openMenu(collectionView: collectionView, location: coordinator.session.location(in: collectionView))
  109. }
  110. }
  111. func collectionView(_ collectionView: UICollectionView, dropSessionDidExit session: UIDropSession) {
  112. DragDropHover.shared.cleanPushDragDropHover()
  113. }
  114. func collectionView(_ collectionView: UICollectionView, dropSessionDidEnd session: UIDropSession) {
  115. DragDropHover.shared.cleanPushDragDropHover()
  116. }
  117. // MARK: -
  118. private func openMenu(collectionView: UICollectionView, location: CGPoint) {
  119. var listMenuItems: [UIMenuItem] = []
  120. listMenuItems.append(UIMenuItem(title: NSLocalizedString("_copy_", comment: ""), action: #selector(copyMenuFile)))
  121. listMenuItems.append(UIMenuItem(title: NSLocalizedString("_move_", comment: ""), action: #selector(moveMenuFile)))
  122. UIMenuController.shared.menuItems = listMenuItems
  123. UIMenuController.shared.showMenu(from: collectionView, rect: CGRect(x: location.x, y: location.y, width: 0, height: 0))
  124. }
  125. @objc func copyMenuFile() {
  126. guard let sourceMetadatas = DragDropHover.shared.sourceMetadatas else { return }
  127. var serverUrl: String = self.serverUrl
  128. if let destinationMetadata = DragDropHover.shared.destinationMetadata, destinationMetadata.directory {
  129. serverUrl = destinationMetadata.serverUrl + "/" + destinationMetadata.fileName
  130. }
  131. NCDragDrop().copyFile(metadatas: sourceMetadatas, serverUrl: serverUrl)
  132. }
  133. @objc func moveMenuFile() {
  134. guard let sourceMetadatas = DragDropHover.shared.sourceMetadatas else { return }
  135. var serverUrl: String = self.serverUrl
  136. if let destinationMetadata = DragDropHover.shared.destinationMetadata, destinationMetadata.directory {
  137. serverUrl = destinationMetadata.serverUrl + "/" + destinationMetadata.fileName
  138. }
  139. NCDragDrop().moveFile(metadatas: sourceMetadatas, serverUrl: serverUrl)
  140. }
  141. }
  142. // MARK: - Drop Interaction Delegate
  143. extension NCCollectionViewCommon: UIDropInteractionDelegate { }