123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- //
- // TSLiveWallpaperBrowseVC.swift
- // TSLiveWallpaper
- //
- // Created by 100Years on 2024/12/24.
- //
- import Photos
- import PhotosUI
- private let topLineH = k_Height_statusBar()
- class TSLiveWallpaperBrowseItemModel {
- var style:ImageDataStyple = .homeLiveList
- var imageUrl:String = ""
- var videoUrl:String = ""
-
- var livePhoto:PHLivePhoto? = nil
- var livePhotoResources:(pairedImage: URL, pairedVideo: URL)?
- }
- class TSLiveWallpaperBrowseVC: TSBaseVC {
-
- private var isPanningDown: Bool?
- lazy var isPreview = false {
- didSet {
- self.previewView.isHidden = !isPreview
- self.btnsAllView.isHidden = isPreview
- }
- }
-
- private var dataModelArray = [TSLiveWallpaperBrowseItemModel]()
- var currentIndex:Int
- init(itemModels: [TSImageDataItemModel],currentIndex:Int) {
- self.currentIndex = currentIndex
- for itemModel in itemModels {
- let model = TSLiveWallpaperBrowseItemModel()
- model.style = itemModel.style
- model.imageUrl = itemModel.imageUrl
- model.videoUrl = itemModel.videoUrl
- dataModelArray.append(model)
- }
- super.init()
- }
-
- @MainActor required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- lazy var backBtn: UIButton = {
- return UIButton.createButton(image: UIImage(named: "navi_back_white"),backgroundColor: UIColor.fromHex("#111111", alpha: 0.2),corner: 16.0) { [weak self] in
- self?.pop()
- }
- }()
-
-
- //MARK: btnsAllView
-
- lazy var saveBtn: UIButton = {
- let saveBtn = TSViewTool.createNormalSubmitBtn(title: "save".localized) { [weak self] in
- guard let self = self else { return }
- if let cell = collectionView.cellForItem(at: IndexPath(item: currentIndex, section: 0)) as? TSLiveWallpaperBrowseCell {
- cell.saveLivePhoto { [weak self] success in
- guard let self = self else { return }
- if success {
- kSavePhotoSuccesswShared.show(atView: self.view)
- }else{
- TSToastShared.showToast(message: "Save Fail".localized)
- }
- }
- }
- }
- saveBtn.cornerRadius = 24
- return saveBtn
- }()
-
-
- lazy var btnsAllView: UIView = {
- let btnsAllView = UIView()
-
- //版权信息按钮
- let copyrightBtn = UIButton.createButton(image: UIImage(named: "info_white"),backgroundColor: UIColor.fromHex("#111111", alpha: 0.2),corner: 16.0) { [weak self] in
- guard let self = self else { return }
- navigationController?.pushViewController(TSLiveWallpaperCopyrightVC(), animated: true)
- }
- btnsAllView.addSubview(copyrightBtn)
- copyrightBtn.snp.makeConstraints { make in
- make.width.height.equalTo(44)
- make.trailing.equalTo(-16)
- make.top.equalTo(topLineH)
- }
-
- //预览按钮
- let previewBtn = UIButton.createButton(image: UIImage(named: "random_preview"),backgroundColor: UIColor.fromHex("#000000", alpha: 0.5),corner: 24) { [weak self] in
- guard let self = self else { return }
- self.isPreview = !self.isPreview
- }
- btnsAllView.addSubview(previewBtn)
- previewBtn.snp.makeConstraints { make in
- make.trailing.equalTo(-42)
- make.bottom.equalTo(-16-k_Height_safeAreaInsetsBottom())
- make.width.height.equalTo(48)
- }
-
- btnsAllView.addSubview(saveBtn)
- saveBtn.snp.makeConstraints { make in
- make.trailing.equalTo(previewBtn.snp.leading).offset(-18)
- make.leading.equalTo(42)
- make.bottom.equalTo(-16-k_Height_safeAreaInsetsBottom())
- make.height.equalTo(48)
- }
-
- return btnsAllView
- }()
-
- //MARK: previewView
- lazy var previewView: UIView = {
- let previewView = UIView()
- previewView.isHidden = true
-
- let imageView = UIImageView.createImageView(imageName:"iPhone_lock_screen_preview")
- previewView.addSubview(imageView)
- imageView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- let tap = UITapGestureRecognizer(target: self, action: #selector(onPreviewButton))
- previewView.addGestureRecognizer(tap)
-
- return previewView
- }()
-
- lazy var collectionView: UICollectionView = {
- let collectionView = UICollectionView.createCommon(delegate: self, cellReuseIds: ["TSLiveWallpaperBrowseCell"])
- if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
- flowLayout.minimumInteritemSpacing = 0
- flowLayout.minimumLineSpacing = 0
- flowLayout.itemSize = UIScreen.main.bounds.size
- flowLayout.scrollDirection = .horizontal
- }
- return collectionView
- }()
-
-
- override func createView() {
- setNavBarViewHidden(true)
- view.backgroundColor = .clear
- contentView.addSubview(collectionView)
- contentView.addSubview(btnsAllView)
- contentView.addSubview(previewView)
- contentView.addSubview(backBtn)
- collectionView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- btnsAllView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- previewView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- backBtn.snp.makeConstraints { make in
- make.leading.equalTo(16)
- make.top.equalTo(topLineH)
- make.width.height.equalTo(44)
- }
-
- let pan = UIPanGestureRecognizer(target: self, action: #selector(onPanGesture(_:)))
- view.addGestureRecognizer(pan)
-
- kDelayMainShort {
- self.collectionView.setContentOffset(CGPoint(x: CGFloat(self.currentIndex) * self.collectionView.frame.size.width, y: 0), animated: false)
- }
-
- }
- }
- //MARK: 点击操作
- extension TSLiveWallpaperBrowseVC{
- @objc func onPreviewButton() {
- isPreview = !isPreview
- }
-
- @objc func onPanGesture(_ pan: UIPanGestureRecognizer) {
- let trans = pan.translation(in: self.view)
- let velocity = pan.velocity(in: nil)
-
- switch pan.state {
- case .began:
- if abs(trans.x) > abs(trans.y) {
- isPanningDown = false
- }
- else if trans.y > 0 {
- isPanningDown = true
- }
-
- case .changed:
-
- switch isPanningDown {
- case .none:
-
- if abs(trans.x) > abs(trans.y) {
- isPanningDown = false
- }
- else if trans.y > 0 {
- isPanningDown = true
- }
-
- case .some(true):
- var viewTrans = self.view.transform
- viewTrans = viewTrans.translatedBy(x: 0, y: trans.y)
- if viewTrans.ty >= 0 {
- self.view.transform = viewTrans
- }
-
- case .some(false):
- let newOffsetX = self.collectionView.contentOffset.x - trans.x
- if newOffsetX >= 0 &&
- newOffsetX <= (self.collectionView.contentSize.width - self.collectionView.bounds.width) {
- self.collectionView.contentOffset.x -= trans.x
- }
- }
- pan.setTranslation(.zero, in: pan.view)
- case .ended:
-
- switch isPanningDown {
- case .none:
- debugPrint("no thing to do ")
- self.view.transform = .identity
-
- case .some(true):
- if self.view.transform.ty > 80 ||
- velocity.y >= 500 {
- UIView.animate(withDuration: 0.2) { [weak self] in
- self?.view.transform.ty = k_ScreenHeight
- } completion: { [weak self] finished in
- if finished {
- self?.dismiss(animated: false)
- }
- }
- }
- else {
- self.view.transform = .identity
- }
- case .some(false):
-
- let velocity = pan.velocity(in: pan.view)
-
- let page: CGFloat
- if velocity.x >= 500 {
- page = (collectionView.contentOffset.x / collectionView.bounds.width).rounded(.down)
- }
- else if velocity.x <= 500 {
- page = (collectionView.contentOffset.x / collectionView.bounds.width).rounded(.up)
- }
- else {
- page = (collectionView.contentOffset.x / collectionView.bounds.width).rounded()
- }
- let newOffsetX = page * collectionView.bounds.width
- collectionView.setContentOffset(CGPoint(x: newOffsetX, y: 0), animated: true)
- }
-
- isPanningDown = nil
- case .cancelled, .failed:
- self.view.transform = CGAffineTransform.identity
- isPanningDown = nil
-
- default:
- debugPrint(pan.state)
- debugPrint(pan.translation(in: self.view))
- }
- }
- }
- //MARK: UICollectionViewDataSource
- extension TSLiveWallpaperBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate {
-
- func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
- resetIndexWithOffset(scrollView)
- }
- func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
- resetIndexWithOffset(scrollView)
- }
- private func resetIndexWithOffset(_ scrollView: UIScrollView) {
- let item = Int((scrollView.contentOffset.x / scrollView.bounds.width).rounded())
- currentIndex = item
- }
-
- func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
- return dataModelArray.count
- }
-
- func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TSLiveWallpaperBrowseCell", for: indexPath) as! TSLiveWallpaperBrowseCell
-
- debugPrint("collectionView cellForItemAt=\(indexPath)")
-
- if let wallpaperModel = dataModelArray.safeObj(At: indexPath.item){
- cell.itemModel = wallpaperModel
- }
- return cell
- }
-
-
- func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
-
- debugPrint("collectionView didEndDisplaying=\(indexPath)")
-
- if let cell = cell as? TSLiveWallpaperBrowseCell {
- cell.stopPlayLive()
- }
- }
-
- func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath){
-
- debugPrint("collectionView willDisplay=\(indexPath)")
-
- if let cell = cell as? TSLiveWallpaperBrowseCell {
- cell.stratPlayLive()
- }
- }
- }
- class TSLiveWallpaperBrowseCell : TSBaseCollectionCell,PHLivePhotoViewDelegate{
-
- private let showImageViewW = k_ScreenWidth - 32
- private let livePhotoTool = LivePhoto()
- lazy var livePhotoView: PHLivePhotoView = {
- let liveIv = PHLivePhotoView()
- liveIv.delegate = self
- liveIv.contentMode = .scaleAspectFill
- liveIv.isHidden = true
- return liveIv
- }()
-
- lazy var loading: UIActivityIndicatorView = {
- let loading = UIActivityIndicatorView(style: .large)
- loading.hidesWhenStopped = true
- loading.color = .white
- return loading
- }()
-
- var itemModel:TSLiveWallpaperBrowseItemModel? {
- didSet {
-
- if let livePhoto = itemModel?.livePhoto {
- self.livePhotoView.livePhoto = livePhoto
- self.livePhotoView.isHidden = false
- self.livePhotoView.startPlayback(with: .full)
- return
- }
- if let wallpaperModel = itemModel, wallpaperModel.imageUrl.count > 0 {
- loading.startAnimating()
- var imageCachePath = ""
- var videoCachePath = ""
-
- let group = DispatchGroup()
-
- group.enter()
- TSCommonTool.downloadAndCacheFile(from: wallpaperModel.imageUrl,fileEx: "jpeg") { path, error in
- if let path = path { imageCachePath = path }
- group.leave()
- }
-
- group.enter()
- TSCommonTool.downloadAndCacheFile(from: wallpaperModel.videoUrl,fileEx: "mov") { path, error in
- if let path = path { videoCachePath = path }
- group.leave()
- }
-
-
- group.notify(queue: .main) { [self] in
- loading.stopAnimating()
-
- if imageCachePath.count == 0 || videoCachePath.count == 0 {
- return
- }
-
- let imageCacheUrl = URL(fileURLWithPath: imageCachePath)
- let videoCacheUrl = URL(fileURLWithPath: videoCachePath)
-
- livePhotoTool.generate(from: imageCacheUrl, videoURL: videoCacheUrl, progress: { (percent) in
- debugPrint(percent)
- }) { [weak self] (livePhoto, resources) in
- guard let self = self else { return }
-
-
- itemModel?.livePhoto = livePhoto
- itemModel?.livePhotoResources = resources
-
- if let livePhoto = livePhoto {
- self.livePhotoView.livePhoto = livePhoto
- self.livePhotoView.isHidden = false
- self.livePhotoView.startPlayback(with: .full)
- }else{
- debugPrint("livePhoto.generate fail")
- }
- }
- }
- }
- }
- }
-
- override func creatUI() {
- self.backgroundColor = UIColor.clear
- self.contentView.backgroundColor = UIColor.black
- contentView.addSubview(livePhotoView)
- livePhotoView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- contentView.addSubview(loading)
- loading.snp.makeConstraints { make in
- make.center.equalToSuperview()
- }
- }
-
- func livePhotoView(_ livePhotoView: PHLivePhotoView, didEndPlaybackWith playbackStyle: PHLivePhotoViewPlaybackStyle) {
- if !livePhotoView.isHidden {
- kDelayOnMainThread(1.0) {
- livePhotoView.startPlayback(with: PHLivePhotoViewPlaybackStyle.full)
- }
- }
- }
-
- func saveLivePhoto(completion: @escaping (Bool) -> Void){
- if let resources = itemModel?.livePhotoResources {
- LivePhoto.saveToLibrary(resources, completion: { (success) in
- kExecuteOnMainThread {
- if success {
- debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
- completion(true)
- }else {
- debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
- completion(false)
- }
- }
- })
- }
- }
-
- func stopPlayLive() {
- livePhotoView.isHidden = true
- livePhotoView.stopPlayback()
- }
-
- func stratPlayLive() {
- self.livePhotoView.isHidden = false
- self.livePhotoView.startPlayback(with: .full)
- }
-
- }
|