TSEditLiveVC.swift 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. //
  2. // TSEditLiveVC.swift
  3. // TSLiveWallpaper
  4. //
  5. // Created by 100Years on 2024/12/20.
  6. //
  7. import PhotosUI
  8. class TSEditLiveVC: TSBaseVC, UINavigationControllerDelegate {
  9. lazy var editLiveSectionModel: TSEditLiveSectionModel = {
  10. let section = TSEditLiveSectionModel()
  11. section.items = [TSEditLiveItemModel()]
  12. return section
  13. }()
  14. lazy var editLiveHistorySectionModel: TSImageDataSectionModel = {
  15. return kImageDataCenterShared.editLiveHistoryListArray.first!
  16. }()
  17. var dataArray:[Component] = [Component]()
  18. lazy var navBarView: TSBaseNavContentBarView = {
  19. let navBarView = TSBaseNavContentBarView()
  20. let titleImageView = UIImageView.createImageView(imageName: "nav_title_editlive",contentMode: .scaleToFill)
  21. navBarView.barView.addSubview(titleImageView)
  22. titleImageView.snp.makeConstraints { make in
  23. make.centerY.equalToSuperview()
  24. make.left.equalTo(16)
  25. make.width.equalTo(252)
  26. make.height.equalTo(24)
  27. }
  28. return navBarView
  29. }()
  30. lazy var collectionComponent: CollectionViewComponent = {
  31. let layout = UICollectionViewFlowLayout()
  32. let cp = CollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [ :])
  33. cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: k_Height_TabBar, right: 0)
  34. cp.itemActionHandler = { [weak self] cellCp, indexPath in
  35. guard let self = self else { return }
  36. //判断 vip
  37. if kPurchaseDefault.freeNumAvailable() == false{
  38. TSPurchaseVC.show(target: self) {[weak self] in
  39. guard let self = self else { return }
  40. reloadView()
  41. }
  42. return
  43. }
  44. //生成视频
  45. self.openVideoPicker()
  46. }
  47. cp.itemDidSelectedHandler = { [weak self] (object, indexPath) in
  48. guard let self = self else { return }
  49. let obj = dataArray.safeObj(At: indexPath.section)
  50. if let liveModel = obj as? TSImageDataSectionModel {
  51. if liveModel.style == .homeLiveList{
  52. let vc = TSLiveWallpaperBrowseVC(itemModels: liveModel.items,currentIndex: indexPath.row)
  53. vc.isCanDelete = true
  54. vc.deleteCompletion = {[weak self] item in
  55. guard let self = self else { return }
  56. if let itemModel = editLiveHistorySectionModel.items.safeObj(At: item) {
  57. editLiveHistorySectionModel.items.remove(at: item)
  58. TSFileManagerTool.removeItem(from: itemModel.imageUrl.fillCacheURL)
  59. TSFileManagerTool.removeItem(from: itemModel.videoUrl.fillCacheURL)
  60. kImageDataCenterShared.editLiveHistoryListArray = [editLiveHistorySectionModel]
  61. reloadView()
  62. }
  63. }
  64. kPresentModalVC(target: self, modelVC: vc)
  65. }
  66. }
  67. }
  68. return cp
  69. }()
  70. override func createView() {
  71. setViewBgImageNamed(named: "view_main_bg")
  72. navBarContentView.addSubview(navBarView)
  73. navBarView.snp.makeConstraints { make in
  74. make.edges.equalToSuperview()
  75. }
  76. contentView.addSubview(collectionComponent.collectionView)
  77. collectionComponent.collectionView.snp.makeConstraints { make in
  78. make.edges.equalToSuperview()
  79. }
  80. reloadView()
  81. }
  82. func reloadView(){
  83. collectionComponent.clear()
  84. if editLiveHistorySectionModel.items.count > 0 {
  85. dataArray = [editLiveSectionModel,editLiveHistorySectionModel]
  86. }else{
  87. dataArray = [editLiveSectionModel]
  88. }
  89. collectionComponent.reloadView(with:dataArray)
  90. }
  91. }
  92. import UniformTypeIdentifiers
  93. extension TSEditLiveVC: UIImagePickerControllerDelegate {
  94. func openVideoPicker() {
  95. TSToastShared.showLoading()
  96. let picker = UIImagePickerController()
  97. picker.sourceType = .photoLibrary
  98. picker.mediaTypes = [UTType.movie.identifier] // 仅允许选择视频
  99. picker.allowsEditing = true // 启用编辑功能
  100. picker.delegate = self
  101. picker.videoMaximumDuration = 3.0
  102. present(picker, animated: true) {
  103. self.hideLoading()
  104. }
  105. }
  106. // 用户完成选择
  107. func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
  108. hideLoading()
  109. if let editedURL = info[.mediaURL] as? URL {
  110. debugPrint("Selected video: \(editedURL)")
  111. // 在这里处理选中的视频(例如上传或保存)
  112. let cachesDirectory = TSFileManagerTool.editLiveVideoPathURL
  113. let targetURL = cachesDirectory.appendingPathComponent("assemblePickerVideo").appendingPathExtension(editedURL.pathExtension)
  114. TSFileManagerTool.copyFileWithOverwrite(from: editedURL, to: targetURL)
  115. // LivePhotoUtil.convertVideo(targetURL.path) { success, msg in
  116. // debugPrint(msg)
  117. // }
  118. // LivePhotoConverter.convertVideo(targetURL) { success, image, video, msg in
  119. // debugPrint(msg)
  120. // }
  121. saveLive(videoPath: targetURL)
  122. }
  123. picker.dismiss(animated: true, completion: nil)
  124. }
  125. // 用户取消选择
  126. func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
  127. hideLoading()
  128. picker.dismiss(animated: true, completion: nil)
  129. }
  130. func hideLoading(){
  131. kDelayMainShort {
  132. TSToastShared.hideLoading()
  133. }
  134. }
  135. }
  136. extension TSEditLiveVC{
  137. func openVideoClipperVC(videoURL:URL) {
  138. let clipperController = GPVideoClipperController.clipperWithVideoURL(videoURL, makerBlock: { (maker) in
  139. maker.startTime = 0
  140. maker.endTime = 15
  141. maker.clippedVideoMinDuration = 1
  142. maker.clippedVideoMaxDuration = 3
  143. maker.leftSelectedImage = UIImage(named: "eidt_arrow_left")!
  144. maker.selectedBoxColor = .white
  145. maker.rightSelectedImage = UIImage(named: "eidt_arrow_right")!
  146. maker.leftMargin = 77
  147. maker.rightMargin = 37
  148. maker.selectedImageWidth = 14
  149. }) {[weak self] (videoURL, videoAsset, coverImage) in
  150. guard let self = self else { return }
  151. self.saveLive(videoPath: videoURL)
  152. }
  153. kPresentModalVC(target: self, modelVC: clipperController)
  154. }
  155. func saveLive(videoPath:URL){
  156. TSToastShared.showLoading()
  157. LivePhotoConverter.convertVideo(videoPath) { success, imageURL, videoURL, errorMsg in
  158. if success {
  159. debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
  160. if let imageURL = imageURL,let videoURL = videoURL {
  161. LivePhotoConverter.saveToLibrary(videoURL: videoURL, imageURL: imageURL) { success in
  162. kSavePhotoSuccesswShared.show(atView: self.view,text: "DIY Successfully".localized)
  163. }
  164. kPurchaseDefault.useOnceForFree()
  165. let saveURL = TSFileManagerTool.saveLiveVideoPathURL
  166. let timestampString = Date.timestampString
  167. let saveImageURL = saveURL.appendingPathComponent("image\(timestampString).heic")
  168. let saveVideoURL = saveURL.appendingPathComponent("video\(timestampString).mov")
  169. TSFileManagerTool.copyFileWithOverwrite(from: imageURL, to: saveImageURL)
  170. TSFileManagerTool.copyFileWithOverwrite(from: videoURL, to: saveVideoURL)
  171. let itemModel = TSImageDataItemModel()
  172. itemModel.imageUrl = TSFileManagerTool.getCacheSubPath(at: saveImageURL)!
  173. itemModel.videoUrl = TSFileManagerTool.getCacheSubPath(at: saveVideoURL)!
  174. self.editLiveHistorySectionModel.items.insert(itemModel, at: 0)
  175. kImageDataCenterShared.editLiveHistoryListArray = [self.editLiveHistorySectionModel]
  176. self.reloadView()
  177. }
  178. }else {
  179. debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
  180. }
  181. }
  182. // let ts = Date().timeIntervalSince1970
  183. // let documentURL = TSFileManagerTool.documentsDirectory.appendingPathComponent("\(Int(ts)).mov")
  184. // let documentURL = TSFileManagerTool.documentsDirectory
  185. // Converter4Video(path: videoPath.path).resizeVideo(at: videoPath.path, outputPath: documentURL.path, outputSize: CGSize(width: 1080, height: 1920)) { success, error in
  186. // guard success else{
  187. // debugPrint(error)
  188. // return
  189. // }
  190. //
  191. // LivePhoto.generate(from: nil, videoURL: documentURL) { progress in
  192. //
  193. // } completion: {[weak self] (livePhoto, resources) in
  194. // guard let self = self else { return }
  195. //
  196. // if let resources = resources {
  197. // LivePhoto.saveToLibrary(resources, completion: { (success) in
  198. // kExecuteOnMainThread {
  199. // hideLoading()
  200. // if success {
  201. // debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
  202. // kSavePhotoSuccesswShared.show(atView: self.view)
  203. // }else {
  204. // debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
  205. // }
  206. //
  207. // TSFileManagerTool.removeItem(from: resources.pairedImage)
  208. // TSFileManagerTool.removeItem(from: resources.pairedVideo)
  209. // }
  210. // })
  211. // }
  212. // }
  213. // }
  214. // LivePhoto.resizeVideoToFixedHeight(videoURL: videoPath, outputFolder: documentURL) { outputURL in
  215. // if let outputURL = outputURL {
  216. // print("Resized video saved to: \(outputURL)")
  217. //
  218. // LivePhoto.generate(from: nil, videoURL: outputURL) { progress in
  219. //
  220. // } completion: {[weak self] (livePhoto, resources) in
  221. // guard let self = self else { return }
  222. //
  223. // if let resources = resources {
  224. // LivePhoto.saveToLibrary(resources, completion: { (success) in
  225. // kExecuteOnMainThread {
  226. // hideLoading()
  227. // if success {
  228. // debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
  229. // kSavePhotoSuccesswShared.show(atView: self.view)
  230. // }else {
  231. // debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
  232. // }
  233. //
  234. // TSFileManagerTool.removeItem(from: resources.pairedImage)
  235. // TSFileManagerTool.removeItem(from: resources.pairedVideo)
  236. // }
  237. // })
  238. // }
  239. // }
  240. //
  241. // } else {
  242. // print("Failed to resize video.")
  243. // }
  244. // }
  245. // VideoRecorder.shared.saveLivePhoto(duration: 2.5, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { [weak self] recordHandler in
  246. //
  247. //// recordHandler?()
  248. //
  249. // } completion: { [weak self] videoURL, imageURL, errorMsg in
  250. // guard let self = self else { return }
  251. //// }
  252. //// LivePhotoCreater().saveLivePhoto(from: videoPath, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { videoURL, imageURL, errorMsg in
  253. // if let imageURL = imageURL,let videoURL = videoURL {
  254. // LivePhotoConverter.saveToLibrary(videoURL: videoURL, imageURL: imageURL) { success in
  255. // kSavePhotoSuccesswShared.show(atView: self.view)
  256. // }
  257. //
  258. //
  259. // let saveURL = TSFileManagerTool.saveLiveVideoPathURL
  260. // let timestampString = Date.timestampString
  261. // let saveImageURL = saveURL.appendingPathComponent("image\(timestampString).heic")
  262. // let saveVideoURL = saveURL.appendingPathComponent("video\(timestampString).mov")
  263. // TSFileManagerTool.copyFileWithOverwrite(from: imageURL, to: saveImageURL)
  264. // TSFileManagerTool.copyFileWithOverwrite(from: videoURL, to: saveVideoURL)
  265. //
  266. //
  267. // let itemModel = TSImageDataItemModel()
  268. // itemModel.imageUrl = TSFileManagerTool.getCacheSubPath(at: saveImageURL)!
  269. // itemModel.videoUrl = TSFileManagerTool.getCacheSubPath(at: saveVideoURL)!
  270. // self.editLiveHistorySectionModel.items.append(itemModel)
  271. // kImageDataCenterShared.editLiveHistoryListArray = [self.editLiveHistorySectionModel]
  272. // self.reloadView()
  273. // }
  274. // }
  275. }
  276. // func saveLivePhotoVideoRecorder(){
  277. //
  278. //
  279. // VideoRecorder.shared.saveLivePhoto(duration: 3.0, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { [weak self] recordHandler in
  280. //
  281. //// recordHandler?()
  282. //
  283. // } completion: { [weak self] videoURL, imageURL, errorMsg in
  284. // guard let self = self else { return }
  285. //// }
  286. //// LivePhotoCreater().saveLivePhoto(from: videoPath, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { videoURL, imageURL, errorMsg in
  287. // if let imageURL = imageURL,let videoURL = videoURL {
  288. // LivePhotoConverter.saveToLibrary(videoURL: videoURL, imageURL: imageURL) { success in
  289. // kSavePhotoSuccesswShared.show(atView: self.view)
  290. // }
  291. //
  292. //
  293. // let saveURL = TSFileManagerTool.saveLiveVideoPathURL
  294. // let timestampString = Date.timestampString
  295. // let saveImageURL = saveURL.appendingPathComponent("image\(timestampString).heic")
  296. // let saveVideoURL = saveURL.appendingPathComponent("video\(timestampString).mov")
  297. // TSFileManagerTool.copyFileWithOverwrite(from: imageURL, to: saveImageURL)
  298. // TSFileManagerTool.copyFileWithOverwrite(from: videoURL, to: saveVideoURL)
  299. //
  300. //
  301. // let itemModel = TSImageDataItemModel()
  302. // itemModel.imageUrl = TSFileManagerTool.getCacheSubPath(at: saveImageURL)!
  303. // itemModel.videoUrl = TSFileManagerTool.getCacheSubPath(at: saveVideoURL)!
  304. // self.editLiveHistorySectionModel.items.append(itemModel)
  305. // kImageDataCenterShared.editLiveHistoryListArray = [self.editLiveHistorySectionModel]
  306. // self.reloadView()
  307. // }
  308. // }
  309. // }
  310. }
  311. // MARK: - PHPickerViewControllerDelegate
  312. //extension TSEditLiveVC: PHPickerViewControllerDelegate {
  313. //
  314. // /// Present `PHPickerViewController`
  315. // func pick(_ filter: PHPickerFilter) {
  316. // var config = PHPickerConfiguration()
  317. // config.filter = filter
  318. // config.selectionLimit = 1
  319. // config.preferredAssetRepresentationMode = .current
  320. // let picker = PHPickerViewController(configuration: config)
  321. // picker.delegate = self
  322. // picker.modalPresentationStyle = .overFullScreen
  323. // present(picker, animated: true, completion: nil)
  324. // }
  325. //
  326. // func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
  327. // defer { picker.dismiss(animated: true) }
  328. // assemblePicker(picker, didFinishPicking: results)
  329. // }
  330. //
  331. // func assemblePicker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
  332. // guard let itemProvider = results.first?.itemProvider else {
  333. // return
  334. // }
  335. //
  336. // if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
  337. // itemProvider.loadFileRepresentation(forTypeIdentifier: itemProvider.registeredTypeIdentifiers.first!) { [weak self] url, error in
  338. // guard let self, let url = url else {
  339. // return
  340. // }
  341. // do {
  342. // let cachesDirectory = try self.cachesDirectory()
  343. // let targetURL = cachesDirectory.appendingPathComponent("assemblePickerVideo").appendingPathExtension(url.pathExtension)
  344. // let fileManager = FileManager.default
  345. // // 如果目标路径存在同名文件,先删除旧文件
  346. // if fileManager.fileExists(atPath: targetURL.path) {
  347. // try fileManager.removeItem(at: targetURL)
  348. // }
  349. //
  350. // try fileManager.copyItem(at: url, to: targetURL)
  351. //
  352. // kExecuteOnMainThread {
  353. // self.openVideoClipperVC(videoURL: targetURL)
  354. // }
  355. //
  356. // } catch {
  357. // TSToastShared.showToast(message: "An error occurred")
  358. // }
  359. // }
  360. // }
  361. // }
  362. //
  363. // private func cachesDirectory() throws -> URL {
  364. // let cachesDirectoryURL = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
  365. // let cachesDirectory = cachesDirectoryURL.appendingPathComponent("asemble", isDirectory: true)
  366. // if !FileManager.default.fileExists(atPath: cachesDirectory.absoluteString) {
  367. // try FileManager.default.createDirectory(at: cachesDirectory, withIntermediateDirectories: true, attributes: nil)
  368. // }
  369. // return cachesDirectory
  370. // }
  371. //}