TSLiveWallpaperBrowseVC.swift 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. //
  2. // TSLiveWallpaperBrowseVC.swift
  3. // TSLiveWallpaper
  4. //
  5. // Created by 100Years on 2024/12/24.
  6. //
  7. import Photos
  8. import PhotosUI
  9. private let topLineH = k_Height_statusBar()
  10. class TSLiveWallpaperBrowseItemModel {
  11. var style:ImageDataStyple = .homeLiveList
  12. var imageUrl:String = ""
  13. var videoUrl:String = ""
  14. var vip:Bool = false
  15. var livePhoto:PHLivePhoto? = nil
  16. var livePhotoResources:(pairedImage: URL, pairedVideo: URL)?
  17. var imageCacheUrl:URL?
  18. var videoCacheUrl:URL?
  19. }
  20. class TSLiveWallpaperBrowseVC: TSBaseVC {
  21. private var isPanningDown: Bool?
  22. lazy var isPreview = false {
  23. didSet {
  24. self.previewView.isHidden = !isPreview
  25. self.btnsAllView.isHidden = isPreview
  26. }
  27. }
  28. private var dataModelArray = [TSLiveWallpaperBrowseItemModel]()
  29. var currentIndex:Int {
  30. didSet{
  31. reloadUI()
  32. }
  33. }
  34. init(itemModels: [TSImageDataItemModel],currentIndex:Int) {
  35. for itemModel in itemModels {
  36. let model = TSLiveWallpaperBrowseItemModel()
  37. model.style = itemModel.style
  38. model.imageUrl = itemModel.imageUrl
  39. model.videoUrl = itemModel.videoUrl
  40. model.vip = itemModel.vip
  41. dataModelArray.append(model)
  42. }
  43. self.currentIndex = currentIndex
  44. super.init()
  45. }
  46. var isCanDelete:Bool = false {
  47. didSet{
  48. deleteBtn.isHidden = !isCanDelete
  49. copyrightBtn.isHidden = isCanDelete
  50. }
  51. }
  52. var deleteCompletion:((_ item:Int)->Void)?
  53. @MainActor required init?(coder: NSCoder) {
  54. fatalError("init(coder:) has not been implemented")
  55. }
  56. lazy var backBtn: UIButton = {
  57. return UIButton.createButton(image: UIImage(named: "navi_back_white"),backgroundColor: UIColor.fromHex("#111111", alpha: 0.2),corner: 16.0) { [weak self] in
  58. self?.pop()
  59. }
  60. }()
  61. //MARK: btnsAllView
  62. lazy var saveBtn: UIButton = {
  63. let saveBtn = TSViewTool.createNormalSubmitBtn(title: "Save".localized) { [weak self] in
  64. guard let self = self else { return }
  65. let cell = collectionView.cellForItem(at: IndexPath(item: currentIndex, section: 0)) as? TSLiveWallpaperBrowseCell
  66. //判断 vip
  67. if let itemModel = self.dataModelArray.safeObj(At: currentIndex),
  68. itemModel.vip == true,
  69. PurchaseManager.default.isVip == false
  70. {
  71. cell?.stopPlayLive()
  72. TSPurchaseVC.show(target: self) {[weak self] in
  73. guard let self = self else { return }
  74. cell?.stratPlayLive()
  75. }
  76. return
  77. }
  78. //保存图片
  79. if let cell = collectionView.cellForItem(at: IndexPath(item: currentIndex, section: 0)) as? TSLiveWallpaperBrowseCell {
  80. cell.saveLivePhoto { [weak self] success in
  81. guard let self = self else { return }
  82. if success {
  83. kSaveSuccesswShared.show(atView: self.view)
  84. }else{
  85. TSToastShared.showToast(text: "Save Fail".localized)
  86. }
  87. }
  88. }
  89. }
  90. saveBtn.cornerRadius = 24
  91. return saveBtn
  92. }()
  93. lazy var deleteBtn: UIButton = {//删除按钮
  94. let deleteBtn = UIButton.createButton(image: UIImage(named: "delete_white"),backgroundColor: UIColor.fromHex("#111111", alpha: 0.2),corner: 16.0) { [weak self] in
  95. guard let self = self else { return }
  96. showCustomAlert(
  97. message: "Are you sure to delete".localized,
  98. deleteHandler: { [weak self] in
  99. guard let self = self else { return }
  100. if let itemModel = self.dataModelArray.safeObj(At: currentIndex) {
  101. self.dataModelArray.remove(at: currentIndex)
  102. }
  103. deleteCompletion?(currentIndex)
  104. if self.dataModelArray.count == 0 {
  105. self.pop()
  106. }else{
  107. self.collectionView.reloadData()
  108. }
  109. },
  110. cancelHandler: {
  111. }
  112. )
  113. }
  114. deleteBtn.isHidden = true
  115. return deleteBtn
  116. }()
  117. lazy var copyrightBtn: UIButton = {
  118. //版权信息按钮
  119. let copyrightBtn = UIButton.createButton(image: UIImage(named: "info_white"),backgroundColor: UIColor.fromHex("#111111", alpha: 0.2),corner: 16.0) { [weak self] in
  120. guard let self = self else { return }
  121. navigationController?.pushViewController(TSLiveWallpaperCopyrightVC(), animated: true)
  122. }
  123. return copyrightBtn
  124. }()
  125. lazy var btnsAllView: UIView = {
  126. let btnsAllView = UIView()
  127. btnsAllView.addSubview(copyrightBtn)
  128. copyrightBtn.snp.makeConstraints { make in
  129. make.width.height.equalTo(44)
  130. make.trailing.equalTo(-16)
  131. make.top.equalTo(topLineH)
  132. }
  133. btnsAllView.addSubview(deleteBtn)
  134. deleteBtn.snp.makeConstraints { make in
  135. make.width.height.equalTo(44)
  136. make.trailing.equalTo(-16)
  137. make.top.equalTo(topLineH)
  138. }
  139. //预览按钮
  140. let previewBtn = UIButton.createButton(image: UIImage(named: "random_preview"),backgroundColor: UIColor.fromHex("#000000", alpha: 0.5),corner: 24) { [weak self] in
  141. guard let self = self else { return }
  142. self.isPreview = !self.isPreview
  143. }
  144. btnsAllView.addSubview(previewBtn)
  145. previewBtn.snp.makeConstraints { make in
  146. make.trailing.equalTo(-42)
  147. make.bottom.equalTo(-16-k_Height_safeAreaInsetsBottom())
  148. make.width.height.equalTo(48)
  149. }
  150. btnsAllView.addSubview(saveBtn)
  151. saveBtn.snp.makeConstraints { make in
  152. make.trailing.equalTo(previewBtn.snp.leading).offset(-18)
  153. make.leading.equalTo(42)
  154. make.bottom.equalTo(-16-k_Height_safeAreaInsetsBottom())
  155. make.height.equalTo(48)
  156. }
  157. return btnsAllView
  158. }()
  159. //MARK: previewView
  160. lazy var previewView: UIView = {
  161. let previewView = UIView()
  162. previewView.isHidden = true
  163. let imageView = UIImageView.createImageView(imageName:"iPhone_lock_screen_preview")
  164. previewView.addSubview(imageView)
  165. imageView.snp.makeConstraints { make in
  166. make.edges.equalToSuperview()
  167. }
  168. let tap = UITapGestureRecognizer(target: self, action: #selector(onPreviewButton))
  169. previewView.addGestureRecognizer(tap)
  170. return previewView
  171. }()
  172. lazy var collectionView: UICollectionView = {
  173. let collectionView = UICollectionView.createCommon(delegate: self, cellReuseIds: ["TSLiveWallpaperBrowseCell"])
  174. collectionView.backgroundColor = .black
  175. if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
  176. flowLayout.minimumInteritemSpacing = 0
  177. flowLayout.minimumLineSpacing = 0
  178. flowLayout.itemSize = UIScreen.main.bounds.size
  179. flowLayout.scrollDirection = .horizontal
  180. }
  181. return collectionView
  182. }()
  183. override func createView() {
  184. setNavBarViewHidden(true)
  185. view.backgroundColor = .clear
  186. contentView.addSubview(collectionView)
  187. contentView.addSubview(btnsAllView)
  188. contentView.addSubview(previewView)
  189. contentView.addSubview(backBtn)
  190. collectionView.snp.makeConstraints { make in
  191. make.edges.equalToSuperview()
  192. }
  193. btnsAllView.snp.makeConstraints { make in
  194. make.edges.equalToSuperview()
  195. }
  196. previewView.snp.makeConstraints { make in
  197. make.edges.equalToSuperview()
  198. }
  199. backBtn.snp.makeConstraints { make in
  200. make.leading.equalTo(16)
  201. make.top.equalTo(topLineH)
  202. make.width.height.equalTo(44)
  203. }
  204. let pan = UIPanGestureRecognizer(target: self, action: #selector(onPanGesture(_:)))
  205. view.addGestureRecognizer(pan)
  206. kDelayMainShort {
  207. self.collectionView.setContentOffset(CGPoint(x: CGFloat(self.currentIndex) * self.collectionView.frame.size.width, y: 0), animated: false)
  208. }
  209. self.reloadUI()
  210. }
  211. func reloadUI() {
  212. if let itemModel = self.dataModelArray.safeObj(At: currentIndex) {
  213. TSViewTool.setNormalSubmitBtn(btn: saveBtn, showVip: itemModel.vip)
  214. }
  215. }
  216. }
  217. //MARK: 点击操作
  218. extension TSLiveWallpaperBrowseVC{
  219. @objc func onPreviewButton() {
  220. isPreview = !isPreview
  221. }
  222. @objc func onPanGesture(_ pan: UIPanGestureRecognizer) {
  223. let trans = pan.translation(in: self.view)
  224. let velocity = pan.velocity(in: nil)
  225. switch pan.state {
  226. case .began:
  227. if abs(trans.x) > abs(trans.y) {
  228. isPanningDown = false
  229. }
  230. else if trans.y > 0 {
  231. isPanningDown = true
  232. }
  233. case .changed:
  234. switch isPanningDown {
  235. case .none:
  236. if abs(trans.x) > abs(trans.y) {
  237. isPanningDown = false
  238. }
  239. else if trans.y > 0 {
  240. isPanningDown = true
  241. }
  242. case .some(true):
  243. var viewTrans = self.view.transform
  244. viewTrans = viewTrans.translatedBy(x: 0, y: trans.y)
  245. if viewTrans.ty >= 0 {
  246. self.view.transform = viewTrans
  247. }
  248. case .some(false):
  249. let newOffsetX = self.collectionView.contentOffset.x - trans.x
  250. if newOffsetX >= 0 &&
  251. newOffsetX <= (self.collectionView.contentSize.width - self.collectionView.bounds.width) {
  252. self.collectionView.contentOffset.x -= trans.x
  253. }
  254. }
  255. pan.setTranslation(.zero, in: pan.view)
  256. case .ended:
  257. switch isPanningDown {
  258. case .none:
  259. debugPrint("no thing to do ")
  260. self.view.transform = .identity
  261. case .some(true):
  262. if self.view.transform.ty > 80 ||
  263. velocity.y >= 500 {
  264. UIView.animate(withDuration: 0.2) { [weak self] in
  265. self?.view.transform.ty = k_ScreenHeight
  266. } completion: { [weak self] finished in
  267. if finished {
  268. self?.dismiss(animated: false)
  269. }
  270. }
  271. }
  272. else {
  273. self.view.transform = .identity
  274. }
  275. case .some(false):
  276. let velocity = pan.velocity(in: pan.view)
  277. let page: CGFloat
  278. if velocity.x >= 500 {
  279. page = (collectionView.contentOffset.x / collectionView.bounds.width).rounded(.down)
  280. }
  281. else if velocity.x <= 500 {
  282. page = (collectionView.contentOffset.x / collectionView.bounds.width).rounded(.up)
  283. }
  284. else {
  285. page = (collectionView.contentOffset.x / collectionView.bounds.width).rounded()
  286. }
  287. let newOffsetX = page * collectionView.bounds.width
  288. collectionView.setContentOffset(CGPoint(x: newOffsetX, y: 0), animated: true)
  289. }
  290. isPanningDown = nil
  291. case .cancelled, .failed:
  292. self.view.transform = CGAffineTransform.identity
  293. isPanningDown = nil
  294. default:
  295. debugPrint(pan.state)
  296. debugPrint(pan.translation(in: self.view))
  297. }
  298. }
  299. }
  300. //MARK: UICollectionViewDataSource
  301. extension TSLiveWallpaperBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate {
  302. func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
  303. resetIndexWithOffset(scrollView)
  304. }
  305. func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
  306. resetIndexWithOffset(scrollView)
  307. }
  308. private func resetIndexWithOffset(_ scrollView: UIScrollView) {
  309. let item = Int((scrollView.contentOffset.x / scrollView.bounds.width).rounded())
  310. currentIndex = item
  311. }
  312. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  313. return dataModelArray.count
  314. }
  315. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  316. let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TSLiveWallpaperBrowseCell", for: indexPath) as! TSLiveWallpaperBrowseCell
  317. debugPrint("collectionView cellForItemAt=\(indexPath)")
  318. if let wallpaperModel = dataModelArray.safeObj(At: indexPath.item){
  319. cell.itemModel = wallpaperModel
  320. }
  321. return cell
  322. }
  323. func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
  324. debugPrint("collectionView didEndDisplaying=\(indexPath)")
  325. if let cell = cell as? TSLiveWallpaperBrowseCell {
  326. cell.stopPlayLive()
  327. }
  328. }
  329. func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath){
  330. debugPrint("collectionView willDisplay=\(indexPath)")
  331. if let cell = cell as? TSLiveWallpaperBrowseCell {
  332. cell.stratPlayLive()
  333. }
  334. }
  335. }
  336. class TSLiveWallpaperBrowseCell : TSBaseCollectionCell,PHLivePhotoViewDelegate{
  337. private let showImageViewW = k_ScreenWidth - 32
  338. private lazy var livePhotoTool = LivePhoto()
  339. private var isCanPlay = true
  340. lazy var livePhotoView: PHLivePhotoView = {
  341. let liveIv = PHLivePhotoView()
  342. liveIv.delegate = self
  343. liveIv.contentMode = .scaleAspectFill
  344. liveIv.isHidden = true
  345. return liveIv
  346. }()
  347. lazy var loading: UIActivityIndicatorView = {
  348. let loading = UIActivityIndicatorView(style: .large)
  349. loading.hidesWhenStopped = true
  350. loading.color = .white
  351. return loading
  352. }()
  353. var itemModel:TSLiveWallpaperBrowseItemModel? {
  354. didSet {
  355. self.livePhotoView.livePhoto = nil
  356. self.livePhotoView.isHidden = true
  357. if let livePhoto = itemModel?.livePhoto {
  358. self.livePhotoView.livePhoto = livePhoto
  359. self.livePhotoView.isHidden = false
  360. self.livePhotoView.startPlayback(with: .full)
  361. return
  362. }
  363. if let wallpaperModel = itemModel, wallpaperModel.imageUrl.count > 0 {
  364. loading.startAnimating()
  365. var imageCachePath = ""
  366. var videoCachePath = ""
  367. let group = DispatchGroup()
  368. group.enter()
  369. TSCommonTool.downloadAndCacheFile(from: wallpaperModel.imageUrl,fileEx: "jpeg") { path, error in
  370. if let path = path { imageCachePath = path }
  371. group.leave()
  372. }
  373. group.enter()
  374. TSCommonTool.downloadAndCacheFile(from: wallpaperModel.videoUrl,fileEx: "mov") { path, error in
  375. if let path = path { videoCachePath = path }
  376. group.leave()
  377. }
  378. group.notify(queue: .main) { [self] in
  379. if imageCachePath.count == 0 || videoCachePath.count == 0 {
  380. return
  381. }
  382. let imageCacheUrl = URL(fileURLWithPath: imageCachePath)
  383. let videoCacheUrl = URL(fileURLWithPath: videoCachePath)
  384. if !TSFileManagerTool.fileExists(at: imageCacheUrl) || !TSFileManagerTool.fileExists(at: videoCacheUrl){
  385. return
  386. }
  387. self.itemModel?.imageCacheUrl = imageCacheUrl
  388. self.itemModel?.videoCacheUrl = videoCacheUrl
  389. // if videoCacheUrl.path.contains("/saveVideo/") {
  390. // self.loading.stopAnimating()
  391. //
  392. // LivePhotoConverter.livePhotoRequest(videoURL: videoCacheUrl, imageURL: imageCacheUrl) { livePhoto in
  393. // self.itemModel?.livePhoto = livePhoto
  394. // self.itemModel?.livePhotoResources = (imageCacheUrl,videoCacheUrl)
  395. //
  396. // if let livePhoto = livePhoto {
  397. // self.livePhotoView.livePhoto = livePhoto
  398. // self.livePhotoView.isHidden = false
  399. // self.livePhotoView.startPlayback(with: .full)
  400. // }else{
  401. // debugPrint("livePhoto.generate fail")
  402. // }
  403. // }
  404. // return
  405. // }
  406. //
  407. // LivePhotoConverter.convertVideo(videoCacheUrl, imageURL: imageCacheUrl) { success, photoURL, videoURL, errorMsg in
  408. // DispatchQueue.main.async {
  409. // self.loading.stopAnimating()
  410. // if success {
  411. // LivePhotoConverter.livePhotoRequest(videoURL: videoURL!, imageURL: photoURL!) { livePhoto in
  412. // self.itemModel?.livePhoto = livePhoto
  413. // self.itemModel?.livePhotoResources = (photoURL!,videoURL!)
  414. //
  415. // if let livePhoto = livePhoto {
  416. // self.livePhotoView.livePhoto = livePhoto
  417. // self.livePhotoView.isHidden = false
  418. // self.livePhotoView.startPlayback(with: .full)
  419. // }else{
  420. // debugPrint("livePhoto.generate fail")
  421. // }
  422. // }
  423. // }else{
  424. // debugPrint(errorMsg)
  425. // }
  426. // }
  427. // }
  428. livePhotoTool.generate(from: imageCacheUrl, videoURL: videoCacheUrl, progress: { (percent) in
  429. debugPrint(percent)
  430. }) { [weak self] (livePhoto, resources) in
  431. guard let self = self else { return }
  432. loading.stopAnimating()
  433. itemModel?.livePhoto = livePhoto
  434. itemModel?.livePhotoResources = resources
  435. if let livePhoto = livePhoto {
  436. self.livePhotoView.livePhoto = livePhoto
  437. self.livePhotoView.isHidden = false
  438. self.livePhotoView.startPlayback(with: .full)
  439. }else{
  440. debugPrint("livePhoto.generate fail")
  441. }
  442. }
  443. }
  444. }
  445. }
  446. }
  447. override func creatUI() {
  448. self.backgroundColor = UIColor.clear
  449. self.contentView.backgroundColor = UIColor.black
  450. contentView.addSubview(livePhotoView)
  451. livePhotoView.snp.makeConstraints { make in
  452. make.edges.equalToSuperview()
  453. }
  454. contentView.addSubview(loading)
  455. loading.snp.makeConstraints { make in
  456. make.center.equalToSuperview()
  457. }
  458. }
  459. func livePhotoView(_ livePhotoView: PHLivePhotoView, didEndPlaybackWith playbackStyle: PHLivePhotoViewPlaybackStyle) {
  460. // if !livePhotoView.isHidden {
  461. if self.isCanPlay {
  462. debugPrint("startPlayback")
  463. kDelayOnMainThread(1.0) {
  464. livePhotoView.startPlayback(with: .full)
  465. }
  466. }
  467. }
  468. func saveLivePhoto(completion: @escaping (Bool) -> Void){
  469. // if let resources = itemModel?.livePhotoResources {
  470. // LivePhoto.saveToLibrary(resources, completion: { (success) in
  471. // kMainAsync {
  472. // if success {
  473. // debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
  474. // completion(true)
  475. // }else {
  476. // debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
  477. // completion(false)
  478. // }
  479. // }
  480. // })
  481. // }
  482. // if let resources = itemModel?.livePhotoResources {
  483. // LivePhotoConverter.saveToLibrary(videoURL: resources.pairedVideo, imageURL: resources.pairedImage) { success in
  484. // kMainAsync {
  485. // if success {
  486. // debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
  487. // completion(true)
  488. // }else {
  489. // debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
  490. // completion(false)
  491. // }
  492. // }
  493. // }
  494. // }
  495. guard let videoCacheUrl = itemModel?.videoCacheUrl, let imageCacheUrl = itemModel?.imageCacheUrl else{
  496. TSToastShared.showToast(text: "save fail")
  497. return
  498. }
  499. TSToastShared.showLoading()
  500. if videoCacheUrl.path.contains("/saveVideo/") {
  501. LivePhotoConverter.saveToLibrary(videoURL: videoCacheUrl, imageURL: imageCacheUrl) { success in
  502. kMainAsync {
  503. TSToastShared.hideLoading()
  504. if success {
  505. debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
  506. completion(true)
  507. }else {
  508. debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
  509. completion(false)
  510. }
  511. }
  512. }
  513. return
  514. }
  515. LivePhotoConverter.convertVideo(videoCacheUrl, imageURL: imageCacheUrl) { success, photoURL, videoURL, errorMsg in
  516. DispatchQueue.main.async {
  517. TSToastShared.hideLoading()
  518. if success {
  519. LivePhotoConverter.saveToLibrary(videoURL: videoURL!, imageURL: photoURL!) { success in
  520. kMainAsync {
  521. if success {
  522. debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
  523. completion(true)
  524. }else {
  525. debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
  526. completion(false)
  527. }
  528. }
  529. }
  530. }else{
  531. debugPrint(errorMsg)
  532. }
  533. }
  534. }
  535. }
  536. func stopPlayLive() {
  537. debugPrint("stopPlayLive")
  538. self.isCanPlay = false
  539. livePhotoView.isHidden = true
  540. livePhotoView.stopPlayback()
  541. }
  542. func stratPlayLive() {
  543. debugPrint("stratPlayLive")
  544. self.isCanPlay = true
  545. self.livePhotoView.isHidden = false
  546. self.livePhotoView.startPlayback(with: .full)
  547. }
  548. }