NCUploadAssetsView.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //
  2. // NCUploadAssetsView.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 03/06/24.
  6. // Copyright © 2024 Marino Faggiana. All rights reserved.
  7. //
  8. import SwiftUI
  9. struct NCUploadAssetsView: View {
  10. @ObservedObject var model: NCUploadAssetsModel
  11. @State private var showSelect = false
  12. @State private var showUploadConflict = false
  13. @State private var showQuickLook = false
  14. @State private var shorRenameAlert = false
  15. @State private var renameFileName: String = ""
  16. @State private var renameIndex: Int = 0
  17. @State private var index: Int = 0
  18. var metadata: tableMetadata?
  19. let gridItems: [GridItem] = [GridItem()]
  20. let fileNamePath = NSTemporaryDirectory() + "Photo.jpg"
  21. @Environment(\.presentationMode) var presentationMode
  22. var body: some View {
  23. let utilityFileSystem = NCUtilityFileSystem()
  24. NavigationView {
  25. ZStack(alignment: .top) {
  26. List {
  27. Section(footer: Text(NSLocalizedString("_modify_image_desc_", comment: ""))) {
  28. ScrollView(.horizontal) {
  29. LazyHGrid(rows: gridItems, alignment: .center, spacing: 10) {
  30. ForEach(0..<model.previewStore.count, id: \.self) { index in
  31. let item = model.previewStore[index]
  32. Menu {
  33. Button(action: {
  34. renameFileName = model.previewStore[index].fileName
  35. renameIndex = index
  36. shorRenameAlert = true
  37. }) {
  38. Label(NSLocalizedString("_rename_", comment: ""), systemImage: "pencil")
  39. }
  40. if item.asset.type == .photo || item.asset.type == .livePhoto {
  41. Button(action: {
  42. if model.presentedQuickLook(index: index, fileNamePath: fileNamePath) {
  43. self.index = index
  44. showQuickLook = true
  45. }
  46. }) {
  47. Label(NSLocalizedString("_modify_", comment: ""), systemImage: "pencil.tip.crop.circle")
  48. }
  49. }
  50. if item.data != nil {
  51. Button(action: {
  52. if let image = model.previewStore[index].asset.fullResolutionImage?.resizeImage(size: CGSize(width: 300, height: 300), isAspectRation: true) {
  53. model.previewStore[index].image = image
  54. model.previewStore[index].data = nil
  55. model.previewStore[index].assetType = model.previewStore[index].asset.type
  56. }
  57. }) {
  58. Label(NSLocalizedString("_undo_modify_", comment: ""), systemImage: "arrow.uturn.backward.circle")
  59. }
  60. }
  61. if item.data == nil && item.asset.type == .livePhoto && item.assetType == .livePhoto {
  62. Button(action: {
  63. model.previewStore[index].assetType = .photo
  64. }) {
  65. Label(NSLocalizedString("_disable_livephoto_", comment: ""), systemImage: "livephoto.slash")
  66. }
  67. } else if item.data == nil && item.asset.type == .livePhoto && item.assetType == .photo {
  68. Button(action: {
  69. model.previewStore[index].assetType = .livePhoto
  70. }) {
  71. Label(NSLocalizedString("_enable_livephoto_", comment: ""), systemImage: "livephoto")
  72. }
  73. }
  74. Button(role: .destructive, action: {
  75. model.deleteAsset(index: index)
  76. }) {
  77. Label(NSLocalizedString("_remove_", comment: ""), systemImage: "trash")
  78. }
  79. } label: {
  80. ImageAsset(model: model, index: index)
  81. .alert(NSLocalizedString("_rename_file_", comment: ""), isPresented: $shorRenameAlert) {
  82. TextField(NSLocalizedString("_enter_filename_", comment: ""), text: $renameFileName)
  83. .autocapitalization(.none)
  84. .autocorrectionDisabled()
  85. Button(NSLocalizedString("_rename_", comment: ""), action: {
  86. model.previewStore[renameIndex].fileName = renameFileName.trimmingCharacters(in: .whitespacesAndNewlines)
  87. })
  88. Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel, action: {})
  89. }
  90. }
  91. }
  92. }
  93. }
  94. }
  95. // .redacted(reason: uploadAssets.previewStore.isEmpty ? .placeholder : [])
  96. Section {
  97. Toggle(isOn: $model.useAutoUploadFolder, label: {
  98. Text(NSLocalizedString("_use_folder_auto_upload_", comment: ""))
  99. .font(.system(size: 15))
  100. })
  101. .toggleStyle(SwitchToggleStyle(tint: Color(NCBrandColor.shared.brandElement)))
  102. if model.useAutoUploadFolder {
  103. Toggle(isOn: $model.useAutoUploadFolder, label: {
  104. Text(NSLocalizedString("_autoupload_create_subfolder_", comment: ""))
  105. .font(.system(size: 15))
  106. })
  107. .toggleStyle(SwitchToggleStyle(tint: Color(NCBrandColor.shared.brandElement)))
  108. }
  109. if !model.useAutoUploadFolder {
  110. HStack {
  111. Label {
  112. if utilityFileSystem.getHomeServer(urlBase: model.userBaseUrl.urlBase, userId: model.userBaseUrl.userId) == model.serverUrl {
  113. Text("/")
  114. .font(.system(size: 15))
  115. .frame(maxWidth: .infinity, alignment: .trailing)
  116. } else {
  117. Text(model.getTextServerUrl())
  118. .font(.system(size: 15))
  119. .frame(maxWidth: .infinity, alignment: .trailing)
  120. }
  121. } icon: {
  122. Image("folder")
  123. .renderingMode(.template)
  124. .resizable()
  125. .scaledToFit()
  126. .foregroundColor(Color(NCBrandColor.shared.brandElement))
  127. }
  128. }
  129. .contentShape(Rectangle())
  130. .onTapGesture {
  131. showSelect = true
  132. }
  133. }
  134. }
  135. Button(NSLocalizedString("_save_", comment: "")) {
  136. if model.useAutoUploadFolder, model.useAutoUploadSubFolder {
  137. model.showHUD = true
  138. }
  139. model.uploadInProgress.toggle()
  140. model.save { metadatasNOConflict, metadatasUploadInConflict in
  141. if metadatasUploadInConflict.isEmpty {
  142. model.dismissCreateFormUploadConflict(metadatas: metadatasNOConflict)
  143. } else {
  144. model.metadatasNOConflict = metadatasNOConflict
  145. model.metadatasUploadInConflict = metadatasUploadInConflict
  146. showUploadConflict = true
  147. }
  148. }
  149. }
  150. .frame(maxWidth: .infinity)
  151. .buttonStyle(ButtonRounded(disabled: model.uploadInProgress))
  152. .listRowBackground(Color(UIColor.systemGroupedBackground))
  153. .disabled(model.uploadInProgress)
  154. .hiddenConditionally(isHidden: model.hiddenSave)
  155. }
  156. .navigationTitle(NSLocalizedString("_upload_photos_videos_", comment: ""))
  157. .navigationBarTitleDisplayMode(.inline)
  158. .navigationBarItems(trailing: Button(action: {
  159. presentationMode.wrappedValue.dismiss()
  160. }) {
  161. Image(systemName: "xmark")
  162. .font(Font.system(.body).weight(.light))
  163. .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
  164. })
  165. HUDView(showHUD: $model.showHUD, textLabel: NSLocalizedString("_wait_", comment: ""), image: "doc.badge.arrow.up")
  166. .offset(y: model.showHUD ? 5 : -200)
  167. .animation(.easeOut, value: model.showHUD)
  168. }
  169. }
  170. .navigationViewStyle(StackNavigationViewStyle())
  171. .sheet(isPresented: $showSelect) {
  172. SelectView(serverUrl: $model.serverUrl)
  173. }
  174. .sheet(isPresented: $showUploadConflict) {
  175. UploadConflictView(delegate: model, serverUrl: model.serverUrl, metadatasUploadInConflict: model.metadatasUploadInConflict, metadatasNOConflict: model.metadatasNOConflict)
  176. }
  177. .fullScreenCover(isPresented: $showQuickLook) {
  178. NCViewerQuickLookView(url: URL(fileURLWithPath: fileNamePath), index: $index, isPresentedQuickLook: $showQuickLook, model: model)
  179. .ignoresSafeArea()
  180. }
  181. .onReceive(model.$dismissView) { newValue in
  182. if newValue {
  183. presentationMode.wrappedValue.dismiss()
  184. }
  185. }
  186. .onTapGesture {
  187. SceneManager.shared.getWindow(controller: model.controller)?.endEditing(true)
  188. }
  189. .onDisappear {
  190. model.dismissView = true
  191. }
  192. }
  193. struct ImageAsset: View {
  194. @ObservedObject var model: NCUploadAssetsModel
  195. @State var index: Int
  196. var body: some View {
  197. ZStack(alignment: .bottomTrailing) {
  198. if index < model.previewStore.count {
  199. let item = model.previewStore[index]
  200. Image(uiImage: item.image)
  201. .resizable()
  202. .aspectRatio(contentMode: .fill)
  203. .frame(width: 80, height: 80, alignment: .center)
  204. .cornerRadius(10)
  205. if item.assetType == .livePhoto && item.data == nil {
  206. Image(systemName: "livephoto")
  207. .resizable()
  208. .scaledToFit()
  209. .frame(width: 15, height: 15)
  210. .foregroundColor(.white)
  211. .padding(.horizontal, 5)
  212. .padding(.vertical, 5)
  213. } else if item.assetType == .video {
  214. Image(systemName: "video.fill")
  215. .resizable()
  216. .scaledToFit()
  217. .frame(width: 15, height: 15)
  218. .foregroundColor(.white)
  219. .padding(.horizontal, 5)
  220. .padding(.vertical, 5)
  221. }
  222. }
  223. }
  224. }
  225. }
  226. }
  227. #Preview {
  228. NCUploadAssetsView(model: NCUploadAssetsModel(assets: [], serverUrl: "/", userBaseUrl: (UIApplication.shared.delegate as? AppDelegate)!, controller: nil))
  229. }