NCShareExtension+Files.swift 8.2 KB

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