NCMenuAction.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. //
  2. // NCMenuAction.swift
  3. // Nextcloud
  4. //
  5. // Created by Henrik Storch on 17.02.22.
  6. // Copyright © 2022 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Henrik Storch <henrik.storch@nextcloud.com>
  9. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  10. //
  11. // This program is free software: you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation, either version 3 of the License, or
  14. // (at your option) any later version.
  15. //
  16. // This program is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. // GNU General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU General Public License
  22. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. //
  24. import Foundation
  25. import UIKit
  26. class NCMenuAction {
  27. let title: String
  28. let details: String?
  29. let icon: UIImage
  30. let selectable: Bool
  31. var onTitle: String?
  32. var onIcon: UIImage?
  33. var selected: Bool = false
  34. var isOn: Bool = false
  35. var action: ((_ menuAction: NCMenuAction) -> Void)?
  36. var rowHeight: CGFloat { self.title == NCMenuAction.seperatorIdentifier ? NCMenuAction.seperatorHeight : self.details != nil ? 80 : 60 }
  37. init(title: String, details: String? = nil, icon: UIImage, action: ((_ menuAction: NCMenuAction) -> Void)?) {
  38. self.title = title
  39. self.details = details
  40. self.icon = icon
  41. self.action = action
  42. self.selectable = false
  43. }
  44. init(title: String, details: String? = nil, icon: UIImage, onTitle: String? = nil, onIcon: UIImage? = nil, selected: Bool, on: Bool, action: ((_ menuAction: NCMenuAction) -> Void)?) {
  45. self.title = title
  46. self.details = details
  47. self.icon = icon
  48. self.onTitle = onTitle ?? title
  49. self.onIcon = onIcon ?? icon
  50. self.action = action
  51. self.selected = selected
  52. self.isOn = on
  53. self.selectable = true
  54. }
  55. }
  56. // MARK: - Actions
  57. extension NCMenuAction {
  58. static let seperatorIdentifier = "NCMenuAction.SEPARATOR"
  59. static let seperatorHeight: CGFloat = 0.5
  60. /// A static seperator, with no actions, text, or icons
  61. static var seperator: NCMenuAction {
  62. return NCMenuAction(title: seperatorIdentifier, icon: UIImage(), action: nil)
  63. }
  64. /// Select all items
  65. static func selectAllAction(action: @escaping () -> Void) -> NCMenuAction {
  66. NCMenuAction(
  67. title: NSLocalizedString("_select_all_", comment: ""),
  68. icon: NCUtility.shared.loadImage(named: "checkmark.circle.fill"),
  69. action: { _ in action() }
  70. )
  71. }
  72. /// Copy files to pasteboard
  73. static func copyAction(selectOcId: [String], hudView: UIView, completion: (() -> Void)? = nil) -> NCMenuAction {
  74. NCMenuAction(
  75. title: NSLocalizedString("_copy_file_", comment: ""),
  76. icon: NCUtility.shared.loadImage(named: "doc.on.doc"),
  77. action: { _ in
  78. NCFunctionCenter.shared.copyPasteboard(pasteboardOcIds: selectOcId, hudView: hudView)
  79. completion?()
  80. }
  81. )
  82. }
  83. /// Delete files either from cache or from Nextcloud
  84. static func deleteAction(selectedMetadatas: [tableMetadata], metadataFolder: tableMetadata? = nil, viewController: UIViewController, completion: (() -> Void)? = nil) -> NCMenuAction {
  85. var titleDelete = NSLocalizedString("_delete_", comment: "")
  86. if selectedMetadatas.count > 1 {
  87. titleDelete = NSLocalizedString("_delete_selected_files_", comment: "")
  88. } else if let metadata = selectedMetadatas.first {
  89. if NCManageDatabase.shared.isMetadataShareOrMounted(metadata: metadata, metadataFolder: metadataFolder) {
  90. titleDelete = NSLocalizedString("_leave_share_", comment: "")
  91. } else if metadata.directory {
  92. titleDelete = NSLocalizedString("_delete_folder_", comment: "")
  93. } else {
  94. titleDelete = NSLocalizedString("_delete_file_", comment: "")
  95. }
  96. if let metadataFolder = metadataFolder {
  97. let isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionShared)
  98. let isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionMounted)
  99. if isShare || isMounted {
  100. titleDelete = NSLocalizedString("_leave_share_", comment: "")
  101. }
  102. }
  103. } // else: no metadata selected
  104. let canDeleteServer = selectedMetadatas.allSatisfy { !$0.lock }
  105. var fileList = ""
  106. for (ix, metadata) in selectedMetadatas.enumerated() {
  107. guard ix < 3 else { fileList += "\n - ..."; break }
  108. fileList += "\n - " + metadata.fileNameView
  109. }
  110. return NCMenuAction(
  111. title: titleDelete,
  112. icon: NCUtility.shared.loadImage(named: "trash"),
  113. action: { _ in
  114. let alertController = UIAlertController(
  115. title: titleDelete,
  116. message: NSLocalizedString("_want_delete_", comment: "") + fileList,
  117. preferredStyle: .alert)
  118. if canDeleteServer {
  119. alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in
  120. selectedMetadatas.forEach({ NCOperationQueue.shared.delete(metadata: $0, onlyLocalCache: false) })
  121. completion?()
  122. })
  123. }
  124. // NCMedia removes image from collection view if removed from cache
  125. if !(viewController is NCMedia) {
  126. alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_local_file_", comment: ""), style: .default) { (_: UIAlertAction) in
  127. selectedMetadatas.forEach({ NCOperationQueue.shared.delete(metadata: $0, onlyLocalCache: true) })
  128. completion?()
  129. })
  130. }
  131. alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in })
  132. viewController.present(alertController, animated: true, completion: nil)
  133. }
  134. )
  135. }
  136. /// Open "share view" (activity VC) to open files in another app
  137. static func openInAction(selectedMetadatas: [tableMetadata], viewController: UIViewController, completion: (() -> Void)? = nil) -> NCMenuAction {
  138. NCMenuAction(
  139. title: NSLocalizedString("_open_in_", comment: ""),
  140. icon: NCUtility.shared.loadImage(named: "square.and.arrow.up"),
  141. action: { _ in
  142. NCFunctionCenter.shared.openActivityViewController(selectedMetadata: selectedMetadatas)
  143. completion?()
  144. }
  145. )
  146. }
  147. /// Save selected files to user's photo library
  148. static func saveMediaAction(selectedMediaMetadatas: [tableMetadata], completion: (() -> Void)? = nil) -> NCMenuAction {
  149. var title: String = NSLocalizedString("_save_selected_files_", comment: "")
  150. var icon = NCUtility.shared.loadImage(named: "square.and.arrow.down")
  151. if selectedMediaMetadatas.allSatisfy({ NCManageDatabase.shared.getMetadataLivePhoto(metadata: $0) != nil }) {
  152. title = NSLocalizedString("_livephoto_save_", comment: "")
  153. icon = NCUtility.shared.loadImage(named: "livephoto")
  154. }
  155. return NCMenuAction(
  156. title: title,
  157. icon: icon,
  158. action: { _ in
  159. for metadata in selectedMediaMetadatas {
  160. if let metadataMOV = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) {
  161. NCFunctionCenter.shared.saveLivePhoto(metadata: metadata, metadataMOV: metadataMOV)
  162. } else {
  163. if CCUtility.fileProviderStorageExists(metadata) {
  164. NCFunctionCenter.shared.saveAlbum(metadata: metadata)
  165. } else {
  166. NCOperationQueue.shared.download(metadata: metadata, selector: NCGlobal.shared.selectorSaveAlbum)
  167. }
  168. }
  169. }
  170. completion?()
  171. }
  172. )
  173. }
  174. /// Set (or remove) a file as *available offline*. Downloads the file if not downloaded already
  175. static func setAvailableOfflineAction(selectedMetadatas: [tableMetadata], isAnyOffline: Bool, viewController: UIViewController, completion: (() -> Void)? = nil) -> NCMenuAction {
  176. NCMenuAction(
  177. title: isAnyOffline ? NSLocalizedString("_remove_available_offline_", comment: "") : NSLocalizedString("_set_available_offline_", comment: ""),
  178. icon: NCUtility.shared.loadImage(named: "tray.and.arrow.down"),
  179. action: { _ in
  180. if !isAnyOffline, selectedMetadatas.count > 3 {
  181. let alert = UIAlertController(
  182. title: NSLocalizedString("_set_available_offline_", comment: ""),
  183. message: NSLocalizedString("_select_offline_warning_", comment: ""),
  184. preferredStyle: .alert)
  185. alert.addAction(UIAlertAction(title: NSLocalizedString("_continue_", comment: ""), style: .default, handler: { _ in
  186. selectedMetadatas.forEach { NCFunctionCenter.shared.setMetadataAvalableOffline($0, isOffline: isAnyOffline) }
  187. completion?()
  188. }))
  189. alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel))
  190. viewController.present(alert, animated: true)
  191. } else {
  192. selectedMetadatas.forEach { NCFunctionCenter.shared.setMetadataAvalableOffline($0, isOffline: isAnyOffline) }
  193. completion?()
  194. }
  195. }
  196. )
  197. }
  198. /// Open view that lets the user move or copy the files within Nextcloud
  199. static func moveOrCopyAction(selectedMetadatas: [tableMetadata], completion: (() -> Void)? = nil) -> NCMenuAction {
  200. NCMenuAction(
  201. title: NSLocalizedString("_move_or_copy_selected_files_", comment: ""),
  202. icon: NCUtility.shared.loadImage(named: "arrow.up.right.square"),
  203. action: { _ in
  204. NCFunctionCenter.shared.openSelectView(items: selectedMetadatas)
  205. completion?()
  206. }
  207. )
  208. }
  209. /// Open AirPrint view to print a single file
  210. static func printAction(metadata: tableMetadata) -> NCMenuAction {
  211. NCMenuAction(
  212. title: NSLocalizedString("_print_", comment: ""),
  213. icon: NCUtility.shared.loadImage(named: "printer"),
  214. action: { _ in
  215. NCFunctionCenter.shared.openDownload(metadata: metadata, selector: NCGlobal.shared.selectorPrint)
  216. }
  217. )
  218. }
  219. /// Lock or unlock a file using *files_lock*
  220. static func lockUnlockFiles(shouldLock: Bool, metadatas: [tableMetadata], completion: (() -> Void)? = nil) -> NCMenuAction {
  221. let titleKey: String
  222. if metadatas.count == 1 {
  223. titleKey = shouldLock ? "_lock_file_" : "_unlock_file_"
  224. } else {
  225. titleKey = shouldLock ? "_lock_selected_files_" : "_unlock_selected_files_"
  226. }
  227. let imageName = !shouldLock ? "lock_open" : "lock"
  228. return NCMenuAction(
  229. title: NSLocalizedString(titleKey, comment: ""),
  230. icon: NCUtility.shared.loadImage(named: imageName),
  231. action: { _ in
  232. for metadata in metadatas where metadata.lock != shouldLock {
  233. NCNetworking.shared.lockUnlockFile(metadata, shoulLock: shouldLock)
  234. }
  235. completion?()
  236. }
  237. )
  238. }
  239. }