NCUploadAssetsModel.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. //
  2. // NCUploadAssetsModel.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 04/01/23.
  6. // Copyright © 2023 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 SwiftUI
  24. import NextcloudKit
  25. import TLPhotoPicker
  26. import Mantis
  27. import Photos
  28. import QuickLook
  29. // MARK: - Class
  30. struct PreviewStore {
  31. var id: String
  32. var asset: TLPHAsset
  33. var assetType: TLPHAsset.AssetType
  34. var data: Data?
  35. var fileName: String
  36. var image: UIImage
  37. }
  38. class NCUploadAssetsModel: NSObject, ObservableObject, NCCreateFormUploadConflictDelegate {
  39. @Published var serverUrl: String
  40. @Published var assets: [TLPHAsset]
  41. @Published var userBaseUrl: NCUserBaseUrl
  42. @Published var previewStore: [PreviewStore] = []
  43. @Published var dismissView = false
  44. @Published var hiddenSave = true
  45. @Published var useAutoUploadFolder = false
  46. @Published var useAutoUploadSubFolder = false
  47. @Published var showHUD = false
  48. @Published var uploadInProgress = false
  49. /// Root View Controller
  50. @Published var controller: NCMainTabBarController?
  51. var metadatasNOConflict: [tableMetadata] = []
  52. var metadatasUploadInConflict: [tableMetadata] = []
  53. var timer: Timer?
  54. init(assets: [TLPHAsset], serverUrl: String, userBaseUrl: NCUserBaseUrl, controller: NCMainTabBarController?) {
  55. self.assets = assets
  56. self.serverUrl = serverUrl
  57. self.userBaseUrl = userBaseUrl
  58. self.controller = controller
  59. self.showHUD = true
  60. super.init()
  61. DispatchQueue.global(qos: .userInteractive).async {
  62. for asset in self.assets {
  63. guard let image = asset.fullResolutionImage?.resizeImage(size: CGSize(width: 300, height: 300), isAspectRation: true),
  64. let localIdentifier = asset.phAsset?.localIdentifier else { continue }
  65. self.previewStore.append(PreviewStore(id: localIdentifier, asset: asset, assetType: asset.type, fileName: "", image: image))
  66. }
  67. DispatchQueue.main.async {
  68. self.showHUD = false
  69. self.hiddenSave = false
  70. }
  71. }
  72. }
  73. func getTextServerUrl() -> String {
  74. if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", userBaseUrl.account, serverUrl)), let metadata = NCManageDatabase.shared.getMetadataFromOcId(directory.ocId) {
  75. return (metadata.fileNameView)
  76. } else {
  77. return (serverUrl as NSString).lastPathComponent
  78. }
  79. }
  80. func getOriginalFilenameForPreview() -> NSString {
  81. if let asset = assets.first?.phAsset {
  82. return asset.originalFilename
  83. } else {
  84. return ""
  85. }
  86. }
  87. func deleteAsset(index: Int) {
  88. assets.remove(at: index)
  89. previewStore.remove(at: index)
  90. if previewStore.isEmpty {
  91. dismissView = true
  92. }
  93. }
  94. func presentedQuickLook(index: Int, fileNamePath: String) -> Bool {
  95. var image: UIImage?
  96. if let imageData = previewStore[index].data {
  97. image = UIImage(data: imageData)
  98. } else if let imageFullResolution = previewStore[index].asset.fullResolutionImage?.fixedOrientation() {
  99. image = imageFullResolution
  100. }
  101. if let image = image {
  102. if let data = image.jpegData(compressionQuality: 1) {
  103. do {
  104. try data.write(to: URL(fileURLWithPath: fileNamePath))
  105. return true
  106. } catch {
  107. }
  108. }
  109. }
  110. return false
  111. }
  112. func startTimer(navigationItem: UINavigationItem) {
  113. self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in
  114. guard let buttonDone = navigationItem.leftBarButtonItems?.first, let buttonCrop = navigationItem.leftBarButtonItems?.last else { return }
  115. buttonCrop.isEnabled = true
  116. buttonDone.isEnabled = true
  117. if let markup = navigationItem.rightBarButtonItems?.first(where: { $0.accessibilityIdentifier == "QLOverlayMarkupButtonAccessibilityIdentifier" }) {
  118. if let originalButton = markup.value(forKey: "originalButton") as AnyObject? {
  119. if let symbolImageName = originalButton.value(forKey: "symbolImageName") as? String {
  120. if symbolImageName == "pencil.tip.crop.circle.on" {
  121. buttonCrop.isEnabled = false
  122. buttonDone.isEnabled = false
  123. }
  124. }
  125. }
  126. }
  127. })
  128. }
  129. func stopTimer() {
  130. self.timer?.invalidate()
  131. }
  132. func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) {
  133. guard let metadatas = metadatas else {
  134. self.showHUD = false
  135. self.uploadInProgress.toggle()
  136. return
  137. }
  138. func createProcessUploads() {
  139. if !self.dismissView {
  140. NCNetworkingProcess.shared.createProcessUploads(metadatas: metadatas, completion: { _ in
  141. self.dismissView = true
  142. })
  143. }
  144. }
  145. if useAutoUploadFolder {
  146. DispatchQueue.global().async {
  147. let assets = self.assets.compactMap { $0.phAsset }
  148. let result = NCNetworking.shared.createFolder(assets: assets, useSubFolder: self.useAutoUploadSubFolder, account: self.userBaseUrl.account, urlBase: self.userBaseUrl.urlBase, userId: self.userBaseUrl.userId, withPush: false)
  149. DispatchQueue.main.async {
  150. self.showHUD = false
  151. self.uploadInProgress.toggle()
  152. if result {
  153. createProcessUploads()
  154. } else {
  155. let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_error_createsubfolders_upload_")
  156. NCContentPresenter().showError(error: error)
  157. }
  158. }
  159. }
  160. } else {
  161. createProcessUploads()
  162. }
  163. }
  164. func save(completion: @escaping (_ metadatasNOConflict: [tableMetadata], _ metadatasUploadInConflict: [tableMetadata]) -> Void) {
  165. let utilityFileSystem = NCUtilityFileSystem()
  166. var metadatasNOConflict: [tableMetadata] = []
  167. var metadatasUploadInConflict: [tableMetadata] = []
  168. let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: userBaseUrl.urlBase, userId: userBaseUrl.userId, account: userBaseUrl.account)
  169. var serverUrl = useAutoUploadFolder ? autoUploadPath : serverUrl
  170. for tlAsset in assets {
  171. guard let asset = tlAsset.phAsset, let previewStore = previewStore.first(where: { $0.id == asset.localIdentifier }) else { continue }
  172. let assetFileName = asset.originalFilename
  173. var livePhoto: Bool = false
  174. let creationDate = asset.creationDate ?? Date()
  175. let ext = assetFileName.pathExtension.lowercased()
  176. let fileName = previewStore.fileName.isEmpty ? utilityFileSystem.createFileName(assetFileName as String, fileDate: creationDate, fileType: asset.mediaType)
  177. : (previewStore.fileName + "." + ext)
  178. if previewStore.assetType == .livePhoto && NCKeychain().livePhoto && previewStore.data == nil {
  179. livePhoto = true
  180. }
  181. // Auto upload with subfolder
  182. if useAutoUploadSubFolder {
  183. serverUrl = utilityFileSystem.createGranularityPath(serverUrl: serverUrl)
  184. }
  185. // Check if is in upload
  186. if let results = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@ AND session != ''", userBaseUrl.account, serverUrl, fileName), sorted: "fileName", ascending: false), !results.isEmpty {
  187. continue
  188. }
  189. let metadata = NCManageDatabase.shared.createMetadata(account: userBaseUrl.account, user: userBaseUrl.user, userId: userBaseUrl.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: userBaseUrl.urlBase, url: "", contentType: "")
  190. if livePhoto {
  191. metadata.livePhotoFile = (metadata.fileName as NSString).deletingPathExtension + ".mov"
  192. }
  193. metadata.assetLocalIdentifier = asset.localIdentifier
  194. metadata.session = NCNetworking.shared.sessionUploadBackground
  195. metadata.sessionSelector = NCGlobal.shared.selectorUploadFile
  196. metadata.status = NCGlobal.shared.metadataStatusWaitUpload
  197. metadata.sessionDate = Date()
  198. // Modified
  199. if let previewStore = self.previewStore.first(where: { $0.id == asset.localIdentifier }), let data = previewStore.data {
  200. if metadata.contentType == "image/heic" {
  201. let fileNameNoExtension = (fileName as NSString).deletingPathExtension
  202. metadata.contentType = "image/jpeg"
  203. metadata.fileName = fileNameNoExtension + ".jpg"
  204. metadata.fileNameView = fileNameNoExtension + ".jpg"
  205. }
  206. let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
  207. do {
  208. try data.write(to: URL(fileURLWithPath: fileNamePath))
  209. metadata.isExtractFile = true
  210. metadata.size = utilityFileSystem.getFileSize(filePath: fileNamePath)
  211. metadata.creationDate = asset.creationDate as? NSDate ?? (Date() as NSDate)
  212. metadata.date = asset.modificationDate as? NSDate ?? (Date() as NSDate)
  213. } catch { }
  214. }
  215. if let result = NCManageDatabase.shared.getMetadataConflict(account: userBaseUrl.account, serverUrl: serverUrl, fileNameView: fileName) {
  216. metadata.fileName = result.fileName
  217. metadatasUploadInConflict.append(metadata)
  218. } else {
  219. metadatasNOConflict.append(metadata)
  220. }
  221. }
  222. completion(metadatasNOConflict, metadatasUploadInConflict)
  223. }
  224. }