NCShareExtension+Files.swift 8.4 KB

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