NCShareExtension+Files.swift 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. //
  2. // NCShareExtension+Files.swift
  3. // Share
  4. //
  5. // Created by Henrik Storch on 29.12.21.
  6. // Copyright © 2021 Henrik Storch. All rights reserved.
  7. //
  8. // Author Henrik Storch <henrik.storch@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 UniformTypeIdentifiers
  25. extension NCShareExtension {
  26. @objc func reloadDatasource(withLoadFolder: Bool) {
  27. var groupByField = "name"
  28. layoutForView = NCManageDatabase.shared.setLayoutForView(account: activeAccount.account, key: keyLayout, serverUrl: serverUrl)
  29. // set GroupField for Grid
  30. if layoutForView?.layout == NCGlobal.shared.layoutGrid {
  31. groupByField = "classFile"
  32. }
  33. let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND directory == true", activeAccount.account, serverUrl))
  34. self.dataSource = NCDataSource(
  35. metadatas: metadatas,
  36. account: activeAccount.account,
  37. sort: layoutForView?.sort,
  38. ascending: layoutForView?.ascending,
  39. directoryOnTop: layoutForView?.directoryOnTop,
  40. favoriteOnTop: true,
  41. filterLivePhoto: true,
  42. groupByField: groupByField)
  43. if withLoadFolder {
  44. loadFolder()
  45. } else {
  46. self.refreshControl.endRefreshing()
  47. }
  48. collectionView.reloadData()
  49. }
  50. @objc func didCreateFolder(_ notification: NSNotification) {
  51. guard let userInfo = notification.userInfo as NSDictionary?,
  52. let ocId = userInfo["ocId"] as? String,
  53. let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId)
  54. else { return }
  55. self.serverUrl += "/" + metadata.fileName
  56. self.reloadDatasource(withLoadFolder: true)
  57. self.setNavigationBar(navigationTitle: metadata.fileName)
  58. }
  59. func loadFolder() {
  60. networkInProgress = true
  61. collectionView.reloadData()
  62. NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { _, metadataFolder, _, _, _, _, error in
  63. DispatchQueue.main.async {
  64. if error != .success {
  65. self.showAlert(description: error.errorDescription)
  66. }
  67. self.networkInProgress = false
  68. self.metadataFolder = metadataFolder
  69. self.reloadDatasource(withLoadFolder: false)
  70. }
  71. }
  72. }
  73. }
  74. class NCFilesExtensionHandler {
  75. var itemsProvider: [NSItemProvider] = []
  76. lazy var fileNames: [String] = []
  77. let dateFormatter: DateFormatter = {
  78. let formatter = DateFormatter()
  79. formatter.dateFormat = "yyyy-MM-dd HH-mm-ss-"
  80. return formatter
  81. }()
  82. @discardableResult
  83. init(items: [NSExtensionItem], completion: @escaping ([String]) -> Void) {
  84. CCUtility.emptyTemporaryDirectory()
  85. var counter = 0
  86. self.itemsProvider = items.compactMap({ $0.attachments }).flatMap { $0.filter({
  87. $0.hasItemConformingToTypeIdentifier(UTType.item.identifier as String) || $0.hasItemConformingToTypeIdentifier("public.url")
  88. }) }
  89. for (ix, provider) in itemsProvider.enumerated() {
  90. provider.loadItem(forTypeIdentifier: provider.typeIdentifier) { [self] item, error in
  91. defer {
  92. counter += 1
  93. if counter == itemsProvider.count { completion(self.fileNames) }
  94. }
  95. guard error == nil else { return }
  96. var originalName = (dateFormatter.string(from: Date())) + String(ix)
  97. if let url = item as? URL, url.isFileURL, !url.lastPathComponent.isEmpty {
  98. originalName = url.lastPathComponent
  99. if fileNames.contains(originalName), let incrementalNumber = CCUtility.getIncrementalNumber() {
  100. originalName = "\(url.deletingPathExtension().lastPathComponent) \(incrementalNumber).\(url.pathExtension)"
  101. }
  102. }
  103. var fileName: String?
  104. switch item {
  105. case let image as UIImage:
  106. fileName = getItem(image: image, fileName: originalName)
  107. case let url as URL:
  108. fileName = getItem(url: url, fileName: originalName)
  109. case let data as Data:
  110. fileName = getItem(data: data, fileName: originalName, provider: provider)
  111. case let text as String:
  112. fileName = getItem(string: text, fileName: originalName)
  113. default: return
  114. }
  115. if let fileName, !fileNames.contains(fileName) {
  116. fileNames.append(fileName)
  117. }
  118. }
  119. }
  120. }
  121. // Image
  122. func getItem(image: UIImage, fileName: String) -> String? {
  123. var fileUrl = URL(fileURLWithPath: NSTemporaryDirectory() + fileName)
  124. if fileUrl.pathExtension.isEmpty { fileUrl.appendPathExtension("png") }
  125. guard let pngImageData = image.pngData(), (try? pngImageData.write(to: fileUrl, options: [.atomic])) != nil
  126. else { return nil }
  127. return fileUrl.lastPathComponent
  128. }
  129. // URL
  130. // Does not work for directories
  131. func getItem(url: URL, fileName: String) -> String? {
  132. var fileName = fileName
  133. guard url.isFileURL else {
  134. guard !fileNames.contains(url.lastPathComponent) else { return nil }
  135. if !url.deletingPathExtension().lastPathComponent.isEmpty { fileName = url.deletingPathExtension().lastPathComponent }
  136. fileName += "." + (url.pathExtension.isEmpty ? "html" : url.pathExtension)
  137. let filenamePath = NSTemporaryDirectory() + fileName
  138. do {
  139. let downloadedContent = try Data(contentsOf: url)
  140. guard !FileManager.default.fileExists(atPath: filenamePath) else { return nil }
  141. try downloadedContent.write(to: URL(fileURLWithPath: filenamePath))
  142. } catch { print(error); return nil }
  143. return fileName
  144. }
  145. let filenamePath = NSTemporaryDirectory() + fileName
  146. try? FileManager.default.removeItem(atPath: filenamePath)
  147. do {
  148. try FileManager.default.copyItem(atPath: url.path, toPath: filenamePath)
  149. let attr = try FileManager.default.attributesOfItem(atPath: filenamePath)
  150. guard !attr.isEmpty else { return nil }
  151. return fileName
  152. } catch { return nil }
  153. }
  154. // Data
  155. func getItem(data: Data, fileName: String, provider: NSItemProvider) -> String? {
  156. guard !data.isEmpty else { return nil }
  157. var fileName = fileName
  158. if let url = URL(string: fileName), !url.pathExtension.isEmpty {
  159. fileName = url.lastPathComponent
  160. } else if let name = provider.suggestedName {
  161. fileName = name
  162. } else if let ext = provider.registeredTypeIdentifiers.last?.split(separator: ".").last {
  163. fileName += "." + ext
  164. } // else: no file information, use default name without ext
  165. // when sharing images in safari only data is retuned.
  166. // also, when sharing option "Automatic" is slected extension will return both raw data and a url, which will be downloaded, causing the image to appear twice with different names
  167. if let image = UIImage(data: data) {
  168. return getItem(image: image, fileName: fileName)
  169. }
  170. let filenamePath = NSTemporaryDirectory() + fileName
  171. FileManager.default.createFile(atPath: filenamePath, contents: data, attributes: nil)
  172. return fileName
  173. }
  174. // String
  175. func getItem(string: String, fileName: String) -> String? {
  176. guard !string.isEmpty else { return nil }
  177. let filenamePath = NSTemporaryDirectory() + fileName + ".txt"
  178. FileManager.default.createFile(atPath: filenamePath, contents: string.data(using: String.Encoding.utf8), attributes: nil)
  179. return fileName
  180. }
  181. }
  182. extension NSItemProvider {
  183. var typeIdentifier: String {
  184. if hasItemConformingToTypeIdentifier("public.url") { return "public.url" } else
  185. if hasItemConformingToTypeIdentifier(kUTTypeItem as String) { return kUTTypeItem as String } else { return "" }
  186. }
  187. }