瀏覽代碼

3.6.11(1)去除之前旧项目无用的代码文件和 pod

100Years 3 周之前
父節點
當前提交
eebf3424f3
共有 59 個文件被更改,包括 15 次插入11508 次删除
  1. 0 2
      Bridging-Header.h
  2. 7 7
      Podfile
  3. 1 62
      Podfile.lock
  4. 1 353
      TSLiveWallpaper.xcodeproj/project.pbxproj
  5. 1 7
      TSLiveWallpaper/AppDelegate.swift
  6. 0 131
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditLiveEidtCell.swift
  7. 0 406
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditLiveVC.swift
  8. 0 253
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/EditorVideo/EditorVideoControlMaskView.swift
  9. 0 1101
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/EditorVideo/EditorVideoControlView.swift
  10. 0 38
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/EditorVideo/EditorVideoControlViewCell.swift
  11. 0 312
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoClipperController.swift
  12. 0 570
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoClipperView.swift
  13. 0 85
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoConfigMaker.swift
  14. 0 70
      TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoPlayerView.swift
  15. 0 74
      TSLiveWallpaper/Business/TSHomeVC/TSHomeCell.swift
  16. 0 124
      TSLiveWallpaper/Business/TSHomeVC/TSHomeVC.swift
  17. 0 54
      TSLiveWallpaper/Business/TSHomeVC/TSLiveWallpaperBrowseVC/EasyVC/TSLiveWallpaperCopyrightVC.swift
  18. 0 25
      TSLiveWallpaper/Business/TSHomeVC/TSLiveWallpaperBrowseVC/EasyVC/TSLiveWallpaperTutorialsVC.swift
  19. 0 677
      TSLiveWallpaper/Business/TSHomeVC/TSLiveWallpaperBrowseVC/TSLiveWallpaperBrowseVC.swift
  20. 0 141
      TSLiveWallpaper/Business/TSHomeVC/View/TSHomeTopBannerCell.swift
  21. 0 26
      TSLiveWallpaper/Business/TSMusic/MusicBase/GradientBackgroundModifier.swift
  22. 0 48
      TSLiveWallpaper/Business/TSMusic/MusicBase/GradientButton.swift
  23. 0 44
      TSLiveWallpaper/Business/TSMusic/MusicBase/GradientText.swift
  24. 0 17
      TSLiveWallpaper/Business/TSMusic/MusicBase/LWBaseNavigationController.swift
  25. 0 59
      TSLiveWallpaper/Business/TSMusic/MusicBase/LWBaseViewController.swift
  26. 0 293
      TSLiveWallpaper/Business/TSMusic/MusicBase/LWNavigationBar.swift
  27. 0 116
      TSLiveWallpaper/Business/TSMusic/MusicBase/SaveSuccessTipsView.swift
  28. 0 68
      TSLiveWallpaper/Business/TSMusic/MusicBase/SpacedButton.swift
  29. 5 6
      TSLiveWallpaper/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift
  30. 0 52
      TSLiveWallpaper/Business/TSRandomWallpaperVC/EasyVC/TSRandomWallpaperCopyrightVC.swift
  31. 0 30
      TSLiveWallpaper/Business/TSRandomWallpaperVC/EasyVC/TSRandomWallpaperTutorialsVC.swift
  32. 0 140
      TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperBrowseVC/TSRandomWallpaperBrowseSelectView.swift
  33. 0 433
      TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperBrowseVC/TSRandomWallpaperBrowseVC.swift
  34. 0 70
      TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperBrowseVC/TSRandomWallpaperBrowseView.swift
  35. 0 109
      TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperVC.swift
  36. 0 72
      TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperView/TSRandomWallpaperBannerCell.swift
  37. 0 73
      TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperView/TSRandomWallpaperCell.swift
  38. 0 139
      TSLiveWallpaper/Common/Ex/UICollectionView+Ex.swift
  39. 0 0
      TSLiveWallpaper/Common/TSConfig.swift
  40. 0 600
      TSLiveWallpaper/Common/ThirdParty/LivePhoto.swift
  41. 0 269
      TSLiveWallpaper/Common/ThirdParty/LivePhotoCreater.swift
  42. 0 74
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.h
  43. 0 319
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.m
  44. 0 180
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.h
  45. 0 607
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.m
  46. 0 47
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.h
  47. 0 285
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.m
  48. 0 136
      TSLiveWallpaper/Common/ThirdParty/Util/AVAssetExtension.swift
  49. 0 57
      TSLiveWallpaper/Common/ThirdParty/Util/Converter4Image.swift
  50. 0 663
      TSLiveWallpaper/Common/ThirdParty/Util/Converter4Video.swift
  51. 0 279
      TSLiveWallpaper/Common/ThirdParty/Util/LivePhotoConverter.swift
  52. 0 7
      TSLiveWallpaper/Common/ThirdParty/Util/LivePhotoUtil.h
  53. 0 168
      TSLiveWallpaper/Common/ThirdParty/Util/LivePhotoUtil.m
  54. 二進制
      TSLiveWallpaper/Common/ThirdParty/Util/metadata.mov
  55. 0 450
      TSLiveWallpaper/Common/ThirdParty/VideoRecorder.swift
  56. 0 562
      TSLiveWallpaper/Common/Tool/PhotoTools.swift
  57. 0 81
      TSLiveWallpaper/DataManger/TSHomeDataModel.swift
  58. 0 355
      TSLiveWallpaper/DataManger/TSImageDataCenter.swift
  59. 0 82
      TSLiveWallpaper/DataManger/TSRandomWallpaperModel.swift

+ 0 - 2
Bridging-Header.h

@@ -2,5 +2,3 @@
 //  Use this file to import your target's public headers that you would like to expose to Swift.
 //
 
-#import "LivePhotoUtil.h"
-#import "TYCyclePagerView.h"

+ 7 - 7
Podfile

@@ -16,13 +16,13 @@ target 'TSLiveWallpaper' do
   pod 'TYCyclePagerView'
   pod 'Alamofire'
   
-  pod 'TZImagePickerController'
-  pod 'MarqueeLabel'
-  pod 'MJRefresh'
-  pod 'KLExtension',:git=>"https://gitee.com/WanlanNeel/klextension.git"
-  pod 'KLTips',:git=>"https://gitee.com/WanlanNeel/kltips.git"
-  pod 'Localize-Swift', '~> 3.2'
-  pod "KingfisherWebP"
+#  pod 'TZImagePickerController'
+#  pod 'MarqueeLabel'
+#  pod 'MJRefresh'
+#  pod 'KLExtension',:git=>"https://gitee.com/WanlanNeel/klextension.git"
+#  pod 'KLTips',:git=>"https://gitee.com/WanlanNeel/kltips.git"
+#  pod 'Localize-Swift', '~> 3.2'
+#  pod "KingfisherWebP"
 
 
   pod 'AFNetworking',:git => "https://github.com/xlDon/AFNetworking-PrivacyInfo.git"

+ 1 - 62
Podfile.lock

@@ -29,31 +29,6 @@ PODS:
     - HXPhotoPicker/Core
   - HXPhotoPicker/Resources (5.0.3)
   - Kingfisher (7.10.0)
-  - KingfisherWebP (1.5.4):
-    - Kingfisher (~> 7.9)
-    - libwebp (>= 1.1.0)
-  - KLExtension (0.1.0)
-  - KLTips (0.1.0)
-  - libwebp (1.5.0):
-    - libwebp/demux (= 1.5.0)
-    - libwebp/mux (= 1.5.0)
-    - libwebp/sharpyuv (= 1.5.0)
-    - libwebp/webp (= 1.5.0)
-  - libwebp/demux (1.5.0):
-    - libwebp/webp
-  - libwebp/mux (1.5.0):
-    - libwebp/demux
-  - libwebp/sharpyuv (1.5.0)
-  - libwebp/webp (1.5.0):
-    - libwebp/sharpyuv
-  - Localize-Swift (3.2.0):
-    - Localize-Swift/LocalizeSwiftCore (= 3.2.0)
-    - Localize-Swift/UIKit (= 3.2.0)
-  - Localize-Swift/LocalizeSwiftCore (3.2.0)
-  - Localize-Swift/UIKit (3.2.0):
-    - Localize-Swift/LocalizeSwiftCore
-  - MarqueeLabel (4.5.0)
-  - MJRefresh (3.7.5)
   - ObjectMapper (4.2.0)
   - Realm (10.54.4):
     - Realm/Headers (= 10.54.4)
@@ -71,11 +46,6 @@ PODS:
     - SnapKit
     - SVProgressHUD
   - TYCyclePagerView (1.2.0)
-  - TZImagePickerController (3.8.8):
-    - TZImagePickerController/Basic (= 3.8.8)
-    - TZImagePickerController/Location (= 3.8.8)
-  - TZImagePickerController/Basic (3.8.8)
-  - TZImagePickerController/Location (3.8.8)
 
 DEPENDENCIES:
   - AFNetworking (from `https://github.com/xlDon/AFNetworking-PrivacyInfo.git`)
@@ -86,19 +56,12 @@ DEPENDENCIES:
   - HXPhotoPicker/Editor
   - HXPhotoPicker/Picker
   - Kingfisher (= 7.10.0)
-  - KingfisherWebP
-  - KLExtension (from `https://gitee.com/WanlanNeel/klextension.git`)
-  - KLTips (from `https://gitee.com/WanlanNeel/kltips.git`)
-  - Localize-Swift (~> 3.2)
-  - MarqueeLabel
-  - MJRefresh
   - ObjectMapper (= 4.2)
   - RealmSwift (~> 10)
   - SnapKit
   - SVProgressHUD
   - TSSmalCoacopods (from `../TSSmalCoacopods`)
   - TYCyclePagerView
-  - TZImagePickerController
 
 SPEC REPOS:
   trunk:
@@ -107,26 +70,16 @@ SPEC REPOS:
     - DynamicBlurView
     - HXPhotoPicker
     - Kingfisher
-    - KingfisherWebP
-    - libwebp
-    - Localize-Swift
-    - MarqueeLabel
-    - MJRefresh
     - ObjectMapper
     - Realm
     - RealmSwift
     - SnapKit
     - SVProgressHUD
     - TYCyclePagerView
-    - TZImagePickerController
 
 EXTERNAL SOURCES:
   AFNetworking:
     :git: https://github.com/xlDon/AFNetworking-PrivacyInfo.git
-  KLExtension:
-    :git: https://gitee.com/WanlanNeel/klextension.git
-  KLTips:
-    :git: https://gitee.com/WanlanNeel/kltips.git
   TSSmalCoacopods:
     :path: "../TSSmalCoacopods"
 
@@ -134,12 +87,6 @@ CHECKOUT OPTIONS:
   AFNetworking:
     :commit: dd04a39ae8fb760cfe62ad4c2afe55df8d81de28
     :git: https://github.com/xlDon/AFNetworking-PrivacyInfo.git
-  KLExtension:
-    :commit: 227fcc71c8057c68631a9614265bd584c48ada34
-    :git: https://gitee.com/WanlanNeel/klextension.git
-  KLTips:
-    :commit: dc38e277b3d62f753ce6c73ec62c0f8ae29c1b36
-    :git: https://gitee.com/WanlanNeel/kltips.git
 
 SPEC CHECKSUMS:
   AFNetworking: 07fdd55e08bfc815311d558d62b0f9660ef83d1e
@@ -148,13 +95,6 @@ SPEC CHECKSUMS:
   DynamicBlurView: b57e2f6aa33f85b2bcca272265162a3c7c5cc499
   HXPhotoPicker: 3250e3d7b5c1e9a35888a35f8b8abc99a18ed17f
   Kingfisher: a18f05d3b6d37d8650ee4a3e61d57a28fc6207f6
-  KingfisherWebP: 2c8999d566cce1d3fa28edb7c8a0d259938402cd
-  KLExtension: f8b2a92125ad4bbfc8920ed5e7269aefcdcaa0b3
-  KLTips: 5cf05efac78b9c813887460bebbf436582b20536
-  libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
-  Localize-Swift: 6f4475136bdb0d7b2882ea3d4ea919d70142b232
-  MarqueeLabel: 4b46d196abd253448e830cbd976f9eacc3af0849
-  MJRefresh: fdf5e979eb406a0341468932d1dfc8b7f9fce961
   ObjectMapper: 1eb41f610210777375fa806bf161dc39fb832b81
   Realm: 8b5cda39a41f17a1734da2f39c6004eb8745587a
   RealmSwift: 0b4f808fed6898f1f6c26f501f740efd80dff0b4
@@ -162,8 +102,7 @@ SPEC CHECKSUMS:
   SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
   TSSmalCoacopods: 6aa97167f0c76b16fc7d1fd1eb198bb6aece4f68
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
-  TZImagePickerController: d084a7b97c82d387e7669dd86dc9a9057500aacf
 
-PODFILE CHECKSUM: 06499bee87e2c454ffcd24fb725ea24a695b74fb
+PODFILE CHECKSUM: 19b7027a35730c08f77747b5c613c30b920ded05
 
 COCOAPODS: 1.16.2

+ 1 - 353
TSLiveWallpaper.xcodeproj/project.pbxproj

@@ -9,14 +9,6 @@
 /* Begin PBXBuildFile section */
 		059E844A164B0E39971303B9 /* Pods_TSLiveWallpaper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E33A770AEFA5810AED7219D3 /* Pods_TSLiveWallpaper.framework */; };
 		603901222DF9770A0096551E /* Flash-old-Time.png in Resources */ = {isa = PBXBuildFile; fileRef = 603901212DF9770A0096551E /* Flash-old-Time.png */; };
-		603901612DFFF0330096551E /* SpacedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 603901602DFFF0330096551E /* SpacedButton.swift */; };
-		60553FD02D3B54A400BAAD7F /* LWNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FC72D3B54A400BAAD7F /* LWNavigationBar.swift */; };
-		60553FD22D3B54A400BAAD7F /* GradientButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FCA2D3B54A400BAAD7F /* GradientButton.swift */; };
-		60553FD42D3B54A400BAAD7F /* LWBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FC82D3B54A400BAAD7F /* LWBaseViewController.swift */; };
-		60553FD62D3B54A400BAAD7F /* SaveSuccessTipsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FCB2D3B54A400BAAD7F /* SaveSuccessTipsView.swift */; };
-		60553FD72D3B54A400BAAD7F /* GradientText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FCD2D3B54A400BAAD7F /* GradientText.swift */; };
-		60553FD82D3B54A400BAAD7F /* LWBaseNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FC92D3B54A400BAAD7F /* LWBaseNavigationController.swift */; };
-		60553FD92D3B54A400BAAD7F /* GradientBackgroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FCE2D3B54A400BAAD7F /* GradientBackgroundModifier.swift */; };
 		60553FDD2D3B84E700BAAD7F /* UIScrollView+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60553FDC2D3B84E700BAAD7F /* UIScrollView+Ext.swift */; };
 		609B6EA52D6F1221007942D4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 609B6EA32D6F1221007942D4 /* Localizable.strings */; };
 		A81CA4652D15685F00A3AAC8 /* TSLaunchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4642D15685D00A3AAC8 /* TSLaunchVC.swift */; };
@@ -26,43 +18,23 @@
 		A81CA4852D1582A600A3AAC8 /* UIButton+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4842D15829E00A3AAC8 /* UIButton+Ex.swift */; };
 		A81CA48B2D15843700A3AAC8 /* TSCommonTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA48A2D15843500A3AAC8 /* TSCommonTool.swift */; };
 		A81CA48F2D15857B00A3AAC8 /* TSTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA48E2D15857900A3AAC8 /* TSTabBarController.swift */; };
-		A81CA4952D1652B500A3AAC8 /* TSEditLiveVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4942D1652B300A3AAC8 /* TSEditLiveVC.swift */; };
-		A81CA4972D1652BD00A3AAC8 /* TSRandomWallpaperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4962D1652BB00A3AAC8 /* TSRandomWallpaperVC.swift */; };
 		A81CA4992D1652C400A3AAC8 /* TSMineVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4982D1652C200A3AAC8 /* TSMineVC.swift */; };
-		A81CA49B2D1652CA00A3AAC8 /* TSHomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA49A2D1652C900A3AAC8 /* TSHomeVC.swift */; };
-		A81CA49F2D1655CE00A3AAC8 /* UICollectionView+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA49E2D1655BE00A3AAC8 /* UICollectionView+Ex.swift */; };
 		A81CA4A42D16748800A3AAC8 /* TSViewTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4A32D16748700A3AAC8 /* TSViewTool.swift */; };
 		A81CA4AA2D16943800A3AAC8 /* TSMineCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4A92D16943200A3AAC8 /* TSMineCell.swift */; };
 		A81CA4B82D16A6BD00A3AAC8 /* View+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4B72D16A6B600A3AAC8 /* View+Ex.swift */; };
-		A81CA4BA2D16B6E300A3AAC8 /* TSHomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81CA4B92D16B6DC00A3AAC8 /* TSHomeCell.swift */; };
 		A81E81632E24F05E00207EB8 /* TSFusionImageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81E81622E24F05D00207EB8 /* TSFusionImageVC.swift */; };
 		A81E81652E24F09600207EB8 /* TSAISmallUploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81E81642E24F09500207EB8 /* TSAISmallUploadView.swift */; };
 		A81E81672E25065C00207EB8 /* TSAIPhotoDetailsVC+Comparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81E81662E25065A00207EB8 /* TSAIPhotoDetailsVC+Comparison.swift */; };
-		A81F5B3C2D19087100740085 /* TSRandomWallpaperCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B3B2D19086B00740085 /* TSRandomWallpaperCell.swift */; };
-		A81F5B3E2D19088100740085 /* TSRandomWallpaperBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B3D2D19087600740085 /* TSRandomWallpaperBannerCell.swift */; };
 		A81F5B402D194EA900740085 /* UIDevice+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B3F2D194EA900740085 /* UIDevice+Extension.swift */; };
-		A81F5B442D19559C00740085 /* EditorVideoControlViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B432D19559C00740085 /* EditorVideoControlViewCell.swift */; };
-		A81F5B452D19559C00740085 /* EditorVideoControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B422D19559C00740085 /* EditorVideoControlView.swift */; };
-		A81F5B472D19562800740085 /* EditorVideoControlMaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B462D19562800740085 /* EditorVideoControlMaskView.swift */; };
 		A81F5B492D1956EA00740085 /* UIScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B482D1956E600740085 /* UIScreen.swift */; };
-		A81F5B4B2D19658300740085 /* PhotoTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B4A2D19658300740085 /* PhotoTools.swift */; };
 		A81F5B4F2D19674600740085 /* AVAsset+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B4E2D19673500740085 /* AVAsset+Ex.swift */; };
 		A81F5B522D19685900740085 /* response.json in Resources */ = {isa = PBXBuildFile; fileRef = A81F5B512D19685900740085 /* response.json */; };
-		A81F5B562D1982BF00740085 /* TSImageDataCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B552D1982A900740085 /* TSImageDataCenter.swift */; };
-		A81F5B5B2D1A5F2300740085 /* TSHomeTopBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B5A2D1A5F1800740085 /* TSHomeTopBannerCell.swift */; };
-		A81F5B5D2D1A906C00740085 /* TSHomeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B5C2D1A905800740085 /* TSHomeDataModel.swift */; };
-		A81F5B5F2D1A909300740085 /* TSRandomWallpaperModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B5E2D1A907B00740085 /* TSRandomWallpaperModel.swift */; };
-		A81F5B622D1AB17E00740085 /* TSRandomWallpaperBrowseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B612D1AB17C00740085 /* TSRandomWallpaperBrowseVC.swift */; };
 		A828E9432E03AF4E00E6A9EA /* TSAppUpdateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A828E9422E03AF4D00E6A9EA /* TSAppUpdateManager.swift */; };
 		A83946212D1D61D600ABFF0D /* TSRateUsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946202D1D61D400ABFF0D /* TSRateUsVC.swift */; };
 		A83946272D1D623800ABFF0D /* TSShareUsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946262D1D623800ABFF0D /* TSShareUsVC.swift */; };
 		A839462F2D1D64BF00ABFF0D /* TSAboutUsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A839462E2D1D64B300ABFF0D /* TSAboutUsVC.swift */; };
 		A83946312D1D66A000ABFF0D /* TSTermsServiceVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946302D1D669E00ABFF0D /* TSTermsServiceVC.swift */; };
 		A83946332D1D66A900ABFF0D /* TSPrivacyPolicyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946322D1D66A800ABFF0D /* TSPrivacyPolicyVC.swift */; };
-		A839463A2D1D6E3000ABFF0D /* TSRandomWallpaperTutorialsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946392D1D6E2F00ABFF0D /* TSRandomWallpaperTutorialsVC.swift */; };
-		A839463C2D1D6E3600ABFF0D /* TSRandomWallpaperCopyrightVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A839463B2D1D6E3500ABFF0D /* TSRandomWallpaperCopyrightVC.swift */; };
-		A839463F2D1D6FB700ABFF0D /* TSLiveWallpaperTutorialsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A839463E2D1D6FB600ABFF0D /* TSLiveWallpaperTutorialsVC.swift */; };
-		A83946432D1D701500ABFF0D /* TSLiveWallpaperCopyrightVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946422D1D701300ABFF0D /* TSLiveWallpaperCopyrightVC.swift */; };
 		A83A6A862E1FC99E0084197A /* LanguageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83A6A852E1FC9930084197A /* LanguageManager.swift */; };
 		A83A6A892E1FCF750084197A /* TSChangeLanguageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83A6A882E1FCF740084197A /* TSChangeLanguageVC.swift */; };
 		A83F28892E162343009A4975 /* TSAIListDataVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83F28882E16233B009A4975 /* TSAIListDataVM.swift */; };
@@ -83,11 +55,6 @@
 		A83F28AE2E166391009A4975 /* TSAIRemovePhotlVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83F28AD2E166390009A4975 /* TSAIRemovePhotlVC.swift */; };
 		A83F28B02E168237009A4975 /* UIView+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83F28AF2E168232009A4975 /* UIView+Ex.swift */; };
 		A8477C972D22737900DF0B93 /* TSBusinessWebVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8477C962D22737800DF0B93 /* TSBusinessWebVC.swift */; };
-		A8477C9F2D22ABDA00DF0B93 /* TSEditLiveEidtCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8477C9E2D22ABD500DF0B93 /* TSEditLiveEidtCell.swift */; };
-		A84C239A2D1E3A4300B61B55 /* GPVideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84C23962D1E3A4300B61B55 /* GPVideoPlayerView.swift */; };
-		A84C239B2D1E3A4300B61B55 /* GPVideoClipperController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84C23982D1E3A4300B61B55 /* GPVideoClipperController.swift */; };
-		A84C239C2D1E3A4300B61B55 /* GPVideoClipperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84C23972D1E3A4300B61B55 /* GPVideoClipperView.swift */; };
-		A84C239D2D1E3A4300B61B55 /* GPVideoConfigMaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84C23952D1E3A4300B61B55 /* GPVideoConfigMaker.swift */; };
 		A84C239F2D1E88CD00B61B55 /* TSFileManagerTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84C239E2D1E88C500B61B55 /* TSFileManagerTool.swift */; };
 		A864C1732E211C8C0077DADF /* TSHXPhotoPickerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A864C1722E211C810077DADF /* TSHXPhotoPickerManager.swift */; };
 		A868577C2DF819BB0089D222 /* TSDBManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868577B2DF819BA0089D222 /* TSDBManager.swift */; };
@@ -129,18 +96,6 @@
 		A87CF85A2E02AF070063CB7E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A87CF8582E02AF070063CB7E /* InfoPlist.strings */; };
 		A8884B612E2DE7A3001B41AC /* TSAIPhotoRemoveBgView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8884B602E2DE789001B41AC /* TSAIPhotoRemoveBgView.swift */; };
 		A895B5002E01370E004F9B85 /* TSTextToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A895B4FF2E01370E004F9B85 /* TSTextToastView.swift */; };
-		A895B5102E0287F2004F9B85 /* TYPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = A895B50E2E0287F2004F9B85 /* TYPageControl.m */; };
-		A895B5112E0287F2004F9B85 /* TYCyclePagerView.m in Sources */ = {isa = PBXBuildFile; fileRef = A895B50C2E0287F2004F9B85 /* TYCyclePagerView.m */; };
-		A895B5122E0287F2004F9B85 /* TYCyclePagerTransformLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = A895B50A2E0287F2004F9B85 /* TYCyclePagerTransformLayout.m */; };
-		A8C4C0982D242154003C46FC /* LivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = A858EE162D1CF49B004B680F /* LivePhoto.swift */; };
-		A8C4C0A42D24218A003C46FC /* metadata.mov in Resources */ = {isa = PBXBuildFile; fileRef = A8C4C09E2D24218A003C46FC /* metadata.mov */; };
-		A8C4C0A52D24218A003C46FC /* Converter4Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C09B2D24218A003C46FC /* Converter4Video.swift */; };
-		A8C4C0A62D24218A003C46FC /* AVAssetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C0992D24218A003C46FC /* AVAssetExtension.swift */; };
-		A8C4C0A72D24218A003C46FC /* LivePhotoUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C09D2D24218A003C46FC /* LivePhotoUtil.m */; };
-		A8C4C0A82D24218A003C46FC /* Converter4Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C09A2D24218A003C46FC /* Converter4Image.swift */; };
-		A8C4C0AB2D2427E7003C46FC /* LivePhotoConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C0AA2D2427D3003C46FC /* LivePhotoConverter.swift */; };
-		A8C4C0E62D268D02003C46FC /* LivePhotoCreater.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C0E42D268D02003C46FC /* LivePhotoCreater.swift */; };
-		A8C4C0E72D268D02003C46FC /* VideoRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C0E52D268D02003C46FC /* VideoRecorder.swift */; };
 		A8C4C0EF2D27BFF7003C46FC /* TSNetworkTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C0EE2D27BFEA003C46FC /* TSNetworkTool.swift */; };
 		A8E56BF62D1520EC003C54AF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8E56BEC2D1520EC003C54AF /* AppDelegate.swift */; };
 		A8E56BF92D1520EC003C54AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A8E56BED2D1520EC003C54AF /* Assets.xcassets */; };
@@ -182,10 +137,7 @@
 		A8F3D6552E2F2F5400DE6C9D /* ImageCompositor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F3D6542E2F2F5300DE6C9D /* ImageCompositor.swift */; };
 		A8F76C422D350A9600AA6E93 /* TSPurchaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F76C3E2D350A9600AA6E93 /* TSPurchaseManager.swift */; };
 		A8F76C4D2D3747B400AA6E93 /* TSPurchaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F76C4C2D3747AB00AA6E93 /* TSPurchaseVC.swift */; };
-		A8F778AE2D1AC12400BF55D5 /* TSRandomWallpaperBrowseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F778AD2D1AC12100BF55D5 /* TSRandomWallpaperBrowseView.swift */; };
-		A8F778B22D1BA07200BF55D5 /* TSRandomWallpaperBrowseSelectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F778B12D1BA07000BF55D5 /* TSRandomWallpaperBrowseSelectView.swift */; };
 		A8F778B42D1BB8F600BF55D5 /* PhotoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F778B32D1BB8F300BF55D5 /* PhotoManager.swift */; };
-		A8F778B72D1BE9A500BF55D5 /* TSLiveWallpaperBrowseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F778B62D1BE9A100BF55D5 /* TSLiveWallpaperBrowseVC.swift */; };
 		A8F8BCCF2E03F8BC00EF4AA6 /* TSAIUploadPhotoTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F8BCCE2E03F8BB00EF4AA6 /* TSAIUploadPhotoTextView.swift */; };
 		A8F8BCD12E03FD4200EF4AA6 /* TSAIUploadPhotoVC+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F8BCD02E03FC4E00EF4AA6 /* TSAIUploadPhotoVC+Image.swift */; };
 		A8F8BCD32E03FD5400EF4AA6 /* TSAIUploadPhotoVC+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F8BCD22E03FD4A00EF4AA6 /* TSAIUploadPhotoVC+Video.swift */; };
@@ -210,14 +162,6 @@
 
 /* Begin PBXFileReference section */
 		603901212DF9770A0096551E /* Flash-old-Time.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Flash-old-Time.png"; sourceTree = "<group>"; };
-		603901602DFFF0330096551E /* SpacedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpacedButton.swift; sourceTree = "<group>"; };
-		60553FC72D3B54A400BAAD7F /* LWNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LWNavigationBar.swift; sourceTree = "<group>"; };
-		60553FC82D3B54A400BAAD7F /* LWBaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LWBaseViewController.swift; sourceTree = "<group>"; };
-		60553FC92D3B54A400BAAD7F /* LWBaseNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LWBaseNavigationController.swift; sourceTree = "<group>"; };
-		60553FCA2D3B54A400BAAD7F /* GradientButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientButton.swift; sourceTree = "<group>"; };
-		60553FCB2D3B54A400BAAD7F /* SaveSuccessTipsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveSuccessTipsView.swift; sourceTree = "<group>"; };
-		60553FCD2D3B54A400BAAD7F /* GradientText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientText.swift; sourceTree = "<group>"; };
-		60553FCE2D3B54A400BAAD7F /* GradientBackgroundModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientBackgroundModifier.swift; sourceTree = "<group>"; };
 		60553FDC2D3B84E700BAAD7F /* UIScrollView+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Ext.swift"; sourceTree = "<group>"; };
 		609B6EA12D6F11E0007942D4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
 		609B6EA42D6F1221007942D4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -230,43 +174,23 @@
 		A81CA4842D15829E00A3AAC8 /* UIButton+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Ex.swift"; sourceTree = "<group>"; };
 		A81CA48A2D15843500A3AAC8 /* TSCommonTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSCommonTool.swift; sourceTree = "<group>"; };
 		A81CA48E2D15857900A3AAC8 /* TSTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTabBarController.swift; sourceTree = "<group>"; };
-		A81CA4942D1652B300A3AAC8 /* TSEditLiveVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSEditLiveVC.swift; sourceTree = "<group>"; };
-		A81CA4962D1652BB00A3AAC8 /* TSRandomWallpaperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperVC.swift; sourceTree = "<group>"; };
 		A81CA4982D1652C200A3AAC8 /* TSMineVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSMineVC.swift; sourceTree = "<group>"; };
-		A81CA49A2D1652C900A3AAC8 /* TSHomeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSHomeVC.swift; sourceTree = "<group>"; };
-		A81CA49E2D1655BE00A3AAC8 /* UICollectionView+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Ex.swift"; sourceTree = "<group>"; };
 		A81CA4A32D16748700A3AAC8 /* TSViewTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSViewTool.swift; sourceTree = "<group>"; };
 		A81CA4A92D16943200A3AAC8 /* TSMineCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSMineCell.swift; sourceTree = "<group>"; };
 		A81CA4B72D16A6B600A3AAC8 /* View+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Ex.swift"; sourceTree = "<group>"; };
-		A81CA4B92D16B6DC00A3AAC8 /* TSHomeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSHomeCell.swift; sourceTree = "<group>"; };
 		A81E81622E24F05D00207EB8 /* TSFusionImageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSFusionImageVC.swift; sourceTree = "<group>"; };
 		A81E81642E24F09500207EB8 /* TSAISmallUploadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAISmallUploadView.swift; sourceTree = "<group>"; };
 		A81E81662E25065A00207EB8 /* TSAIPhotoDetailsVC+Comparison.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSAIPhotoDetailsVC+Comparison.swift"; sourceTree = "<group>"; };
-		A81F5B3B2D19086B00740085 /* TSRandomWallpaperCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperCell.swift; sourceTree = "<group>"; };
-		A81F5B3D2D19087600740085 /* TSRandomWallpaperBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperBannerCell.swift; sourceTree = "<group>"; };
 		A81F5B3F2D194EA900740085 /* UIDevice+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extension.swift"; sourceTree = "<group>"; };
-		A81F5B422D19559C00740085 /* EditorVideoControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorVideoControlView.swift; sourceTree = "<group>"; };
-		A81F5B432D19559C00740085 /* EditorVideoControlViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorVideoControlViewCell.swift; sourceTree = "<group>"; };
-		A81F5B462D19562800740085 /* EditorVideoControlMaskView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorVideoControlMaskView.swift; sourceTree = "<group>"; };
 		A81F5B482D1956E600740085 /* UIScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScreen.swift; sourceTree = "<group>"; };
-		A81F5B4A2D19658300740085 /* PhotoTools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoTools.swift; sourceTree = "<group>"; };
 		A81F5B4E2D19673500740085 /* AVAsset+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVAsset+Ex.swift"; sourceTree = "<group>"; };
 		A81F5B512D19685900740085 /* response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = response.json; sourceTree = "<group>"; };
-		A81F5B552D1982A900740085 /* TSImageDataCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSImageDataCenter.swift; sourceTree = "<group>"; };
-		A81F5B5A2D1A5F1800740085 /* TSHomeTopBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSHomeTopBannerCell.swift; sourceTree = "<group>"; };
-		A81F5B5C2D1A905800740085 /* TSHomeDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSHomeDataModel.swift; sourceTree = "<group>"; };
-		A81F5B5E2D1A907B00740085 /* TSRandomWallpaperModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperModel.swift; sourceTree = "<group>"; };
-		A81F5B612D1AB17C00740085 /* TSRandomWallpaperBrowseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperBrowseVC.swift; sourceTree = "<group>"; };
 		A828E9422E03AF4D00E6A9EA /* TSAppUpdateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAppUpdateManager.swift; sourceTree = "<group>"; };
 		A83946202D1D61D400ABFF0D /* TSRateUsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRateUsVC.swift; sourceTree = "<group>"; };
 		A83946262D1D623800ABFF0D /* TSShareUsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSShareUsVC.swift; sourceTree = "<group>"; };
 		A839462E2D1D64B300ABFF0D /* TSAboutUsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAboutUsVC.swift; sourceTree = "<group>"; };
 		A83946302D1D669E00ABFF0D /* TSTermsServiceVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTermsServiceVC.swift; sourceTree = "<group>"; };
 		A83946322D1D66A800ABFF0D /* TSPrivacyPolicyVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPrivacyPolicyVC.swift; sourceTree = "<group>"; };
-		A83946392D1D6E2F00ABFF0D /* TSRandomWallpaperTutorialsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperTutorialsVC.swift; sourceTree = "<group>"; };
-		A839463B2D1D6E3500ABFF0D /* TSRandomWallpaperCopyrightVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperCopyrightVC.swift; sourceTree = "<group>"; };
-		A839463E2D1D6FB600ABFF0D /* TSLiveWallpaperTutorialsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSLiveWallpaperTutorialsVC.swift; sourceTree = "<group>"; };
-		A83946422D1D701300ABFF0D /* TSLiveWallpaperCopyrightVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSLiveWallpaperCopyrightVC.swift; sourceTree = "<group>"; };
 		A83A6A852E1FC9930084197A /* LanguageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageManager.swift; sourceTree = "<group>"; };
 		A83A6A882E1FCF740084197A /* TSChangeLanguageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChangeLanguageVC.swift; sourceTree = "<group>"; };
 		A83F28882E16233B009A4975 /* TSAIListDataVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListDataVM.swift; sourceTree = "<group>"; };
@@ -287,13 +211,7 @@
 		A83F28AD2E166390009A4975 /* TSAIRemovePhotlVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIRemovePhotlVC.swift; sourceTree = "<group>"; };
 		A83F28AF2E168232009A4975 /* UIView+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Ex.swift"; sourceTree = "<group>"; };
 		A8477C962D22737800DF0B93 /* TSBusinessWebVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBusinessWebVC.swift; sourceTree = "<group>"; };
-		A8477C9E2D22ABD500DF0B93 /* TSEditLiveEidtCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSEditLiveEidtCell.swift; sourceTree = "<group>"; };
-		A84C23952D1E3A4300B61B55 /* GPVideoConfigMaker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPVideoConfigMaker.swift; sourceTree = "<group>"; };
-		A84C23962D1E3A4300B61B55 /* GPVideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPVideoPlayerView.swift; sourceTree = "<group>"; };
-		A84C23972D1E3A4300B61B55 /* GPVideoClipperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPVideoClipperView.swift; sourceTree = "<group>"; };
-		A84C23982D1E3A4300B61B55 /* GPVideoClipperController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPVideoClipperController.swift; sourceTree = "<group>"; };
 		A84C239E2D1E88C500B61B55 /* TSFileManagerTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSFileManagerTool.swift; sourceTree = "<group>"; };
-		A858EE162D1CF49B004B680F /* LivePhoto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LivePhoto.swift; sourceTree = "<group>"; };
 		A864C1622E20C3850077DADF /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
 		A864C1632E20C3850077DADF /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		A864C1642E20C3860077DADF /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -353,22 +271,7 @@
 		A895B4FF2E01370E004F9B85 /* TSTextToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextToastView.swift; sourceTree = "<group>"; };
 		A895B5012E025020004F9B85 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
 		A895B5022E025020004F9B85 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
-		A895B5092E0287F2004F9B85 /* TYCyclePagerTransformLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TYCyclePagerTransformLayout.h; sourceTree = "<group>"; };
-		A895B50A2E0287F2004F9B85 /* TYCyclePagerTransformLayout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TYCyclePagerTransformLayout.m; sourceTree = "<group>"; };
-		A895B50B2E0287F2004F9B85 /* TYCyclePagerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TYCyclePagerView.h; sourceTree = "<group>"; };
-		A895B50C2E0287F2004F9B85 /* TYCyclePagerView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TYCyclePagerView.m; sourceTree = "<group>"; };
-		A895B50D2E0287F2004F9B85 /* TYPageControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TYPageControl.h; sourceTree = "<group>"; };
-		A895B50E2E0287F2004F9B85 /* TYPageControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TYPageControl.m; sourceTree = "<group>"; };
-		A8C4C0992D24218A003C46FC /* AVAssetExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVAssetExtension.swift; sourceTree = "<group>"; };
-		A8C4C09A2D24218A003C46FC /* Converter4Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Converter4Image.swift; sourceTree = "<group>"; };
-		A8C4C09B2D24218A003C46FC /* Converter4Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Converter4Video.swift; sourceTree = "<group>"; };
-		A8C4C09C2D24218A003C46FC /* LivePhotoUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LivePhotoUtil.h; sourceTree = "<group>"; };
-		A8C4C09D2D24218A003C46FC /* LivePhotoUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LivePhotoUtil.m; sourceTree = "<group>"; };
-		A8C4C09E2D24218A003C46FC /* metadata.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = metadata.mov; sourceTree = "<group>"; };
 		A8C4C0A92D242204003C46FC /* Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
-		A8C4C0AA2D2427D3003C46FC /* LivePhotoConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LivePhotoConverter.swift; sourceTree = "<group>"; };
-		A8C4C0E42D268D02003C46FC /* LivePhotoCreater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LivePhotoCreater.swift; sourceTree = "<group>"; };
-		A8C4C0E52D268D02003C46FC /* VideoRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRecorder.swift; sourceTree = "<group>"; };
 		A8C4C0EE2D27BFEA003C46FC /* TSNetworkTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSNetworkTool.swift; sourceTree = "<group>"; };
 		A8E56BD42D1520DD003C54AF /* TSLiveWallpaper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TSLiveWallpaper.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		A8E56BEC2D1520EC003C54AF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -412,10 +315,7 @@
 		A8F3D6542E2F2F5300DE6C9D /* ImageCompositor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCompositor.swift; sourceTree = "<group>"; };
 		A8F76C3E2D350A9600AA6E93 /* TSPurchaseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchaseManager.swift; sourceTree = "<group>"; };
 		A8F76C4C2D3747AB00AA6E93 /* TSPurchaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchaseVC.swift; sourceTree = "<group>"; };
-		A8F778AD2D1AC12100BF55D5 /* TSRandomWallpaperBrowseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperBrowseView.swift; sourceTree = "<group>"; };
-		A8F778B12D1BA07000BF55D5 /* TSRandomWallpaperBrowseSelectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperBrowseSelectView.swift; sourceTree = "<group>"; };
 		A8F778B32D1BB8F300BF55D5 /* PhotoManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoManager.swift; sourceTree = "<group>"; };
-		A8F778B62D1BE9A100BF55D5 /* TSLiveWallpaperBrowseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSLiveWallpaperBrowseVC.swift; sourceTree = "<group>"; };
 		A8F8BCCE2E03F8BB00EF4AA6 /* TSAIUploadPhotoTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIUploadPhotoTextView.swift; sourceTree = "<group>"; };
 		A8F8BCD02E03FC4E00EF4AA6 /* TSAIUploadPhotoVC+Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSAIUploadPhotoVC+Image.swift"; sourceTree = "<group>"; };
 		A8F8BCD22E03FD4A00EF4AA6 /* TSAIUploadPhotoVC+Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSAIUploadPhotoVC+Video.swift"; sourceTree = "<group>"; };
@@ -470,29 +370,6 @@
 			path = Pods;
 			sourceTree = "<group>";
 		};
-		60553F022D3B4DF800BAAD7F /* TSMusic */ = {
-			isa = PBXGroup;
-			children = (
-				60553FCF2D3B54A400BAAD7F /* MusicBase */,
-			);
-			path = TSMusic;
-			sourceTree = "<group>";
-		};
-		60553FCF2D3B54A400BAAD7F /* MusicBase */ = {
-			isa = PBXGroup;
-			children = (
-				603901602DFFF0330096551E /* SpacedButton.swift */,
-				60553FC72D3B54A400BAAD7F /* LWNavigationBar.swift */,
-				60553FC82D3B54A400BAAD7F /* LWBaseViewController.swift */,
-				60553FC92D3B54A400BAAD7F /* LWBaseNavigationController.swift */,
-				60553FCA2D3B54A400BAAD7F /* GradientButton.swift */,
-				60553FCB2D3B54A400BAAD7F /* SaveSuccessTipsView.swift */,
-				60553FCD2D3B54A400BAAD7F /* GradientText.swift */,
-				60553FCE2D3B54A400BAAD7F /* GradientBackgroundModifier.swift */,
-			);
-			path = MusicBase;
-			sourceTree = "<group>";
-		};
 		606372D62D545E55005C82CF /* Example */ = {
 			isa = PBXGroup;
 			children = (
@@ -512,12 +389,12 @@
 		A81CA4662D156A8100A3AAC8 /* Common */ = {
 			isa = PBXGroup;
 			children = (
+				A81CA47E2D15789A00A3AAC8 /* TSConfig.swift */,
 				A8FD8F3A2DFC0A63008CAACF /* SwiftUI */,
 				A86857C12DF926EB0089D222 /* TSPhotoSizeHelper.swift */,
 				A86857A52DF920400089D222 /* ViewTool */,
 				A86857832DF81B510089D222 /* TSNetWork */,
 				A8F76C402D350A9600AA6E93 /* Purchase */,
-				A858EE182D1CF635004B680F /* ThirdParty */,
 				A81CA4882D15840F00A3AAC8 /* Tool */,
 				A81CA4752D15778800A3AAC8 /* Ex */,
 				A81CA46C2D156C6800A3AAC8 /* GlobalImports */,
@@ -540,7 +417,6 @@
 				A86857C32DF92AE30089D222 /* UIFont+Ex.swift */,
 				A81F5B4E2D19673500740085 /* AVAsset+Ex.swift */,
 				A81CA4B72D16A6B600A3AAC8 /* View+Ex.swift */,
-				A81CA49E2D1655BE00A3AAC8 /* UICollectionView+Ex.swift */,
 				A81F5B3F2D194EA900740085 /* UIDevice+Extension.swift */,
 				A81CA4822D157F5200A3AAC8 /* UIImageView+Ex.swift */,
 				A81CA4842D15829E00A3AAC8 /* UIButton+Ex.swift */,
@@ -550,25 +426,6 @@
 			path = Ex;
 			sourceTree = "<group>";
 		};
-		A81CA47C2D15787D00A3AAC8 /* DataManger */ = {
-			isa = PBXGroup;
-			children = (
-				A81F5B552D1982A900740085 /* TSImageDataCenter.swift */,
-				A81F5B5C2D1A905800740085 /* TSHomeDataModel.swift */,
-				A81F5B5E2D1A907B00740085 /* TSRandomWallpaperModel.swift */,
-				A81CA47D2D15788C00A3AAC8 /* Config */,
-			);
-			path = DataManger;
-			sourceTree = "<group>";
-		};
-		A81CA47D2D15788C00A3AAC8 /* Config */ = {
-			isa = PBXGroup;
-			children = (
-				A81CA47E2D15789A00A3AAC8 /* TSConfig.swift */,
-			);
-			path = Config;
-			sourceTree = "<group>";
-		};
 		A81CA4882D15840F00A3AAC8 /* Tool */ = {
 			isa = PBXGroup;
 			children = (
@@ -577,7 +434,6 @@
 				A8F8BCD92E040D8100EF4AA6 /* TSDownloadManager.swift */,
 				A8C4C0EE2D27BFEA003C46FC /* TSNetworkTool.swift */,
 				A84C239E2D1E88C500B61B55 /* TSFileManagerTool.swift */,
-				A81F5B4A2D19658300740085 /* PhotoTools.swift */,
 				A81CA4892D15841600A3AAC8 /* TSCommonTool */,
 			);
 			path = Tool;
@@ -598,13 +454,9 @@
 				A86857AD2DF9218C0089D222 /* General */,
 				A86857A92DF9210D0089D222 /* TSAIListVC */,
 				A868578D2DF845D00089D222 /* BusinessView */,
-				60553F022D3B4DF800BAAD7F /* TSMusic */,
 				A8F76C3A2D35022300AA6E93 /* TSPurchaseMembershipVC */,
 				A8477C952D2272FB00DF0B93 /* TSBusinessWebVC */,
-				A81CA4932D16527E00A3AAC8 /* TSEditLiveVC */,
-				A81CA4922D16525C00A3AAC8 /* TSRandomWallpaperVC */,
 				A81CA4912D16521300A3AAC8 /* TSMineVC */,
-				A81CA4902D16520500A3AAC8 /* TSHomeVC */,
 				A81CA48D2D15855B00A3AAC8 /* TSTabBarController */,
 			);
 			path = Business;
@@ -618,17 +470,6 @@
 			path = TSTabBarController;
 			sourceTree = "<group>";
 		};
-		A81CA4902D16520500A3AAC8 /* TSHomeVC */ = {
-			isa = PBXGroup;
-			children = (
-				A8F778B52D1BE98D00BF55D5 /* TSLiveWallpaperBrowseVC */,
-				A81F5B572D1A5F0100740085 /* View */,
-				A81CA49A2D1652C900A3AAC8 /* TSHomeVC.swift */,
-				A81CA4B92D16B6DC00A3AAC8 /* TSHomeCell.swift */,
-			);
-			path = TSHomeVC;
-			sourceTree = "<group>";
-		};
 		A81CA4912D16521300A3AAC8 /* TSMineVC */ = {
 			isa = PBXGroup;
 			children = (
@@ -642,27 +483,6 @@
 			path = TSMineVC;
 			sourceTree = "<group>";
 		};
-		A81CA4922D16525C00A3AAC8 /* TSRandomWallpaperVC */ = {
-			isa = PBXGroup;
-			children = (
-				A83946382D1D6DEA00ABFF0D /* EasyVC */,
-				A81F5B602D1AB14700740085 /* TSRandomWallpaperBrowseVC */,
-				A81F5B3A2D19085F00740085 /* TSRandomWallpaperView */,
-				A81CA4962D1652BB00A3AAC8 /* TSRandomWallpaperVC.swift */,
-			);
-			path = TSRandomWallpaperVC;
-			sourceTree = "<group>";
-		};
-		A81CA4932D16527E00A3AAC8 /* TSEditLiveVC */ = {
-			isa = PBXGroup;
-			children = (
-				A83946442D1D7C2B00ABFF0D /* TSEditVideoVC */,
-				A81CA4942D1652B300A3AAC8 /* TSEditLiveVC.swift */,
-				A8477C9E2D22ABD500DF0B93 /* TSEditLiveEidtCell.swift */,
-			);
-			path = TSEditLiveVC;
-			sourceTree = "<group>";
-		};
 		A81CA4A22D16747900A3AAC8 /* TSViewTool */ = {
 			isa = PBXGroup;
 			children = (
@@ -705,25 +525,6 @@
 			path = TSFusionImageVC;
 			sourceTree = "<group>";
 		};
-		A81F5B3A2D19085F00740085 /* TSRandomWallpaperView */ = {
-			isa = PBXGroup;
-			children = (
-				A81F5B3D2D19087600740085 /* TSRandomWallpaperBannerCell.swift */,
-				A81F5B3B2D19086B00740085 /* TSRandomWallpaperCell.swift */,
-			);
-			path = TSRandomWallpaperView;
-			sourceTree = "<group>";
-		};
-		A81F5B412D19558E00740085 /* EditorVideo */ = {
-			isa = PBXGroup;
-			children = (
-				A81F5B462D19562800740085 /* EditorVideoControlMaskView.swift */,
-				A81F5B422D19559C00740085 /* EditorVideoControlView.swift */,
-				A81F5B432D19559C00740085 /* EditorVideoControlViewCell.swift */,
-			);
-			path = EditorVideo;
-			sourceTree = "<group>";
-		};
 		A81F5B502D19684D00740085 /* Json */ = {
 			isa = PBXGroup;
 			children = (
@@ -732,24 +533,6 @@
 			path = Json;
 			sourceTree = "<group>";
 		};
-		A81F5B572D1A5F0100740085 /* View */ = {
-			isa = PBXGroup;
-			children = (
-				A81F5B5A2D1A5F1800740085 /* TSHomeTopBannerCell.swift */,
-			);
-			path = View;
-			sourceTree = "<group>";
-		};
-		A81F5B602D1AB14700740085 /* TSRandomWallpaperBrowseVC */ = {
-			isa = PBXGroup;
-			children = (
-				A8F778B12D1BA07000BF55D5 /* TSRandomWallpaperBrowseSelectView.swift */,
-				A8F778AD2D1AC12100BF55D5 /* TSRandomWallpaperBrowseView.swift */,
-				A81F5B612D1AB17C00740085 /* TSRandomWallpaperBrowseVC.swift */,
-			);
-			path = TSRandomWallpaperBrowseVC;
-			sourceTree = "<group>";
-		};
 		A828E9412E03AF3200E6A9EA /* TSAppUpdateManager */ = {
 			isa = PBXGroup;
 			children = (
@@ -778,33 +561,6 @@
 			path = CellVC;
 			sourceTree = "<group>";
 		};
-		A83946382D1D6DEA00ABFF0D /* EasyVC */ = {
-			isa = PBXGroup;
-			children = (
-				A83946392D1D6E2F00ABFF0D /* TSRandomWallpaperTutorialsVC.swift */,
-				A839463B2D1D6E3500ABFF0D /* TSRandomWallpaperCopyrightVC.swift */,
-			);
-			path = EasyVC;
-			sourceTree = "<group>";
-		};
-		A839463D2D1D6F9400ABFF0D /* EasyVC */ = {
-			isa = PBXGroup;
-			children = (
-				A839463E2D1D6FB600ABFF0D /* TSLiveWallpaperTutorialsVC.swift */,
-				A83946422D1D701300ABFF0D /* TSLiveWallpaperCopyrightVC.swift */,
-			);
-			path = EasyVC;
-			sourceTree = "<group>";
-		};
-		A83946442D1D7C2B00ABFF0D /* TSEditVideoVC */ = {
-			isa = PBXGroup;
-			children = (
-				A84C23992D1E3A4300B61B55 /* GPVideoClipper */,
-				A81F5B412D19558E00740085 /* EditorVideo */,
-			);
-			path = TSEditVideoVC;
-			sourceTree = "<group>";
-		};
 		A83A6A872E1FCF680084197A /* TSChangeLanguageVC */ = {
 			isa = PBXGroup;
 			children = (
@@ -868,29 +624,6 @@
 			path = TSBusinessWebVC;
 			sourceTree = "<group>";
 		};
-		A84C23992D1E3A4300B61B55 /* GPVideoClipper */ = {
-			isa = PBXGroup;
-			children = (
-				A84C23952D1E3A4300B61B55 /* GPVideoConfigMaker.swift */,
-				A84C23962D1E3A4300B61B55 /* GPVideoPlayerView.swift */,
-				A84C23972D1E3A4300B61B55 /* GPVideoClipperView.swift */,
-				A84C23982D1E3A4300B61B55 /* GPVideoClipperController.swift */,
-			);
-			path = GPVideoClipper;
-			sourceTree = "<group>";
-		};
-		A858EE182D1CF635004B680F /* ThirdParty */ = {
-			isa = PBXGroup;
-			children = (
-				A895B50F2E0287F2004F9B85 /* TYCyclePagerView */,
-				A8C4C0E42D268D02003C46FC /* LivePhotoCreater.swift */,
-				A8C4C0E52D268D02003C46FC /* VideoRecorder.swift */,
-				A8C4C0A12D24218A003C46FC /* Util */,
-				A858EE162D1CF49B004B680F /* LivePhoto.swift */,
-			);
-			path = ThirdParty;
-			sourceTree = "<group>";
-		};
 		A868577A2DF819AA0089D222 /* TSDBManager */ = {
 			isa = PBXGroup;
 			children = (
@@ -1084,33 +817,6 @@
 			path = View;
 			sourceTree = "<group>";
 		};
-		A895B50F2E0287F2004F9B85 /* TYCyclePagerView */ = {
-			isa = PBXGroup;
-			children = (
-				A895B5092E0287F2004F9B85 /* TYCyclePagerTransformLayout.h */,
-				A895B50A2E0287F2004F9B85 /* TYCyclePagerTransformLayout.m */,
-				A895B50B2E0287F2004F9B85 /* TYCyclePagerView.h */,
-				A895B50C2E0287F2004F9B85 /* TYCyclePagerView.m */,
-				A895B50D2E0287F2004F9B85 /* TYPageControl.h */,
-				A895B50E2E0287F2004F9B85 /* TYPageControl.m */,
-			);
-			path = TYCyclePagerView;
-			sourceTree = "<group>";
-		};
-		A8C4C0A12D24218A003C46FC /* Util */ = {
-			isa = PBXGroup;
-			children = (
-				A8C4C0AA2D2427D3003C46FC /* LivePhotoConverter.swift */,
-				A8C4C0992D24218A003C46FC /* AVAssetExtension.swift */,
-				A8C4C09A2D24218A003C46FC /* Converter4Image.swift */,
-				A8C4C09B2D24218A003C46FC /* Converter4Video.swift */,
-				A8C4C09C2D24218A003C46FC /* LivePhotoUtil.h */,
-				A8C4C09D2D24218A003C46FC /* LivePhotoUtil.m */,
-				A8C4C09E2D24218A003C46FC /* metadata.mov */,
-			);
-			path = Util;
-			sourceTree = "<group>";
-		};
 		A8E56BCB2D1520DD003C54AF = {
 			isa = PBXGroup;
 			children = (
@@ -1136,7 +842,6 @@
 				A86857802DF81AC20089D222 /* Data */,
 				A81CA4B12D1695F300A3AAC8 /* Resource */,
 				A81CA48C2D15855300A3AAC8 /* Business */,
-				A81CA47C2D15787D00A3AAC8 /* DataManger */,
 				A81CA4662D156A8100A3AAC8 /* Common */,
 				A81CA45F2D1567CD00A3AAC8 /* LaunchVC */,
 				A8E56BEC2D1520EC003C54AF /* AppDelegate.swift */,
@@ -1237,15 +942,6 @@
 			path = Purchase;
 			sourceTree = "<group>";
 		};
-		A8F778B52D1BE98D00BF55D5 /* TSLiveWallpaperBrowseVC */ = {
-			isa = PBXGroup;
-			children = (
-				A8F778B62D1BE9A100BF55D5 /* TSLiveWallpaperBrowseVC.swift */,
-				A839463D2D1D6F9400ABFF0D /* EasyVC */,
-			);
-			path = TSLiveWallpaperBrowseVC;
-			sourceTree = "<group>";
-		};
 		A8F8BCCD2E03F88700EF4AA6 /* View */ = {
 			isa = PBXGroup;
 			children = (
@@ -1391,7 +1087,6 @@
 			files = (
 				603901222DF9770A0096551E /* Flash-old-Time.png in Resources */,
 				A87CF85A2E02AF070063CB7E /* InfoPlist.strings in Resources */,
-				A8C4C0A42D24218A003C46FC /* metadata.mov in Resources */,
 				A86857D72DF983620089D222 /* generat_loading.gif in Resources */,
 				A86857C62DF92BE70089D222 /* ZillaSlab-Bold.ttf in Resources */,
 				609B6EA52D6F1221007942D4 /* Localizable.strings in Resources */,
@@ -1495,44 +1190,27 @@
 				A8EE92D02DFFF2860077DFFD /* TSBaseOperationQueue.swift in Sources */,
 				A8FD8F412DFC138A008CAACF /* TYCycleImageComparisonView.swift in Sources */,
 				A83F28892E162343009A4975 /* TSAIListDataVM.swift in Sources */,
-				A8C4C0E62D268D02003C46FC /* LivePhotoCreater.swift in Sources */,
 				A8EB1A3E2E2F879C001F58D7 /* TSAIListStyleMoreVC.swift in Sources */,
 				A83F288D2E162B19009A4975 /* TSAILIstFullCardCell.swift in Sources */,
 				A8EB1A322E2F716A001F58D7 /* TSImagesComparisonView.swift in Sources */,
-				A8C4C0E72D268D02003C46FC /* VideoRecorder.swift in Sources */,
 				A8F76C4D2D3747B400AA6E93 /* TSPurchaseVC.swift in Sources */,
 				A895B5002E01370E004F9B85 /* TSTextToastView.swift in Sources */,
-				A81F5B5B2D1A5F2300740085 /* TSHomeTopBannerCell.swift in Sources */,
 				A83F288F2E162B7C009A4975 /* TSAILIstStyleMoreCell.swift in Sources */,
 				A81E81672E25065C00207EB8 /* TSAIPhotoDetailsVC+Comparison.swift in Sources */,
 				A83946312D1D66A000ABFF0D /* TSTermsServiceVC.swift in Sources */,
 				A8F8BCD52E03FE5000EF4AA6 /* TSAIUploadPhotoVC+View.swift in Sources */,
-				A8C4C0982D242154003C46FC /* LivePhoto.swift in Sources */,
-				A81F5B472D19562800740085 /* EditorVideoControlMaskView.swift in Sources */,
 				A81CA4AA2D16943800A3AAC8 /* TSMineCell.swift in Sources */,
 				A83946212D1D61D600ABFF0D /* TSRateUsVC.swift in Sources */,
 				A81F5B4F2D19674600740085 /* AVAsset+Ex.swift in Sources */,
 				A8E56BF62D1520EC003C54AF /* AppDelegate.swift in Sources */,
 				A8F778B42D1BB8F600BF55D5 /* PhotoManager.swift in Sources */,
 				A83A6A862E1FC99E0084197A /* LanguageManager.swift in Sources */,
-				60553FD02D3B54A400BAAD7F /* LWNavigationBar.swift in Sources */,
-				60553FD22D3B54A400BAAD7F /* GradientButton.swift in Sources */,
-				60553FD42D3B54A400BAAD7F /* LWBaseViewController.swift in Sources */,
 				A8F3D6552E2F2F5400DE6C9D /* ImageCompositor.swift in Sources */,
 				A8F3D64D2E2E399600DE6C9D /* TSAIPhotoRemoveVC.swift in Sources */,
-				60553FD62D3B54A400BAAD7F /* SaveSuccessTipsView.swift in Sources */,
-				60553FD72D3B54A400BAAD7F /* GradientText.swift in Sources */,
-				60553FD82D3B54A400BAAD7F /* LWBaseNavigationController.swift in Sources */,
 				A8F8BCE62E04F62400EF4AA6 /* TSAIListPhotoGeneratorModel.swift in Sources */,
-				60553FD92D3B54A400BAAD7F /* GradientBackgroundModifier.swift in Sources */,
-				A895B5102E0287F2004F9B85 /* TYPageControl.m in Sources */,
-				A895B5112E0287F2004F9B85 /* TYCyclePagerView.m in Sources */,
-				A895B5122E0287F2004F9B85 /* TYCyclePagerTransformLayout.m in Sources */,
 				A8FD8F432DFC1656008CAACF /* TSImageComparisonView.swift in Sources */,
 				A868579E2DF915E90089D222 /* TSPurchaseBusiness.swift in Sources */,
 				A83F28B02E168237009A4975 /* UIView+Ex.swift in Sources */,
-				A81F5B5D2D1A906C00740085 /* TSHomeDataModel.swift in Sources */,
-				A81CA49B2D1652CA00A3AAC8 /* TSHomeVC.swift in Sources */,
 				A8F8BCDA2E040D8100EF4AA6 /* TSDownloadManager.swift in Sources */,
 				A86857B02DF921970089D222 /* TSAppBtnView.swift in Sources */,
 				A81CA4B82D16A6BD00A3AAC8 /* View+Ex.swift in Sources */,
@@ -1541,21 +1219,14 @@
 				A8EE92C42DFFC5830077DFFD /* TSBootCell.swift in Sources */,
 				A81CA4852D1582A600A3AAC8 /* UIButton+Ex.swift in Sources */,
 				A81CA47F2D15789C00A3AAC8 /* TSConfig.swift in Sources */,
-				A81CA49F2D1655CE00A3AAC8 /* UICollectionView+Ex.swift in Sources */,
-				A81CA4BA2D16B6E300A3AAC8 /* TSHomeCell.swift in Sources */,
 				A87CF8542E029B450063CB7E /* TSAIPhotoDetailsBrowserCell.swift in Sources */,
 				A864C1732E211C8C0077DADF /* TSHXPhotoPickerManager.swift in Sources */,
-				A8F778B22D1BA07200BF55D5 /* TSRandomWallpaperBrowseSelectView.swift in Sources */,
-				A8477C9F2D22ABDA00DF0B93 /* TSEditLiveEidtCell.swift in Sources */,
 				A81CA4652D15685F00A3AAC8 /* TSLaunchVC.swift in Sources */,
 				A83F28A92E165B1D009A4975 /* TSAIUploadPhotoVC+Remove.swift in Sources */,
 				A8F8BCEB2E0501DC00EF4AA6 /* TSAppUpdateAlertVC.swift in Sources */,
 				A81F5B402D194EA900740085 /* UIDevice+Extension.swift in Sources */,
-				A8F778AE2D1AC12400BF55D5 /* TSRandomWallpaperBrowseView.swift in Sources */,
-				A81F5B4B2D19658300740085 /* PhotoTools.swift in Sources */,
 				A83946272D1D623800ABFF0D /* TSShareUsVC.swift in Sources */,
 				A81CA48B2D15843700A3AAC8 /* TSCommonTool.swift in Sources */,
-				A84C239A2D1E3A4300B61B55 /* GPVideoPlayerView.swift in Sources */,
 				A868577E2DF81A940089D222 /* TSDBActionInfoModel.swift in Sources */,
 				A8EE92C22DFFC54C0077DFFD /* TSBootModel.swift in Sources */,
 				A86857B72DF9258D0089D222 /* TSAIUploadPhotoVC.swift in Sources */,
@@ -1587,11 +1258,6 @@
 				A8F8BCD32E03FD5400EF4AA6 /* TSAIUploadPhotoVC+Video.swift in Sources */,
 				A86857942DF845F60089D222 /* TSGeneratorView.swift in Sources */,
 				A868578C2DF843F90089D222 /* TSRealmManager.swift in Sources */,
-				A84C239B2D1E3A4300B61B55 /* GPVideoClipperController.swift in Sources */,
-				A84C239C2D1E3A4300B61B55 /* GPVideoClipperView.swift in Sources */,
-				A84C239D2D1E3A4300B61B55 /* GPVideoConfigMaker.swift in Sources */,
-				A839463C2D1D6E3600ABFF0D /* TSRandomWallpaperCopyrightVC.swift in Sources */,
-				A81CA4952D1652B500A3AAC8 /* TSEditLiveVC.swift in Sources */,
 				A8EE92D42DFFFFAD0077DFFD /* TSAIListVM.swift in Sources */,
 				A86857D12DF977980089D222 /* TSAIListPhotoGeneratorVM.swift in Sources */,
 				A8E590392DFFAE4400C2533F /* TSBootVC.swift in Sources */,
@@ -1600,43 +1266,25 @@
 				A86857982DF846FE0089D222 /* TSDynamicBlurView.swift in Sources */,
 				A83946332D1D66A900ABFF0D /* TSPrivacyPolicyVC.swift in Sources */,
 				A86857C22DF926ED0089D222 /* TSPhotoSizeHelper.swift in Sources */,
-				A839463A2D1D6E3000ABFF0D /* TSRandomWallpaperTutorialsVC.swift in Sources */,
 				A84C239F2D1E88CD00B61B55 /* TSFileManagerTool.swift in Sources */,
 				A8FD8F3C2DFC0A72008CAACF /* HighlightedText.swift in Sources */,
 				A86857D52DF97A2A0089D222 /* TSAIExpandChangeView.swift in Sources */,
-				A81F5B562D1982BF00740085 /* TSImageDataCenter.swift in Sources */,
 				A86857A82DF9204B0089D222 /* TSPhotoPickerManager.swift in Sources */,
 				A839462F2D1D64BF00ABFF0D /* TSAboutUsVC.swift in Sources */,
 				A8477C972D22737900DF0B93 /* TSBusinessWebVC.swift in Sources */,
-				A81CA4972D1652BD00A3AAC8 /* TSRandomWallpaperVC.swift in Sources */,
 				A8F8BCD82E0407C800EF4AA6 /* TSAIListVideoPlayerVC.swift in Sources */,
 				A8EB1A342E2F7327001F58D7 /* TSAIListHeaderView.swift in Sources */,
-				A81F5B622D1AB17E00740085 /* TSRandomWallpaperBrowseVC.swift in Sources */,
-				A839463F2D1D6FB700ABFF0D /* TSLiveWallpaperTutorialsVC.swift in Sources */,
 				A8EE92C02DFFC3B50077DFFD /* TSImageProComparisonView.swift in Sources */,
 				A86857C42DF92AEB0089D222 /* UIFont+Ex.swift in Sources */,
 				A86857A12DF91EB90089D222 /* TSAIListVC.swift in Sources */,
 				A83F28AE2E166391009A4975 /* TSAIRemovePhotlVC.swift in Sources */,
 				A8F8BCE32E0423B100EF4AA6 /* TSAIPhotoDetailsVC+View.swift in Sources */,
-				A81F5B5F2D1A909300740085 /* TSRandomWallpaperModel.swift in Sources */,
-				A8F778B72D1BE9A500BF55D5 /* TSLiveWallpaperBrowseVC.swift in Sources */,
 				A81CA48F2D15857B00A3AAC8 /* TSTabBarController.swift in Sources */,
-				A8C4C0A52D24218A003C46FC /* Converter4Video.swift in Sources */,
-				A8C4C0A62D24218A003C46FC /* AVAssetExtension.swift in Sources */,
 				A81E81652E24F09600207EB8 /* TSAISmallUploadView.swift in Sources */,
-				A8C4C0A72D24218A003C46FC /* LivePhotoUtil.m in Sources */,
 				A8F8BCDE2E0420EE00EF4AA6 /* TSAIPhotoDetailsVC+Image.swift in Sources */,
 				A86857AC2DF921160089D222 /* TSAIListHintBaseVC.swift in Sources */,
-				A8C4C0A82D24218A003C46FC /* Converter4Image.swift in Sources */,
-				A83946432D1D701500ABFF0D /* TSLiveWallpaperCopyrightVC.swift in Sources */,
 				A8F8BCDC2E040D9E00EF4AA6 /* TSBusinessFileManager.swift in Sources */,
-				A8C4C0AB2D2427E7003C46FC /* LivePhotoConverter.swift in Sources */,
 				A8F3D6532E2E540C00DE6C9D /* TSColorPickerVC.swift in Sources */,
-				A81F5B3C2D19087100740085 /* TSRandomWallpaperCell.swift in Sources */,
-				A81F5B442D19559C00740085 /* EditorVideoControlViewCell.swift in Sources */,
-				603901612DFFF0330096551E /* SpacedButton.swift in Sources */,
-				A81F5B452D19559C00740085 /* EditorVideoControlView.swift in Sources */,
-				A81F5B3E2D19088100740085 /* TSRandomWallpaperBannerCell.swift in Sources */,
 				A81CA4A42D16748800A3AAC8 /* TSViewTool.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 1 - 7
TSLiveWallpaper/AppDelegate.swift

@@ -85,7 +85,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 }
 
 
-import KingfisherWebP
 extension AppDelegate {
     
     static func isFirstInstallApp() -> Bool {
@@ -107,12 +106,7 @@ extension AppDelegate {
         cache.diskStorage.config.expiration = .never    // 永不过期
         cache.diskStorage.config.sizeLimit = 0          // 无大小限制
         KingfisherManager.shared.cache = cache
-        
-        
-//        KingfisherManager.shared.defaultOptions += [
-//            .processor(WebPProcessor.default),
-//            .cacheSerializer(WebPSerializer.default),
-//        ]
+
         checkAppConfig()
         
         kHandleDBHistoryOperation()

+ 0 - 131
TSLiveWallpaper/Business/TSEditLiveVC/TSEditLiveEidtCell.swift

@@ -1,131 +0,0 @@
-//
-//  TSEditLiveEidtCell.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/30.
-//
-
-
-class TSEditLiveSectionModel: TSCollectionViewSectionComponent{
-    var style:ImageDataStyple = .homeLiveBanner
-    var items:[TSEditLiveItemModel] = [TSEditLiveItemModel]()
-
-    var sectionInset: UIEdgeInsets {
-        return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
-    }
-    
-    var lineSpacing: CGFloat {
-        return 0
-    }
-    
-    var itemSpacing: CGFloat {
-        return 0
-    }
-    var headerComponent: TSCollectionViewReuseViewComponent? {
-        return nil
-    }
-    
-    var cells: [TSCollectionViewCellComponent] {
-        return items
-    }
-
-}
-class TSEditLiveItemModel: TSCollectionViewCellComponent {
-    var style:ImageDataStyple = .homeLiveBanner
-    
-    var imageUrl:String = ""
-    var videoUrl:String = ""
-    
-    var cellClass: UICollectionViewCell.Type {
-        return TSEditLiveEidtCell.self
-    }
-    
-    func cellSize(with attrubites: [String : Any]?) -> CGSize {
-        return CGSize(width: k_ScreenWidth, height: 414*kDesignScale)
-    }
-}
-
-
-class TSEditLiveEidtCell : TSBaseCollectionCell{
-    
-    var component:TSCollectionViewComponent?
-    lazy var diyBtn: UIButton = {
-        let diyBtn: UIButton = TSViewTool.createNormalSubmitBtn(title: getVipText(), imageNamed: "edit_black") { [weak self]  in
-            guard let self = self else { return }
-            if let component = self.component {
-                if let itemActionHandler = component.itemActionHandler {
-                    itemActionHandler(self, IndexPath(row: 0, section: 0))
-                }
-            }
-        }
-        diyBtn.cornerRadius = 30
-        return diyBtn
-    }()
-    
-    override func creatUI() {
-        let topEditView = creatTopEditVideoView()
-        bgContentView.addSubview(topEditView)
-        topEditView.snp.makeConstraints { make in
-            make.top.leading.trailing.equalTo(0)
-            make.height.equalTo(414*kDesignScale)
-        }
-    }
-    
-    override func dealThings() {
-        NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
-    }
-    
-    func creatTopEditVideoView() -> UIView {
-        
-        let bgView = UIView()
-        
-        let videoUpImageView = UIImageView.createImageView(imageName: "video_up")
-        bgView.addSubview(videoUpImageView)
-        videoUpImageView.snp.makeConstraints { make in
-            make.top.equalTo(80)
-            make.centerX.equalToSuperview()
-            make.width.height.equalTo(153)
-        }
-        
-        let videoText = UILabel.createLabel(text: "Upload Video".localized,font: UIFont.systemFont(ofSize: 16, weight: .medium),textColor: .white,textAlignment: .center)
-        bgView.addSubview(videoText)
-        videoText.snp.makeConstraints { make in
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-            make.top.equalTo(videoUpImageView.snp.bottom).offset(12)
-            make.height.equalTo(16)
-        }
-        
-        bgView.addSubview(diyBtn)
-        diyBtn.snp.makeConstraints { make in
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-            make.top.equalTo(videoText.snp.bottom).offset(53)
-            make.height.equalTo(60)
-        }
-        
-        return bgView
-    }
-    override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String: Any]?){
-        self.component = component
-        diyBtn.setTitle(getVipText(), for: .normal)
-    }
-    
-    
-    func getVipText()->String{
-        if kPurchaseBusiness.isVip {
-            return "DIY Live Wallpaper"
-        }
-        return "DIY Live Wallpaper (\(kPurchaseBusiness.freeNum(type: .general)))"
-    }
-
-    deinit {
-        NotificationCenter.default.removeObserver(self)
-    }
-    
-    @objc func vipInfoChanged() {
-        kMainAsync {
-            self.diyBtn.setTitle(self.getVipText(), for: .normal)
-        }
-    }
-}

+ 0 - 406
TSLiveWallpaper/Business/TSEditLiveVC/TSEditLiveVC.swift

@@ -1,406 +0,0 @@
-//
-//  TSEditLiveVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/20.
-//
-
-import PhotosUI
-
-class TSEditLiveVC: TSBaseVC, UINavigationControllerDelegate {
-    lazy var editLiveSectionModel: TSEditLiveSectionModel = {
-        let section = TSEditLiveSectionModel()
-        section.items = [TSEditLiveItemModel()]
-        return section
-    }()
-
-    lazy var editLiveHistorySectionModel: TSImageDataSectionModel = {
-        kImageDataCenterShared.editLiveHistoryListArray.first!
-    }()
-
-    var dataArray: [TSComponent] = [TSComponent]()
-
-    lazy var navBarView: LWSubNavigationBar = {
-        let navBarView = LWSubNavigationBar()
-        navBarView.backButton.addTarget(self, action: #selector(pop), for: .touchUpInside)
-        navBarView.backButton.setImage(.icClose, for: .normal)
-        navBarView.titleLabel.text = "DIY Live Wallpaper"
-        return navBarView
-    }()
-
-    lazy var collectionComponent: TSCollectionViewComponent = {
-        let layout = UICollectionViewFlowLayout()
-        let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
-        cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: k_Height_TabBar, right: 0)
-
-        cp.itemActionHandler = { [weak self] _, _ in
-            guard let self = self else { return }
-
-            // 判断 vip
-            if kPurchaseBusiness.freeNumAvailable(type: .general) == false {
-                TSPurchaseVC.show(target: self) { [weak self] in
-                    guard let self = self else { return }
-                    reloadView()
-                }
-                return
-            }
-
-            // 生成视频
-            self.openVideoPicker()
-        }
-
-        cp.itemDidSelectedHandler = { [weak self] _, indexPath in
-            guard let self = self else { return }
-            let obj = dataArray.safeObj(At: indexPath.section)
-            if let liveModel = obj as? TSImageDataSectionModel {
-                if liveModel.style == .homeLiveList {
-                    let vc = TSLiveWallpaperBrowseVC(itemModels: liveModel.items, currentIndex: indexPath.row)
-                    vc.isCanDelete = true
-                    vc.deleteCompletion = { [weak self] item in
-                        guard let self = self else { return }
-                        if let itemModel = editLiveHistorySectionModel.items.safeObj(At: item) {
-                            editLiveHistorySectionModel.items.remove(at: item)
-                            TSFileManagerTool.removeItem(from: itemModel.imageUrl.fillCacheURL)
-                            TSFileManagerTool.removeItem(from: itemModel.videoUrl.fillCacheURL)
-                            kImageDataCenterShared.editLiveHistoryListArray = [editLiveHistorySectionModel]
-                            reloadView()
-                        }
-                    }
-                    kPresentModalVC(target: self, modelVC: vc)
-                }
-            }
-        }
-
-        return cp
-    }()
-
-    override func createView() {
-        //setViewBgImageNamed(named: "view_main_bg")
-        navBarContentView.addSubview(navBarView)
-        navBarContentView.snp.remakeConstraints { make in
-            make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
-            make.leading.trailing.equalToSuperview()
-            make.height.equalTo(44.0)
-        }
-        navBarView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-
-        contentView.addSubview(collectionComponent.collectionView)
-        collectionComponent.collectionView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-
-        reloadView()
-    }
-
-    func reloadView() {
-        collectionComponent.clear()
-        if editLiveHistorySectionModel.items.count > 0 {
-            dataArray = [editLiveSectionModel, editLiveHistorySectionModel]
-        } else {
-            dataArray = [editLiveSectionModel]
-        }
-        collectionComponent.reloadView(with: dataArray)
-    }
-}
-
-import UniformTypeIdentifiers
-extension TSEditLiveVC: UIImagePickerControllerDelegate {
-    func openVideoPicker() {
-        TSToastShared.showLoading(containerView: self.view)
-        let picker = UIImagePickerController()
-        picker.sourceType = .photoLibrary
-        picker.mediaTypes = [UTType.movie.identifier] // 仅允许选择视频
-        picker.allowsEditing = true // 启用编辑功能
-        picker.delegate = self
-        picker.videoMaximumDuration = 3.0
-        present(picker, animated: true) {
-            self.hideLoading()
-        }
-    }
-
-    // 用户完成选择
-    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
-        hideLoading()
-        if let editedURL = info[.mediaURL] as? URL {
-            debugPrint("Selected video: \(editedURL)")
-            // 在这里处理选中的视频(例如上传或保存)
-
-            let cachesDirectory = TSFileManagerTool.editLiveVideoPathURL
-            let targetURL = cachesDirectory.appendingPathComponent("assemblePickerVideo").appendingPathExtension(editedURL.pathExtension)
-            TSFileManagerTool.copyFileWithOverwrite(from: editedURL, to: targetURL)
-
-//            LivePhotoUtil.convertVideo(targetURL.path) { success, msg in
-//                debugPrint(msg)
-//            }
-
-//            LivePhotoConverter.convertVideo(targetURL) { success, image, video, msg in
-//                debugPrint(msg)
-//            }
-
-            saveLive(videoPath: targetURL)
-        }
-        picker.dismiss(animated: true, completion: nil)
-    }
-
-    // 用户取消选择
-    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
-        hideLoading()
-        picker.dismiss(animated: true, completion: nil)
-    }
-
-    func hideLoading() {
-        kDelayMainShort {
-            TSToastShared.hideLoading()
-        }
-    }
-}
-
-extension TSEditLiveVC {
-    func openVideoClipperVC(videoURL: URL) {
-        let clipperController = GPVideoClipperController.clipperWithVideoURL(videoURL, makerBlock: { maker in
-            maker.startTime = 0
-            maker.endTime = 15
-            maker.clippedVideoMinDuration = 1
-            maker.clippedVideoMaxDuration = 3
-            maker.leftSelectedImage = UIImage(named: "eidt_arrow_left")!
-            maker.selectedBoxColor = .white
-            maker.rightSelectedImage = UIImage(named: "eidt_arrow_right")!
-            maker.leftMargin = 77
-            maker.rightMargin = 37
-            maker.selectedImageWidth = 14
-        }) { [weak self] videoURL, _, _ in
-            guard let self = self else { return }
-            self.saveLive(videoPath: videoURL)
-        }
-
-        kPresentModalVC(target: self, modelVC: clipperController)
-    }
-
-    func saveLive(videoPath: URL) {
-        TSToastShared.showLoading(containerView: self.view)
-        LivePhotoConverter.convertVideo(videoPath) { success, imageURL, videoURL, _ in
-            if success {
-                debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
-
-                if let imageURL = imageURL, let videoURL = videoURL {
-                    LivePhotoConverter.saveToLibrary(videoURL: videoURL, imageURL: imageURL) { _ in
-                        kSaveSuccesswShared.show(atView: self.view, text: "DIY Successfully".localized)
-                    }
-                    kPurchaseBusiness.useOnceForFree(type: .general)
-
-                    let saveURL = TSFileManagerTool.saveLiveVideoPathURL
-                    let timestampString = Date.timestampString
-                    let saveImageURL = saveURL.appendingPathComponent("image\(timestampString).heic")
-                    let saveVideoURL = saveURL.appendingPathComponent("video\(timestampString).mov")
-                    TSFileManagerTool.copyFileWithOverwrite(from: imageURL, to: saveImageURL)
-                    TSFileManagerTool.copyFileWithOverwrite(from: videoURL, to: saveVideoURL)
-
-                    let itemModel = TSImageDataItemModel()
-                    itemModel.imageUrl = TSFileManagerTool.getCacheSubPath(at: saveImageURL)!
-                    itemModel.videoUrl = TSFileManagerTool.getCacheSubPath(at: saveVideoURL)!
-                    self.editLiveHistorySectionModel.items.insert(itemModel, at: 0)
-                    kImageDataCenterShared.editLiveHistoryListArray = [self.editLiveHistorySectionModel]
-                    self.reloadView()
-                }
-            } else {
-                debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
-            }
-        }
-
-//        let ts = Date().timeIntervalSince1970
-//        let documentURL = TSFileManagerTool.documentsDirectory.appendingPathComponent("\(Int(ts)).mov")
-//        let documentURL = TSFileManagerTool.documentsDirectory
-//        Converter4Video(path: videoPath.path).resizeVideo(at: videoPath.path, outputPath: documentURL.path, outputSize: CGSize(width: 1080, height: 1920)) { success, error in
-//            guard success else{
-//                debugPrint(error)
-//                return
-//            }
-//
-//            LivePhoto.generate(from: nil, videoURL: documentURL) { progress in
-//
-//            } completion: {[weak self] (livePhoto, resources) in
-//                guard let self = self else { return }
-//
-//                if let resources = resources {
-//                    LivePhoto.saveToLibrary(resources, completion: { (success) in
-//                        kMainAsync {
-//                            hideLoading()
-//                            if success {
-//                                debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
-//                                kSaveSuccesswShared.show(atView: self.view)
-//                            }else {
-//                                debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
-//                            }
-//
-//                            TSFileManagerTool.removeItem(from: resources.pairedImage)
-//                            TSFileManagerTool.removeItem(from: resources.pairedVideo)
-//                        }
-//                    })
-//                }
-//            }
-//        }
-
-//        LivePhoto.resizeVideoToFixedHeight(videoURL: videoPath, outputFolder: documentURL) { outputURL in
-//            if let outputURL = outputURL {
-//                print("Resized video saved to: \(outputURL)")
-//
-//                LivePhoto.generate(from: nil, videoURL: outputURL) { progress in
-//
-//                } completion: {[weak self] (livePhoto, resources) in
-//                    guard let self = self else { return }
-//
-//                    if let resources = resources {
-//                        LivePhoto.saveToLibrary(resources, completion: { (success) in
-//                            kMainAsync {
-//                                hideLoading()
-//                                if success {
-//                                    debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
-//                                    kSaveSuccesswShared.show(atView: self.view)
-//                                }else {
-//                                    debugPrint("Live Photo Not Saved,The live photo was not saved to Photos.")
-//                                }
-//
-//                                TSFileManagerTool.removeItem(from: resources.pairedImage)
-//                                TSFileManagerTool.removeItem(from: resources.pairedVideo)
-//                            }
-//                        })
-//                    }
-//                }
-//
-//            } else {
-//                print("Failed to resize video.")
-//            }
-//        }
-
-//        VideoRecorder.shared.saveLivePhoto(duration: 2.5, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { [weak self] recordHandler in
-//
-        ////                    recordHandler?()
-//
-//        } completion: { [weak self] videoURL, imageURL, errorMsg in
-//            guard let self = self else { return }
-        ////        }
-        ////        LivePhotoCreater().saveLivePhoto(from: videoPath, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { videoURL, imageURL, errorMsg in
-//            if let imageURL = imageURL,let videoURL = videoURL {
-//                LivePhotoConverter.saveToLibrary(videoURL: videoURL, imageURL: imageURL) { success in
-//                    kSaveSuccesswShared.show(atView: self.view)
-//                }
-//
-//
-//                let saveURL = TSFileManagerTool.saveLiveVideoPathURL
-//                let timestampString = Date.timestampString
-//                let saveImageURL = saveURL.appendingPathComponent("image\(timestampString).heic")
-//                let saveVideoURL = saveURL.appendingPathComponent("video\(timestampString).mov")
-//                TSFileManagerTool.copyFileWithOverwrite(from: imageURL, to: saveImageURL)
-//                TSFileManagerTool.copyFileWithOverwrite(from: videoURL, to: saveVideoURL)
-//
-//
-//                let itemModel = TSImageDataItemModel()
-//                itemModel.imageUrl = TSFileManagerTool.getCacheSubPath(at: saveImageURL)!
-//                itemModel.videoUrl = TSFileManagerTool.getCacheSubPath(at: saveVideoURL)!
-//                self.editLiveHistorySectionModel.items.append(itemModel)
-//                kImageDataCenterShared.editLiveHistoryListArray = [self.editLiveHistorySectionModel]
-//                self.reloadView()
-//            }
-//        }
-    }
-
-//    func saveLivePhotoVideoRecorder(){
-//
-//
-//        VideoRecorder.shared.saveLivePhoto(duration: 3.0, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { [weak self] recordHandler in
-//
-    ////                    recordHandler?()
-//
-//        } completion: { [weak self] videoURL, imageURL, errorMsg in
-//            guard let self = self else { return }
-    ////        }
-    ////        LivePhotoCreater().saveLivePhoto(from: videoPath, outputDirectory: TSFileManagerTool.saveLiveVideoPathURL) { videoURL, imageURL, errorMsg in
-//            if let imageURL = imageURL,let videoURL = videoURL {
-//                LivePhotoConverter.saveToLibrary(videoURL: videoURL, imageURL: imageURL) { success in
-//                    kSaveSuccesswShared.show(atView: self.view)
-//                }
-//
-//
-//                let saveURL = TSFileManagerTool.saveLiveVideoPathURL
-//                let timestampString = Date.timestampString
-//                let saveImageURL = saveURL.appendingPathComponent("image\(timestampString).heic")
-//                let saveVideoURL = saveURL.appendingPathComponent("video\(timestampString).mov")
-//                TSFileManagerTool.copyFileWithOverwrite(from: imageURL, to: saveImageURL)
-//                TSFileManagerTool.copyFileWithOverwrite(from: videoURL, to: saveVideoURL)
-//
-//
-//                let itemModel = TSImageDataItemModel()
-//                itemModel.imageUrl = TSFileManagerTool.getCacheSubPath(at: saveImageURL)!
-//                itemModel.videoUrl = TSFileManagerTool.getCacheSubPath(at: saveVideoURL)!
-//                self.editLiveHistorySectionModel.items.append(itemModel)
-//                kImageDataCenterShared.editLiveHistoryListArray = [self.editLiveHistorySectionModel]
-//                self.reloadView()
-//            }
-//        }
-//    }
-}
-
-// MARK: - PHPickerViewControllerDelegate
-
-// extension TSEditLiveVC: PHPickerViewControllerDelegate {
-//
-//    /// Present `PHPickerViewController`
-//    func pick(_ filter: PHPickerFilter) {
-//        var config = PHPickerConfiguration()
-//        config.filter = filter
-//        config.selectionLimit = 1
-//        config.preferredAssetRepresentationMode = .current
-//        let picker = PHPickerViewController(configuration: config)
-//        picker.delegate = self
-//        picker.modalPresentationStyle = .overFullScreen
-//        present(picker, animated: true, completion: nil)
-//    }
-//
-//    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
-//        defer { picker.dismiss(animated: true) }
-//        assemblePicker(picker, didFinishPicking: results)
-//    }
-//
-//    func assemblePicker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
-//        guard let itemProvider = results.first?.itemProvider else {
-//            return
-//        }
-//
-//        if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
-//            itemProvider.loadFileRepresentation(forTypeIdentifier: itemProvider.registeredTypeIdentifiers.first!) { [weak self] url, error in
-//                guard let self, let url = url else {
-//                    return
-//                }
-//                do {
-//                    let cachesDirectory = try self.cachesDirectory()
-//                    let targetURL = cachesDirectory.appendingPathComponent("assemblePickerVideo").appendingPathExtension(url.pathExtension)
-//                    let fileManager = FileManager.default
-//                    // 如果目标路径存在同名文件,先删除旧文件
-//                    if fileManager.fileExists(atPath: targetURL.path) {
-//                        try fileManager.removeItem(at: targetURL)
-//                    }
-//
-//                    try fileManager.copyItem(at: url, to: targetURL)
-//
-//                    kMainAsync {
-//                        self.openVideoClipperVC(videoURL: targetURL)
-//                    }
-//
-//                } catch {
-//                    TSToastShared.showToast(message: "An error occurred")
-//                }
-//            }
-//        }
-//    }
-//
-//    private func cachesDirectory() throws -> URL {
-//        let cachesDirectoryURL = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
-//        let cachesDirectory = cachesDirectoryURL.appendingPathComponent("asemble", isDirectory: true)
-//        if !FileManager.default.fileExists(atPath: cachesDirectory.absoluteString) {
-//            try FileManager.default.createDirectory(at: cachesDirectory, withIntermediateDirectories: true, attributes: nil)
-//        }
-//        return cachesDirectory
-//    }
-// }

+ 0 - 253
TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/EditorVideo/EditorVideoControlMaskView.swift

@@ -1,253 +0,0 @@
-//
-//  EditorVideoControlMaskView.swift
-//  HXPhotoPicker
-//
-//  Created by Silence on 2023/5/13.
-//
-
-import UIKit
-
-protocol EditorVideoControlMaskViewDelegate: AnyObject {
-    func frameMaskView(leftValidRectDidChanged frameMaskView: EditorVideoControlMaskView)
-    func frameMaskView(leftValidRectEndChanged frameMaskView: EditorVideoControlMaskView)
-    func frameMaskView(rightValidRectDidChanged frameMaskView: EditorVideoControlMaskView)
-    func frameMaskView(rightValidRectEndChanged frameMaskView: EditorVideoControlMaskView)
-}
-
-class PhotoPanGestureRecognizer: UIPanGestureRecognizer {
-    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
-        super.touchesBegan(touches, with: event)
-        state = .began
-    }
-}
-
-class EditorVideoControlMaskView: UIView {
-    let controlWidth: CGFloat = 18
-    
-    weak var delegate: EditorVideoControlMaskViewDelegate?
-    
-    private var maskLayer: CAShapeLayer!
-    private var topView: UIView!
-    private var bottomView: UIView!
-    private var leftImageView: UIImageView!
-    private var leftControl: UIView!
-    private var rightImageView: UIImageView!
-    private var rightControl: UIView!
-    private var mask_View: UIView!
-    
-    var validRect: CGRect = .zero {
-        didSet {
-            leftControl.frame = CGRect(x: validRect.minX - controlWidth, y: 0, width: controlWidth, height: height)
-            leftImageView.center = .init(x: leftControl.width / 2, y: leftControl.height / 2)
-            rightControl.frame = CGRect(x: validRect.maxX, y: 0, width: controlWidth, height: height)
-            rightImageView.center = .init(x: rightControl.width / 2, y: rightControl.height / 2)
-            topView.frame = .init(x: leftControl.frame.maxX, y: 0, width: validRect.width, height: 4)
-            bottomView.frame = .init(
-                x: leftControl.frame.maxX,
-                y: leftControl.frame.maxY - 4,
-                width: validRect.width,
-                height: 4
-            )
-            drawMaskLayer()
-            guard #available(iOS 11.0, *) else {
-                leftControl.cornersRound(radius: 4, corner: [.topLeft, .bottomLeft])
-                rightControl.cornersRound(radius: 4, corner: [.topRight, .bottomRight])
-                return
-            }
-        }
-    }
-    var isShowFrame: Bool = false
-    var minWidth: CGFloat = 0
-    
-    var arrowNormalColor: UIColor = .white
-    var arrowHighlightedColor: UIColor = .black
-    var frameHighlightedColor: UIColor = "#FDCC00".uiColor
-    
-    init() {
-        super.init(frame: .zero)
-        initViews()
-    }
-    
-    private func initViews() {
-        maskLayer = CAShapeLayer()
-        maskLayer.contentsScale = UIScreen._scale
-        mask_View = UIView()
-        mask_View.backgroundColor = .black.withAlphaComponent(0.5)
-        mask_View.layer.mask = maskLayer
-        addSubview(mask_View)
-        
-        topView = UIView()
-        topView.backgroundColor = .clear
-        addSubview(topView)
-        
-        bottomView = UIView()
-        bottomView.backgroundColor = .clear
-        addSubview(bottomView)
-        
-        leftImageView = UIImageView(image: UIImage(named: "hx_editor_video_control_arrow_left")?.withRenderingMode(.alwaysTemplate))
-        leftImageView.size = leftImageView.image?.size ?? .zero
-        leftImageView.tintColor = arrowNormalColor
-        leftControl = UIView()
-        leftControl.tag = 0
-        if #available(iOS 11.0, *) {
-            leftControl.cornersRound(radius: 4, corner: [.topLeft, .bottomLeft])
-        }
-        leftControl.addSubview(leftImageView)
-        let leftControlPanGR = PhotoPanGestureRecognizer(target: self, action: #selector(panGestureRecognizerAction(panGR:)))
-        leftControl.addGestureRecognizer(leftControlPanGR)
-        addSubview(leftControl)
-        
-        rightImageView = UIImageView(image: UIImage(named: "hx_editor_video_control_arrow_right")?.withRenderingMode(.alwaysTemplate))
-        rightImageView.size = rightImageView.image?.size ?? .zero
-        rightImageView.tintColor = arrowNormalColor
-        rightControl = UIView()
-        rightControl.tag = 1
-        rightControl.addSubview(rightImageView)
-        if #available(iOS 11.0, *) {
-            rightControl.cornersRound(radius: 4, corner: [.topRight, .bottomRight])
-        }
-        let rightControlPanGR = PhotoPanGestureRecognizer(target: self, action: #selector(panGestureRecognizerAction(panGR:)))
-        rightControl.addGestureRecognizer(rightControlPanGR)
-        addSubview(rightControl)
-    }
-    
-    private func drawMaskLayer() {
-        let maskPath = UIBezierPath(rect: bounds)
-        maskPath.append(
-            UIBezierPath(
-                rect: CGRect(
-                    x: validRect.minX,
-                    y: validRect.minY + 4,
-                    width: validRect.width,
-                    height: validRect.height - 8
-                )
-            ).reversing()
-        )
-        maskLayer.path = maskPath.cgPath
-        
-    }
-    
-    override func layoutSubviews() {
-        super.layoutSubviews()
-        mask_View.frame = bounds
-    }
-    
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    var leftBeginRect: CGRect = .zero
-    var rightBeginRect: CGRect = .zero
-    @objc func panGestureRecognizerAction(panGR: UIPanGestureRecognizer) {
-        let point = panGR.translation(in: self)
-        switch panGR.state {
-        case .began:
-            leftBeginRect = leftControl.frame
-            rightBeginRect = rightControl.frame
-            switch panGR.view?.tag {
-            case 0:
-                delegate?.frameMaskView(leftValidRectDidChanged: self)
-            case 1:
-                delegate?.frameMaskView(rightValidRectDidChanged: self)
-            default:
-                break
-            }
-            updateFrameView()
-        case .changed:
-            var leftRect = leftBeginRect
-            var rightRect = rightBeginRect
-            switch panGR.view?.tag {
-            case 0:
-                leftRect.origin.x += point.x
-                if leftRect.origin.x < 0 {
-                    leftRect.origin.x = 0
-                }
-                if rightRect.origin.x - leftRect.maxX <= minWidth {
-                    leftRect.origin.x = rightRect.origin.x - minWidth - leftRect.width
-                }
-                validRect = .init(
-                    x: leftRect.maxX,
-                    y: validRect.minY,
-                    width: rightRect.origin.x - leftRect.maxX,
-                    height: leftRect.height
-                )
-                delegate?.frameMaskView(leftValidRectDidChanged: self)
-            case 1:
-                rightRect.origin.x += point.x
-                if rightRect.maxX > width {
-                    rightRect.origin.x = width - rightRect.width
-                }
-                if rightRect.origin.x - leftRect.maxX <= minWidth {
-                    rightRect.origin.x = leftRect.maxX + minWidth
-                }
-                validRect = .init(
-                    x: leftRect.maxX,
-                    y: validRect.minY,
-                    width: rightRect.origin.x - leftRect.maxX,
-                    height: leftRect.height
-                )
-                delegate?.frameMaskView(rightValidRectDidChanged: self)
-            default:
-                break
-            }
-            updateFrameView()
-        case .ended, .failed, .cancelled:
-            let leftRect = leftControl.frame
-            let rightRect = rightControl.frame
-            validRect = .init(
-                x: leftRect.maxX,
-                y: validRect.minY,
-                width: rightRect.origin.x - leftRect.maxX,
-                height: leftRect.height
-            )
-            switch panGR.view?.tag {
-            case 0:
-                delegate?.frameMaskView(leftValidRectEndChanged: self)
-            case 1:
-                delegate?.frameMaskView(rightValidRectEndChanged: self)
-            default:
-                break
-            }
-            updateFrameView()
-        default:
-            break
-        }
-    }
-    
-    func updateFrameView() {
-        if rightControl.x - leftControl.frame.maxX < width - controlWidth * 2 || isShowFrame {
-            UIView.animate(withDuration: 0.2) {
-                self.topView.backgroundColor = self.frameHighlightedColor
-                self.bottomView.backgroundColor = self.frameHighlightedColor
-                self.leftControl.backgroundColor = self.frameHighlightedColor
-                self.rightControl.backgroundColor = self.frameHighlightedColor
-                self.leftImageView.tintColor = self.arrowHighlightedColor
-                self.rightImageView.tintColor = self.arrowHighlightedColor
-                self.mask_View.backgroundColor = .black.withAlphaComponent(0.5)
-            }
-        }else {
-            UIView.animate(withDuration: 0.2) {
-                self.topView.backgroundColor = .clear
-                self.bottomView.backgroundColor = .clear
-                self.leftControl.backgroundColor = .clear
-                self.rightControl.backgroundColor = .clear
-                self.leftImageView.tintColor = self.arrowNormalColor
-                self.rightImageView.tintColor = self.arrowNormalColor
-                self.mask_View.backgroundColor = .clear
-            }
-        }
-    }
-    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
-        var leftRect = leftControl.frame
-        leftRect.origin.x -= controlWidth
-        leftRect.size.width += controlWidth
-        var rightRect = rightControl.frame
-        rightRect.size.width += controlWidth
-        if leftRect.contains(point) {
-            return leftControl
-        }
-        if rightRect.contains(point) {
-            return rightControl
-        }
-        return nil
-    }
-}

+ 0 - 1101
TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/EditorVideo/EditorVideoControlView.swift

@@ -1,1101 +0,0 @@
-//
-//  EditorVideoControlView.swift
-//  HXPhotoPicker
-//
-//  Created by Silence on 2023/5/13.
-//
-
-import UIKit
-import AVFoundation
-
-public enum ExportPreset {
-    case lowQuality
-    case mediumQuality
-    case highQuality
-    case ratio_640x480
-    case ratio_960x540
-    case ratio_1280x720
-    
-    public var name: String {
-        switch self {
-        case .lowQuality:
-            return AVAssetExportPresetLowQuality
-        case .mediumQuality:
-            return AVAssetExportPresetMediumQuality
-        case .highQuality:
-            return AVAssetExportPresetHighestQuality
-        case .ratio_640x480:
-            return AVAssetExportPreset640x480
-        case .ratio_960x540:
-            return AVAssetExportPreset960x540
-        case .ratio_1280x720:
-            return AVAssetExportPreset1280x720
-        }
-    }
-}
-
-struct Video {
-    
-    /// Video export resolution
-    /// 视频导出的分辨率
-    public var preset: ExportPreset = .ratio_960x540
-    
-    /// Quality of video export [0-10]
-    /// 视频导出的质量[0-10]
-    public var quality: Int = 6
-    
-    /// Autoplay after loading is complete
-    /// 加载完成后自动播放
-    public var isAutoPlay: Bool = true
-    
-    /// Clipping duration configuration
-    /// 裁剪时长配置
-    public var cropTime: CropTime = .init()
-    
-
-    public init() { }
-    
-    public struct CropTime {
-        
-        /// Video maximum cropping duration
-        /// > 0 The video must be cropped when it is longer than
-        /// = 0 for no clipping
-        /// 视频最大裁剪时长
-        /// > 0 视频时长超过时必须裁剪
-        /// = 0 可不裁剪
-        public var maximumTime: TimeInterval = 0
-        
-        /// Video minimum cropping duration, minimum 1
-        /// 视频最小裁剪时长,最小1
-        public var minimumTime: TimeInterval = 1
-        
-        /// The color of the left and right arrows in normal state
-        /// 左右箭头正常状态下的颜色
-        public var arrowNormalColor: UIColor = .white
-        
-        /// The color of the left and right arrows when they are highlighted
-        /// 左右箭头高亮状态下的颜色
-        public var arrowHighlightedColor: UIColor = .black
-        
-        /// The color of the highlighted border
-        /// 边框高亮状态下的颜色
-        public var frameHighlightedColor: UIColor = "#FDCC00".uiColor
-        
-        public init() { }
-    }
-}
-
-
-protocol EditorVideoControlViewDelegate: AnyObject {
-    func controlView(_ controlView: EditorVideoControlView, didPlayAt isSelected: Bool)
-    func controlView(_ controlView: EditorVideoControlView, leftDidChangedValidRectAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, leftEndChangedValidRectAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, rightDidChangedValidRectAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, rightEndChangedValidRectAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, progressLineDragBeganAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, progressLineDragChangedAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, progressLineDragEndAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, didScrollAt time: CMTime)
-    func controlView(_ controlView: EditorVideoControlView, endScrollAt time: CMTime)
-}
-
-// swiftlint:disable type_body_length
-class EditorVideoControlView: UIView {
-    // swiftlint:enable type_body_length
-    
-    weak var delegate: EditorVideoControlViewDelegate?
-    let config: Video.CropTime
-    
-//    private var textSize:CGFloat = !
-    
-    private var playView: UIVisualEffectView!
-    private var playButton: UIButton!
-    private var frameMaskView: EditorVideoControlMaskView!
-    private var flowLayout: UICollectionViewFlowLayout!
-    private var bgView: UIVisualEffectView!
-    private var collectionView: UICollectionView!
-    private var beginLineFrame: CGRect = .zero
-    private var progressLineView: UIView!
-    private var currentLineView: UIView!
-    private var currentTimeView: UIVisualEffectView!
-    private var currentTimeLb: UILabel!
-    private var startLineView: UIView!
-    private var endLineView: UIView!
-    private var startTimeView: UIVisualEffectView!
-    private var startTimeLb: UILabel!
-    private var endTimeView: UIVisualEffectView!
-    private var endTimeLb: UILabel!
-    private var totalTimeView: UIVisualEffectView!
-    private var totalTimeLb: UILabel!
-    
-    var isPlaying: Bool {
-        get {
-            playButton.isSelected
-        }
-        set {
-            playButton.isSelected = newValue
-            if newValue {
-                startLineAnimation()
-            }else {
-                stopLineAnimation()
-            }
-        }
-    }
-    
-    init(config: Video.CropTime) {
-        self.config = config
-        super.init(frame: .zero)
-        initViews()
-    }
-    
-    private func initViews() {
-        flowLayout = UICollectionViewFlowLayout()
-        flowLayout.scrollDirection = .horizontal
-        flowLayout.minimumLineSpacing = 0
-        flowLayout.minimumInteritemSpacing = 0
-        collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
-        collectionView.backgroundColor = .clear
-        collectionView.dataSource = self
-        collectionView.delegate = self
-        collectionView.showsVerticalScrollIndicator = false
-        collectionView.showsHorizontalScrollIndicator = false
-        if #available(iOS 11.0, *) {
-            collectionView.contentInsetAdjustmentBehavior = .never
-        }
-        collectionView.register(
-            EditorVideoControlViewCell.self,
-            forCellWithReuseIdentifier: "EditorVideoControlViewCellID"
-        )
-        
-        frameMaskView = EditorVideoControlMaskView()
-        frameMaskView.frameHighlightedColor = config.frameHighlightedColor
-        frameMaskView.arrowNormalColor = config.arrowNormalColor
-        frameMaskView.arrowHighlightedColor = config.arrowHighlightedColor
-        frameMaskView.delegate = self
-        
-        bgView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        bgView.contentView.addSubview(collectionView)
-        bgView.contentView.addSubview(frameMaskView)
-        bgView.layer.cornerRadius = 4
-        bgView.layer.masksToBounds = true
-        addSubview(bgView)
-        
-        playButton = UIButton(type: .custom)
-        playButton.setImage(UIImage(named: "hx_editor_video_control_play"), for: .normal)
-        playButton.setImage(UIImage(named: "hx_editor_video_control_pause"), for: .selected)
-        playButton.addTarget(self, action: #selector(didPlayButtonClick), for: .touchUpInside)
-        playView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        playView.contentView.addSubview(playButton)
-        playView.layer.cornerRadius = 4
-        playView.layer.masksToBounds = true
-        addSubview(playView)
-        
-        progressLineView = UIView()
-        progressLineView.backgroundColor = .white
-        if #available(iOS 11.0, *) {
-            progressLineView.cornersRound(radius: 2, corner: .allCorners)
-        }
-        progressLineView.layer.borderColor = UIColor.black.cgColor
-        progressLineView.layer.borderWidth = 0.25
-        progressLineView.alpha = 0
-        progressLineView.addGestureRecognizer(
-            PhotoPanGestureRecognizer(
-                target: self,
-                action: #selector(progressLinePanGestureClick(pan:))
-            )
-        )
-        addSubview(progressLineView)
-        
-        startTimeLb = UILabel()
-        startTimeLb.font = .systemFont(ofSize: 12)
-        startTimeLb.textColor = .white
-        startTimeView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        startTimeView.contentView.addSubview(startTimeLb)
-        startTimeView.layer.cornerRadius = 4
-        startTimeView.layer.masksToBounds = true
-        startTimeView.alpha = 0
-        addSubview(startTimeView)
-        
-        startLineView = UIView()
-        startLineView.backgroundColor = .white
-        startLineView.size = .init(width: 1, height: 10)
-        startLineView.cornersRound(radius: 0.5, corner: .allCorners)
-        startLineView.alpha = 0
-        addSubview(startLineView)
-        
-        endTimeLb = UILabel()
-        endTimeLb.textAlignment = .right
-        endTimeLb.font = .systemFont(ofSize: 12)
-        endTimeLb.textColor = .white
-        endTimeView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        endTimeView.contentView.addSubview(endTimeLb)
-        endTimeView.layer.cornerRadius = 4
-        endTimeView.layer.masksToBounds = true
-        endTimeView.alpha = 0
-        addSubview(endTimeView)
-        
-        endLineView = UIView()
-        endLineView.backgroundColor = .white
-        endLineView.size = .init(width: 1, height: 10)
-        endLineView.cornersRound(radius: 0.5, corner: .allCorners)
-        endLineView.alpha = 0
-        addSubview(endLineView)
-        
-        currentTimeLb = UILabel()
-        currentTimeLb.font = .systemFont(ofSize: 12)
-        currentTimeLb.textColor = .white
-        currentTimeView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        currentTimeView.contentView.addSubview(currentTimeLb)
-        currentTimeView.layer.cornerRadius = 4
-        currentTimeView.layer.masksToBounds = true
-        currentTimeView.alpha = 0
-        addSubview(currentTimeView)
-        
-        currentLineView = UIView()
-        currentLineView.backgroundColor = .white
-        currentLineView.size = .init(width: 1, height: 10)
-        currentLineView.cornersRound(radius: 0.5, corner: .allCorners)
-        currentLineView.alpha = 0
-        addSubview(currentLineView)
-        
-        totalTimeLb = UILabel.init()
-        totalTimeLb.textAlignment = .center
-        totalTimeLb.font = .systemFont(ofSize: 12)
-        totalTimeLb.textColor = .white
-        totalTimeView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
-        totalTimeView.contentView.addSubview(totalTimeLb)
-        totalTimeView.layer.cornerRadius = 4
-        totalTimeView.layer.masksToBounds = true
-        totalTimeView.alpha = 0
-        addSubview(totalTimeView)
-    }
-    
-    @objc
-    private func didPlayButtonClick() {
-        playButton.isSelected = !playButton.isSelected
-        delegate?.controlView(self, didPlayAt: playButton.isSelected)
-        if playButton.isSelected {
-            startLineAnimation()
-        }else {
-            stopLineAnimation()
-        }
-    }
-    
-    private let controlWidth: CGFloat = 18
-    private var contentWidth: CGFloat = 0
-    private var videoFrameCount: Int = 0
-    
-    private var videoFrameMap: [Int: CGImage] = [:]
-    private var videoFrameLock: DispatchQueue = .init(label: "com.hxpicker.editorvideoframelock")
-    var videoSize: CGSize = .zero
-    /// 一个item代表多少秒
-    private var interval: CGFloat = -1
-    private var itemWidth: CGFloat = 0
-    private var imageGenerator: AVAssetImageGenerator?
-    private var assetDuration: TimeInterval = 0
-    private weak var timeLabelsTimer: Timer?
-    private var avAsset: AVAsset?
-    private var margin: CGFloat {
-        var leftMargin: CGFloat = 15 + UIDevice.leftMargin
-        var rightMargin: CGFloat = UIDevice.rightMargin + 15
-        if (width - leftMargin - rightMargin) > 450 {
-            let maxWidth = max(width * 0.5, 450)
-            leftMargin = (width - maxWidth) * 0.5
-            rightMargin = leftMargin
-        }
-        return leftMargin - UIDevice.leftMargin
-    }
-    private var bgWidth: CGFloat {
-        if UIDevice.isPortrait {
-            return width - UIDevice.rightMargin - margin - (margin + UIDevice.leftMargin + playWidth) - 1
-        }else {
-            return width - UIDevice.rightMargin - margin - (margin + UIDevice.leftMargin + playWidth) - 1
-        }
-    }
-    private var isBeginScrolling: Bool = false
-    private var isFirstLoad: Bool = true
-    private var playWidth: CGFloat {
-        if UIDevice.isPortrait {
-            return height
-        }else {
-            return height * 1.5
-        }
-    }
-    var currentDuration: Double {
-        let lineFrame = progressLineView.layer.presentation()?.frame ?? progressLineView.frame
-        let scale = (
-            lineFrame.minX - bgView.x - frameMaskView.validRect.minX
-        ) / (
-            frameMaskView.validRect.width - lineFrame.width
-        )
-        let totalDuration = endDuration - startDuration
-        let time = startDuration + totalDuration * scale
-        return time
-    }
-    private var currentTime: CMTime {
-        CMTimeMakeWithSeconds(
-            Float64(currentDuration),
-            preferredTimescale: 1000
-        )
-    }
-    
-    func loadData(_ avAsset: AVAsset) {
-        self.avAsset = avAsset
-        videoSize = PhotoTools.getVideoThumbnailImage(avAsset: avAsset, atTime: 0.1)?.size ?? .zero
-        assetDuration = avAsset.duration.seconds
-        imageGenerator?.cancelAllCGImageGeneration()
-        videoFrameMap.removeAll()
-        
-        collectionView.contentInset = UIEdgeInsets(
-            top: 4,
-            left: controlWidth,
-            bottom: 4,
-            right: controlWidth
-        )
-        loadItemSize()
-        resetValidRect()
-        collectionView.reloadData()
-        loadVideoFrame(avAsset)
-        updateTimeLabels()
-        updateTimeLabelsFrame()
-        let totalDuration = endDuration - startDuration
-        frameMaskView.isShowFrame = totalDuration < assetDuration
-        frameMaskView.updateFrameView()
-        showLineView(at: startTime)
-    }
-    
-    func loadItemSize() {
-        if videoSize == .zero {
-            return
-        }
-        let cellHeight = height - 8
-        itemWidth = cellHeight / 16 * 9
-        var imgWidth = videoSize.width
-        let imgHeight = videoSize.height
-        imgWidth = cellHeight / imgHeight * imgWidth
-        if imgWidth > itemWidth {
-            itemWidth = cellHeight / imgHeight * videoSize.width
-            if itemWidth > imgHeight / 9 * 16 {
-                itemWidth = imgHeight / 9 * 16
-            }
-        }
-        var videoSecond = assetDuration
-        if videoSecond <= 0 {
-            videoSecond = 1
-        }
-        let maxWidth = bgWidth - controlWidth * 2
-        var singleItemSecond: CGFloat
-        let videoMaximumCropDuration = CGFloat(config.maximumTime)
-        if videoSecond <= videoMaximumCropDuration || videoMaximumCropDuration <= 0 {
-            let itemCount = maxWidth / itemWidth
-            singleItemSecond = videoSecond / itemCount
-            
-            contentWidth = maxWidth
-            videoFrameCount = Int(ceilf(Float(itemCount)))
-            interval = singleItemSecond
-        }else {
-            let singleSecondWidth = maxWidth / videoMaximumCropDuration
-            singleItemSecond = itemWidth / singleSecondWidth
-            
-            contentWidth = singleSecondWidth * videoSecond
-            videoFrameCount = Int(ceilf(Float(contentWidth / itemWidth)))
-            interval = singleItemSecond
-        }
-        if round(videoSecond) <= 0 {
-            frameMaskView.minWidth = contentWidth
-        }else {
-            var videoMinimunCropDuration = CGFloat(config.minimumTime)
-            if videoMinimunCropDuration < 1 {
-                videoMinimunCropDuration = 1
-            }
-            let scale = videoMinimunCropDuration / videoSecond
-            frameMaskView.minWidth = contentWidth * scale
-        }
-    }
-    
-    func loadVideoFrame(_ avAsset: AVAsset) {
-        if videoFrameCount < 0 {
-            return
-        }
-        imageGenerator = AVAssetImageGenerator(asset: avAsset)
-        imageGenerator?.maximumSize = CGSize(width: itemWidth * 2, height: height * 2)
-        imageGenerator?.appliesPreferredTrackTransform = true
-        imageGenerator?.requestedTimeToleranceAfter = .zero
-        imageGenerator?.requestedTimeToleranceBefore = .zero
-         
-        var times: [NSValue] = []
-        for index in 0..<videoFrameCount {
-            let time = getVideoCurrentTime(for: index)
-            times.append(NSValue.init(time: time))
-        }
-        var index: Int = 0
-        var hasError = false
-        var errorIndex: [Int] = []
-        imageGenerator?.generateCGImagesAsynchronously(forTimes: times) { (_, cgImage, _, result, _) in
-            if result != .cancelled {
-                if let cgImage = cgImage {
-                    self.videoFrameLock.sync {
-                        self.videoFrameMap[index] = cgImage
-                    }
-                    if hasError {
-                        for inde in errorIndex {
-                            self.setCurrentCell(image: UIImage(cgImage: cgImage), index: inde)
-                        }
-                        errorIndex.removeAll()
-                        hasError = false
-                    }
-                    self.setCurrentCell(image: UIImage(cgImage: cgImage), index: index)
-                }else {
-                    var cg_image: CGImage?
-                    self.videoFrameLock.sync {
-                        cg_image = self.videoFrameMap[index - 1]
-                    }
-                    if let cgImage = cg_image {
-                        self.setCurrentCell(image: UIImage(cgImage: cgImage), index: index)
-                    }else {
-                        errorIndex.append(index)
-                        hasError = true
-                    }
-                }
-                index += 1
-            }
-        }
-    }
-    
-    func reloadVideo() {
-        guard let avAsset = avAsset else {
-            return
-        }
-        imageGenerator?.cancelAllCGImageGeneration()
-        loadItemSize()
-        collectionView.reloadData()
-        loadVideoFrame(avAsset)
-    }
-    
-    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
-        let lineFrame = progressLineView.layer.presentation()?.frame ?? progressLineView.frame
-        let rect = lineFrame.inset(by: .init(top: 4, left: 10, bottom: 4, right: 10))
-        if rect.contains(point) {
-            return progressLineView
-        }
-        return super.hitTest(point, with: event)
-    }
-    
-    override func layoutSubviews() {
-        super.layoutSubviews()
-        progressLineView.size = .init(width: 4, height: height - 4)
-        progressLineView.centerY = height / 2
-        if UIDevice.isPortrait {
-            let leftMargin: CGFloat = margin + UIDevice.leftMargin
-            let rightMargin: CGFloat = UIDevice.rightMargin + margin
-            playView.frame = .init(x: leftMargin, y: 0, width: playWidth, height: height)
-            bgView.frame = .init(
-                x: playView.frame.maxX + 1,
-                y: 0,
-                width: width - rightMargin - playView.frame.maxX - 1,
-                height: height
-            )
-        }else {
-            playView.frame = .init(x: margin + UIDevice.leftMargin, y: 0, width: playWidth, height: height)
-            bgView.frame = .init(
-                x: playView.frame.maxX + 1,
-                y: 0,
-                width: width - UIDevice.rightMargin - margin - playView.frame.maxX - 1,
-                height: height
-            )
-        }
-        playButton.frame = playView.bounds
-        collectionView.frame = bgView.bounds
-        frameMaskView.frame = bgView.bounds
-        if isFirstLoad {
-            resetValidRect()
-            isFirstLoad = false
-        }
-        guard #available(iOS 11.0, *) else {
-            progressLineView.cornersRound(radius: 2, corner: .allCorners)
-            return
-        }
-    }
-    deinit {
-        imageGenerator?.cancelAllCGImageGeneration()
-        videoFrameMap.removeAll()
-    }
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
-extension EditorVideoControlView {
-    @objc
-    private func progressLinePanGestureClick(pan: UIPanGestureRecognizer) {
-        if isHidden {
-            return
-        }
-        let point = pan.translation(in: progressLineView)
-        switch pan.state {
-        case .began:
-            if playButton.isSelected {
-                didPlayButtonClick()
-            }
-            beginLineFrame = progressLineView.frame
-            hideTimeLabels(false)
-            updateCurrentTime()
-            showCurrentTime()
-            delegate?.controlView(self, progressLineDragBeganAt: currentTime)
-        case .changed:
-            var lineX = beginLineFrame.minX + point.x
-            if lineX < bgView.x + frameMaskView.validRect.minX {
-                lineX = bgView.x + frameMaskView.validRect.minX
-            }
-            if lineX > bgView.x + frameMaskView.validRect.maxX - progressLineView.width {
-                lineX = bgView.x + frameMaskView.validRect.maxX - progressLineView.width
-            }
-            progressLineView.x = lineX
-            updateCurrentTime()
-            delegate?.controlView(self, progressLineDragChangedAt: currentTime)
-        case .ended, .cancelled, .failed:
-            hideCurrentTime()
-            delegate?.controlView(self, progressLineDragEndAt: currentTime)
-        default:
-            break
-        }
-    }
-    func updateCurrentTime() {
-        currentTimeLb.text = currentDuration.time
-        currentTimeLb.size = currentTimeLb.textSize
-        currentTimeView.size = .init(width: currentTimeLb.width + 10, height: currentTimeLb.size.height + 5)
-        currentTimeLb.center = .init(x: currentTimeView.width / 2, y: currentTimeView.height / 2)
-        currentLineView.y = -currentLineView.height - 5
-        currentLineView.centerX = progressLineView.centerX
-        currentTimeView.y = currentLineView.y - currentTimeView.height - 2
-        currentTimeView.centerX = currentLineView.centerX
-        if currentTimeView.frame.maxX + margin + UIDevice.rightMargin > width {
-            currentTimeView.x = width - margin - UIDevice.rightMargin - currentTimeView.width
-        }
-    }
-    func showCurrentTime() {
-        if currentLineView.alpha == 1 {
-            return
-        }
-        UIView.animate(withDuration: 0.2) {
-            self.currentLineView.alpha = 1
-            self.currentTimeView.alpha = 1
-        }
-    }
-    
-    func hideCurrentTime() {
-        UIView.animate(withDuration: 0.2) {
-            self.currentLineView.alpha = 0
-            self.currentTimeView.alpha = 0
-        }
-    }
-    func resetLineViewFrsme(at time: CMTime) {
-        updateLineViewFrame(at: time)
-        if isPlaying {
-            startLineAnimation()
-        }
-    }
-    func updateLineViewFrame(at time: CMTime) {
-        stopLineAnimation()
-        let totalDuration = endDuration - startDuration
-        let seconds = (time.seconds - startDuration) / totalDuration
-        progressLineView.x = bgView.x + frameMaskView.validRect.minX + (
-            frameMaskView.validRect.width - progressLineView.width
-        ) * CGFloat(seconds)
-    }
-    func updateLineViewFrame(at time: TimeInterval) {
-        stopLineAnimation()
-        let totalDuration = endDuration - startDuration
-        let seconds = (time - startDuration) / totalDuration
-        progressLineView.x = bgView.x + frameMaskView.validRect.minX + (
-            frameMaskView.validRect.width - progressLineView.width
-        ) * CGFloat(seconds)
-    }
-    func showLineView(at time: CMTime? = nil) {
-        stopLineAnimation()
-        if let time = time {
-            updateLineViewFrame(at: time)
-        }
-        if progressLineView.alpha == 1 {
-            return
-        }
-        UIView.animate(withDuration: 0.2) {
-            self.progressLineView.alpha = 1
-        }
-    }
-    func hideLineView(at time: CMTime? = nil) {
-        stopLineAnimation()
-        if let time = time {
-            updateLineViewFrame(at: time)
-        }
-        if progressLineView.alpha == 0 {
-            return
-        }
-        UIView.animate(withDuration: 0.2) {
-            self.progressLineView.alpha = 0
-        }
-    }
-    func startLineAnimation() {
-        stopLineAnimation()
-        let scale = (
-            progressLineView.x - bgView.x - frameMaskView.validRect.minX
-        ) / (
-            frameMaskView.validRect.width - progressLineView.width
-        )
-        let totalDuration = endDuration - startDuration
-        let duration = totalDuration - totalDuration * scale
-        let toX = bgView.x + frameMaskView.validRect.maxX - progressLineView.width
-        setLineAnimation(toX: toX, duration: duration)
-    }
-    func setLineAnimation(toX: CGFloat, duration: TimeInterval) {
-        UIView.animate(
-            withDuration: duration,
-            delay: 0,
-            options: [.curveLinear, .allowUserInteraction, .overrideInheritedDuration, .overrideInheritedCurve]
-        ) {
-            self.progressLineView.x = toX
-        } completion: { (isFinished) in
-            if isFinished {
-                self.stopLineAnimation()
-                let startX = self.bgView.x + self.frameMaskView.validRect.minX
-                self.progressLineView.x = startX
-                let totalDuration = self.endDuration - self.startDuration
-                self.setLineAnimation(toX: toX, duration: totalDuration)
-            }
-        }
-    }
-    func stopLineAnimation() {
-        guard let animationKeys = progressLineView.layer.animationKeys(),
-              !animationKeys.isEmpty else {
-            return
-        }
-        let rect = progressLineView.layer.presentation()?.frame ?? progressLineView.frame
-        progressLineView.layer.removeAllAnimations()
-        progressLineView.frame = rect
-    }
-    func resetValidRect() {
-        frameMaskView.validRect = CGRect(
-            x: controlWidth,
-            y: 0,
-            width: bgView.width - controlWidth * 2,
-            height: bgView.height
-        )
-    }
-    func updateTimeLabels() {
-        if assetDuration == 0 {
-            return
-        }
-        var endDuration = self.endDuration
-        if let duration = Double(String(format: "%.2f", arguments: [endDuration])) {
-            endDuration = duration
-        }
-        var startDuration = self.startDuration
-        if let duration = Double(String(format: "%.2f", arguments: [startDuration])) {
-            startDuration = duration
-        }
-        var totalDuration = endDuration - startDuration
-        if totalDuration > config.maximumTime && config.maximumTime > 0 {
-            totalDuration = config.maximumTime
-        }
-        if endDuration > startDuration + totalDuration {
-            endDuration = startDuration + totalDuration
-        }
-        endTimeLb.text = endDuration.time
-        totalTimeLb.text = totalDuration.time
-        startTimeLb.text = startDuration.time
-        startTimeLb.size = startTimeLb.textSize
-        totalTimeLb.size = totalTimeLb.textSize
-        endTimeLb.size = endTimeLb.textSize
-    }
-    var middleDuration: Double {
-        endDuration - startDuration
-    }
-    var startDuration: Double {
-        var offsetX = collectionView.contentOffset.x + collectionView.contentInset.left
-        let validX = frameMaskView.validRect.minX - controlWidth
-        let maxOfssetX = contentWidth - (collectionView.width - collectionView.contentInset.left * 2.0)
-        if offsetX > maxOfssetX {
-            offsetX = maxOfssetX
-        }
-        var second = (offsetX + validX) / contentWidth * assetDuration
-        if second < 0 {
-            second = 0
-        }else if second > assetDuration {
-            second = assetDuration
-        }
-        return second
-    }
-    var startTime: CMTime {
-        CMTimeMakeWithSeconds(
-            Float64(startDuration),
-            preferredTimescale: 1000
-        )
-    }
-    var endDuration: Double {
-        let videoSecond = assetDuration
-        let validWidth = frameMaskView.validRect.width
-        var second = startDuration + validWidth / contentWidth * videoSecond
-        if second > videoSecond {
-            second = videoSecond
-        }
-        return second
-    }
-    var endTime: CMTime {
-        CMTimeMakeWithSeconds(
-            Float64(endDuration),
-            preferredTimescale: 1000
-        )
-    }
-    func stopScroll() {
-        let inset = collectionView.contentInset
-        var currentOffset = collectionView.contentOffset
-        let maxOffsetX = contentWidth - (collectionView.width - inset.left)
-        if currentOffset.x < -inset.left {
-            currentOffset.x = -inset.left
-        }else if currentOffset.x > maxOffsetX {
-            currentOffset.x = maxOffsetX
-        }
-        collectionView.setContentOffset(currentOffset, animated: false)
-    }
-    
-    func showTimeLabels() {
-        if assetDuration == 0 {
-            return
-        }
-        timeLabelsTimer?.invalidate()
-        if startLineView.alpha == 1 {
-            return
-        }
-        UIView.animate(withDuration: 0.2) {
-            self.startLineView.alpha = 1
-            self.startTimeView.alpha = 1
-            self.endLineView.alpha = 1
-            self.endTimeView.alpha = 1
-            self.totalTimeView.alpha = 1
-        }
-    }
-    
-    func hideTimeLabels(_ isDelay: Bool = true) {
-        timeLabelsTimer?.invalidate()
-        if isDelay {
-            timeLabelsTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { [weak self] _ in
-                guard let self = self else { return }
-                UIView.animate(withDuration: 0.2) {
-                    self.startLineView.alpha = 0
-                    self.startTimeView.alpha = 0
-                    self.endLineView.alpha = 0
-                    self.endTimeView.alpha = 0
-                    self.totalTimeView.alpha = 0
-                }
-            })
-        }else {
-            if startLineView.alpha == 0 {
-                return
-            }
-            UIView.animate(withDuration: 0.2) {
-                self.startLineView.alpha = 0
-                self.startTimeView.alpha = 0
-                self.endLineView.alpha = 0
-                self.endTimeView.alpha = 0
-                self.totalTimeView.alpha = 0
-            }
-        }
-    }
-    
-    func updateTimeLabelsFrame() {
-        startTimeLb.size = startTimeLb.textSize
-        startTimeView.size = .init(width: startTimeLb.width + 10, height: startTimeLb.size.height + 5)
-        startTimeLb.center = .init(x: startTimeView.width / 2, y: startTimeView.height / 2)
-        totalTimeLb.size = totalTimeLb.textSize
-        totalTimeView.size = .init(width: totalTimeLb.width + 10, height: totalTimeLb.size.height + 5)
-        totalTimeLb.center = .init(x: totalTimeView.width / 2, y: totalTimeView.height / 2)
-        endTimeLb.size = endTimeLb.textSize
-        endTimeView.size = .init(width: endTimeLb.width + 10, height: endTimeLb.size.height + 5)
-        endTimeLb.center = .init(x: endTimeView.width / 2, y: endTimeView.height / 2)
-        
-        startLineView.y = -startLineView.height - 5
-        startLineView.centerX = bgView.x + frameMaskView.validRect.minX
-        
-        var startTimeX = startLineView.centerX - startTimeView.width / 2
-        startTimeView.y = startLineView.y - startTimeView.height - 2
-        
-        endLineView.y = -endLineView.height - 5
-        endLineView.centerX = bgView.x + frameMaskView.validRect.maxX
-        
-        var endTimeX = endLineView.centerX - endTimeView.width / 2
-        endTimeView.y = endLineView.y - endTimeView.height - 2
-        
-        if endTimeX + endTimeView.width + margin + UIDevice.rightMargin > width {
-            endTimeX = width - margin - UIDevice.rightMargin - endTimeView.width
-        }
-        if startTimeX + startTimeView.width + 5 > endTimeX {
-            startTimeX = endTimeX - 5 - startTimeView.width
-        }
-        if startTimeX < UIDevice.leftMargin + margin {
-            startTimeX = UIDevice.leftMargin + margin
-        }
-        if endTimeX < startTimeX + startTimeView.width + 5 {
-            endTimeX = startTimeX + startTimeView.width + 5
-        }
-        startTimeView.x = startTimeX
-        endTimeView.x = endTimeX
-        
-        totalTimeView.centerX = bgView.x + frameMaskView.validRect.minX + frameMaskView.validRect.width * 0.5
-        if totalTimeView.frame.maxX > width - UIDevice.rightMargin - margin {
-            totalTimeView.x = width - UIDevice.rightMargin - margin - totalTimeView.width
-        }
-        totalTimeView.y = height + 5
-    }
-}
-extension EditorVideoControlView: UICollectionViewDataSource,
-                               UICollectionViewDelegate,
-                               UICollectionViewDelegateFlowLayout {
-    
-    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        videoFrameCount
-    }
-    func collectionView(
-        _ collectionView: UICollectionView,
-        cellForItemAt indexPath: IndexPath
-    ) -> UICollectionViewCell {
-        let cell = collectionView.dequeueReusableCell(
-            withReuseIdentifier: "EditorVideoControlViewCellID",
-            for: indexPath
-        ) as! EditorVideoControlViewCell
-        return cell
-    }
-    func collectionView(
-        _ collectionView: UICollectionView,
-        layout collectionViewLayout: UICollectionViewLayout,
-        sizeForItemAt indexPath: IndexPath
-    ) -> CGSize {
-        if indexPath.item < videoFrameCount - 1 {
-            return CGSize(width: itemWidth, height: height - 8)
-        }
-        let itemW = contentWidth - CGFloat(indexPath.item) * itemWidth
-        return CGSize(width: itemW, height: height - 8)
-    }
-    func collectionView(
-        _ collectionView: UICollectionView,
-        willDisplay cell: UICollectionViewCell,
-        forItemAt indexPath: IndexPath
-    ) {
-        let myCell = cell as! EditorVideoControlViewCell
-        self.videoFrameLock.sync {
-            if videoFrameMap.keys.contains(indexPath.item),
-               let cgImage = videoFrameMap[indexPath.item] {
-                myCell.image = UIImage(cgImage: cgImage)
-            }else {
-                if let result = videoFrameMap.first {
-                    myCell.image = UIImage(cgImage: result.value)
-                }
-            }
-        }
-    }
-    func setCurrentCell(image: UIImage, index: Int) {
-        DispatchQueue.main.async {
-            let cell = self.collectionView.cellForItem(
-                at: IndexPath(item: index, section: 0)
-            ) as? EditorVideoControlViewCell
-            cell?.image = image
-        }
-    }
-    func getVideoCurrentTime(for index: Int) -> CMTime {
-        var second: CGFloat
-        let maxIndex = videoFrameCount - 1
-        if index == 0 {
-            second = 0.1
-        }else if index >= maxIndex {
-            if assetDuration < 1 {
-                second = CGFloat(assetDuration - 0.1)
-            }else {
-                second = CGFloat(assetDuration - 0.5)
-            }
-        }else {
-            if assetDuration < 1 {
-                second = 0
-            }else {
-                second = CGFloat(index) * interval + interval * 0.5
-            }
-        }
-        let time = CMTimeMakeWithSeconds(Float64(second), preferredTimescale: 1000)
-        return time
-    }
-    func scrollViewDidScroll(_ scrollView: UIScrollView) {
-        if videoFrameCount > 0 {
-            if !scrollView.isTracking && !scrollView.isDragging && !scrollView.isDecelerating {
-                return
-            }
-            isBeginScrolling = true
-            delegate?.controlView(self, didScrollAt: startTime)
-            updateTimeLabels()
-            updateTimeLabelsFrame()
-            if scrollView.isTracking {
-                showTimeLabels()
-                hideLineView()
-                stopLineAnimation()
-            }
-        }
-    }
-    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
-        if !decelerate && isBeginScrolling {
-            showLineView(at: startTime)
-            delegate?.controlView(self, endScrollAt: startTime)
-            updateTimeLabels()
-            updateTimeLabelsFrame()
-            hideTimeLabels()
-        }
-        isBeginScrolling = false
-    }
-    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
-        if !isBeginScrolling {
-            return
-        }
-        showLineView(at: startTime)
-        delegate?.controlView(self, endScrollAt: startTime)
-        updateTimeLabels()
-        updateTimeLabelsFrame()
-        hideTimeLabels()
-        isBeginScrolling = false
-    }
-}
-
-extension EditorVideoControlView: EditorVideoControlMaskViewDelegate {
-    func frameMaskView(leftValidRectDidChanged frameMaskView: EditorVideoControlMaskView) {
-        updateTimes(true)
-        hideLineView(at: startTime)
-        delegate?.controlView(self, leftDidChangedValidRectAt: startTime)
-    }
-    func frameMaskView(leftValidRectEndChanged frameMaskView: EditorVideoControlMaskView) {
-        updateTimes(false)
-        showLineView(at: startTime)
-        delegate?.controlView(self, leftEndChangedValidRectAt: startTime)
-    }
-    func frameMaskView(rightValidRectDidChanged frameMaskView: EditorVideoControlMaskView) {
-        updateTimes(true)
-        hideLineView(at: endTime)
-        delegate?.controlView(self, rightDidChangedValidRectAt: endTime)
-    }
-    func frameMaskView(rightValidRectEndChanged frameMaskView: EditorVideoControlMaskView) {
-        updateTimes(false)
-        showLineView(at: endTime)
-        delegate?.controlView(self, rightEndChangedValidRectAt: endTime)
-    }
-    
-    func updateTimes(_ isShow: Bool) {
-        let totalDuration = endDuration - startDuration
-        frameMaskView.isShowFrame = totalDuration < assetDuration
-        updateTimeLabels()
-        updateTimeLabelsFrame()
-        if isShow {
-            showTimeLabels()
-        }else {
-            hideTimeLabels()
-        }
-    }
-}
-
-struct EditorVideoControlInfo: Codable {
-    let offsetXScale: CGFloat
-    let validXScale: CGFloat
-    let validWithScale: CGFloat
-}
-
-extension EditorVideoControlView {
-    
-    var controlInfo: EditorVideoControlInfo {
-        let offsetX = collectionView.contentOffset.x
-        let validX = frameMaskView.validRect.minX
-        let validWidth = frameMaskView.validRect.width
-        
-        let insert = collectionView.contentInset
-        let offsetXScale = (offsetX + insert.left) / contentWidth
-        let validInitialX = controlWidth
-        let validMaxWidth = bgView.width - validInitialX * 2
-        let validXScale = (validX - validInitialX) / validMaxWidth
-        let validWithScale = validWidth / validMaxWidth
-        return .init(offsetXScale: offsetXScale, validXScale: validXScale, validWithScale: validWithScale)
-    }
-    
-    func setControlInfo(_ info: EditorVideoControlInfo) {
-        if avAsset == nil {
-            return
-        }
-        let insert = collectionView.contentInset
-        let offsetX = -insert.left + contentWidth * info.offsetXScale
-        collectionView.setContentOffset(CGPoint(x: offsetX, y: -insert.top), animated: false)
-        let validInitialX = controlWidth
-        let validMaxWidth = bgView.width - validInitialX * 2
-        let validX = validMaxWidth * info.validXScale + validInitialX
-        let vaildWidth = validMaxWidth * info.validWithScale
-        frameMaskView.validRect = CGRect(x: validX, y: 0, width: vaildWidth, height: bgView.height)
-        let totalDuration = endDuration - startDuration
-        frameMaskView.isShowFrame = totalDuration < assetDuration
-        frameMaskView.updateFrameView()
-        updateTimeLabels()
-        updateTimeLabelsFrame()
-        showLineView(at: startTime)
-    }
-}
-
-fileprivate extension Double {
-    var time: String {
-        if self < 60 {
-            let sec = Double(String(format: "%.2f", arguments: [self])) ?? self
-            if sec < 10 {
-                return String(format: "00:0%.2f", arguments: [sec])
-            }else {
-                return String(format: "00:%.2f", arguments: [sec])
-            }
-        }else {
-            var min = Double(Int(self / 60))
-            let sec = Double(String(format: "%.2f", arguments: [self - (min * 60)])) ?? self - (min * 60)
-            if min < 60 {
-                if min < 10 {
-                    if sec < 10 {
-                        return String(format: "0%.0f:0%.2f", arguments: [min, sec])
-                    }else {
-                        return String(format: "0%.0f:%.2f", arguments: [min, sec])
-                    }
-                }else {
-                    if sec < 10 {
-                        return String(format: "%.0f:0%.2f", arguments: [min, sec])
-                    }else {
-                        return String(format: "%.0f:%.2f", arguments: [min, sec])
-                    }
-                }
-            }else {
-                let hour = Double(Int(min / 60))
-                min -= hour * 60
-                if hour < 10 {
-                    if min < 10 {
-                        if sec < 10 {
-                            return String(format: "0%.0f:0%.0f:0%.2f", arguments: [hour, min, sec])
-                        }else {
-                            return String(format: "0%.0f:0%.0f:%.2f", arguments: [hour, min, sec])
-                        }
-                    }else {
-                        if sec < 10 {
-                            return String(format: "0%.0f:%.0f:0%.2f", arguments: [hour, min, sec])
-                        }else {
-                            return String(format: "0%.0f:%.0f:%.2f", arguments: [hour, min, sec])
-                        }
-                    }
-                }
-                if min < 10 {
-                    if sec < 10 {
-                        return String(format: "%.0f:0%.0f:0%.2f", arguments: [hour, min, sec])
-                    }else {
-                        return String(format: "%.0f:0%.0f:%.2f", arguments: [hour, min, sec])
-                    }
-                }else {
-                    if sec < 10 {
-                        return String(format: "%.0f:%.0f:0%.2f", arguments: [hour, min, sec])
-                    }else {
-                        return String(format: "%.0f:%.0f:%.2f", arguments: [hour, min, sec])
-                    }
-                }
-            }
-        }
-    }
-}

+ 0 - 38
TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/EditorVideo/EditorVideoControlViewCell.swift

@@ -1,38 +0,0 @@
-//
-//  EditorVideoControlViewCell.swift
-//  HXPhotoPicker
-//
-//  Created by Silence on 2023/5/13.
-//
-
-import UIKit
-
-class EditorVideoControlViewCell: UICollectionViewCell {
-    
-    private var imageView: UIImageView!
-    
-    var image: UIImage? {
-        didSet {
-            if let image = image {
-                imageView.setImage(image, animated: true)
-            }
-        }
-    }
-    
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        imageView = UIImageView()
-        imageView.clipsToBounds = true
-        imageView.contentMode = .scaleAspectFill
-        addSubview(imageView)
-    }
-    
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-    override func layoutSubviews() {
-        super.layoutSubviews()
-        imageView.frame = bounds
-    }
-}

+ 0 - 312
TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoClipperController.swift

@@ -1,312 +0,0 @@
-//
-//  GPVideoClipperController.swift
-//  GPVideoClipperDemo-Swift
-//
-//  Created by Roc Kwok on 2020/5/19.
-//  Copyright © 2020 Roc Kwok. All rights reserved.
-//
-
-import UIKit
-import AVKit
-import Photos
-
-typealias ClipperCallback = (_ videoURL: URL, _ videoAsset: PHAsset, _ coverImage: UIImage) -> Void;
-
-class GPVideoClipperController: TSBaseVC, GPVideoPlayerViewDelegate, GPVideoClipperViewDelegate {
-    
-    let kClipViewHeight = 188
-    let kCutVideoPath = "cutDoneVideo.mp4"
-    var videoURL: URL!
-    var timeObserver: Any!
-    var outputURL: URL!
-    var coverImage: UIImage!
-    var callback: ClipperCallback?
-    
-    lazy var maker: GPVideoConfigMaker = {
-        var maker = GPVideoConfigMaker.init()
-        maker.startTime = 0
-        maker.endTime = 15
-        maker.clippedVideoMinDuration = 3
-        maker.clippedVideoMaxDuration = 15
-        maker.sourceVideoTotalDuration = CGFloat(CMTimeGetSeconds(AVURLAsset.init(url: self.videoURL).duration))
-        return maker
-    }()
-    
-    lazy var playerView: GPVideoPlayerView = {
-        let x = 53.0
-        let y = k_Nav_Height
-        let width = self.view.frame.size.width - x * 2
-        let bottomMargin = self.gp_safeAreaBottomHeight() + 25
-        let height = self.view.frame.size.height - y - bottomMargin - CGFloat(kClipViewHeight)
-        let playerView = GPVideoPlayerView.init(frame: CGRect.init(x: x, y: y, width: width, height: height), videoURL: self.videoURL)
-        playerView.delegate = self
-        playerView.maker = self.maker
-        return playerView
-    }()
-    
-    lazy var clipperView: GPVideoClipperView = {
-        let x = CGFloat(0)
-        let y = self.view.bounds.size.height - self.gp_safeAreaBottomHeight() - CGFloat(kClipViewHeight) - 25
-        let width = self.view.bounds.size.width
-        let height = CGFloat(kClipViewHeight)
- 
-        var clipperView = GPVideoClipperView.init(frame: CGRect.init(x: x, y: y, width: width, height: height), maker: self.maker)
-        clipperView.delegate = self
-        clipperView.avAsset = AVAsset.init(url: self.videoURL)
-        return clipperView
-    }()
-    
-    
-    //MARK: - Life cycle
-    
-    override func viewDidLoad() {
-        super.viewDidLoad()
-        addNormalNavBarView()
-        setTitleText("DIY Live Wallpaper".localized)
-        _ = setNavigationItem("", imageName: "close_down_white", direction: .left, action: #selector(navBarClickLeftAction))
-        
-        self.view.addSubview(self.playerView)
-        self.view.addSubview(self.clipperView)
-    }
-    
-    override func viewWillAppear(_ animated: Bool) {
-        self.navigationController?.setNavigationBarHidden(true, animated: true)
-    }
-    
-    override func viewWillDisappear(_ animated: Bool) {
-        self.navigationController?.setNavigationBarHidden(false, animated: true)
-    }
-    
-    deinit {
-          if self.timeObserver != nil {
-            self.playerView.player.removeTimeObserver(self.timeObserver as Any)
-            self.timeObserver = nil
-          }
-    }
-    
-    //MARK: - Public
-    static func clipperWithVideoURL(_ videoURL: URL, makerBlock:@escaping(GPVideoConfigMaker)->Void, callback: @escaping ClipperCallback) -> GPVideoClipperController {
-        let maker = GPVideoConfigMaker.init()
-        makerBlock(maker)
-        maker.sourceVideoTotalDuration = CGFloat(CMTimeGetSeconds(AVURLAsset.init(url: videoURL).duration))
-        let controller = GPVideoClipperController.init()
-        controller.videoURL = videoURL
-        controller.maker = maker
-        controller.callback = callback
-        return controller
-    }
-    
-    //MARK: - Private
-    
-    func gp_back() {
-        let array: NSArray = NSArray.init(array: self.navigationController!.viewControllers)
-        if (self.navigationController != nil) && array.index(of: self) != 0 {
-            self.navigationController?.popViewController(animated: true)
-        } else {
-            self.dismiss(animated: true, completion: nil)
-        }
-    }
-    
-    func gp_playVideo() {
-        self.playerView.player.seek(to: CMTime.init(value: CMTimeValue(self.maker.startTime * 1000), timescale: 1000), toleranceBefore: .zero, toleranceAfter: .zero)
-        self.playerView.player.play()
-        if self.timeObserver != nil {
-            self.playerView.player.removeTimeObserver(self.timeObserver as Any)
-            self.timeObserver = nil
-        }
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
-            self.timeObserver = self.playerView.player.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 10), queue: .main, using: { [weak self](time) in
-                guard let self = self else { return }
-                
-                let delta = CMTimeGetSeconds(time)
-                let temp = CGFloat((self.maker.endTime)) - CGFloat((self.maker.startTime))
-                self.clipperView.gp_updateProgressViewWithProgress((CGFloat(delta) - self.maker.startTime) / CGFloat(temp))
-            })
-        }
-    }
-    
-    func gp_safeAreaBottomHeight() -> CGFloat {
-        var bottom: CGFloat!
-        if #available(iOS 11.0, *) {
-            bottom = (UIApplication.shared.windows.first?.safeAreaInsets.bottom)!
-        }
-        if bottom <= 0 && self.gp_isIphoneXSeries() {
-            bottom = 34
-        }
-        return bottom
-    }
-    
-    func gp_statusBarHeight() -> CGFloat {
-        var statusBarHeight: CGFloat
-        if #available(iOS 13.0, *) {
-            statusBarHeight = (UIApplication.shared.windows.first?.windowScene?.statusBarManager?.statusBarFrame.size.height)!
-        } else {
-            statusBarHeight = UIApplication.shared.statusBarFrame.size.height
-        }
-        return statusBarHeight
-    }
-    
-    func gp_isIphoneXSeries() -> Bool {
-        return self.gp_statusBarHeight() == 40 ? true : false
-    }
-    
-    func gp_saveVideo() {
-        if self.videoURL.absoluteString.count > 0 && self.maker.startTime >= 0 && self.maker.endTime > self.maker.startTime {
-            self.gp_clippVideoWithCompletion {
-                
-                
-                if self.maker.saveClipViewToPhoto {
-                    self.gp_saveVideoToAlbumWithVideoURL(URL: self.outputURL, success: { (asset) in
-                        PHImageManager.default().requestAVAsset(forVideo: asset!, options: nil) { (avAsset, audioMix, info) in
-                            let urlAsset:AVURLAsset = avAsset as! AVURLAsset
-                            let url = urlAsset.url
-                            DispatchQueue.main.async {
-                                print(url, asset as Any, self.coverImage as Any)
-                                self.gp_back()
-                                if self.callback != nil {
-                                    self.callback!(url, asset!, self.coverImage!)
-                                }
-                            }
-                        }
-                    }) { (message) in
-                        print(String.init(format: "Save failed:%@", message!))
-                    }
-                }else {
-                    DispatchQueue.main.async {
-                        self.coverImage = self.gp_getVideoPreViewImage(path: self.outputURL)
-                        self.gp_back()
-                        self.callback?(self.outputURL, PHAsset(), self.coverImage)
-                    }
-                }
-                
-
-            }
-        }
-    }
-    
-    func gp_clippVideoWithCompletion(completionHandle: @escaping() -> Void) {
-        let asset = AVURLAsset.init(url: self.videoURL)
-        let exportSession = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetPassthrough)
-        let outputPath = NSString.init(string: NSTemporaryDirectory()).appendingPathComponent(kCutVideoPath)
-        self.outputURL = URL.init(fileURLWithPath: outputPath)
-        if FileManager.default.fileExists(atPath: outputPath) {
-            do {
-                try FileManager.default.removeItem(atPath: outputPath)
-            } catch {}
-        }
-        exportSession!.outputFileType = .mp4
-        exportSession!.outputURL = self.outputURL as URL?
-        exportSession!.shouldOptimizeForNetworkUse = true
-        
-        let start = CMTimeMakeWithSeconds(Float64(maker.startTime), preferredTimescale: asset.duration.timescale)
-        let duration = CMTimeMakeWithSeconds(Float64(maker.endTime - maker.startTime), preferredTimescale: asset.duration.timescale)
-        let range = CMTimeRangeMake(start: start, duration: duration)
-        exportSession?.timeRange = range
-        
-        exportSession?.exportAsynchronously(completionHandler: {
-            completionHandle()
-        })
-    }
-    
-    func gp_saveVideoToAlbumWithVideoURL(URL: URL, success completionHandler: @escaping(PHAsset?) -> Void, failure:@escaping(String?)->Void) {
-        var _targetCollection: PHAssetCollection? = nil
-        var _asset: PHAsset? = nil
-        var _assetIdentifier: String? = nil
-        var _collectionIdentifier: String? = nil
-
-        let collectionTitle = Bundle.main.infoDictionary?[kCFBundleNameKey as String] as? String
-        let results:PHFetchResult<PHAssetCollection> = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: nil)
-        
-        results.enumerateObjects { (collection, index, protocol) in
-            if collection.localizedTitle == collectionTitle {
-                _targetCollection = collection
-            }
-        }
-        
-        PHPhotoLibrary.shared().performChanges({
-            _assetIdentifier = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL)?.placeholderForCreatedAsset?.localIdentifier
-        }) { (success, error) in
-            if success {
-                PHPhotoLibrary.shared().performChanges({
-                    if _targetCollection == nil {
-                        _collectionIdentifier = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: collectionTitle!).placeholderForCreatedAssetCollection.localIdentifier
-                    }
-                    
-                }) { (success1, error1) in
-                    if success1 {
-                        PHPhotoLibrary.shared().performChanges({
-                            if _targetCollection == nil {
-                                _targetCollection = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [_collectionIdentifier!], options: nil).lastObject
-                             }
-                             _asset = PHAsset.fetchAssets(withLocalIdentifiers: [_assetIdentifier!], options: nil).lastObject
-                             let requestCollection = PHAssetCollectionChangeRequest.init(for: _targetCollection!)
-                             let enumeration: NSArray = [_asset!]
-                             requestCollection?.addAssets(enumeration)
-                            
-                        }) { (success2, error2) in
-                            if success2 {
-                                self.coverImage = self.gp_getVideoPreViewImage(path: self.outputURL)
-                                completionHandler(_asset)
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-    
-    func gp_getVideoPreViewImage(path: URL) -> UIImage {
-        var videoImage:UIImage!
-        let asset = AVURLAsset.init(url: path, options: nil)
-        let assetGen = AVAssetImageGenerator.init(asset: asset)
-        assetGen.appliesPreferredTrackTransform = true
-        let time = CMTimeMakeWithSeconds(0.0, preferredTimescale: 600)
-        let pointer = UnsafeMutablePointer<CMTime>.allocate(capacity: 1);
-        do {
-            let image = try assetGen.copyCGImage(at: time, actualTime: pointer)
-            videoImage = UIImage.init(cgImage: image)
-            return videoImage
-        } catch {}
-        return videoImage
-    }
-    
-    //MARK: - <GPVideoPlayerViewDelegate>
-    
-    func gp_videoReadyToPlay() {
-        self.playerView.playerItem.forwardPlaybackEndTime = CMTime.init(value: (CMTimeValue(self.maker.endTime * 1000)), timescale: 1000)
-        self.gp_playVideo()
-    }
-    
-    //MARK: - <GPVideoClipperViewDelegate>
-    
-    func gp_cancelButtonAction(button: UIButton) {
-        self.gp_back()
-    }
-    
-    func gp_doneButtonAction(button: UIButton) {
-        self.gp_saveVideo()
-    }
-    
-    func gp_playButtonAction(button: UIButton) {
-        if self.playerView.player.rate > 0 {
-            self.playerView.player.pause()
-        }else{
-            self.playerView.player.play()
-        }
-    }
-    
-    func gp_videoLengthDidChanged(time: CGFloat) {
-        guard time < 0 else {
-            if self.playerView.playerItem.status == .readyToPlay {
-                self.playerView.player.seek(to: CMTime.init(value: CMTimeValue(time * 1000), timescale: 1000), toleranceBefore: .zero, toleranceAfter: .zero)
-                self.playerView.player.pause()
-            }
-            return
-        }
-    }
-    
-    func gp_didEndDragging() {
-        self.playerView.playerItem.forwardPlaybackEndTime =  CMTime.init(value: (CMTimeValue(self.maker.endTime * 1000)), timescale: 1000)
-        self.gp_playVideo()
-    }
-}

+ 0 - 570
TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoClipperView.swift

@@ -1,570 +0,0 @@
-//
-//  GPVideoClipperView.swift
-//  GPVideoClipperDemo-Swift
-//
-//  Created by Roc Kwok on 2020/5/19.
-//  Copyright © 2020 Roc Kwok. All rights reserved.
-//
-
-import UIKit
-import AVKit
-
-@objc protocol GPVideoClipperViewDelegate: NSObjectProtocol {
-    @objc func gp_playButtonAction(button: UIButton)
-    @objc func gp_cancelButtonAction(button: UIButton)
-    @objc func gp_doneButtonAction(button: UIButton)
-    @objc func gp_videoLengthDidChanged(time: CGFloat)
-    @objc func gp_didEndDragging()
-}
-
-class GPVideoClipperView: UIView, UICollectionViewDelegate, UICollectionViewDataSource {
-
-    // Const
-    let kDurationLabelWidth = 70.0
-    let kButtonWidth: CGFloat = 60.0
-    let kButtonHeight: CGFloat = 30.0
-    let kLineHeight: CGFloat = 3.0
-    
-    // Public
-    weak var delegate:GPVideoClipperViewDelegate?
-    var avAsset: AVAsset! {
-          willSet {
-            self.avAsset = newValue
-              kDelayMainShort {
-                  self.p_loadThumbnailImages()
-              }
-          }
-    }
-    var progressTime: CGFloat! {
-        return (self.progressView.frame.minX - self.leftImageView.frame.maxX) / self.perSecondWidth
-    }
-    
-    // Private
-    private var maker: GPVideoConfigMaker!
-    private var selectedTime: CGFloat!
-    private var cellWidth: CGFloat!
-    private var cellCount: UInt!
-    private var perSecondWidth: CGFloat!
-    private var collectionInsets: UIEdgeInsets!
-    private var imageArray:[UIImage] = []
-    private var preOriginX: CGFloat!
-    private var selectedImageView: UIImageView!
-    
-    private lazy var collectionView: UICollectionView = {
-        var layout = UICollectionViewFlowLayout.init()
-        layout.itemSize = CGSize.init(width: self.cellWidth, height: 40)
-        layout.minimumInteritemSpacing = 0.0
-        layout.minimumLineSpacing = 0.01
-        layout.scrollDirection = .horizontal
-        
-        var collectionView = UICollectionView.init(frame:.zero, collectionViewLayout: layout)
-        collectionView.backgroundColor = .clear
-        collectionView.alwaysBounceHorizontal = true
-        collectionView.showsHorizontalScrollIndicator = false
-        collectionView.clipsToBounds = false
-        collectionView.delegate = self
-        collectionView.dataSource = self
-        collectionView.contentInset = self.collectionInsets;
-        collectionView.clipsToBounds = true
-        collectionView.register(GPVideoClipperImageCell.self, forCellWithReuseIdentifier: NSStringFromClass(GPVideoClipperImageCell.self))
-        return collectionView
-    }()
-    
-    private lazy var imageGenerator: AVAssetImageGenerator = {
-        var imageGenerator = AVAssetImageGenerator.init(asset: self.avAsset)
-        imageGenerator.appliesPreferredTrackTransform = true;
-        imageGenerator.requestedTimeToleranceBefore = .zero;
-        imageGenerator.requestedTimeToleranceAfter = .zero;
-        imageGenerator.maximumSize = CGSize.init(width: 320, height: 320)
-        return imageGenerator
-    }()
-    
-    private lazy var durationLabel: UILabel = {
-        var durationLabel = UILabel.init()
-        durationLabel.font = UIFont.boldSystemFont(ofSize: 12)
-        durationLabel.backgroundColor = .black
-        durationLabel.textColor = .white
-        durationLabel.textAlignment = .right
-        durationLabel.isHidden = self.maker.isHiddenSelectedTimeTag
-        return durationLabel
-    }()
-    
-    private lazy var startTimeLabel: UILabel = {
-        var durationLabel = UILabel.init()
-        durationLabel.font = UIFont.boldSystemFont(ofSize: 12)
-        durationLabel.backgroundColor = .black
-        durationLabel.textColor = .white
-        durationLabel.textAlignment = .left
-        durationLabel.isHidden = self.maker.isHiddenSelectedTimeTag
-        return durationLabel
-    }()
-    
-    private lazy var endTimeLabel: UILabel = {
-        var durationLabel = UILabel.init()
-        durationLabel.font = UIFont.boldSystemFont(ofSize: 12)
-        durationLabel.backgroundColor = .black
-        durationLabel.textColor = .white
-        durationLabel.textAlignment = .right
-        durationLabel.isHidden = self.maker.isHiddenSelectedTimeTag
-        return durationLabel
-    }()
-    
-    private lazy var playBtn: UIButton = {
-        var playBtn = UIButton.createButton(image: UIImage(named: "edit_pause"))
-        playBtn.addTarget(self, action: #selector(palyButtonAction(_:)), for: .touchUpInside)
-        playBtn.isSelected = true
-        return playBtn
-    }()
-    
-    private lazy var leftPlayBtnView: UIView = {
-        let view = UIView()
-        
-        let bgImageView = UIImageView.createImageView(imageName:"edit_play_bg")
-        bgImageView.frame = CGRect(x: 0, y: 0, width: 54, height: 40)
-        view.addSubview(bgImageView)
-        
-        playBtn.frame = CGRect(x: 12, y: 7, width: 24, height: 24)
-        view.addSubview(playBtn)
-        
-        return view
-        
-    }()
-    
-    private lazy var doneButton: UIButton = {
-        var doneButton = TSViewTool.createNormalSubmitBtn(title: "Create Live Wallpaper".localized)
-        doneButton.layer.cornerRadius = 24
-        doneButton.clipsToBounds = true
-        doneButton.addTarget(self, action: #selector(doneButtonAction(_:)), for: .touchUpInside)
-        return doneButton
-    }()
-    
-    private lazy var leftImageView: UIImageView = {
-        var leftImageView = UIImageView.init()
-        leftImageView.isUserInteractionEnabled = true
-        leftImageView.contentMode = .scaleToFill
-//        if ((self.maker?.selectedBoxColor) != nil) {
-//            leftImageView.backgroundColor = self.maker.selectedBoxColor
-//        }
-        if ((self.maker?.leftSelectedImage) != nil) {
-            leftImageView.image = self.maker.leftSelectedImage
-        }
-        var panGesture = UIPanGestureRecognizer.init(target: self, action: Selector.init(("panGesture:")))
-        panGesture.maximumNumberOfTouches = 1
-        leftImageView.addGestureRecognizer(panGesture)
-        return leftImageView
-    }()
-    
-    private lazy var rightImageView: UIImageView = {
-        var rightImageView = UIImageView.init()
-        rightImageView.isUserInteractionEnabled = true
-        rightImageView.contentMode = .scaleAspectFill
-//        if ((self.maker?.selectedBoxColor) != nil) {
-//            rightImageView.backgroundColor = self.maker.selectedBoxColor
-//        }
-        if ((self.maker?.rightSelectedImage) != nil) {
-            rightImageView.image = self.maker.rightSelectedImage
-        }
-        var panGesture = UIPanGestureRecognizer.init(target: self, action: Selector.init(("panGesture:")))
-        panGesture.maximumNumberOfTouches = 1
-        rightImageView.addGestureRecognizer(panGesture)
-        return rightImageView
-    }()
-    
-    private lazy var topLine: UIImageView = {
-        var topLine = UIImageView()
-        if ((self.maker?.selectedBoxColor) != nil ){
-            topLine.backgroundColor = self.maker.selectedBoxColor
-        }
-        return topLine
-    }()
-    
-    private lazy var bottomLine: UIImageView = {
-        var bottomLine = UIImageView()
-        if ((self.maker?.selectedBoxColor) != nil ){
-            bottomLine.backgroundColor = self.maker.selectedBoxColor
-        }
-        return bottomLine
-    }()
-    
-    private lazy var progressView: UIButton = {
-        var progressView = UIButton.init(type:.custom)
-        progressView.isEnabled = true
-        progressView.isUserInteractionEnabled = true
-        progressView.backgroundColor = UIColor.white
-        return progressView
-    }()
-    
-    //MARK: - Action
-    
-    @objc func panGesture(_ gesture: UIPanGestureRecognizer) {
-        let point = gesture.translation(in: self.superview)
-        switch gesture.state {
-        case .began:
-            self.preOriginX = 0
-            self.selectedImageView = gesture.view as? UIImageView
-            break
-        case .changed:
-            var offsetX = point.x - self.preOriginX
-            self.preOriginX = point.x
-            if self.selectedImageView == self.leftImageView {
-                var frame = self.leftImageView.frame
-                frame.origin.x += offsetX
-                if frame.origin.x <= self.maker.leftMargin {
-                    offsetX += self.maker.leftMargin - frame.origin.x;
-                    frame.origin.x = self.maker.leftMargin;
-                }
-                let minLength = self.rightImageView.frame.origin.x - self.maker.clippedVideoMinDuration * self.perSecondWidth - self.maker.selectedImageWidth
-                if (frame.origin.x >= minLength) {
-                    offsetX -= frame.origin.x - minLength;
-                    frame.origin.x = minLength;
-                }
-                let time = offsetX / self.perSecondWidth;
-                self.maker.startTime = self.maker.startTime + time;
-                self.leftImageView.frame = frame;
-                if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_videoLengthDidChanged(time:))))! {
-                    self.delegate?.gp_videoLengthDidChanged(time: self.maker!.startTime)
-                }
-            } else if self.selectedImageView == self.rightImageView {
-                var frame = self.rightImageView.frame
-                frame.origin.x += offsetX
-                let rightImageMaxX = self.frame.size.width - self.maker.rightMargin - self.maker.selectedImageWidth
-                if (frame.origin.x >= rightImageMaxX) {
-                    offsetX -= frame.origin.x - rightImageMaxX;
-                    frame.origin.x = rightImageMaxX;
-                }
-                let rightImageMinX = self.leftImageView.frame.maxX + self.maker.clippedVideoMinDuration * self.perSecondWidth;
-                if (frame.origin.x <= rightImageMinX) {
-                    offsetX += rightImageMinX - frame.origin.x;
-                    frame.origin.x = rightImageMinX;
-                }
-                let time = offsetX / self.perSecondWidth;
-                self.maker.endTime = self.maker.endTime + time;
-                self.rightImageView.frame = frame;
-                if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_videoLengthDidChanged(time:))))! {
-                    self.delegate?.gp_videoLengthDidChanged(time: self.maker!.endTime)
-                }
-            }
-            
-            self.progressView.frame = CGRect.init(x: self.leftImageView.frame.maxX, y: self.progressView.frame.origin.y, width: self.progressView.frame.size.width, height: self.progressView.frame.size.height)
-            self.selectedTime = self.maker.endTime - self.maker.startTime;
-            self.durationLabel.text = String.init(format: "已选取%.1fs", self.selectedTime)
-            
-            
-            var startDuration:Double = self.maker.startTime
-            if let duration = Double(String(format: "%.2f", arguments: [startDuration])) {
-                startDuration = duration
-            }
-            var endDuration:Double = self.maker.endTime
-            if let duration = Double(String(format: "%.2f", arguments: [endDuration])) {
-                endDuration = duration
-            }
-            self.startTimeLabel.text = startDuration.time
-            self.endTimeLabel.text = endDuration.time
-            
-            
-            var topLineFrame = self.topLine.frame;
-            var bottomLineFrame = self.bottomLine.frame;
-            topLineFrame.origin.x = self.leftImageView.frame.maxX
-            bottomLineFrame.origin.x = self.leftImageView.frame.maxX
-            topLineFrame.size.width = self.rightImageView.frame.minX - self.leftImageView.frame.maxX
-            bottomLineFrame.size.width = self.rightImageView.frame.minX - self.leftImageView.frame.maxX
-            
-            self.topLine.frame = topLineFrame;
-            self.bottomLine.frame = bottomLineFrame;
-            break
-        case .ended:
-            self.selectedImageView = nil
-            if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_didEndDragging)))! {
-                self.delegate?.gp_didEndDragging()
-            }
-            break
-        default:
-            break
-        }
-    }
-    
-    //MARK: - <UICollectionViewDelegate, UICollectionViewDataSource>
-    
-    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        return self.imageArray.count
-    }
-    
-    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(GPVideoClipperImageCell.self), for: indexPath) as! GPVideoClipperImageCell
-        cell.imageView.image = self.imageArray[indexPath.item]
-        return cell
-    }
-    
-    //MARK: - <ScrollViewDelegate>
-    
-    func scrollViewDidScroll(_ scrollView: UIScrollView) {
-        let time = (scrollView.contentOffset.x + self.collectionInsets.left) / self.perSecondWidth
-        let startTime = time + (self.leftImageView.frame.maxX - self.collectionInsets.left) / self.perSecondWidth
-        
-        guard startTime < 0 else {
-            self.maker.startTime = startTime
-            let endTime = self.maker.startTime + self.selectedTime
-            self.maker.endTime = endTime > self.maker.sourceVideoTotalDuration ? self.maker.sourceVideoTotalDuration:endTime
-            self.maker.startTime = self.maker.endTime - self.selectedTime
-            self.gp_updateProgressViewWithProgress(0.0)
-            if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_videoLengthDidChanged(time:))))! {
-                self.delegate?.gp_videoLengthDidChanged(time: self.maker!.startTime + self.progressTime)
-            }
-            return
-        }
-    }
-    
-    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
-        if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_didEndDragging)))! {
-            self.delegate?.gp_didEndDragging()
-        }
-    }
-    
-    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
-        if !decelerate {
-           if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_didEndDragging)))! {
-               self.delegate?.gp_didEndDragging()
-           }
-        }
-    }
-    
-    @objc func cancelButtonAction(_ button: UIButton) {
-        if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_cancelButtonAction(button:))))! {
-            self.delegate?.gp_cancelButtonAction(button: button)
-        }
-    }
-    
-    @objc func doneButtonAction(_ button: UIButton) {
-        if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_doneButtonAction(button:))))! {
-            self.delegate?.gp_doneButtonAction(button: button)
-        }
-    }
-    
-    @objc func palyButtonAction(_ button: UIButton) {
-        if (self.delegate != nil) && (self.delegate?.responds(to: #selector(self.delegate?.gp_playButtonAction(button:))))! {
-            self.delegate?.gp_playButtonAction(button: button)
-            
-            button.isSelected = !button.isSelected
-            button.setImage(UIImage(named: button.isSelected ? "edit_pause" : "edit_play"), for: .normal)
-        }
-    }
-    
-    
-    //MARK: - Init
-    
-    init(frame: CGRect, maker: GPVideoConfigMaker) {
-        self.maker = maker
-        super.init(frame: frame)
-        self.isUserInteractionEnabled = true
-        self.clipsToBounds = true
-        self.backgroundColor = .clear
-        
-        let length = self.frame.size.width - self.maker.leftMargin - self.maker.rightMargin - self.maker.selectedImageWidth * 2
-        self.cellWidth = length / CGFloat(self.maker.defaultSelectedImageCount)
-        
-        if self.maker.sourceVideoTotalDuration <= self.maker.clippedVideoMaxDuration {
-            self.maker.endTime = self.maker.sourceVideoTotalDuration;
-            self.cellCount = self.maker.defaultSelectedImageCount
-        } else {
-            self.maker.endTime = self.maker.clippedVideoMaxDuration;
-            let temp = self.maker.endTime / CGFloat(self.maker.defaultSelectedImageCount)
-            self.cellCount = UInt(self.maker.sourceVideoTotalDuration / CGFloat(temp))
-        }
-        
-        let value = self.frame.size.width - self.maker.leftMargin - self.maker.rightMargin - self.maker.selectedImageWidth - self.maker.selectedImageWidth
-        self.perSecondWidth = value / CGFloat(self.maker.endTime - self.maker.startTime)
-        self.collectionInsets = UIEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
-        self.p_configSubview()
-    }
-    
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-    //MARK: - Private
-    
-    func p_configSubview() {
-        
-        let topLineY = 40.0
-        let collectionViewH = 40.0
-        
-        leftPlayBtnView.frame = CGRect(x: 37, y: topLineY, width: 54, height: 40)
-        self.addSubview(leftPlayBtnView)
-        
-        let collectionViewX = self.maker.leftMargin + self.maker.selectedImageWidth
-        let collectionViewW = self.frame.size.width - self.maker.selectedImageWidth - self.maker.rightMargin - collectionViewX
-        self.addSubview(self.collectionView)
-        self.collectionView.frame = CGRect.init(x: collectionViewX, y: topLineY, width:collectionViewW, height: collectionViewH)
-    
-        self.addSubview(self.durationLabel)
-        self.durationLabel.frame = CGRect.init(x: (self.frame.size.width - kDurationLabelWidth)/2.0, y: topLineY + collectionViewH, width: kDurationLabelWidth, height: 14)
-        
-        self.addSubview(self.startTimeLabel)
-        self.startTimeLabel.frame = CGRect.init(x: self.maker.leftMargin, y: 16, width: 60, height: 16)
-        
-        self.addSubview(self.endTimeLabel)
-        self.endTimeLabel.frame = CGRect.init(x: self.frame.size.width - 37.0 - 60.0, y: 16, width: 60, height: 16)
-        
-        
-        self.addSubview(self.leftImageView)
-        self.leftImageView.frame = CGRect.init(x: self.maker.leftMargin, y: topLineY, width: self.maker.selectedImageWidth, height: collectionViewH)
-        
-        self.addSubview(self.rightImageView)
-        self.rightImageView.frame = CGRect.init(x: self.frame.size.width - self.maker.selectedImageWidth - self.maker.rightMargin, y:topLineY, width: self.maker.selectedImageWidth, height: collectionViewH)
-        
-        self.addSubview(self.topLine)
-        self.topLine.frame = CGRect.init(x: self.maker.leftMargin + self.maker.selectedImageWidth, y: topLineY, width: self.frame.size.width - self.maker.leftMargin - self.maker.rightMargin - self.maker.selectedImageWidth * 2, height: kLineHeight)
-        
-        self.addSubview(self.bottomLine)
-        self.bottomLine.frame = CGRect.init(x: self.topLine.frame.origin.x, y: self.collectionView.frame.maxY - kLineHeight, width: self.topLine.frame.size.width, height: kLineHeight)
-        
-        self.addSubview(self.progressView)
-        self.progressView.frame = CGRect.init(x: self.leftImageView.frame.maxX, y: topLineY, width: 2.0, height: collectionViewH)
-        
-        self.addSubview(self.doneButton)
-        self.doneButton.frame = CGRect.init(x: 48, y: self.frame.size.height - 48, width: self.frame.size.width - 48*2, height: 48)
-    }
-    
-    func p_loadThumbnailImages () {
-        self.selectedTime = self.maker.endTime - self.maker.startTime
-        self.durationLabel.text = String.init(format: "已选取%.1fs", self.selectedTime)
-        
-        
-        var startDuration:Double = self.maker.startTime
-        if let duration = Double(String(format: "%.2f", arguments: [startDuration])) {
-            startDuration = duration
-        }
-        var endDuration:Double = self.maker.endTime
-        if let duration = Double(String(format: "%.2f", arguments: [endDuration])) {
-            endDuration = duration
-        }
-        self.startTimeLabel.text = startDuration.time
-        self.endTimeLabel.text = endDuration.time
-        
-        var array: [NSValue] = []
-        
-        var startTime: CMTime = .zero
-        let addTime: CMTime = CMTimeMakeWithSeconds(Float64(self.maker.sourceVideoTotalDuration/CGFloat(self.cellCount)), preferredTimescale: 1000)
-        let endTime: CMTime = CMTimeMakeWithSeconds(Float64(self.maker!.sourceVideoTotalDuration), preferredTimescale: 1000)
-
-        while startTime <= endTime {
-            array.append(NSValue.init(time: startTime))
-            startTime = CMTimeAdd(startTime, addTime)
-        }
-        weak var weakSelf = self
-        var index = 0
-        self.imageGenerator.generateCGImagesAsynchronously(forTimes: array) { (requestedTime, image, actualTime, result, error) in
-            if result == .succeeded {
-                let img = UIImage.init(cgImage: image!)
-                DispatchQueue.main.async {
-                    self.imageArray.append(img)
-                    let indexPath = NSIndexPath.init(item: index, section: 0)
-                    weakSelf?.collectionView.insertItems(at: [(indexPath as IndexPath)])
-                    index += 1
-                }
-            }else{
-                debugPrint(error)
-            }
-        }
-    }
-    
-    //MARK: - Public
-    
-    func gp_updateProgressViewWithProgress(_ progress: CGFloat) {
-        guard self.selectedImageView != nil else {
-            let width = self.rightImageView.frame.minX - self.leftImageView.frame.maxX;
-            let newX = self.leftImageView.frame.maxX + progress * width;
-
-            UIView.animate(withDuration: 0.1, delay: 0, options:[.curveLinear, .allowUserInteraction], animations: {
-                self.progressView.frame = CGRect.init(x: newX, y: self.progressView.frame.origin.y, width: self.progressView.frame.size.width, height: self.progressView.frame.size.height)
-            }, completion: nil)
-            return
-        }
-    }
-}
-
-class GPVideoClipperImageCell: UICollectionViewCell {
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        self.addSubview(self.imageView)
-        self.contentView.backgroundColor = .clear
-        self.backgroundColor = .clear
-    }
-    
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-    //MARK: - Getters
-    
-    public lazy var imageView: UIImageView = {
-        var imageView = UIImageView()
-        imageView.frame = self.contentView.bounds
-        imageView.contentMode = .scaleAspectFill
-        imageView.clipsToBounds = true
-        return imageView
-    }()
-}
-
-
-fileprivate extension Double {
-    var time: String {
-        if self < 60 {
-            let sec = Double(String(format: "%.2f", arguments: [self])) ?? self
-            if sec < 10 {
-                return String(format: "00:0%.2f", arguments: [sec])
-            }else {
-                return String(format: "00:%.2f", arguments: [sec])
-            }
-        }else {
-            var min = Double(Int(self / 60))
-            let sec = Double(String(format: "%.2f", arguments: [self - (min * 60)])) ?? self - (min * 60)
-            if min < 60 {
-                if min < 10 {
-                    if sec < 10 {
-                        return String(format: "0%.0f:0%.2f", arguments: [min, sec])
-                    }else {
-                        return String(format: "0%.0f:%.2f", arguments: [min, sec])
-                    }
-                }else {
-                    if sec < 10 {
-                        return String(format: "%.0f:0%.2f", arguments: [min, sec])
-                    }else {
-                        return String(format: "%.0f:%.2f", arguments: [min, sec])
-                    }
-                }
-            }else {
-                let hour = Double(Int(min / 60))
-                min -= hour * 60
-                if hour < 10 {
-                    if min < 10 {
-                        if sec < 10 {
-                            return String(format: "0%.0f:0%.0f:0%.2f", arguments: [hour, min, sec])
-                        }else {
-                            return String(format: "0%.0f:0%.0f:%.2f", arguments: [hour, min, sec])
-                        }
-                    }else {
-                        if sec < 10 {
-                            return String(format: "0%.0f:%.0f:0%.2f", arguments: [hour, min, sec])
-                        }else {
-                            return String(format: "0%.0f:%.0f:%.2f", arguments: [hour, min, sec])
-                        }
-                    }
-                }
-                if min < 10 {
-                    if sec < 10 {
-                        return String(format: "%.0f:0%.0f:0%.2f", arguments: [hour, min, sec])
-                    }else {
-                        return String(format: "%.0f:0%.0f:%.2f", arguments: [hour, min, sec])
-                    }
-                }else {
-                    if sec < 10 {
-                        return String(format: "%.0f:%.0f:0%.2f", arguments: [hour, min, sec])
-                    }else {
-                        return String(format: "%.0f:%.0f:%.2f", arguments: [hour, min, sec])
-                    }
-                }
-            }
-        }
-    }
-}

+ 0 - 85
TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoConfigMaker.swift

@@ -1,85 +0,0 @@
-//
-//  GPVideoConfigMaker.swift
-//  GPVideoClipperDemo-Swift
-//
-//  Created by Roc Kwok on 2020/5/19.
-//  Copyright © 2020 Roc Kwok. All rights reserved.
-//
-
-import UIKit
-
-class GPVideoConfigMaker: NSObject {
-    // MARK: - Required
-    /** 开始时间 */
-    var startTime: CGFloat
-    /** 结束时间 */
-    var endTime: CGFloat
-    /** 裁剪后视频的最小时长 */
-    var clippedVideoMinDuration: CGFloat
-    /** 裁剪后视频的最长时长 */
-    var clippedVideoMaxDuration: CGFloat
-    
-    // MARK: - User ignore
-    /** 源视频总时长(框架内部进行计算,使用者不需要关心) */
-    var sourceVideoTotalDuration: CGFloat
-    
-    // MARK: - Optional
-    /** 是否隐藏已选择时间标签 */
-    var isHiddenSelectedTimeTag: Bool
-    /** 选择框颜色 */
-    var selectedBoxColor: UIColor
-    /** 左边框图片 */
-    var leftSelectedImage: UIImage
-    /** 右边框图片 */
-    var rightSelectedImage: UIImage
-    /** 左右选择框图片的宽度 */
-    var selectedImageWidth: CGFloat
-    /** 初始化时选择框中选中的图片张数 */
-    var defaultSelectedImageCount: UInt
-    /** 选择框整体左间距 */
-    var leftMargin: CGFloat
-    /** 选择框整体右间距 */
-    var rightMargin: CGFloat
-    /** 左边按钮字体 */
-    var leftButtonFont: UIFont
-    /** 左边按钮文字颜色 */
-    var leftButtonFontColor: UIColor
-    /** 左边按钮背景色 */
-    var leftButtonBackgroundColor: UIColor
-    /** 左边按钮标题 */
-    var leftButtonTitle: String
-    /** 右边按钮字体 */
-    var rightButtonFont: UIFont
-    /** 右边按钮文字颜色 */
-    var rightButtonFontColor: UIColor
-    /** 右边按钮背景色 */
-    var rightButtonBackgroundColor: UIColor
-    /** 右边按钮标题 */
-    var rightButtonTitle: String
-    /** 是否保存剪裁后的视频到相册 */
-    var saveClipViewToPhoto:Bool = false
-    
-    override init() {
-        startTime = 0
-        endTime = 0
-        clippedVideoMinDuration = 3
-        clippedVideoMaxDuration = 15
-        sourceVideoTotalDuration = 0
-        isHiddenSelectedTimeTag = false
-        selectedBoxColor = .white
-        leftSelectedImage = UIImage()
-        rightSelectedImage = UIImage()
-        selectedImageWidth = 15.0
-        defaultSelectedImageCount = 8
-        leftMargin = 30.0
-        rightMargin = 30.0
-        leftButtonFont = UIFont.boldSystemFont(ofSize: 16)
-        leftButtonFontColor = .white
-        leftButtonBackgroundColor = .clear
-        leftButtonTitle = "取消"
-        rightButtonFont =  UIFont.boldSystemFont(ofSize: 16)
-        rightButtonFontColor = .white
-        rightButtonBackgroundColor = .init(red: 65/255.0, green: 200/255.0, blue: 86/255.0, alpha: 1.0)
-        rightButtonTitle = "完成"
-    }
-}

+ 0 - 70
TSLiveWallpaper/Business/TSEditLiveVC/TSEditVideoVC/GPVideoClipper/GPVideoPlayerView.swift

@@ -1,70 +0,0 @@
-//
-//  GPVideoPlayerView.swift
-//  GPVideoClipperDemo-Swift
-//
-//  Created by Roc Kwok on 2020/5/19.
-//  Copyright © 2020 Roc Kwok. All rights reserved.
-//
-
-import UIKit
-import AVFoundation
-
-@objc protocol GPVideoPlayerViewDelegate: NSObjectProtocol {
-    @objc optional func gp_videoReadyToPlay()
-}
-
-class GPVideoPlayerView: UIView {
-    var playerItem: AVPlayerItem!
-    var player: AVPlayer!
-    var maker: GPVideoConfigMaker!
-    weak var delegate:GPVideoPlayerViewDelegate?
-    
-    private var avPlayer: AVPlayerLayer!
-    private var videoURL: URL!
-    
-    init(frame: CGRect, videoURL: URL) {
-        self.videoURL = videoURL
-        self.playerItem = AVPlayerItem.init(url: videoURL)
-        self.player = AVPlayer.init(playerItem: self.playerItem)
-        self.avPlayer = AVPlayerLayer.init(player: self.player)
-        self.maker = GPVideoConfigMaker.init()
-        
-        super.init(frame: frame)
-        
-        self.layer.addSublayer(self.avPlayer)
-        self.avPlayer.frame = self.bounds
-        self.playerItem.addObserver(self, forKeyPath: "status", options: .new, context: nil)
-        
-        NotificationCenter.default.addObserver(self, selector: #selector(videoDidPlayEnd(notification:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
-    }
-    
-    deinit {
-        NotificationCenter.default.removeObserver(self)
-    }
-    
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-    // MARK: - Action
-    
-    @objc func videoDidPlayEnd(notification: Notification) {
-        self.player.pause()
-        self.player.seek(to: CMTime.init(value: CMTimeValue(self.maker.startTime * 1000), timescale: 1000), toleranceBefore: .zero, toleranceAfter: .zero)
-        self.player.play()
-    }
-    
-    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
-        if keyPath == "status" {
-            let status = self.playerItem.status
-            if status == .readyToPlay {
-                if (self.delegate != nil) && self.delegate!.responds(to: Selector.init(("gp_videoReadyToPlay"))) {
-                    self.delegate!.gp_videoReadyToPlay?()
-                }
-                self.playerItem.removeObserver(self, forKeyPath: "status")
-            } else {
-                assert(false, "Video play failed:\(String(describing: keyPath))")
-            }
-        }
-    }
-}

+ 0 - 74
TSLiveWallpaper/Business/TSHomeVC/TSHomeCell.swift

@@ -1,74 +0,0 @@
-//
-//  TSHomeCell.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/21.
-//
-
-class TSHomeCollectionCell : TSBaseCollectionCell{
-    
-    static let reuseIdentifier = "TSHomeCollectionCell"
-    
-    lazy var imageView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.image = kWapppaperPlaceholderImage
-        imageView.contentMode = .scaleAspectFill
-        return imageView
-    }()
-    
-    lazy var liveIconView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.image = KIconLiveImage
-        return imageView
-    }()
-
-    override func creatUI() {
-        bgContentView.cornerRadius = 16
-        
-        bgContentView.addSubview(imageView)
-        imageView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-        
-        bgContentView.addSubview(liveIconView)
-        liveIconView.snp.makeConstraints { make in
-            make.left.equalTo(8)
-            make.top.equalTo(8)
-            make.width.height.equalTo(24)
-        }
-    }
-
-    override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
-        if let itemModel = object as? TSImageDataItemModel{
-            imageView.setAsyncImage(urlString: itemModel.imageUrl,placeholder: kWapppaperPlaceholderImage,showLoading: true)
-        }
-    }
-}
-
-
-
-//MARK: TSHomeCollectionReusableView
-class TSHomeCollectionReusableView: TSBaseCollectionnReusableView{
-    
-    static let reuseIdentifier = "TSHomeCollectionReusableView"
-    
-    lazy var leftLab: UILabel = {
-        return UILabel.createLabel(font: .font(size: 16,weight: .medium),textColor: .fromHex("FFFFFF", alpha: 0.8))
-    }()
-    override func creatUI() {
-        bgContentView.addSubview(leftLab)
-        leftLab.snp.makeConstraints { make in
-            make.leading.equalTo(16)
-            make.centerY.equalToSuperview()
-        }
-    }
-    
-    override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
-        if let componentReuseViewModel = object as? TSComponentReuseViewModel {
-            leftLab.text = componentReuseViewModel.sectionModel.name
-        }
-    }
-    
-    
-
-}

+ 0 - 124
TSLiveWallpaper/Business/TSHomeVC/TSHomeVC.swift

@@ -1,124 +0,0 @@
-//
-//  TSHomeVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/20.
-//
-
-import TYCyclePagerView
-
-import Photos
-import PhotosUI
-
-class TSHomeVC: TSBaseVC {
-    lazy var navBarView: TSBaseNavContentBarView = {
-        let navBarView = TSBaseNavContentBarView()
-        let titleImageView = UIImageView.createImageView(imageName: "nav_title_home", contentMode: .scaleToFill)
-
-        navBarView.barView.addSubview(titleImageView)
-        titleImageView.snp.makeConstraints { make in
-            make.centerY.equalToSuperview()
-            make.left.equalTo(16)
-        }
-
-        return navBarView
-    }()
-
-    lazy var hStack: UIStackView = {
-        let stack = UIStackView()
-        stack.axis = .horizontal
-        stack.distribution = .fillEqually
-        stack.spacing = 16
-        return stack
-    }()
-
-    lazy var diyButton: SpacedButton = {
-        let btn = SpacedButton()
-        btn.setTitle("DIY Live Photo", for: .normal)
-        btn.setTitleColor(.white, for: .normal)
-        btn.setImage(UIImage(named: "top_diy"), for: .normal)
-        btn.setBackgroundImage(UIImage(named: "WallpaperBg"), for: .normal)
-        btn.addTarget(self, action: #selector(showDiyPaperController), for: .touchUpInside)
-        btn.titleLabel?.font = .systemFont14
-        return btn
-    }()
-
-    lazy var shuffleButton: SpacedButton = {
-        let btn = SpacedButton()
-        btn.setTitle("Shuffle Packs", for: .normal)
-        btn.setTitleColor(.white, for: .normal)
-        btn.setImage(UIImage(named: "top_shuffle"), for: .normal)
-        btn.setBackgroundImage(UIImage(named: "WallpaperBg"), for: .normal)
-        btn.addTarget(self, action: #selector(showRandomWallpaperVC), for: .touchUpInside)
-        btn.titleLabel?.font = .systemFont14
-        return btn
-    }()
-
-    lazy var collectionComponent: TSCollectionViewComponent = {
-        let layout = UICollectionViewFlowLayout()
-        let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
-        cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: k_Height_TabBar, right: 0)
-        cp.itemDidSelectedHandler = { [weak self] _, indexPath in
-            guard let self = self else { return }
-
-            let obj = dataArray.safeObj(At: indexPath.section)
-            if let bannerModel = obj as? TSHomeBannerDataSectionModel {
-                if let items = bannerModel.itemModels.first {
-                    kPresentModalVC(target: self, modelVC: TSLiveWallpaperBrowseVC(itemModels: items.items, currentIndex: indexPath.row))
-                }
-            } else if let liveModel = obj as? TSImageDataSectionModel {
-                kPresentModalVC(target: self, modelVC: TSLiveWallpaperBrowseVC(itemModels: liveModel.items, currentIndex: indexPath.row))
-            }
-        }
-
-        return cp
-    }()
-
-    var dataArray: [TSComponent] = kImageDataCenterShared.liveBannerArray + kImageDataCenterShared.liveListArray
-    override func createView() {
-        //setViewBgImageNamed(named: "view_main_bg")
-
-        navBarContentView.addSubview(navBarView)
-        navBarView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-
-        hStack.addArrangedSubview(diyButton)
-        hStack.addArrangedSubview(shuffleButton)
-        contentView.addSubview(hStack)
-        hStack.snp.makeConstraints { make in
-            make.horizontalEdges.equalToSuperview().inset(16)
-            make.top.equalToSuperview().offset(16)
-            make.height.equalTo(60)
-        }
-
-        contentView.addSubview(collectionComponent.collectionView)
-        collectionComponent.collectionView.snp.makeConstraints { make in
-            make.top.equalTo(diyButton.snp.bottom)
-            make.leading.trailing.bottom.equalToSuperview()
-        }
-
-        collectionComponent.reloadView(with: dataArray)
-
-        TSNetworkShard.monitorNetworkPermission { success in
-            if success {
-                self.collectionComponent.reloadData()
-            }
-        }
-    }
-
-    @objc func showDiyPaperController() {
-        let vc = TSEditLiveVC()
-        vc.modalPresentationStyle = .overFullScreen
-        present(vc, animated: true)
-    }
-    
-    @objc func showRandomWallpaperVC() {
-        let vc = TSRandomWallpaperVC()
-        let nav = TSBaseNavigationC(rootViewController: vc)
-        nav.modalPresentationStyle = .overFullScreen
-        present(nav, animated: true)
-    }
-    
-    
-}

+ 0 - 54
TSLiveWallpaper/Business/TSHomeVC/TSLiveWallpaperBrowseVC/EasyVC/TSLiveWallpaperCopyrightVC.swift

@@ -1,54 +0,0 @@
-//
-//  TSLiveWallpaperCopyrightVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/26.
-//
-
-
-class TSLiveWallpaperCopyrightVC: TSBaseVC {
-    
-    
-    lazy var titleLabel: UILabel = {
-        let view = UILabel.createLabel(text: "Copyright Notice",font: .font(size: 24,weight: .medium),textColor: UIColor.fromHex("FFFFFF",alpha: 0.8),numberOfLines: 0)
-        return view
-    }()
-    
-    lazy var contentLabel: UILabel = {
-        let view = UILabel.createLabel(text: "100 Years Later Company attaches great importance to the copyright of images, but as a content provider, we cannot guarantee the accuracy of the reviewed content. If you find any infringing content, please inform us immediately and we will immediately remove it. Contact",font: .font(size: 14,weight: .regular),textColor: UIColor.fromHex("FFFFFF",alpha: 0.6),numberOfLines: 0)
-        return view
-    }()
-    
-    lazy var emailLabel: UILabel = {
-        let view = UILabel.createLabel(text: "Email: snapmusic6688@gmail.com",font: .font(size: 16,weight: .regular),textColor: UIColor.fromHex("FFFFFF"),numberOfLines: 0)
-        return view
-    }()
-    
-    override func createView() {
-        addNormalNavBarView()
-        setPageTitle("")
-        
-        contentView.addSubview(titleLabel)
-        contentView.addSubview(contentLabel)
-        contentView.addSubview(emailLabel)
-        
-        titleLabel.snp.makeConstraints { make in
-            make.top.equalTo(11)
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-        }
-        
-        contentLabel.snp.makeConstraints { make in
-            make.top.equalTo(titleLabel.snp.bottom).offset(24)
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-        }
-        
-        emailLabel.snp.makeConstraints { make in
-            make.top.equalTo(contentLabel.snp.bottom).offset(16)
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-        }
-    }
-    
-}

+ 0 - 25
TSLiveWallpaper/Business/TSHomeVC/TSLiveWallpaperBrowseVC/EasyVC/TSLiveWallpaperTutorialsVC.swift

@@ -1,25 +0,0 @@
-//
-//  TSLiveWallpaperTutorialsVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/26.
-//
-
-class TSLiveWallpaperTutorialsVC: TSBaseVC {
-    
-    lazy var imageView: UIImageView = {
-        let imageView = UIImageView.createImageView(imageName: "live_tutorials")
-        imageView.frame = CGRectMake(0, 0, k_ScreenWidth, kDesignScale*(imageView.image?.size.height ?? k_ScreenHeight))
-        return imageView
-    }()
-    
-    override func createView() {
-        addNormalNavBarView()
-        setPageTitle("Tutorials")
-        contentView.addSubview(imageView)
-    }
-    
-    
-    
-    
-}

+ 0 - 677
TSLiveWallpaper/Business/TSHomeVC/TSLiveWallpaperBrowseVC/TSLiveWallpaperBrowseVC.swift

@@ -1,677 +0,0 @@
-//
-//  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 vip:Bool = false
-    
-    var livePhoto:PHLivePhoto? = nil
-    var livePhotoResources:(pairedImage: URL, pairedVideo: URL)?
-    
-    var imageCacheUrl:URL?
-    var videoCacheUrl: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 {
-        didSet{
-            reloadUI()
-        }
-    }
-    init(itemModels: [TSImageDataItemModel],currentIndex:Int) {
-        for itemModel in itemModels {
-            let model = TSLiveWallpaperBrowseItemModel()
-            model.style = itemModel.style
-            model.imageUrl = itemModel.imageUrl
-            model.videoUrl = itemModel.videoUrl
-            model.vip = itemModel.vip
-            dataModelArray.append(model)
-        }
-        self.currentIndex = currentIndex
-        super.init()
-    }
-    
-    var isCanDelete:Bool = false {
-        didSet{
-            deleteBtn.isHidden = !isCanDelete
-            copyrightBtn.isHidden = isCanDelete
-        }
-    }
-    
-    var deleteCompletion:((_ item:Int)->Void)?
-    
-    @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 }
-            
-            let cell = collectionView.cellForItem(at: IndexPath(item: currentIndex, section: 0)) as? TSLiveWallpaperBrowseCell
-            
-            //判断 vip
-            if let itemModel = self.dataModelArray.safeObj(At: currentIndex),
-               itemModel.vip == true,
-               PurchaseManager.default.isVip == false
-            {
-                cell?.stopPlayLive()
-                TSPurchaseVC.show(target: self) {[weak self]  in
-                    guard let self = self else { return }
-                    cell?.stratPlayLive()
-                }
-                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 {
-                        kSaveSuccesswShared.show(atView: self.view)
-                    }else{
-                        TSToastShared.showToast(text: "Save Fail".localized)
-                    }
-                }
-            }
-            
-            
-
-        }
-        saveBtn.cornerRadius = 24
-        return saveBtn
-    }()
-    
-    lazy var deleteBtn: UIButton = {//删除按钮
-        let deleteBtn = UIButton.createButton(image: UIImage(named: "delete_white"),backgroundColor: UIColor.fromHex("#111111", alpha: 0.2),corner: 16.0) { [weak self]  in
-            guard let self = self else { return }
-            
-            showCustomAlert(
-                message: "Are you sure to delete".localized,
-                deleteHandler: { [weak self]  in
-                    guard let self = self else { return }
-                    
-                    if let itemModel = self.dataModelArray.safeObj(At: currentIndex) {
-                        self.dataModelArray.remove(at: currentIndex)
-                    }
-                    deleteCompletion?(currentIndex)
-                    
-                    if self.dataModelArray.count == 0 {
-                        self.pop()
-                    }else{
-                        self.collectionView.reloadData()
-                    }
-          
-                },
-                cancelHandler: {
-                   
-                }
-            )
-        }
-        deleteBtn.isHidden = true
-        return deleteBtn
-    }()
-    
-    
-    lazy var copyrightBtn: UIButton = {
-        //版权信息按钮
-        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)
-        }
-        return copyrightBtn
-    }()
-    
-    lazy var btnsAllView: UIView = {
-        let btnsAllView = UIView()
-        
-        btnsAllView.addSubview(copyrightBtn)
-        copyrightBtn.snp.makeConstraints { make in
-            make.width.height.equalTo(44)
-            make.trailing.equalTo(-16)
-            make.top.equalTo(topLineH)
-        }
-    
-        btnsAllView.addSubview(deleteBtn)
-        deleteBtn.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"])
-        collectionView.backgroundColor = .black
-        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)
-            
-        }
-        
-        self.reloadUI()
-    }
-    
-    func reloadUI() {
-        if let itemModel = self.dataModelArray.safeObj(At: currentIndex) {
-            TSViewTool.setNormalSubmitBtn(btn: saveBtn, showVip: itemModel.vip)
-        }
-    }
-}
-
-
-//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 lazy var livePhotoTool = LivePhoto()
-    private var isCanPlay = true
-    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 {
-            self.livePhotoView.livePhoto = nil
-            self.livePhotoView.isHidden = true
-            
-            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
-                    
-                    if imageCachePath.count == 0 || videoCachePath.count == 0 {
-                        return
-                    }
-                    
-                    let imageCacheUrl = URL(fileURLWithPath: imageCachePath)
-                    let videoCacheUrl = URL(fileURLWithPath: videoCachePath)
-                    
-                    
-                    if !TSFileManagerTool.fileExists(at: imageCacheUrl) || !TSFileManagerTool.fileExists(at: videoCacheUrl){
-                        return
-                    }
-                    
-                    
-                    self.itemModel?.imageCacheUrl = imageCacheUrl
-                    self.itemModel?.videoCacheUrl = videoCacheUrl
-                    
-//                    if videoCacheUrl.path.contains("/saveVideo/") {
-//                        self.loading.stopAnimating()
-//                        
-//                        LivePhotoConverter.livePhotoRequest(videoURL: videoCacheUrl, imageURL: imageCacheUrl) { livePhoto in
-//                            self.itemModel?.livePhoto = livePhoto
-//                            self.itemModel?.livePhotoResources = (imageCacheUrl,videoCacheUrl)
-//                            
-//                            if let livePhoto = livePhoto {
-//                                self.livePhotoView.livePhoto = livePhoto
-//                                self.livePhotoView.isHidden = false
-//                                self.livePhotoView.startPlayback(with: .full)
-//                            }else{
-//                                debugPrint("livePhoto.generate fail")
-//                            }
-//                        }
-//                        return
-//                    }
-//                    
-//                    LivePhotoConverter.convertVideo(videoCacheUrl, imageURL: imageCacheUrl) { success, photoURL, videoURL, errorMsg in
-//                        DispatchQueue.main.async {
-//                            self.loading.stopAnimating()
-//                            if success {
-//                                LivePhotoConverter.livePhotoRequest(videoURL: videoURL!, imageURL: photoURL!) { livePhoto in
-//                                    self.itemModel?.livePhoto = livePhoto
-//                                    self.itemModel?.livePhotoResources = (photoURL!,videoURL!)
-//                                    
-//                                    if let livePhoto = livePhoto {
-//                                        self.livePhotoView.livePhoto = livePhoto
-//                                        self.livePhotoView.isHidden = false
-//                                        self.livePhotoView.startPlayback(with: .full)
-//                                    }else{
-//                                        debugPrint("livePhoto.generate fail")
-//                                    }
-//                                }
-//                            }else{
-//                                debugPrint(errorMsg)
-//                            }
-//                        }
-//                    }
-                    
-                    
-                    livePhotoTool.generate(from: imageCacheUrl, videoURL: videoCacheUrl, progress: { (percent) in
-                        debugPrint(percent)
-                    }) { [weak self] (livePhoto, resources) in
-                        guard let self = self else { return }
-                        
-                        loading.stopAnimating()
-                        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 {
-        if self.isCanPlay {
-            debugPrint("startPlayback")
-            kDelayOnMainThread(1.0) {
-                livePhotoView.startPlayback(with: .full)
-            }
-        }
-    }
-    
-    func saveLivePhoto(completion: @escaping (Bool) -> Void){
-//        if let resources = itemModel?.livePhotoResources {
-//            LivePhoto.saveToLibrary(resources, completion: { (success) in
-//                kMainAsync {
-//                    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)
-//                    }
-//                }
-//            })
-//        }
-        
-//        if let resources = itemModel?.livePhotoResources {
-//            LivePhotoConverter.saveToLibrary(videoURL: resources.pairedVideo, imageURL: resources.pairedImage) { success in
-//                kMainAsync {
-//                    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)
-//                    }
-//                }
-//            }
-//        }
-
-        guard let videoCacheUrl = itemModel?.videoCacheUrl, let imageCacheUrl = itemModel?.imageCacheUrl else{
-            TSToastShared.showToast(text: "save fail")
-            return
-        }
-        
-        TSToastShared.showLoading()
-        if videoCacheUrl.path.contains("/saveVideo/") {
-            LivePhotoConverter.saveToLibrary(videoURL: videoCacheUrl, imageURL: imageCacheUrl) { success in
-                kMainAsync {
-                    TSToastShared.hideLoading()
-                    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)
-                    }
-                }
-            }
-            return
-        }
-        
-        
-        LivePhotoConverter.convertVideo(videoCacheUrl, imageURL: imageCacheUrl) { success, photoURL, videoURL, errorMsg in
-            DispatchQueue.main.async {
-                TSToastShared.hideLoading()
-                if success {
-                    LivePhotoConverter.saveToLibrary(videoURL: videoURL!, imageURL: photoURL!) { success in
-                        kMainAsync {
-                            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)
-                            }
-                        }
-                    }
-                }else{
-                    debugPrint(errorMsg)
-                }
-            }
-        }
-    }
-    
-    func stopPlayLive() {
-        debugPrint("stopPlayLive")
-        self.isCanPlay = false
-        livePhotoView.isHidden = true
-        livePhotoView.stopPlayback()
-    }
-    
-    func stratPlayLive() {
-        debugPrint("stratPlayLive")
-        self.isCanPlay = true
-        self.livePhotoView.isHidden = false
-        self.livePhotoView.startPlayback(with: .full)
-        
-    }
-    
-
-}

+ 0 - 141
TSLiveWallpaper/Business/TSHomeVC/View/TSHomeTopBannerCell.swift

@@ -1,141 +0,0 @@
-//
-//  TSHomeTopBannerCell.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/23.
-//
-
-
-import TYCyclePagerView
-
-//MARK: TSHomeTopBannerCell
-private let topBarnerItemW = 225.0
-private let topBarnerItemH = 486.41
-
-class TSHomeTopBannerCell : TSBaseCollectionCell , TYCyclePagerViewDelegate, TYCyclePagerViewDataSource {
-    var itemDidSelectedHandler: ((Any?, IndexPath) -> Void)?
-    
-    lazy var cyclePagerView: TYCyclePagerView = {
-        let pagerView = TYCyclePagerView()
-        pagerView.isInfiniteLoop = true
-        pagerView.autoScrollInterval = 0.0
-        pagerView.delegate = self
-        pagerView.dataSource = self
-        pagerView.layout.layoutType = TYCyclePagerTransformLayoutType.linear
-        pagerView.register(TSHomeCyclePagerViewCell.classForCoder(), forCellWithReuseIdentifier: TSHomeCyclePagerViewCell.reuseIdentifier)
-        return pagerView
-    }()
-
-    lazy var topBarnerView: UIView = {
-        let topBarnerView = UIView()
-        topBarnerView.addSubview(cyclePagerView)
-        cyclePagerView.snp.makeConstraints { make in
-            make.leading.trailing.equalToSuperview()
-            make.top.equalToSuperview()
-            make.height.equalTo(topBarnerItemH)
-        }
-   
-        return topBarnerView
-    }()
-    
-    lazy var itemModelArray:[TSImageDataItemModel] = []
-    
-    override func creatUI() {
-        bgContentView.addSubview(topBarnerView)
-        topBarnerView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-            make.height.equalToSuperview()
-        }
-        
-        let previewImageView = UIImageView.createImageView(imageName: "iPhone_lock_screen_preview")
-        bgContentView.addSubview(previewImageView)
-        previewImageView.snp.makeConstraints { make in
-            make.top.equalToSuperview()
-            make.centerX.equalToSuperview()
-            make.width.equalTo(topBarnerItemW)
-            make.height.equalTo(topBarnerItemH)
-        }
-    }
-
-    func numberOfItems(in pageView: TYCyclePagerView) -> Int {
-        return itemModelArray.count
-    }
-    
-    func pagerView(_ pagerView: TYCyclePagerView, cellForItemAt index: Int) -> UICollectionViewCell {
-        let cell = pagerView.dequeueReusableCell(withReuseIdentifier: TSHomeCyclePagerViewCell.reuseIdentifier, for: index) as! TSHomeCyclePagerViewCell
-        
-        if let itemModel = itemModelArray.safeObj(At: index) {
-            cell.itemModel = itemModel
-        }
-        
-        return cell
-    }
-    
-    func layout(for pageView: TYCyclePagerView) -> TYCyclePagerViewLayout {
-        let layout = TYCyclePagerViewLayout()
-        layout.itemSize = CGSize(width:topBarnerItemW, height: topBarnerItemH)
-        layout.itemSpacing = 23
-        layout.itemHorizontalCenter = true
-        layout.layoutType = .linear
-        return layout
-    }
-
-    override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
-        if let model = object as? TSHomeBannerDataItemModel {
-            if itemModelArray.isEmpty {
-                itemModelArray = model.items
-                cyclePagerView.reloadData()
-                
-                itemDidSelectedHandler = component.itemDidSelectedHandler
-            }else{
-                cyclePagerView.reloadData()
-            }
-        }
-    }
-    
-    func pagerView(_ pageView: TYCyclePagerView, didSelectedItemCell cell: UICollectionViewCell, at index: Int) {
-        if let itemModel = itemModelArray.safeObj(At: index) {
-            itemDidSelectedHandler?(itemModel,NSIndexPath(item: index, section: 0) as IndexPath)
-        }
-    }
-}
-
-
-//MARK: TSHomeCyclePagerViewCell
-class TSHomeCyclePagerViewCell: TSBaseCollectionCell {
-    static let reuseIdentifier = "TSHomeCyclePagerViewCell"
-    lazy var imageView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.image = kWapppaperPlaceholderImage
-        return imageView
-    }()
-    
-    lazy var liveIconView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.image = KIconLiveImage
-        return imageView
-    }()
-    
-    var itemModel:TSImageDataItemModel = TSImageDataItemModel(){
-        didSet{
-            imageView.setAsyncImage(urlString: itemModel.imageUrl,placeholder: kWapppaperPlaceholderImage,showLoading: true)
-        }
-    }
-    
-    override func creatUI() {
-        bgContentView.cornerRadius = 24
-        
-        bgContentView.addSubview(imageView)
-        imageView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-
-        bgContentView.addSubview(liveIconView)
-        liveIconView.snp.makeConstraints { make in
-            make.left.equalTo(8)
-            make.top.equalTo(8)
-            make.width.height.equalTo(24)
-        }
-    }
-}
-

+ 0 - 26
TSLiveWallpaper/Business/TSMusic/MusicBase/GradientBackgroundModifier.swift

@@ -1,26 +0,0 @@
-//
-//  GradientButtonView.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/12.
-//
-
-import Foundation
-import SwiftUI
-
-struct GradientBackgroundModifier: ViewModifier {
-    var colors : [Color]
-
-    func body(content: Content) -> some View {
-        content
-            .background(
-                LinearGradient(gradient: Gradient(colors: colors), startPoint: .leading, endPoint: .trailing)
-            )
-    }
-}
-
-extension View {
-    func gradientBackground(colors:[Color]) -> some View {
-        modifier(GradientBackgroundModifier(colors: colors))
-    }
-}

+ 0 - 48
TSLiveWallpaper/Business/TSMusic/MusicBase/GradientButton.swift

@@ -1,48 +0,0 @@
-//
-//  GradientButton.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/8.
-//
-
-import Foundation
-import UIKit
-
-public class GradientButton: UIButton {
-    var colors: [UIColor]?
-    var from: CGPoint = CGPoint(x: 0, y: 0)
-    var to: CGPoint = CGPoint(x: 1, y: 0)
-    var index: Int?
-    
-    public required init(colors: [UIColor]? = nil,
-                  from: CGPoint = CGPoint(x: 0, y: 0),
-                  to: CGPoint = CGPoint(x: 1, y: 0),
-                  index: Int? = nil) {
-        self.colors = colors
-        self.from = from
-        self.to = to
-        self.index = index
-        super.init(frame: .zero)
-    }
-    
-    required init?(coder: NSCoder) {
-        super.init(coder: coder)
-    }
-    
-    public override func layoutSubviews() {
-        super.layoutSubviews()
-        if let colors = colors {
-            setGradient(colors: colors, from: from, to: to, index: index)
-        }
-    }
-    
-    public func set(colors: [UIColor]? = nil,
-                    from: CGPoint = CGPoint(x: 0, y: 0),
-                    to: CGPoint = CGPoint(x: 1, y: 0),
-                    index: Int? = nil) {
-        self.colors = colors
-        self.from = from
-        self.to = to
-        self.index = index
-    }
-}

+ 0 - 44
TSLiveWallpaper/Business/TSMusic/MusicBase/GradientText.swift

@@ -1,44 +0,0 @@
-//
-//  GradientText.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/12.
-//
-
-import Foundation
-import SwiftUI
-
-struct GradientText: View {
-    var text: String
-    var gradientColors: [Color]
-    var font: Font
-    var backgroundColor: Color = .clear
-    var cornerRadius: CGFloat = 8
-    var verticalPadding: CGFloat = 4
-    var horizontalPadding: CGFloat = 4
-
-    var body: some View {
-        // 外层背景和圆角
-        Text(text)
-            .font(font)
-            .foregroundColor(.clear) // 文字颜色透明
-            .padding(.horizontal, horizontalPadding) // 让背景有一些内边距
-            .padding(.vertical, verticalPadding) // 让背景有一些内边距
-            .background(
-                backgroundColor // 设置背景色
-                    .cornerRadius(cornerRadius) // 圆角背景
-            )
-            .overlay(
-                LinearGradient(
-                    colors: gradientColors,
-                    startPoint: .leading,
-                    endPoint: .trailing
-                )
-                .mask( // 使用文字本身作为遮罩
-                    Text(text)
-                        .font(font)
-                        .padding() // 确保遮罩和背景对齐
-                )
-            )
-    }
-}

+ 0 - 17
TSLiveWallpaper/Business/TSMusic/MusicBase/LWBaseNavigationController.swift

@@ -1,17 +0,0 @@
-//
-//  KlBaseNavigationController.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/7.
-//
-
-import Foundation
-import UIKit
-
-class LWBaseNavigationController: UINavigationController {
-    override func viewDidLoad() {
-        super.viewDidLoad()
-        navigationBar.isHidden = true
-        view.backgroundColor = .white
-    }
-}

+ 0 - 59
TSLiveWallpaper/Business/TSMusic/MusicBase/LWBaseViewController.swift

@@ -1,59 +0,0 @@
-//
-//  PWBaseViewController.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/6.
-//
-
-import Combine
-import Foundation
-import UIKit
-
-class LWBaseViewController: UIViewController {
-    
-    var cancellabel: [AnyCancellable] = []
-    
-    override func viewDidLoad() {
-        super.viewDidLoad()
-        customView()
-    }
-
-    func customView() {
-        addChildren()
-        makeConstarints()
-        addNotifaction()
-    }
-
-    func addNotifaction() {
-    }
-
-    func addChildren() {
-    }
-
-    func makeConstarints() {
-    }
-
-    @objc func popupCurrentVc() {
-        navigationController?.popViewController(animated: true)
-    }
-
-    deinit {
-        cancellabel.removeAll()
-    }
-}
-
-class LWBGViewController: LWBaseViewController {
-    lazy var bgImageView: UIImageView = .simpleImage(imageName: "view_main_bg")
-
-    override func addChildren() {
-        super.addChildren()
-        view.addSubview(bgImageView)
-    }
-
-    override func makeConstarints() {
-        super.makeConstarints()
-        bgImageView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-    }
-}

+ 0 - 293
TSLiveWallpaper/Business/TSMusic/MusicBase/LWNavigationBar.swift

@@ -1,293 +0,0 @@
-//
-//  PWNavigationBar.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/6.
-//
-
-import Foundation
-import KLExtension
-
-class LWNavigationBar: UIView {
-    lazy var titleView: UIImageView = .simpleImage(imageName: "ic_nav_catalog")
-
-    lazy var rightItems: UIStackView = {
-        let hStack: UIStackView = .hStack
-        hStack.spacing = 24
-        return hStack
-    }()
-
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        addChildren()
-        makeConstraints()
-    }
-
-    func appendItem(item: UIView) {
-        rightItems.addArrangedSubview(item)
-        item.snp.remakeConstraints { make in
-            make.width.height.equalTo(32)
-        }
-    }
-
-    func addChildren() {
-        addSubview(titleView)
-        addSubview(rightItems)
-    }
-
-    func makeConstraints() {
-        titleView.snp.makeConstraints { make in
-            make.leading.equalToSuperview().offset(16)
-            make.centerY.equalToSuperview()
-        }
-
-        rightItems.snp.makeConstraints { make in
-            make.trailing.equalToSuperview().offset(-16)
-            make.centerY.equalToSuperview()
-        }
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
-class LWSubNavigationBar: UIView {
-    lazy var titleLabel: UILabel = .simpleLabel(text: "", font: .font(name: .PingFangSC, size: 20), color: .white)
-    lazy var backButton: UIButton = {
-        let btn = UIButton()
-        btn.setImage(.naviBackWhite, for: .normal)
-        return btn
-    }()
-
-    lazy var leftItems: UIStackView = {
-        let hStack: UIStackView = .hStack
-        hStack.spacing = 24
-        return hStack
-    }()
-
-    lazy var rightItems: UIStackView = {
-        let hStack: UIStackView = .hStack
-        hStack.spacing = 24
-        return hStack
-    }()
-
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        addChildren()
-        makeConstraints()
-    }
-
-    func appendRightItem(item: UIView) {
-        rightItems.addArrangedSubview(item)
-        item.snp.remakeConstraints { make in
-            make.width.height.equalTo(32)
-        }
-    }
-
-    func appendLeftItem(item: UIView) {
-        leftItems.addArrangedSubview(item)
-        item.snp.remakeConstraints { make in
-            make.width.height.equalTo(32)
-        }
-    }
-
-    func addChildren() {
-        addSubview(titleLabel)
-        addSubview(leftItems)
-        addSubview(rightItems)
-        initDefaultItem()
-    }
-
-    func initDefaultItem() {
-        appendLeftItem(item: backButton)
-    }
-
-    func makeConstraints() {
-        leftItems.snp.makeConstraints { make in
-            make.leading.equalToSuperview().offset(16)
-            make.centerY.equalToSuperview()
-        }
-
-        titleLabel.snp.makeConstraints { make in
-            make.center.equalToSuperview()
-        }
-
-        rightItems.snp.makeConstraints { make in
-            make.trailing.equalToSuperview().offset(-16)
-            make.centerY.equalToSuperview()
-        }
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
-class LWPlaylistSubNavigationBar: UIView {
-    lazy var titleLabel: UILabel = .simpleLabel(text: "", font: .font(name: .PingFangSC, size: 20), color: .white, align: .left)
-    lazy var backButton: UIButton = {
-        let btn = UIButton()
-        btn.setImage(.naviBackWhite, for: .normal)
-        return btn
-    }()
-
-    lazy var leftItems: UIStackView = {
-        let hStack: UIStackView = .hStack
-        hStack.spacing = 24
-        return hStack
-    }()
-
-    lazy var rightItems: UIStackView = {
-        let hStack: UIStackView = .hStack
-        hStack.spacing = 24
-        return hStack
-    }()
-
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        addChildren()
-        makeConstraints()
-    }
-
-    func appendRightItem(item: UIView) {
-        rightItems.addArrangedSubview(item)
-        item.snp.remakeConstraints { make in
-            make.width.height.equalTo(32)
-        }
-    }
-
-    func appendLeftItem(item: UIView) {
-        leftItems.addArrangedSubview(item)
-        item.snp.remakeConstraints { make in
-            make.width.height.equalTo(32)
-        }
-    }
-
-    func addChildren() {
-        addSubview(titleLabel)
-        addSubview(leftItems)
-        addSubview(rightItems)
-        initDefaultItem()
-    }
-
-    func initDefaultItem() {
-        appendLeftItem(item: backButton)
-    }
-
-    func makeConstraints() {
-        leftItems.snp.makeConstraints { make in
-            make.leading.equalToSuperview().offset(16)
-            make.centerY.equalToSuperview()
-        }
-
-        titleLabel.snp.makeConstraints { make in
-            make.leading.equalTo(leftItems.snp.trailing).offset(8)
-            make.centerY.equalToSuperview()
-            make.leading.equalTo(leftItems.snp.trailing).offset(8)
-            make.trailing.equalTo(rightItems.snp.leading).offset(-8)
-        }
-
-        rightItems.snp.makeConstraints { make in
-            make.trailing.equalToSuperview().offset(-16)
-            make.centerY.equalToSuperview()
-        }
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
-class LWRightNavigationBar: UIView {
-    lazy var iconView: UIImageView = .simpleImage(imageName: "ic_nav_music")
-
-    lazy var rightItems: UIStackView = {
-        let hStack: UIStackView = .hStack
-        hStack.spacing = 24
-        return hStack
-    }()
-
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        addChildren()
-        makeConstraints()
-    }
-
-    func appendRightItem(item: UIView) {
-        rightItems.addArrangedSubview(item)
-        item.snp.remakeConstraints { make in
-            make.width.height.equalTo(32)
-        }
-    }
-
-    func addChildren() {
-        addSubview(iconView)
-        addSubview(rightItems)
-    }
-
-    func makeConstraints() {
-        iconView.snp.makeConstraints { make in
-            make.leading.equalToSuperview().offset(16)
-            make.centerY.equalToSuperview()
-        }
-
-        rightItems.snp.makeConstraints { make in
-            make.trailing.equalToSuperview().offset(-16)
-            make.centerY.equalToSuperview()
-        }
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
-class LWManageNavigationBar: UIView {
-    lazy var titleLabel: UILabel = .simpleLabel(text: "Select (0/0)", font: .font(name: .PingFangSC, size: 20), color: .black)
-    lazy var backButton: UIButton = {
-        let btn = UIButton()
-        btn.setImage(.naviBackWhite, for: .normal)
-        return btn
-    }()
-
-    lazy var rightItems: UIStackView = {
-        let hStack: UIStackView = .hStack
-        hStack.spacing = 24
-        return hStack
-    }()
-
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        addChildren()
-        makeConstraints()
-    }
-
-    func appendRightItem(item: UIView) {
-        rightItems.addArrangedSubview(item)
-        item.snp.remakeConstraints { make in
-            make.width.height.equalTo(36)
-        }
-    }
-
-    func addChildren() {
-        addSubview(titleLabel)
-        addSubview(rightItems)
-    }
-
-    func makeConstraints() {
-        titleLabel.snp.makeConstraints { make in
-            make.leading.equalToSuperview().offset(16)
-            make.centerY.equalToSuperview()
-        }
-
-        rightItems.snp.makeConstraints { make in
-            make.trailing.equalToSuperview().offset(-16)
-            make.centerY.equalToSuperview()
-        }
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}

+ 0 - 116
TSLiveWallpaper/Business/TSMusic/MusicBase/SaveSuccessTipsView.swift

@@ -1,116 +0,0 @@
-//
-//  SaveSuccessTipsView.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/8.
-//
-
-import Foundation
-import Photos
-import UIKit
-
-class SaveSuccessTipsView: UIView {
-    lazy var iconView: UIImageView = .simpleImage(imageName: "ic_saved")
-    lazy var textLabel = UILabel()
-    lazy var viewButton: UIButton = {
-        let btn = UIButton()
-        btn.backgroundColor = .hexColor("#111111")
-        btn.setTitle("View".localized, for: .normal)
-        btn.setTitleColor(.hexColor("#6EF4F4"), for: .normal)
-        btn.titleLabel?.font = .boldSystemFont16
-        btn.layer.cornerRadius = 14
-        btn.layer.masksToBounds = true
-        btn.addTarget(self, action: #selector(openPhotoLibrary), for: .touchUpInside)
-        return btn
-    }()
-
-    var viewActionHandler: (() -> Void)?
-
-    override init(frame: CGRect) {
-        super.init(frame: CGRect(x: 0, y: 0, width: 288, height: 48))
-
-        layer.cornerRadius = 8
-        backgroundColor = .white
-
-        addSubview(iconView)
-        iconView.snp.makeConstraints { make in
-            make.width.height.equalTo(24)
-            make.centerY.equalToSuperview()
-            make.leading.equalTo(16)
-        }
-
-        textLabel.textColor = UIColor.black
-        textLabel.font = .boldSystemFont14
-        textLabel.text = "Saved"
-        addSubview(textLabel)
-        textLabel.snp.makeConstraints { make in
-            make.leading.equalTo(iconView.snp.trailing).offset(12)
-            make.centerY.equalToSuperview()
-        }
-
-        addSubview(viewButton)
-        viewButton.snp.makeConstraints { make in
-            make.width.equalTo(64)
-            make.height.equalTo(28)
-            make.centerY.equalToSuperview()
-            make.trailing.equalTo(-12)
-        }
-        viewButton.addTarget(self, action: #selector(buttonClick(_:)), for: .touchUpInside)
-    }
-
-    // 打开相册
-    @objc func openPhotoLibrary() {
-        let photosAppURL = URL(string: "photos-redirect://")!
-
-        if UIApplication.shared.canOpenURL(photosAppURL) {
-            UIApplication.shared.open(photosAppURL, options: [:], completionHandler: nil)
-        } else {
-            print("无法打开照片应用")
-        }
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    @objc func buttonClick(_ sender: UIButton) {
-        if let viewActionHandler = viewActionHandler {
-            viewActionHandler()
-        } else {
-//            UIApplication.shared.openPhotoLibrary()
-        }
-    }
-
-    static var isShowing = false
-}
-
-extension SaveSuccessTipsView {
-    static func show(at view: UIView?,
-                     at topOffset: CGFloat? = nil,
-                     viewActionHandler: (() -> Void)? = nil) {
-        guard !Self.isShowing, let view = view else {
-            return
-        }
-        Self.isShowing = true
-        let tip = SaveSuccessTipsView()
-        tip.viewActionHandler = viewActionHandler
-        view.addSubview(tip)
-        tip.snp.makeConstraints { make in
-            make.centerX.equalToSuperview()
-            make.size.equalTo(tip.frame.size)
-            if let topOffset = topOffset {
-                make.top.equalTo(topOffset)
-            } else {
-                make.bottom.equalTo(-200)
-            }
-        }
-        UIImpactFeedbackGenerator(style: .soft).impactOccurred()
-
-        DispatchQueue.global().asyncAfter(deadline: .now() + 2.5) {
-            DispatchQueue.main.async {
-                tip.removeFromSuperview()
-            }
-            Self.isShowing = false
-        }
-    }
-}

+ 0 - 68
TSLiveWallpaper/Business/TSMusic/MusicBase/SpacedButton.swift

@@ -1,68 +0,0 @@
-//
-//  SpacedButton.swift
-//  PhysicalWallPaper
-//
-//  Created by nkl on 2024/11/13.
-//
-
-import Foundation
-import UIKit
-
-class SpacedButton: UIButton {
-
-    var spacing: CGFloat = 8.0 {
-        didSet {
-            updateInsets()
-        }
-    }
-
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        setup()
-    }
-
-    required init?(coder: NSCoder) {
-        super.init(coder: coder)
-        setup()
-    }
-
-    private func setup() {
-        // 初始化配置
-        updateInsets()
-    }
-
-    private func updateInsets() {
-        guard let imageView = imageView, let titleLabel = titleLabel else {
-            return
-        }
-
-        let imageSize = imageView.frame.size
-        let titleSize = titleLabel.intrinsicContentSize
-
-        imageEdgeInsets = UIEdgeInsets(
-            top: 0,
-            left: -spacing/2,
-            bottom: 0,
-            right: spacing/2
-        )
-
-        titleEdgeInsets = UIEdgeInsets(
-            top: 0,
-            left: spacing/2,
-            bottom: 0,
-            right: -spacing/2
-        )
-
-        contentEdgeInsets = UIEdgeInsets(
-            top: 0,
-            left: spacing/2,
-            bottom: 0,
-            right: spacing/2
-        )
-    }
-
-    override func layoutSubviews() {
-        super.layoutSubviews()
-        updateInsets()
-    }
-}

+ 5 - 6
TSLiveWallpaper/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift

@@ -8,7 +8,6 @@
 import Combine
 import SwiftUI
 import SwiftUIX
-import Localize_Swift
 
 class PurchaseViewModel : ObservableObject{
     
@@ -177,7 +176,7 @@ class TSPurchaseVC: TSBaseVC {
                 case .verifyFail:
                 #if DEBUG
                     TSToastShared.hideLoading()
-                    let message = (object as? String) ?? "Verify receipt failed".localized()
+                    let message = (object as? String) ?? "Verify receipt failed".localized
                     TSToastShared.showToast(text:message)
 
                 #endif
@@ -237,10 +236,10 @@ struct PurchaseView :View {
                 Spacer().frame(height: 24)
                 
                 HStack(alignment: .center, spacing: 8*kDesignScale, content: {
-                    TSFeatureItemView(image: .purchaseIconUnlimited, text: "Unlimited Process".localized())
-                    TSFeatureItemView(image: .purchaseIconLock, text: "Unlock All Features".localized())
-                    TSFeatureItemView(image: .purchaseIconHd, text: "High Speed & Quality".localized())
-                    TSFeatureItemView(image: .purchaseIconAd, text: "100%\nNo Ads".localized())
+                    TSFeatureItemView(image: .purchaseIconUnlimited, text: "Unlimited Process".localized)
+                    TSFeatureItemView(image: .purchaseIconLock, text: "Unlock All Features".localized)
+                    TSFeatureItemView(image: .purchaseIconHd, text: "High Speed & Quality".localized)
+                    TSFeatureItemView(image: .purchaseIconAd, text: "100%\nNo Ads".localized)
                 }).multilineTextAlignment(.center).font(.font(size: 12)).foregroundColor(.white)
             }
             

+ 0 - 52
TSLiveWallpaper/Business/TSRandomWallpaperVC/EasyVC/TSRandomWallpaperCopyrightVC.swift

@@ -1,52 +0,0 @@
-//
-//  TSRandomWallpaperCopyrightVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/26.
-//
-
-class TSRandomWallpaperCopyrightVC: TSBaseVC {
-    
-    lazy var titleLabel: UILabel = {
-        let view = UILabel.createLabel(text: "Copyright Notice",font: .font(size: 24,weight: .medium),textColor: UIColor.fromHex("FFFFFF",alpha: 0.8),numberOfLines: 0)
-        return view
-    }()
-    
-    lazy var contentLabel: UILabel = {
-        let view = UILabel.createLabel(text: "100 Years Later Company attaches great importance to the copyright of images, but as a content provider, we cannot guarantee the accuracy of the reviewed content. If you find any infringing content, please inform us immediately and we will immediately remove it. Contact",font: .font(size: 14,weight: .regular),textColor: UIColor.fromHex("FFFFFF",alpha: 0.6),numberOfLines: 0)
-        return view
-    }()
-    
-    lazy var emailLabel: UILabel = {
-        let view = UILabel.createLabel(text: "Email: snapmusic6688@gmail.com",font: .font(size: 16,weight: .regular),textColor: UIColor.fromHex("FFFFFF"),numberOfLines: 0)
-        return view
-    }()
-    
-    override func createView() {
-        addNormalNavBarView()
-        setPageTitle("")
-        
-        contentView.addSubview(titleLabel)
-        contentView.addSubview(contentLabel)
-        contentView.addSubview(emailLabel)
-        
-        titleLabel.snp.makeConstraints { make in
-            make.top.equalTo(11)
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-        }
-        
-        contentLabel.snp.makeConstraints { make in
-            make.top.equalTo(titleLabel.snp.bottom).offset(24)
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-        }
-        
-        emailLabel.snp.makeConstraints { make in
-            make.top.equalTo(contentLabel.snp.bottom).offset(16)
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-        }
-    }
-    
-}

+ 0 - 30
TSLiveWallpaper/Business/TSRandomWallpaperVC/EasyVC/TSRandomWallpaperTutorialsVC.swift

@@ -1,30 +0,0 @@
-//
-//  TSRandomWallpaperTutorialsVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/26.
-//
-
-class TSRandomWallpaperTutorialsVC: TSBaseVC {
-
-    lazy var scrollView: UIScrollView = {
-        let scrollView = UIScrollView()
-        scrollView.backgroundColor = .clear
-        scrollView.frame = self.contentView.bounds
-        scrollView.contentSize = imageView.size
-        return scrollView
-    }()
-    
-    lazy var imageView: UIImageView = {
-        let imageView = UIImageView.createImageView(imageName: "live_tutorials")
-        imageView.frame = CGRectMake(0, 0, k_ScreenWidth, kDesignScale*(imageView.image?.size.height ?? k_ScreenHeight))
-        return imageView
-    }()
-    
-    override func createView() {
-        addNormalNavBarView()
-        setPageTitle("How to set shuffle packs".localized)
-        contentView.addSubview(scrollView)
-        scrollView.addSubview(imageView)
-    }
-}

+ 0 - 140
TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperBrowseVC/TSRandomWallpaperBrowseSelectView.swift

@@ -1,140 +0,0 @@
-//
-//  TSRandomWallpaperBrowseSelectView.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/24.
-//
-
-
-class TSRandomWallpaperBrowseSelectView : TSBaseView{
-    
-    var selectedCallBack:(([IndexPath])->Void)?
-    
-    var items:[TSImageDataItemModel] = [TSImageDataItemModel](){
-        didSet{
-            collectionView.reloadData()
-        }
-    }
-    
-    lazy var collectionView: UICollectionView = {
-        let collectionView = UICollectionView.createCommon(delegate: self, cellReuseIds: ["TSRandomWallpaperBrowseSelectCell"])
-        if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
-            flowLayout.minimumInteritemSpacing = 16
-            flowLayout.itemSize = CGSize(width: 100, height: 100)
-            flowLayout.scrollDirection = .horizontal
-        }
-        collectionView.allowsMultipleSelection = true
-        collectionView.contentInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
-        return collectionView
-    }()
-    
-    lazy var selectNumLabel: UILabel = {
-        return UILabel.createLabel(font: UIFont.font(size: 14),textColor: UIColor.fromHex("FFFFFF", alpha: 0.4))
-    }()
-    
-    override func creatUI() {
-        contentView.addSubview(collectionView)
-        collectionView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-
-        kDelayOnMainThread(0.1) {
-            self.selectAllItems()
-        }
-      
-    }
-    
-    
-    func selectAllItems() {
-        for section in 0..<collectionView.numberOfSections {
-            for item in 0..<collectionView.numberOfItems(inSection: section) {
-                let indexPath = IndexPath(item: item, section: section)
-                collectionView.selectItem(at: indexPath, animated: false, scrollPosition: [])
-            }
-        }
-    }
-    
-    func deselectAllItems() {
-        for section in 0..<collectionView.numberOfSections {
-            for item in 0..<collectionView.numberOfItems(inSection: section) {
-                let indexPath = IndexPath(item: item, section: section)
-                collectionView.deselectItem(at: indexPath, animated: false)
-            }
-        }
-    }
-    
-    func clickSelectHandle(){
-        if let selectedItems = collectionView.indexPathsForSelectedItems {
-            if selectedItems.count == 0 || selectedItems.count < items.count {
-                selectAllItems()
-            }else if selectedItems.count == items.count {
-                deselectAllItems()
-            }
-            
-            selectedCallBack?(collectionView.indexPathsForSelectedItems ?? [IndexPath]())
-        }
-    }
-}
-
-
-extension TSRandomWallpaperBrowseSelectView : UICollectionViewDataSource,UICollectionViewDelegate {
-    
-    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        return items.count
-    }
-    
-    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TSRandomWallpaperBrowseSelectCell", for: indexPath) as! TSRandomWallpaperBrowseSelectCell
-        if let wallpaperModel = items.safeObj(At: indexPath.item), wallpaperModel.imageUrl.count > 0 {
-            cell.showImageView.setAsyncImage(urlString: wallpaperModel.imageUrl,placeholder: kWapppaperPlaceholderImage)
-        }
-        return cell
-    }
-    
-    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath){
-        selectedCallBack?(collectionView.indexPathsForSelectedItems ?? [IndexPath]())
-    }
-    
-    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath){
-        selectedCallBack?(collectionView.indexPathsForSelectedItems ?? [IndexPath]())
-    }
-}
-
-class TSRandomWallpaperBrowseSelectCell : TSBaseCollectionCell {
-    
-    override var isSelected: Bool{
-        didSet{
-            selectImageView.image = UIImage(named: isSelected ? "radiobox_selected" : "radiobox_unSelect" )
-        }
-    }
-    
-    lazy var showImageView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.contentMode = .scaleAspectFill
-        return imageView
-    }()
-    
-    
-    lazy var selectImageView: UIImageView = {
-        return UIImageView.createImageView(imageName: "radiobox_selected")
-    }()
-    
-
-    override func creatUI() {
-
-        bgContentView.cornerRadius = 16
-        
-        bgContentView.addSubview(showImageView)
-        showImageView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-
-        bgContentView.addSubview(selectImageView)
-        selectImageView.snp.makeConstraints { make in
-            make.width.height.equalTo(24)
-            make.trailing.equalTo(-4)
-            make.bottom.equalTo(-4)
-        }
-    }
-    
-}

+ 0 - 433
TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperBrowseVC/TSRandomWallpaperBrowseVC.swift

@@ -1,433 +0,0 @@
-//
-//  TSRandomWallpaperBrowseVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/24.
-//
-
-
-private let topLineH = k_Height_statusBar()
-
-class TSRandomWallpaperBrowseVC: TSBaseVC {
-
-    private var isPanningDown: Bool?
-
-    lazy var isPreview = false {
-        didSet {
-            self.previewView.isHidden = !isPreview
-            self.btnsAllView.isHidden = isPreview
-        }
-    }
-    
-    var dataModel:TSRandomWallpaperDataItemModel
-    
-    init(dataModel: TSRandomWallpaperDataItemModel) {
-        self.dataModel = dataModel
-        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 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(TSRandomWallpaperCopyrightVC(), animated: true)
-        }
-        btnsAllView.addSubview(copyrightBtn)
-        copyrightBtn.snp.makeConstraints { make in
-            make.width.height.equalTo(44)
-            make.trailing.equalTo(-16)
-            make.top.equalTo(topLineH)
-        }
-        
-        btnsAllView.addSubview(saveImagesToolView)
-        saveImagesToolView.snp.makeConstraints { make in
-            make.bottom.leading.trailing.equalTo(0)
-            make.height.equalTo(k_Height_StatusBar+168)
-        }
-        
-        //教程按钮
-        let tutorialsBtn = UIButton.createButton(image: UIImage(named: "random_tutorials"),backgroundColor: UIColor.fromHex("#000000", alpha: 0.5),corner: 19.0) { [weak self]  in
-            guard let self = self else { return }
-            navigationController?.pushViewController(TSRandomWallpaperTutorialsVC(), animated: true)
-        }
-        btnsAllView.addSubview(tutorialsBtn)
-        tutorialsBtn.snp.makeConstraints { make in
-            make.centerX.equalToSuperview().offset(-20-39.0)
-            make.bottom.equalTo(saveImagesToolView.snp.top).offset(-20)
-            make.width.height.equalTo(58)
-        }
-        
-        //预览按钮
-        let previewBtn = UIButton.createButton(image: UIImage(named: "random_preview"),backgroundColor: UIColor.fromHex("#000000", alpha: 0.5),corner: 19.0) { [weak self]  in
-            guard let self = self else { return }
-            self.isPreview = !self.isPreview
-        }
-        btnsAllView.addSubview(previewBtn)
-        previewBtn.snp.makeConstraints { make in
-            make.centerX.equalToSuperview().offset(20+39.0)
-            make.bottom.equalTo(saveImagesToolView.snp.top).offset(-20)
-            make.width.height.equalTo(58)
-        }
-        
-        
-
-        return btnsAllView
-    }()
-
-    //缩略图view
-    lazy var thumbnailView: TSRandomWallpaperBrowseSelectView = {
-        let thumbnailView = TSRandomWallpaperBrowseSelectView()
-        thumbnailView.items = dataModel.items
-        thumbnailView.selectedCallBack = { [weak self] selectedArray in
-            guard let self = self else { return }
-            
-            selecAllView.isSelected = selectedArray.count == 0 ? false : true
-            selecAllView.selectNumLabel.text = "(\(selectedArray.count)/\(self.dataModel.items.count))"
-            saveBtn.isEnabled = selecAllView.isSelected
-        }
-        return thumbnailView
-    }()
-    
-    lazy var selecAllView: TSRandomWallpaperSelecAllView = {
-        let selecAllView = TSRandomWallpaperSelecAllView()
-        selecAllView.selectNumLabel.text = "(\(self.dataModel.items.count)/\(self.dataModel.items.count))"
-        selecAllView.clickCallBack = { [weak self] in
-            guard let self = self else { return }
-            self.thumbnailView.clickSelectHandle()
-            
-        }
-        return selecAllView
-    }()
-    
-    
-    lazy var saveBtn: UIButton = {
-        let imageNamed = isShowVip() ? "vip_icon" : ""
-        let saveBtn = TSViewTool.createNormalSubmitBtn(title: "Save All".localized,imageNamed: imageNamed) { [weak self]  in
-            guard let self = self else { return }
-            //判断 vip
-            if self.dataModel.vip == true,PurchaseManager.default.isVip == false{
-                TSPurchaseVC.show(target: self) {[weak self]  in
-                    guard let self = self else { return }
-                }
-                return
-            }
-            
-            //保存图片
-            var imageUrlSting:[String] = [String]()
-            
-            if let indexArray = self.thumbnailView.collectionView.indexPathsForSelectedItems {
-                for indexPath in indexArray {
-                    if let item = self.dataModel.items.safeObj(At: indexPath.row),item.imageUrl.contains("http")  {
-                        imageUrlSting.append(item.imageUrl)
-                    }
-                }
-            }
-
-            if imageUrlSting.count == 0 {
-                return
-            }
-            
-            TSToastShared.showLoading(containerView: self.view)
-            
-            let group = DispatchGroup()
-            
-            var images = [UIImage]()
-            for urlString in imageUrlSting {
-                group.enter()
-                TSCommonTool.fetchImageWithCache(from: urlString) { image, error in
-                    if let image = image {
-                        images.append(image)
-                    }
-                    group.leave()
-                }
-            }
-            
-            group.notify(queue: .main) {
-                PhotoManagerShared.saveImagesToUniqueAlbum(images: images, baseAlbumName: self.dataModel.type) { success, error in
-                    kMainAsync {
-                        TSToastShared.hideLoading()
-                        if success {
-                            kSaveSuccesswShared.show(atView: self.view)
-                        } else {
-                            TSToastShared.showToast(text: error?.localizedDescription ?? "Save Failure")
-                        }
-                    }
-                }
-            }
-            
-        }
-        saveBtn.titleLabel?.font = UIFont.font(size: 14.0)
-        saveBtn.cornerRadius = 16
-        return saveBtn
-    }()
-    
-    //整个保存 图片的工具栏
-    lazy var saveImagesToolView: UIView = {
-        let saveImagesToolView = UIView()
-        let effctView = TSViewTool.createBlurEffectView(style: .light,backgroundColor: UIColor.fromHex("#000000", alpha: 0.6))
-        saveImagesToolView.addSubview(effctView)
-        effctView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-        
-        saveImagesToolView.addSubview(thumbnailView)
-        thumbnailView.snp.makeConstraints { make in
-            make.top.equalTo(16)
-            make.leading.trailing.equalTo(0)
-            make.height.equalTo(100)
-        }
-        
-        saveImagesToolView.addSubview(selecAllView)
-        selecAllView.snp.makeConstraints { make in
-            make.leading.equalTo(16)
-            make.top.equalTo(thumbnailView.snp.bottom).offset(18)
-        }
-        
-
-        saveImagesToolView.addSubview(saveBtn)
-        saveBtn.snp.makeConstraints { make in
-            make.trailing.equalTo(-16)
-            make.top.equalTo(thumbnailView.snp.bottom).offset(12)
-            make.width.equalTo(110)
-            make.height.equalTo(32)
-        }
-        
-        return saveImagesToolView
-    }()
-    
-    
-    
-    //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 layout = UICollectionViewFlowLayout()
-        layout.scrollDirection = .horizontal // 横向滚动
-        layout.itemSize = UIScreen.main.bounds.size // 每个 item 的大小
-        layout.minimumLineSpacing = 0 // item 之间的间隔
-        layout.minimumInteritemSpacing = 0 // item 之间的间隔
-        let collectionView = UICollectionView(frame: UIScreen.main.bounds, collectionViewLayout: layout)
-        collectionView.translatesAutoresizingMaskIntoConstraints = false
-        collectionView.contentInsetAdjustmentBehavior = .never
-        collectionView.backgroundColor = UIColor.black
-        collectionView.register(TSRandomWallpaperBrowseCell.self, forCellWithReuseIdentifier: "Cell")
-        collectionView.isPagingEnabled = true
-        collectionView.dataSource = self
-        collectionView.delegate = self
-        collectionView.showsVerticalScrollIndicator = false
-        collectionView.showsHorizontalScrollIndicator = false
-        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)
-    }
-    
-    func isShowVip() -> Bool {
-        return self.dataModel.vip
-    }
-}
-
-//MARK: 点击操作
-extension TSRandomWallpaperBrowseVC{
-
-    @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 TSRandomWallpaperBrowseVC: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())
-//    }
-    
-    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        return dataModel.items.count
-    }
-    
-    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! TSRandomWallpaperBrowseCell
-        if let wallpaperModel = dataModel.items.safeObj(At: indexPath.item), wallpaperModel.imageUrl.count > 0 {
-            cell.showImageView.setAsyncImage(urlString: wallpaperModel.imageUrl,placeholder: kWapppaperPlaceholderImage)
-        }
-        return cell
-    }
-}
-
-
-class TSRandomWallpaperBrowseCell : TSBaseCollectionCell {
-    
-    private let showImageViewW = k_ScreenWidth - 32
-    
-    lazy var showImageView: UIImageView = {
-        let imageView = UIImageView()
-        return imageView
-    }()
-    
-    override func creatUI() {
-        self.backgroundColor = UIColor.clear
-        self.contentView.backgroundColor = UIColor.clear
-        
-        bgContentView.addSubview(showImageView)
-        showImageView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-    }
-}

+ 0 - 70
TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperBrowseVC/TSRandomWallpaperBrowseView.swift

@@ -1,70 +0,0 @@
-//
-//  TSRandomWallpaperBrowseView.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/24.
-//
-
-
-class TSRandomWallpaperSelecAllView : TSBaseView {
-    
-    var clickCallBack:(()->Void)?
-    
-    var isSelected: Bool = true {
-        didSet {
-            selectImageView.image = UIImage(named: isSelected ? "radiobox_selected" : "radiobox_unSelect")
-        }
-    }
-    
-    lazy var selectImageView: UIImageView = {
-        return UIImageView.createImageView(imageName: "radiobox_selected")
-    }()
-    
-    lazy var selectTextLabel: UILabel = {
-        return UILabel.createLabel(text: "Select All".localized,font: UIFont.font(size: 14),textColor: UIColor.fromHex("FFFFFF"))
-    }()
-    
-    lazy var selectNumLabel: UILabel = {
-        return UILabel.createLabel(font: UIFont.font(size: 14),textColor: UIColor.fromHex("FFFFFF", alpha: 0.4))
-    }()
-    
-    lazy var clearButton: UIButton = {
-        let clearButton = UIButton()
-        clearButton.isSelected = true
-        clearButton.addTarget(self,action:#selector(clickClearButton(_:)), for: .touchUpInside)
-        return clearButton
-    }()
-    
-    override func creatUI() {
-        contentView.addSubview(selectImageView)
-        contentView.addSubview(selectTextLabel)
-        contentView.addSubview(selectNumLabel)
-        contentView.addSubview(clearButton)
-        
-        selectImageView.snp.makeConstraints { make in
-            make.width.height.equalTo(20)
-            make.centerY.equalToSuperview()
-            make.leading.equalTo(0)
-        }
-        
-        selectTextLabel.snp.makeConstraints { make in
-            make.centerY.equalToSuperview()
-            make.leading.equalTo(selectImageView.snp.trailing).offset(6)
-        }
-        
-        selectNumLabel.snp.makeConstraints { make in
-            make.centerY.equalToSuperview()
-            make.leading.equalTo(selectTextLabel.snp.trailing).offset(0)
-            make.trailing.equalTo(0)
-        }
-        
-        clearButton.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-        
-    }
-    
-    @objc func clickClearButton(_ btn:UIButton){
-        clickCallBack?()
-    }
-}

+ 0 - 109
TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperVC.swift

@@ -1,109 +0,0 @@
-//
-//  TSRandomWallpaperVC.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/20.
-//
-
-class TSRandomWallpaperVC: TSBaseVC {
-    
-    @UserDefault(key: "isShowGuide", defaultValue: true)
-    var isShowGuide: Bool
-    
-//    lazy var navBarView: TSBaseNavContentBarView = {
-//        let navBarView = TSBaseNavContentBarView()
-//        let titleImageView = UIImageView.createImageView(imageName: "nav_title_random",contentMode: .scaleToFill)
-//        
-//        navBarView.barView.addSubview(titleImageView)
-//        titleImageView.snp.makeConstraints { make in
-//            make.centerY.equalToSuperview()
-//            make.left.equalTo(16)
-////            make.width.equalTo(185)
-////            make.height.equalTo(24)
-//        }
-//
-//        return navBarView
-//    }()
-//    
-    
-    lazy var navBarView: LWSubNavigationBar = {
-        let navBarView = LWSubNavigationBar()
-        navBarView.backButton.addTarget(self, action: #selector(pop), for: .touchUpInside)
-        navBarView.backButton.setImage(.icClose, for: .normal)
-        navBarView.titleLabel.text = "DIY Live Wallpaper"
-        return navBarView
-    }()
-    
-    lazy var collectionComponent: TSCollectionViewComponent = {
-        let layout = UICollectionViewFlowLayout()
-        let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [ :])
-        cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: k_Height_TabBar, right: 0)
-        cp.itemDidSelectedHandler = { [weak self] (object, indexPath) in
-            guard let self = self else { return }
-            
-            if let dataModel = object as? TSRandomWallpaperDataItemModel{
-                if dataModel.style == .randomBanner {
-                    let tutorialsVC = TSRandomWallpaperTutorialsVC()
-                    tutorialsVC.hidesBottomBarWhenPushed = true
-                    self.navigationController?.pushViewController(tutorialsVC, animated: true)
-                }else{
-                    kPresentModalVC(target: self, modelVC: TSRandomWallpaperBrowseVC(dataModel: dataModel))
-                }
-            }
-        }
-        
-        cp.itemActionHandler = { [weak self] (object, indexPath) in
-            guard let self = self else { return }
-            if indexPath.section == 0 {
-                isShowGuide = false
-                reloadView()
-            }
-        }
-        cp.itemWillDisplayHandler = { cell, obj, IndexPath in
-
-        }
-        cp.itemDidEndDisplayingHandler = { cell, obj, indexPath in
-      
-        }
-        
-        return cp
-    }()
-    
-    
-    override func createView() {
-        //setViewBgImageNamed(named: "view_main_bg")
-        
-        navBarContentView.addSubview(navBarView)
-        navBarContentView.snp.remakeConstraints { make in
-            make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
-            make.leading.trailing.equalToSuperview()
-            make.height.equalTo(44.0)
-        }
-        navBarView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-
-        
-        contentView.addSubview(collectionComponent.collectionView)
-        collectionComponent.collectionView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-   
-        reloadView()
-        
-        TSNetworkShard.monitorNetworkPermission { success in
-            if success {
-                self.collectionComponent.reloadData()
-            }
-        }
-    }
-    
-    func reloadView() {
-        collectionComponent.clear()
-        if isShowGuide {
-            collectionComponent.reloadView(with:kImageDataCenterShared.randomBannerArray + kImageDataCenterShared.randomListArray)
-        }else{
-            collectionComponent.reloadView(with:kImageDataCenterShared.randomListArray)
-        }
-    }
-}

+ 0 - 72
TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperView/TSRandomWallpaperBannerCell.swift

@@ -1,72 +0,0 @@
-//
-//  TSRandomWallpaperBannerCell.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/22.
-//
-
-//MARK: TSRandomWallpaperBannerCell
-class TSRandomWallpaperBannerCell: TSBaseCollectionCell  {
-    
-    var component:TSCollectionViewComponent?
-    lazy var bannerImageBgView: UIImageView = {
-        return UIImageView.createImageView(imageName: "random_guided_top_bg",corner: 16)
-    }()
-    
-    lazy var bannerImageTextView: UIImageView = {
-        return UIImageView.createImageView(imageName: "random_guided_top_text")
-    }()
-    
-    
-    lazy var closeBtn: TSUIExpandedTouchButton = {
-        let btn = TSUIExpandedTouchButton()
-        btn.setUpButton(image: UIImage(named:"close_gary")) { [weak self]  in
-            guard let self = self else { return }
-        
-            if let component = self.component {
-                if let itemActionHandler = component.itemActionHandler {
-                    itemActionHandler(self, IndexPath(row: 0, section: 0))
-                }
-            }
-        }
-        return btn
-    }()
-    
-    static let reuseIdentifier = "TSHomeCyclePagerViewCell"
-    override func creatUI() {
-        bgContentView.addSubview(bannerImageBgView)
-        bannerImageBgView.snp.makeConstraints { make in
-            make.leading.equalTo(0)
-            make.top.equalTo(0)
-            make.trailing.equalTo(0)
-            make.bottom.equalTo(0)
-        }
-        
-        bgContentView.addSubview(bannerImageTextView)
-        bannerImageTextView.snp.makeConstraints { make in
-            make.leading.equalTo(14)
-            make.centerY.equalToSuperview()
-            make.width.equalTo(200)
-            make.height.equalTo(68)
-        }
-        
-        bgContentView.addSubview(closeBtn)
-        closeBtn.snp.makeConstraints { make in
-            make.top.equalTo(8)
-            make.trailing.equalTo(-8)
-            make.width.equalTo(16)
-            make.height.equalTo(16)
-        }
-    }
-    
-    override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
-        self.component = component
-    }
-}
-
-
-class TSRandomWallpaperHeaderView: UICollectionReusableView {
-    func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
-      
-    }
-}

+ 0 - 73
TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperView/TSRandomWallpaperCell.swift

@@ -1,73 +0,0 @@
-//
-//  TSRandomWallpaperCell.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/22.
-//
-
-
-//MARK: TSRandomWallpaperCell
-class TSRandomWallpaperCell: TSBaseCollectionCell {
-
-    
-    static let reuseIdentifier = "TSHomeCyclePagerViewCell"
-    
-    lazy var showImageView: UIImageView = {
-        return UIImageView.createImageView(imageName: "", corner: 16)
-    }()
-    
-    lazy var show1ImageView: UIImageView = {
-        return UIImageView.createImageView(imageName: "", corner: 16)
-    }()
-    
-    lazy var show2ImageView: UIImageView = {
-        return UIImageView.createImageView(imageName: "", corner: 16)
-    }()
-    
-    
-    override func creatUI() {
-
-        bgContentView.addSubview(show2ImageView)
-        bgContentView.addSubview(show1ImageView)
-        bgContentView.addSubview(showImageView)
-
-        showImageView.snp.makeConstraints { make in
-            make.leading.equalTo(0)
-            make.trailing.equalTo(-32)
-            make.top.equalTo(0)
-            make.bottom.equalTo(0)
-        }
-
-        show1ImageView.snp.makeConstraints { make in
-            make.leading.equalTo(16)
-            make.trailing.equalTo(-16)
-            make.top.equalTo(13)
-            make.bottom.equalTo(-11.66)
-        }
-        
-        show2ImageView.snp.makeConstraints { make in
-            make.leading.equalTo(35)
-            make.trailing.equalTo(0)
-            make.top.equalTo(26)
-            make.bottom.equalTo(-23.66)
-        }
-    }
-    
-    override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
-        if let itemModel = object as? TSRandomWallpaperDataItemModel {
-            
-            if let model = itemModel.items.safeObj(At: 0), model.imageUrl.contains("http") {
-                showImageView.setAsyncImage(urlString: model.imageUrl,placeholder: kWapppaperPlaceholderImage)
-            }
-            
-            if let model = itemModel.items.safeObj(At: 1), model.imageUrl.contains("http") {
-                show1ImageView.setAsyncImage(urlString: model.imageUrl,placeholder: kWapppaperPlaceholderImage)
-            }
-            
-            if let model = itemModel.items.safeObj(At: 2), model.imageUrl.contains("http") {
-                show2ImageView.setAsyncImage(urlString: model.imageUrl,placeholder: kWapppaperPlaceholderImage)
-            }
-        }
-    }
-}
-

+ 0 - 139
TSLiveWallpaper/Common/Ex/UICollectionView+Ex.swift

@@ -1,139 +0,0 @@
-//
-//  UICollectionView+Ex.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/20.
-//
-
-import UIKit
-import MJRefresh
-
-private var isMJRefreshKey = "isMJRefreshKey"
-private var pageNumKey = "pageNumKey"
-private var pageSizeKey = "pageSizeKey"
-private var dataArrayKey = "dataArrayKey"
-
-private let PAGESIZE = 10
-private let PAGENUM = 1
-
-extension UICollectionView {
-    static func createCommon(delegate: UICollectionViewDelegate & UICollectionViewDataSource, cellReuseIds: [String]) -> UICollectionView {
-        let layout = UICollectionViewFlowLayout()
-        layout.scrollDirection = .vertical
-        
-        let collectionView = TSBaseCollectionView(frame: .zero, collectionViewLayout: layout)
-        collectionView.delegate = delegate
-        collectionView.dataSource = delegate
-        collectionView.showsVerticalScrollIndicator = false
-        collectionView.showsHorizontalScrollIndicator = false
-        collectionView.backgroundColor = .clear
-        
-        if #available(iOS 11.0, *) {
-            collectionView.contentInsetAdjustmentBehavior = .never
-        }
-        
-        for cellReuseId in cellReuseIds {
-            collectionView.register(cellReuseId.toClass(), forCellWithReuseIdentifier: cellReuseId)
-        }
-        
-        collectionView.dataArray = []
-        collectionView.pageNum = PAGENUM
-        collectionView.pageSize = PAGESIZE
-        
-        return collectionView
-    }
-    
-    func myReloadData() {
-        reloadData()
-    }
-    
-    func addFooterWithRefreshingBlock(_ block: @escaping () -> Void) {
-        isUseMJRefresh = true
-        mj_footer = MJRefreshAutoNormalFooter(refreshingBlock: { [weak self] in
-            self?.pageNum += 1
-            block()
-        })
-        (mj_footer as? MJRefreshAutoNormalFooter)?.stateLabel?.isHidden = true
-    }
-    
-    func addHeaderWithRefreshingBlock(_ block: @escaping () -> Void) {
-        isUseMJRefresh = true
-        mj_header = MJRefreshNormalHeader(refreshingBlock: { [weak self] in
-            self?.pageNum = PAGENUM
-            block()
-        })
-    }
-    
-    func handleDataArray(_ networkArray: [Any], noMore: Bool) {
-        let count = networkArray.count
-        
-        if count > 0 {
-            if pageNum <= PAGENUM {
-                dataArray.removeAll()
-            }
-            dataArray.append(contentsOf: networkArray)
-            myReloadData()
-        } else if pageNum <= PAGENUM {
-            dataArray.removeAll()
-            myReloadData()
-        }
-        
-        if isUseMJRefresh {
-            if !noMore {
-                mj_footer?.resetNoMoreData()
-            } else {
-                mj_footer?.endRefreshingWithNoMoreData()
-            }
-            
-            if pageNum <= PAGENUM {
-                mj_header?.endRefreshing()
-            }
-        }
-    }
-    
-    func handleDataArray(_ networkArray: [Any]) {
-        handleDataArray(networkArray, noMore: networkArray.count < pageSize)
-    }
-    
-    func handleMJRefreshWithCount(_ count: Int) {
-        if count >= pageSize {
-            mj_footer?.resetNoMoreData()
-        } else {
-            mj_footer?.endRefreshingWithNoMoreData()
-        }
-        
-        if pageNum <= PAGENUM {
-            mj_header?.endRefreshing()
-        }
-    }
-    
-    func handleMJRefreshWithError(_ error: String) {
-        if pageNum <= PAGENUM {
-            mj_header?.endRefreshing()
-        } else {
-            mj_footer?.endRefreshing()
-        }
-    }
-    
-    // MARK: - Properties
-    
-    var isUseMJRefresh: Bool {
-        get { (objc_getAssociatedObject(self, &isMJRefreshKey) as? Bool) ?? false }
-        set { objc_setAssociatedObject(self, &isMJRefreshKey, newValue, .OBJC_ASSOCIATION_ASSIGN) }
-    }
-    
-    var pageNum: Int {
-        get { (objc_getAssociatedObject(self, &pageNumKey) as? Int) ?? PAGENUM }
-        set { objc_setAssociatedObject(self, &pageNumKey, newValue, .OBJC_ASSOCIATION_ASSIGN) }
-    }
-    
-    var pageSize: Int {
-        get { (objc_getAssociatedObject(self, &pageSizeKey) as? Int) ?? PAGESIZE }
-        set { objc_setAssociatedObject(self, &pageSizeKey, newValue, .OBJC_ASSOCIATION_ASSIGN) }
-    }
-    
-    var dataArray: [Any] {
-        get { (objc_getAssociatedObject(self, &dataArrayKey) as? [Any]) ?? [] }
-        set { objc_setAssociatedObject(self, &dataArrayKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
-    }
-}

+ 0 - 0
TSLiveWallpaper/DataManger/Config/TSConfig.swift → TSLiveWallpaper/Common/TSConfig.swift


+ 0 - 600
TSLiveWallpaper/Common/ThirdParty/LivePhoto.swift

@@ -1,600 +0,0 @@
-//
-//  LivePhoto.swift
-//  Live Photos
-//
-//  Read discussion at:
-//  http://www.limit-point.com/blog/2018/live-photos/
-//
-//  Created by Alexander Pagliaro on 7/25/18.
-//  Copyright © 2018 Limit Point LLC. All rights reserved.
-//
-
-import UIKit
-import AVFoundation
-import MobileCoreServices
-import Photos
-
-class LivePhoto {
-    // MARK: PUBLIC
-    typealias LivePhotoResources = (pairedImage: URL, pairedVideo: URL)
-    /// Returns the paired image and video for the given PHLivePhoto
-    public class func extractResources(from livePhoto: PHLivePhoto, completion: @escaping (LivePhotoResources?) -> Void) {
-        queue.async {
-            shared.extractResources(from: livePhoto, completion: completion)
-        }
-    }
-    /// Generates a PHLivePhoto from an image and video.  Also returns the paired image and video.
-    public class func generate(from imageURL: URL?, videoURL: URL, progress: @escaping (CGFloat) -> Void, completion: @escaping (PHLivePhoto?, LivePhotoResources?) -> Void) {
-        queue.async {
-            shared.generate(from: imageURL, videoURL: videoURL, progress: progress, completion: completion)
-        }
-    }
-    /// Save a Live Photo to the Photo Library by passing the paired image and video.
-    public class func saveToLibrary(_ resources: LivePhotoResources, completion: @escaping (Bool) -> Void) {
-        PHPhotoLibrary.shared().performChanges({
-            let creationRequest = PHAssetCreationRequest.forAsset()
-            let options = PHAssetResourceCreationOptions()
-            creationRequest.addResource(with: PHAssetResourceType.pairedVideo, fileURL: resources.pairedVideo, options: options)
-            creationRequest.addResource(with: PHAssetResourceType.photo, fileURL: resources.pairedImage, options: options)
-        }, completionHandler: { (success, error) in
-            if error != nil {
-                print(error as Any)
-            }
-            completion(success)
-        })
-    }
-    
-    // MARK: PRIVATE
-    private static let shared = LivePhoto()
-    private static let queue = DispatchQueue(label: "com.limit-point.LivePhotoQueue", attributes: .concurrent)
-    lazy private var cacheDirectory: URL? = {
-        if let cacheDirectoryURL = try? FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
-            let fullDirectory = cacheDirectoryURL.appendingPathComponent("com.limit-point.LivePhoto", isDirectory: true)
-            if !FileManager.default.fileExists(atPath: fullDirectory.absoluteString) {
-                try? FileManager.default.createDirectory(at: fullDirectory, withIntermediateDirectories: true, attributes: nil)
-            }
-            return fullDirectory
-        }
-        return nil
-    }()
-    
-    deinit {
-        clearCache()
-    }
-    
-    private func generateKeyPhoto(from videoURL: URL,fileName:String) -> URL? {
-        var percent:Float = 0.5
-        let videoAsset = AVURLAsset(url: videoURL)
-        if let stillImageTime = videoAsset.stillImageTime() {
-            percent = Float(stillImageTime.value) / Float(videoAsset.duration.value)
-        }
-        guard let imageFrame = videoAsset.getAssetFrame(percent: percent) else { return nil }
-        guard let jpegData = imageFrame.jpegData(compressionQuality: 1.0) else { return nil }
-        guard let url = cacheDirectory?.appendingPathComponent(fileName).appendingPathExtension("jpg") else { return nil }
-        do {
-            try? jpegData.write(to: url)
-            return url
-        }
-    }
-    private func clearCache() {
-        if let cacheDirectory = cacheDirectory {
-            try? FileManager.default.removeItem(at: cacheDirectory)
-        }
-    }
-    
-    func generate(from imageURL: URL?, videoURL: URL, progress: @escaping (CGFloat) -> Void, completion: @escaping (PHLivePhoto?, LivePhotoResources?) -> Void) {
-        guard let cacheDirectory = cacheDirectory else {
-            DispatchQueue.main.async {
-                completion(nil, nil)
-            }
-            return
-        }
-        
-        let assetIdentifier = UUID().uuidString
-        
-        let fileName = videoURL.lastPathComponent.replacingOccurrences(of: (".\(videoURL.pathExtension)"), with: "")
-        let saveToImagePath = cacheDirectory.appendingPathComponent(fileName).appendingPathExtension("heic")//.appendingPathExtension("jpg")
-        
-        let asset = AVURLAsset(url: videoURL)
-        let targetDuration = CMTimeGetSeconds(asset.duration)
-        let videoSize = asset.tracks(withMediaType: .video).first?.naturalSize
-
-        let fileManager = FileManager.default
-        if fileManager.fileExists(atPath: saveToImagePath.path) {
-            print("文件已存在于缓存中: \(saveToImagePath)")
-        }else{
-            let _keyPhotoURL = imageURL ?? generateKeyPhoto(from: videoURL,fileName: fileName)
-            guard let keyPhotoURL = _keyPhotoURL, let pairedImageURL = addAssetID(assetIdentifier, toImage: keyPhotoURL, saveTo: saveToImagePath) else {
-                DispatchQueue.main.async {
-                    completion(nil, nil)
-                }
-                return
-            }
-        }
-        
-        let pairedImageURL = saveToImagePath
-        let saveToVideoPath = cacheDirectory.appendingPathComponent(fileName).appendingPathExtension("mov")
-        if fileManager.fileExists(atPath: saveToVideoPath.path) {
-            print("文件已存在于缓存中: \(saveToVideoPath)")
-            let pairedVideoURL = saveToVideoPath
-            PHLivePhoto.request(withResourceFileURLs: [pairedVideoURL, pairedImageURL], placeholderImage: nil, targetSize: CGSize.zero, contentMode: PHImageContentMode.aspectFit, resultHandler: { (livePhoto: PHLivePhoto?, info: [AnyHashable : Any]) -> Void in
-                if let isDegraded = info[PHLivePhotoInfoIsDegradedKey] as? Bool, isDegraded {
-                    return
-                }
-                DispatchQueue.main.async {
-                    completion(livePhoto, (pairedImageURL, pairedVideoURL))
-                }
-            })
-        }else{
-            addAssetID(assetIdentifier, toVideo: videoURL, saveTo:saveToVideoPath, progress: progress) { (_videoURL) in
-                if let pairedVideoURL = _videoURL {
-                    _ = PHLivePhoto.request(withResourceFileURLs: [pairedVideoURL, pairedImageURL], placeholderImage: nil, targetSize: CGSize.zero, contentMode: PHImageContentMode.aspectFit, resultHandler: { (livePhoto: PHLivePhoto?, info: [AnyHashable : Any]) -> Void in
-                        if let isDegraded = info[PHLivePhotoInfoIsDegradedKey] as? Bool, isDegraded {
-                            return
-                        }
-                        DispatchQueue.main.async {
-                            completion(livePhoto, (pairedImageURL, pairedVideoURL))
-                        }
-                    })
-                } else {
-                    DispatchQueue.main.async {
-                        completion(nil, nil)
-                    }
-                }
-            }
-        }
-    }
-    
-    private func extractResources(from livePhoto: PHLivePhoto, to directoryURL: URL, completion: @escaping (LivePhotoResources?) -> Void) {
-        let assetResources = PHAssetResource.assetResources(for: livePhoto)
-        let group = DispatchGroup()
-        var keyPhotoURL: URL?
-        var videoURL: URL?
-        for resource in assetResources {
-            let buffer = NSMutableData()
-            let options = PHAssetResourceRequestOptions()
-            options.isNetworkAccessAllowed = true
-            group.enter()
-            PHAssetResourceManager.default().requestData(for: resource, options: options, dataReceivedHandler: { (data) in
-                buffer.append(data)
-            }) { (error) in
-                if error == nil {
-                    if resource.type == .pairedVideo {
-                        videoURL = self.saveAssetResource(resource, to: directoryURL, resourceData: buffer as Data)
-                    } else {
-                        keyPhotoURL = self.saveAssetResource(resource, to: directoryURL, resourceData: buffer as Data)
-                    }
-                } else {
-                    print(error as Any)
-                }
-                group.leave()
-            }
-        }
-        group.notify(queue: DispatchQueue.main) {
-            guard let pairedPhotoURL = keyPhotoURL, let pairedVideoURL = videoURL else {
-                completion(nil)
-                return
-            }
-            completion((pairedPhotoURL, pairedVideoURL))
-        }
-    }
-    
-    private func extractResources(from livePhoto: PHLivePhoto, completion: @escaping (LivePhotoResources?) -> Void) {
-        if let cacheDirectory = cacheDirectory {
-            extractResources(from: livePhoto, to: cacheDirectory, completion: completion)
-        }
-    }
-    
-    private func saveAssetResource(_ resource: PHAssetResource, to directory: URL, resourceData: Data) -> URL? {
-        let fileExtension = UTTypeCopyPreferredTagWithClass(resource.uniformTypeIdentifier as CFString,kUTTagClassFilenameExtension)?.takeRetainedValue()
-        
-        guard let ext = fileExtension else {
-            return nil
-        }
-        
-        var fileUrl = directory.appendingPathComponent(NSUUID().uuidString)
-        fileUrl = fileUrl.appendingPathExtension(ext as String)
-        
-        do {
-            try resourceData.write(to: fileUrl, options: [Data.WritingOptions.atomic])
-        } catch {
-            print("Could not save resource \(resource) to filepath \(String(describing: fileUrl))")
-            return nil
-        }
-        
-        return fileUrl
-    }
-    
-    func addAssetID(_ assetIdentifier: String, toImage imageURL: URL, saveTo destinationURL: URL) -> URL? {
-        guard let imageDestination = CGImageDestinationCreateWithURL(destinationURL as CFURL, kUTTypeJPEG, 1, nil),
-              let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, nil),
-              let imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, nil), 
-                var imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [AnyHashable : Any] else { return nil }
-        let assetIdentifierKey = "17"
-        let assetIdentifierInfo = [assetIdentifierKey : assetIdentifier]
-        imageProperties[kCGImagePropertyMakerAppleDictionary] = assetIdentifierInfo
-        CGImageDestinationAddImage(imageDestination, imageRef, imageProperties as CFDictionary)
-        CGImageDestinationFinalize(imageDestination)
-        return destinationURL
-    }
-    
-    var audioReader: AVAssetReader?
-    var videoReader: AVAssetReader?
-    var assetWriter: AVAssetWriter?
-    
-    func addAssetID(_ assetIdentifier: String, toVideo videoURL: URL, saveTo destinationURL: URL, progress: @escaping (CGFloat) -> Void, completion: @escaping (URL?) -> Void) {
-        
-        var audioWriterInput: AVAssetWriterInput?
-        var audioReaderOutput: AVAssetReaderOutput?
-        let videoAsset = AVURLAsset(url: videoURL)
-        let frameCount = videoAsset.countFrames(exact: false)
-        guard let videoTrack = videoAsset.tracks(withMediaType: .video).first else {
-            completion(nil)
-            return
-        }
-        do {
-            // Create the Asset Writer
-            assetWriter = try AVAssetWriter(outputURL: destinationURL, fileType: .mov)
-            // Create Video Reader Output
-            videoReader = try AVAssetReader(asset: videoAsset)
-            let videoReaderSettings = [kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_32BGRA as UInt32)]
-            let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
-            videoReader?.add(videoReaderOutput)
-            // Create Video Writer Input
-            let videoWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: [AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : videoTrack.naturalSize.width, AVVideoHeightKey : videoTrack.naturalSize.height])
-            videoWriterInput.transform = videoTrack.preferredTransform
-            videoWriterInput.expectsMediaDataInRealTime = true
-            assetWriter?.add(videoWriterInput)
-            // Create Audio Reader Output & Writer Input
-            if let audioTrack = videoAsset.tracks(withMediaType: .audio).first {
-                do {
-                    let _audioReader = try AVAssetReader(asset: videoAsset)
-                    let _audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
-                    _audioReader.add(_audioReaderOutput)
-                    audioReader = _audioReader
-                    audioReaderOutput = _audioReaderOutput
-                    let _audioWriterInput = AVAssetWriterInput(mediaType: .audio, outputSettings: nil)
-                    _audioWriterInput.expectsMediaDataInRealTime = false
-                    assetWriter?.add(_audioWriterInput)
-                    audioWriterInput = _audioWriterInput
-                } catch {
-                    print(error)
-                }
-            }
-            // Create necessary identifier metadata and still image time metadata
-            let assetIdentifierMetadata = metadataForAssetID(assetIdentifier)
-            let stillImageTimeMetadataAdapter = createMetadataAdaptorForStillImageTime()
-            assetWriter?.metadata = [assetIdentifierMetadata]
-            assetWriter?.add(stillImageTimeMetadataAdapter.assetWriterInput)
-            // Start the Asset Writer
-            assetWriter?.startWriting()
-            assetWriter?.startSession(atSourceTime: CMTime.zero)
-            // Add still image metadata
-            let _stillImagePercent: Float = 0.5
-            stillImageTimeMetadataAdapter.append(AVTimedMetadataGroup(items: [metadataItemForStillImageTime()],timeRange: videoAsset.makeStillImageTimeRange(percent: _stillImagePercent, inFrameCount: frameCount)))
-            // For end of writing / progress
-            var writingVideoFinished = false
-            var writingAudioFinished = false
-            var currentFrameCount = 0
-            func didCompleteWriting() {
-                guard writingAudioFinished && writingVideoFinished else { return }
-                assetWriter?.finishWriting {
-                    if self.assetWriter?.status == .completed {
-                        completion(destinationURL)
-                    } else {
-                        completion(nil)
-                    }
-                }
-            }
-            // Start writing video
-            if videoReader?.startReading() ?? false {
-                videoWriterInput.requestMediaDataWhenReady(on: DispatchQueue(label: "videoWriterInputQueue")) {
-                    while videoWriterInput.isReadyForMoreMediaData {
-                        if let sampleBuffer = videoReaderOutput.copyNextSampleBuffer()  {
-                            currentFrameCount += 1
-                            let percent:CGFloat = CGFloat(currentFrameCount)/CGFloat(frameCount)
-                            progress(percent)
-                            if !videoWriterInput.append(sampleBuffer) {
-                                print("Cannot write: \(String(describing: self.assetWriter?.error?.localizedDescription))")
-                                self.videoReader?.cancelReading()
-                            }
-                        } else {
-                            videoWriterInput.markAsFinished()
-                            writingVideoFinished = true
-                            didCompleteWriting()
-                        }
-                    }
-                }
-            } else {
-                writingVideoFinished = true
-                didCompleteWriting()
-            }
-            // Start writing audio
-            if audioReader?.startReading() ?? false {
-                audioWriterInput?.requestMediaDataWhenReady(on: DispatchQueue(label: "audioWriterInputQueue")) {
-                    while audioWriterInput?.isReadyForMoreMediaData ?? false {
-                        guard let sampleBuffer = audioReaderOutput?.copyNextSampleBuffer() else {
-                            audioWriterInput?.markAsFinished()
-                            writingAudioFinished = true
-                            didCompleteWriting()
-                            return
-                        }
-                        audioWriterInput?.append(sampleBuffer)
-                    }
-                }
-            } else {
-                writingAudioFinished = true
-                didCompleteWriting()
-            }
-        } catch {
-            print(error)
-            completion(nil)
-        }
-    }
-    
-    private func metadataForAssetID(_ assetIdentifier: String) -> AVMetadataItem {
-        let item = AVMutableMetadataItem()
-        let keyContentIdentifier =  "com.apple.quicktime.content.identifier"
-        let keySpaceQuickTimeMetadata = "mdta"
-        item.key = keyContentIdentifier as (NSCopying & NSObjectProtocol)?
-        item.keySpace = AVMetadataKeySpace(rawValue: keySpaceQuickTimeMetadata)
-        item.value = assetIdentifier as (NSCopying & NSObjectProtocol)?
-        item.dataType = "com.apple.metadata.datatype.UTF-8"
-        return item
-    }
-    
-    private func createMetadataAdaptorForStillImageTime() -> AVAssetWriterInputMetadataAdaptor {
-        let keyStillImageTime = "com.apple.quicktime.still-image-time"
-        let keySpaceQuickTimeMetadata = "mdta"
-        let spec : NSDictionary = [
-            kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier as NSString:
-            "\(keySpaceQuickTimeMetadata)/\(keyStillImageTime)",
-            kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType as NSString:
-            "com.apple.metadata.datatype.int8"            ]
-        var desc : CMFormatDescription? = nil
-        CMMetadataFormatDescriptionCreateWithMetadataSpecifications(allocator: kCFAllocatorDefault, metadataType: kCMMetadataFormatType_Boxed, metadataSpecifications: [spec] as CFArray, formatDescriptionOut: &desc)
-        let input = AVAssetWriterInput(mediaType: .metadata,
-                                       outputSettings: nil, sourceFormatHint: desc)
-        return AVAssetWriterInputMetadataAdaptor(assetWriterInput: input)
-    }
-    
-    private func metadataItemForStillImageTime() -> AVMetadataItem {
-        let item = AVMutableMetadataItem()
-        let keyStillImageTime = "com.apple.quicktime.still-image-time"
-        let keySpaceQuickTimeMetadata = "mdta"
-        item.key = keyStillImageTime as (NSCopying & NSObjectProtocol)?
-        item.keySpace = AVMetadataKeySpace(rawValue: keySpaceQuickTimeMetadata)
-        item.value = 0 as (NSCopying & NSObjectProtocol)?
-        item.dataType = "com.apple.metadata.datatype.int8"
-        return item
-    }
-    
-
-    static func resizeVideoToFixedHeight(
-        videoURL: URL,
-        fixedHeight: CGFloat = 1920,
-        outputFolder: URL,
-        completion: @escaping (URL?) -> Void
-    ) {
-        let asset = AVURLAsset(url: videoURL)
-        guard let videoTrack = asset.tracks(withMediaType: .video).first else {
-            print("Invalid video track")
-            completion(nil)
-            return
-        }
-        
-        let videoSize = videoTrack.naturalSize
-        let videoWidth = videoSize.width
-        let videoHeight = videoSize.height
-        
-        // Calculate the new width based on the fixed height
-        let scale = fixedHeight / videoHeight
-        let newWidth = videoWidth * scale
-        
-        // Crop the video to the center
-        let xOffset = (newWidth - fixedHeight) / 2
-        let cropRect = CGRect(x: xOffset, y: 0, width: fixedHeight, height: fixedHeight)
-        
-        // Output URL
-        let outputURL = outputFolder.appendingPathComponent("resized_video.mov")
-        if FileManager.default.fileExists(atPath: outputURL.path) {
-            try? FileManager.default.removeItem(at: outputURL)
-        }
-        
-        // Configure the video composition
-        let composition = AVMutableComposition()
-        guard let videoCompositionTrack = composition.addMutableTrack(
-            withMediaType: .video,
-            preferredTrackID: kCMPersistentTrackID_Invalid
-        ) else {
-            print("Unable to create video composition track")
-            completion(nil)
-            return
-        }
-        
-        do {
-            try videoCompositionTrack.insertTimeRange(
-                CMTimeRange(start: .zero, duration: asset.duration),
-                of: videoTrack,
-                at: .zero
-            )
-        } catch {
-            print("Error inserting time range: \(error)")
-            completion(nil)
-            return
-        }
-        
-        // Configure the video transformer
-        let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: videoCompositionTrack)
-        let scaleTransform = CGAffineTransform(scaleX: scale, y: scale)
-        let translateTransform = CGAffineTransform(translationX: -xOffset, y: 0)
-        transformer.setTransform(scaleTransform.concatenating(translateTransform), at: .zero)
-        
-        let videoComposition = AVMutableVideoComposition()
-        videoComposition.renderSize = CGSize(width: fixedHeight, height: fixedHeight)
-        videoComposition.frameDuration = CMTime(value: 1, timescale: Int32(videoTrack.nominalFrameRate))
-        let instruction = AVMutableVideoCompositionInstruction()
-        instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
-        instruction.layerInstructions = [transformer]
-        videoComposition.instructions = [instruction]
-        
-        // Export the video
-        guard let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {
-            print("Unable to create AVAssetExportSession")
-            completion(nil)
-            return
-        }
-        
-        exporter.outputURL = outputURL
-        exporter.outputFileType = .mov
-        exporter.videoComposition = videoComposition
-        
-        exporter.exportAsynchronously {
-            DispatchQueue.main.async {
-                if exporter.status == .completed {
-                    print("Export completed: \(outputURL)")
-                    completion(outputURL)
-                } else {
-                    print("Export failed: \(String(describing: exporter.error))")
-                    completion(nil)
-                }
-            }
-        }
-    }
-
-    
-}
-
-//fileprivate extension AVAsset {
-//    func countFrames(exact:Bool) -> Int {
-//        
-//        var frameCount = 0
-//        
-//        if let videoReader = try? AVAssetReader(asset: self)  {
-//            
-//            if let videoTrack = self.tracks(withMediaType: .video).first {
-//                
-//                frameCount = Int(CMTimeGetSeconds(self.duration) * Float64(videoTrack.nominalFrameRate))
-//                
-//                
-//                if exact {
-//                    
-//                    frameCount = 0
-//                    
-//                    let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: nil)
-//                    videoReader.add(videoReaderOutput)
-//                    
-//                    videoReader.startReading()
-//                    
-//                    // count frames
-//                    while true {
-//                        let sampleBuffer = videoReaderOutput.copyNextSampleBuffer()
-//                        if sampleBuffer == nil {
-//                            break
-//                        }
-//                        frameCount += 1
-//                    }
-//                    
-//                    videoReader.cancelReading()
-//                }
-//                
-//                
-//            }
-//        }
-//        
-//        return frameCount
-//    }
-//    
-//    func stillImageTime() -> CMTime?  {
-//        
-//        var stillTime:CMTime? = nil
-//        
-//        if let videoReader = try? AVAssetReader(asset: self)  {
-//            
-//            if let metadataTrack = self.tracks(withMediaType: .metadata).first {
-//                
-//                let videoReaderOutput = AVAssetReaderTrackOutput(track: metadataTrack, outputSettings: nil)
-//                
-//                videoReader.add(videoReaderOutput)
-//                
-//                videoReader.startReading()
-//                
-//                let keyStillImageTime = "com.apple.quicktime.still-image-time"
-//                let keySpaceQuickTimeMetadata = "mdta"
-//                
-//                var found = false
-//                
-//                while found == false {
-//                    if let sampleBuffer = videoReaderOutput.copyNextSampleBuffer() {
-//                        if CMSampleBufferGetNumSamples(sampleBuffer) != 0 {
-//                            let group = AVTimedMetadataGroup(sampleBuffer: sampleBuffer)
-//                            for item in group?.items ?? [] {
-//                                if item.key as? String == keyStillImageTime && item.keySpace!.rawValue == keySpaceQuickTimeMetadata {
-//                                    stillTime = group?.timeRange.start
-//                                    //print("stillImageTime = \(CMTimeGetSeconds(stillTime!))")
-//                                    found = true
-//                                    break
-//                                }
-//                            }
-//                        }
-//                    }
-//                    else {
-//                        break;
-//                    }
-//                }
-//                
-//                videoReader.cancelReading()
-//                
-//            }
-//        }
-//        
-//        return stillTime
-//    }
-//    
-//    func makeStillImageTimeRange(percent:Float, inFrameCount:Int = 0) -> CMTimeRange {
-//        
-//        var time = self.duration
-//        
-//        var frameCount = inFrameCount
-//        
-//        if frameCount == 0 {
-//            frameCount = self.countFrames(exact: true)
-//        }
-//        
-//        let frameDuration = Int64(Float(time.value) / Float(frameCount))
-//        
-//        time.value = Int64(Float(time.value) * percent)
-//        
-//        //print("stillImageTime = \(CMTimeGetSeconds(time))")
-//        
-//        return CMTimeRangeMake(start: time, duration: CMTimeMake(value: frameDuration, timescale: time.timescale))
-//    }
-//    
-//    func getAssetFrame(percent:Float) -> UIImage?
-//    {
-//        
-//        let imageGenerator = AVAssetImageGenerator(asset: self)
-//        imageGenerator.appliesPreferredTrackTransform = true
-//        
-//        imageGenerator.requestedTimeToleranceAfter = CMTimeMake(value: 1,timescale: 100)
-//        imageGenerator.requestedTimeToleranceBefore = CMTimeMake(value: 1,timescale: 100)
-//        
-//        var time = self.duration
-//        
-//        time.value = Int64(Float(time.value) * percent)
-//        
-//        do {
-//            var actualTime = CMTime.zero
-//            let imageRef = try imageGenerator.copyCGImage(at: time, actualTime:&actualTime)
-//            
-//            let img = UIImage(cgImage: imageRef)
-//            
-//            return img
-//        }
-//        catch let error as NSError
-//        {
-//            print("Image generation failed with error \(error)")
-//            return nil
-//        }
-//    }
-//}

+ 0 - 269
TSLiveWallpaper/Common/ThirdParty/LivePhotoCreater.swift

@@ -1,269 +0,0 @@
-//
-//  LivePhotoCreater.swift
-//  LivePhotoDemoSwift
-//
-//  Created by TSYH on 2024/5/16.
-//  Copyright © 2024 Genady Okrain. All rights reserved.
-//
-
-import UIKit
-import PhotosUI
-//import ExtensionsKit
-
-public class LivePhotoCreater: NSObject {
-    public static let shared = LivePhotoCreater()
-    
-    /// 创建并保存LivePhoto
-    /// - Parameters:
-    ///   - videoURL: 视频本地URL
-    ///   - outputDirectory: LivePhoto资源保存文件夹
-    ///   - completion: (LivePhoto视频URL, LivePhoto图片URL)
-    public func saveLivePhoto(from videoURL: URL, outputDirectory: URL,
-                       completion: ((URL?, URL?, String?) -> Void)?) {
-        createLivePhotoResource(with: videoURL, outputDirectory: outputDirectory) { videoURL, imageURL, erMsg in
-            guard let imageURL = imageURL, let videoURL = videoURL else {
-                DispatchQueue.main.async {
-                    completion?(nil, nil, erMsg ?? "Generate resource failure")
-                }
-                return
-            }
-            self.exportLivePhoto(videoURL: videoURL, imageURL: imageURL) { success, erMsg in
-                DispatchQueue.main.async {
-                    if success {
-                        completion?(videoURL, imageURL, nil)
-                    } else {
-                        completion?(nil, nil, erMsg ?? "Save LivePhoto Failure")
-                    }
-                }
-            }
-        }
-    }
-    
-    /// 根据视频创建LivePhoto, 显示
-    /// - Parameters:
-    ///   - videoURL: 视频本地URL
-    ///   - outputDirectory: LivePhoto资源保存文件夹
-    ///   - completion:
-    public func makeLivePhoto(with videoURL: URL,
-                       outputDirectory: URL,
-                       completion: ((PHLivePhoto?, String?) -> Void)?) {
-        createLivePhotoResource(with: videoURL, outputDirectory: outputDirectory) { videoURL, imageURL, erMsg in
-            DispatchQueue.main.sync {
-                guard let imageURL = imageURL, let videoURL = videoURL else {
-                    completion?(nil, erMsg)
-                    return
-                }
-                PHLivePhoto.request(withResourceFileURLs: [videoURL, imageURL],
-                                    placeholderImage: nil,
-                                    targetSize: .zero,
-                                    contentMode: PHImageContentMode.aspectFit,
-                                    resultHandler: { (livePhoto, info) -> Void in
-                    completion?(livePhoto, info.description)
-                })
-            }
-        }
-    }
-    
-    /// 根据视频创建LivePhoto资源
-    /// - Parameters:
-    ///   - videoURL: 视频本地URL
-    ///   - outputDirectory: LivePhoto资源保存文件夹
-    ///   - completion:
-//    public func makeLivePhotoResource(with videoURL: URL,
-//                                      outputDirectory: URL,
-//                                      completion: ((URL?, URL?, String?) -> Void)?) {
-//        let asset = AVURLAsset(url: videoURL)
-//        
-//        // 截取一帧图片
-//        let generator = AVAssetImageGenerator(asset: asset)
-//        generator.appliesPreferredTrackTransform = true
-//        let time = NSValue(time: CMTimeMakeWithSeconds(CMTimeGetSeconds(asset.duration)/2, preferredTimescale: asset.duration.timescale))
-//        generator.generateCGImagesAsynchronously(forTimes: [time]) { _, image, _, _, _ in
-//            guard let cgimage = image else {
-//                completion?(nil, nil, "Generate image failure~")
-//                return
-//            }
-//            let image = UIImage(cgImage: cgimage)
-//            var data: Data? = image.jpegData(compressionQuality: 1.0)
-//            var orgImageName = "-orgImage.jpg"
-//            var outputImageName = "-IMG.JPG"
-//            
-//            if #available(iOS 17, *) {
-//                data = image.heicData()
-//                orgImageName = "-orgImage.heif"
-//                outputImageName = "-IMG.HEIF"
-//            }
-//            guard let data = data else {
-//                completion?(nil, nil, "Generate image failure~")
-//                return
-//            }
-//                
-//            // 创建文件夹
-//            let _ = try? FileManager.default.createDirectory(atPath: outputDirectory.path, withIntermediateDirectories: true, attributes: nil)
-//            
-//            // 当前时间戳+随机字符串 作为文件名
-//            let outputName: String = "\(Int(Date().timeIntervalSince1970))" + String.randomString(count: 8)
-//            
-//            // 视频截取帧图片保存地址
-//            let originalImageURL = outputDirectory.appendingPathComponent(outputName + orgImageName)
-//            try? data.write(to: originalImageURL, options: [.atomic])
-//            
-//            let imageOutputURL = outputDirectory.appendingPathComponent(outputName + outputImageName)
-//            let videoOutputURL = outputDirectory.appendingPathComponent(outputName + "-IMG.MOV")
-//            
-//            /// 给视频、图片添加LivePhoto信息
-//            let assetIdentifier = UUID().uuidString
-//            LivePhotoJPEG(path: originalImageURL.path).write(imageOutputURL.path, assetIdentifier: assetIdentifier)
-//            LivePhotoMOV(path: videoURL.path).write(videoOutputURL.path, assetIdentifier: assetIdentifier)
-//            
-//            completion?(videoOutputURL, imageOutputURL, nil)
-//        }
-//    }
-    
-    /// 导出LivePhoto到相册
-    public func exportLivePhoto(videoURL: URL, imageURL: URL,
-                         completion: ((Bool, String?) -> Void)?) {
-        PHPhotoLibrary.shared().performChanges({ () -> Void in
-            let creationRequest = PHAssetCreationRequest.forAsset()
-            let options = PHAssetResourceCreationOptions()
-            creationRequest.addResource(with: PHAssetResourceType.pairedVideo, fileURL: videoURL, options: options)
-            creationRequest.addResource(with: PHAssetResourceType.photo, fileURL: imageURL, options: options)
-        }, completionHandler: { (success, error) -> Void in
-            completion?(success, error?.localizedDescription)
-        })
-    }
-}
-
-extension LivePhotoCreater {
-    /// 根据视频创建LivePhoto资源
-    /// - Parameters:
-    ///   - videoURL: 视频本地URL
-    ///   - outputDirectory: LivePhoto资源保存文件夹
-    ///   - completion: (Live视频URL, Live图片URL, 错误信息)
-    func createLivePhotoResource(with videoURL: URL, outputDirectory: URL, completion: ((URL?, URL?, String?) -> Void)?) {
-        
-        guard let metaURL = Bundle(for: self.classForCoder).url(forResource: "metadata", withExtension: "mov") else {
-            completion?(nil, nil, "Metadata file don't exist")
-            return
-        }
-        let videoConverter = Converter4Video(path: videoURL.path)
-        
-        // 创建文件夹
-        let _ = try? FileManager.default.createDirectory(atPath: outputDirectory.path, withIntermediateDirectories: true, attributes: nil)
-        
-        // 当前时间戳+随机字符串 作为文件名
-        let outputName: String = "\(Int(Date().timeIntervalSince1970))" + String.randomString(count: 8)
-        let imageOutputURL = outputDirectory.appendingPathComponent(outputName + "-Live.heic")
-        let videoOutputURL = outputDirectory.appendingPathComponent(outputName + "-Live.mov")
-        
-        let asset = AVURLAsset(url: videoURL, options: nil)
-        Log("===video duration:\(CMTimeGetSeconds(asset.duration))")
-//        guard CMTimeGetSeconds(asset.duration) <= 3 else {
-//            completion?(nil, nil, "The video is too long, please try again")
-//            return
-//        }
-        
-        let assetIdentifier = UUID().uuidString
-        let queue = DispatchQueue(label: "image")
-        queue.async {
-            // 视频写入LivePhoto信息
-            videoConverter.write(dest: videoOutputURL.path, assetIdentifier: assetIdentifier, metaURL: metaURL) { success, error in
-                guard success, FileManager.default.fileExists(atPath: videoOutputURL.path) else {
-                    completion?(nil, nil, "Convert Failure")
-                    return
-                }
-                guard let keyFrame = self.getKeyFrameImage(from: videoOutputURL) else {
-                    return
-                }
-                let imageConverter = Converter4Image(image: keyFrame)
-                // 图片写入LivePhoto信息
-                imageConverter.write(dest: imageOutputURL.path, assetIdentifier: assetIdentifier)
-                
-                guard FileManager.default.fileExists(atPath: imageOutputURL.path) else {
-                    completion?(nil, nil, "Convert Failure")
-                    return
-                }
-                
-                completion?(videoOutputURL, imageOutputURL, nil)
-            }
-        }
-        
-        
-        
-        
-//        let generator = AVAssetImageGenerator(asset: asset)
-//        generator.appliesPreferredTrackTransform = true
-////        generator.requestedTimeToleranceAfter = CMTimeMake(value: 1,timescale: 100)
-//        generator.requestedTimeToleranceAfter = .zero
-//        generator.requestedTimeToleranceBefore = .zero
-//        var times = [NSValue]()
-////        let time = CMTimeMakeWithSeconds(0.5*CMTimeGetSeconds(asset.duration), preferredTimescale: asset.duration.timescale)
-//        let time = CMTimeMakeWithSeconds(0.1, preferredTimescale: asset.duration.timescale)
-//        times.append(NSValue(time: time))
-//        
-//        generator.generateCGImagesAsynchronously(forTimes: times) { requestedTime, image, actualTime, result, error in
-//            guard let cgimage = image else {
-//                completion?(nil, nil, "Generate Frame Failure~")
-//                return
-//            }
-//            
-//            let imageConverter = Converter4Image(image: UIImage(cgImage: cgimage))
-//            queue.async {
-//                // 图片写入LivePhoto信息
-////                imageConverter.write(dest: imageOutputURL.path, assetIdentifier: assetIdentifier)
-//                
-//                // 视频写入LivePhoto信息
-//                videoConverter.write(dest: videoOutputURL.path, assetIdentifier: assetIdentifier, metaURL: metaURL) { success, error in
-//                    guard success else {
-//                        completion?(nil, nil, "Convert Failure")
-//                        return
-//                    }
-//                    guard FileManager.default.fileExists(atPath: videoOutputURL.path) else {
-//                        completion?(nil, nil, "Convert Failure")
-//                        return
-//                    }
-//                    
-//                    guard let keyFrame = self.getKeyFrameImage(from: videoOutputURL) else {
-//                        return
-//                    }
-//                    let imageConverter = Converter4Image(image: keyFrame)
-//                    // 图片写入LivePhoto信息
-//                    imageConverter.write(dest: imageOutputURL.path, assetIdentifier: assetIdentifier)
-//                    guard FileManager.default.fileExists(atPath: imageOutputURL.path) else {
-//                        completion?(nil, nil, "Convert Failure")
-//                        return
-//                    }
-//                    completion?(videoOutputURL, imageOutputURL, nil)
-//                }
-//            }
-//        }
-    }
-    
-    func getKeyFrameImage(from videoURL: URL) -> UIImage? {
-        var percent: Float = 0.5
-        let videoAsset = AVURLAsset(url: videoURL)
-        Log("live video duration: \(CMTimeGetSeconds(videoAsset.duration))")
-        if let stillImageTime = videoAsset.stillImageTime() {
-            percent = Float(stillImageTime.value) / Float(videoAsset.duration.value)
-        }
-        guard let imageFrame = videoAsset.getAssetFrame(percent: percent) else { return nil }
-        return imageFrame
-    }
-}
-
-extension String {
-    /// 获取指定长度随机字符串
-    static func randomString(count: Int) -> String {
-        let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
-        let randomString = String((0..<count).map{ _ in letters.randomElement()! })
-        return randomString
-    }
-}
-
-
-public func Log<T>(_ messsage: T, file: String = #file, funcName: String = #function, lineNum: Int = #line) {
-    #if DEBUG
-    let fileName = (file as NSString).lastPathComponent
-    print(Date().description + " \(fileName) (\(funcName)): [\(lineNum)]- \(messsage)")
-    #endif
-}

+ 0 - 74
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.h

@@ -1,74 +0,0 @@
-//
-//  TYCyclePagerViewLayout.h
-//  TYCyclePagerViewDemo
-//
-//  Created by tany on 2017/6/19.
-//  Copyright © 2017年 tany. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef NS_ENUM(NSUInteger, TYCyclePagerTransformLayoutType) {
-    TYCyclePagerTransformLayoutNormal,
-    TYCyclePagerTransformLayoutLinear,
-    TYCyclePagerTransformLayoutCoverflow,
-};
-
-@class TYCyclePagerTransformLayout;
-@protocol TYCyclePagerTransformLayoutDelegate <NSObject>
-
-// initialize layout attributes
-- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
-
-// apply layout attributes
-- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
-
-@end
-
-
-@interface TYCyclePagerViewLayout : NSObject
-
-@property (nonatomic, assign) CGSize itemSize;
-@property (nonatomic, assign) CGFloat itemSpacing;
-@property (nonatomic, assign) UIEdgeInsets sectionInset;
-
-@property (nonatomic, assign) TYCyclePagerTransformLayoutType layoutType;
-
-@property (nonatomic, assign) CGFloat minimumScale; // sacle default 0.8
-@property (nonatomic, assign) CGFloat minimumAlpha; // alpha default 1.0
-@property (nonatomic, assign) CGFloat maximumAngle; // angle is % default 0.2
-
-@property (nonatomic, assign) BOOL isInfiniteLoop;  // infinte scroll
-@property (nonatomic, assign) CGFloat rateOfChange; // scale and angle change rate
-@property (nonatomic, assign) BOOL adjustSpacingWhenScroling; 
-
-/**
- pageView cell item vertical centering
- */
-@property (nonatomic, assign) BOOL itemVerticalCenter;
-
-/**
- first and last item horizontalc enter, when isInfiniteLoop is NO
- */
-@property (nonatomic, assign) BOOL itemHorizontalCenter;
-
-// sectionInset
-@property (nonatomic, assign, readonly) UIEdgeInsets onlyOneSectionInset;
-@property (nonatomic, assign, readonly) UIEdgeInsets firstSectionInset;
-@property (nonatomic, assign, readonly) UIEdgeInsets lastSectionInset;
-@property (nonatomic, assign, readonly) UIEdgeInsets middleSectionInset;
-
-@end
-
-
-@interface TYCyclePagerTransformLayout : UICollectionViewFlowLayout
-
-@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
-
-@property (nonatomic, weak, nullable) id<TYCyclePagerTransformLayoutDelegate> delegate;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 319
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.m

@@ -1,319 +0,0 @@
-//
-//  TYCyclePagerViewLayout.m
-//  TYCyclePagerViewDemo
-//
-//  Created by tany on 2017/6/19.
-//  Copyright © 2017年 tany. All rights reserved.
-//
-
-#import "TYCyclePagerTransformLayout.h"
-#import "TSLiveWallpaper-Swift.h"
-typedef NS_ENUM(NSUInteger, TYTransformLayoutItemDirection) {
-    TYTransformLayoutItemLeft,
-    TYTransformLayoutItemCenter,
-    TYTransformLayoutItemRight,
-};
-
-
-@interface TYCyclePagerTransformLayout () {
-    struct {
-        unsigned int applyTransformToAttributes   :1;
-        unsigned int initializeTransformAttributes   :1;
-    }_delegateFlags;
-}
-
-@property (nonatomic, assign) BOOL applyTransformToAttributesDelegate;
-
-@end
-
-
-@interface TYCyclePagerViewLayout ()
-
-@property (nonatomic, weak) UIView *pageView;
-
-@end
-
-
-@implementation TYCyclePagerTransformLayout
-
-
-+ (NSString *)appLanguage {
-    id systemLanguages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
-    NSString *currentLanguage = nil;
-    
-    if ([systemLanguages isKindOfClass:[NSArray class]]) {
-        currentLanguage = [systemLanguages firstObject];
-    }
-    else if ([systemLanguages isKindOfClass:[NSString class]]) {
-        currentLanguage = systemLanguages;
-    }
-    
-    return currentLanguage ?: @"";
-}
-
-- (BOOL)flipsHorizontallyInOppositeLayoutDirection {
-    return [[TYCyclePagerTransformLayout appLanguage] compare:@"ar"];
-}
-
-- (instancetype)init {
-    if (self = [super init]) {
-        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
-    }
-    return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
-    if (self = [super initWithCoder:aDecoder]) {
-        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
-    }
-    return self;
-}
-
-#pragma mark - getter setter
-
-- (void)setDelegate:(id<TYCyclePagerTransformLayoutDelegate>)delegate {
-    _delegate = delegate;
-    _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:initializeTransformAttributes:)];
-    _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:applyTransformToAttributes:)];
-}
-
-- (void)setLayout:(TYCyclePagerViewLayout *)layout {
-    _layout = layout;
-    _layout.pageView = self.collectionView;
-    self.itemSize = _layout.itemSize;
-    self.minimumInteritemSpacing = _layout.itemSpacing;
-    self.minimumLineSpacing = _layout.itemSpacing;
-}
-
-- (CGSize)itemSize {
-    if (!_layout) {
-        return [super itemSize];
-    }
-    return _layout.itemSize;
-}
-
-- (CGFloat)minimumLineSpacing {
-    if (!_layout) {
-        return [super minimumLineSpacing];
-    }
-    return _layout.itemSpacing;
-}
-
-- (CGFloat)minimumInteritemSpacing {
-    if (!_layout) {
-        return [super minimumInteritemSpacing];
-    }
-    return _layout.itemSpacing;
-}
-
-- (TYTransformLayoutItemDirection)directionWithCenterX:(CGFloat)centerX {
-    TYTransformLayoutItemDirection direction= TYTransformLayoutItemRight;
-    CGFloat contentCenterX = self.collectionView.contentOffset.x + CGRectGetWidth(self.collectionView.frame)/2;
-    if (ABS(centerX - contentCenterX) < 0.5) {
-        direction = TYTransformLayoutItemCenter;
-    }else if (centerX - contentCenterX < 0) {
-        direction = TYTransformLayoutItemLeft;
-    }
-    return direction;
-}
-
-#pragma mark - layout
-
--(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
-{
-    return _layout.layoutType == TYCyclePagerTransformLayoutNormal ? [super shouldInvalidateLayoutForBoundsChange:newBounds] : YES;
-}
-
-- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
-    if (_delegateFlags.applyTransformToAttributes || _layout.layoutType != TYCyclePagerTransformLayoutNormal) {
-        NSArray *attributesArray = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];
-        CGRect visibleRect = {self.collectionView.contentOffset,self.collectionView.bounds.size};
-        for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
-            if (!CGRectIntersectsRect(visibleRect, attributes.frame)) {
-                continue;
-            }
-            if (_delegateFlags.applyTransformToAttributes) {
-                [_delegate pagerViewTransformLayout:self applyTransformToAttributes:attributes];
-            }else {
-                [self applyTransformToAttributes:attributes layoutType:_layout.layoutType];
-            }
-        }
-        return attributesArray;
-    }
-    return [super layoutAttributesForElementsInRect:rect];
-}
-
-- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
-    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
-    if (_delegateFlags.initializeTransformAttributes) {
-        [_delegate pagerViewTransformLayout:self initializeTransformAttributes:attributes];
-    }else if(_layout.layoutType != TYCyclePagerTransformLayoutNormal){
-        [self initializeTransformAttributes:attributes layoutType:_layout.layoutType];
-    }
-    return attributes;
-}
-
-#pragma mark - transform
-
-- (void)initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
-    switch (layoutType) {
-        case TYCyclePagerTransformLayoutLinear:
-            [self applyLinearTransformToAttributes:attributes scale:_layout.minimumScale alpha:_layout.minimumAlpha];
-            break;
-        case TYCyclePagerTransformLayoutCoverflow:
-        {
-            [self applyCoverflowTransformToAttributes:attributes angle:_layout.maximumAngle alpha:_layout.minimumAlpha];
-            break;
-        }
-        default:
-            break;
-    }
-}
-
-- (void)applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
-    switch (layoutType) {
-        case TYCyclePagerTransformLayoutLinear:
-            [self applyLinearTransformToAttributes:attributes];
-            break;
-        case TYCyclePagerTransformLayoutCoverflow:
-            [self applyCoverflowTransformToAttributes:attributes];
-            break;
-        default:
-            break;
-    }
-}
-
-#pragma mark - LinearTransform
-
-- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
-    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
-    if (collectionViewWidth <= 0) {
-        return;
-    }
-    CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
-    CGFloat delta = ABS(attributes.center.x - centetX);
-    CGFloat scale = MAX(1 - delta/collectionViewWidth*_layout.rateOfChange, _layout.minimumScale);
-    CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
-    [self applyLinearTransformToAttributes:attributes scale:scale alpha:alpha];
-}
-
-- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes scale:(CGFloat)scale alpha:(CGFloat)alpha {
-    CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
-    if (_layout.adjustSpacingWhenScroling) {
-        TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
-        CGFloat translate = 0;
-        switch (direction) {
-            case TYTransformLayoutItemLeft:
-                translate = 1.15 * attributes.size.width*(1-scale)/2;
-                break;
-            case TYTransformLayoutItemRight:
-                translate = -1.15 * attributes.size.width*(1-scale)/2;
-                break;
-            default:
-                // center
-                scale = 1.0;
-                alpha = 1.0;
-                break;
-        }
-        transform = CGAffineTransformTranslate(transform,translate, 0);
-    }
-    attributes.transform = transform;
-    attributes.alpha = alpha;
-}
-
-#pragma mark - CoverflowTransform
-
-- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes{
-    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
-    if (collectionViewWidth <= 0) {
-        return;
-    }
-    CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
-    CGFloat delta = ABS(attributes.center.x - centetX);
-    CGFloat angle = MIN(delta/collectionViewWidth*(1-_layout.rateOfChange), _layout.maximumAngle);
-    CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
-    [self applyCoverflowTransformToAttributes:attributes angle:angle alpha:alpha];
-}
-
-- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes angle:(CGFloat)angle alpha:(CGFloat)alpha {
-    TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
-    CATransform3D transform3D = CATransform3DIdentity;
-    transform3D.m34 = -0.002;
-    CGFloat translate = 0;
-    switch (direction) {
-        case TYTransformLayoutItemLeft:
-            translate = (1-cos(angle*1.2*M_PI))*attributes.size.width;
-            break;
-        case TYTransformLayoutItemRight:
-            translate = -(1-cos(angle*1.2*M_PI))*attributes.size.width;
-            angle = -angle;
-            break;
-        default:
-            // center
-            angle = 0;
-            alpha = 1;
-            break;
-    }
-
-    transform3D = CATransform3DRotate(transform3D, M_PI*angle, 0, 1, 0);
-    if (_layout.adjustSpacingWhenScroling) {
-        transform3D = CATransform3DTranslate(transform3D, translate, 0, 0);
-    }
-    attributes.transform3D = transform3D;
-    attributes.alpha = alpha;
-
-}
-@end
-
-
-@implementation TYCyclePagerViewLayout
-
-- (instancetype)init {
-    if (self = [super init]) {
-        _itemVerticalCenter = YES;
-        _minimumScale = 0.8;
-        _minimumAlpha = 1.0;
-        _maximumAngle = 0.2;
-        _rateOfChange = 0.4;
-        _adjustSpacingWhenScroling = YES;
-    }
-    return self;
-}
-
-#pragma mark - getter
-
-- (UIEdgeInsets)onlyOneSectionInset {
-    CGFloat leftSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.left;
-    CGFloat rightSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.right;
-    if (_itemVerticalCenter) {
-        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
-        return UIEdgeInsetsMake(verticalSpace, leftSpace, verticalSpace, rightSpace);
-    }
-    return UIEdgeInsetsMake(_sectionInset.top, leftSpace, _sectionInset.bottom, rightSpace);
-}
-
-- (UIEdgeInsets)firstSectionInset {
-    if (_itemVerticalCenter) {
-        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
-        return UIEdgeInsetsMake(verticalSpace, _sectionInset.left, verticalSpace, _itemSpacing);
-    }
-    return UIEdgeInsetsMake(_sectionInset.top, _sectionInset.left, _sectionInset.bottom, _itemSpacing);
-}
-
-- (UIEdgeInsets)lastSectionInset {
-    if (_itemVerticalCenter) {
-        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
-        return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _sectionInset.right);
-    }
-    return UIEdgeInsetsMake(_sectionInset.top, 0, _sectionInset.bottom, _sectionInset.right);
-}
-
-- (UIEdgeInsets)middleSectionInset {
-    if (_itemVerticalCenter) {
-        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
-        return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _itemSpacing);
-    }
-    return _sectionInset;
-}
-
-@end

+ 0 - 180
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.h

@@ -1,180 +0,0 @@
-//
-//  TYCyclePagerView.h
-//  TYCyclePagerViewDemo
-//
-//  Created by tany on 2017/6/14.
-//  Copyright © 2017年 tany. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-#import "TYCyclePagerTransformLayout.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef struct {
-    NSInteger index;
-    NSInteger section;
-}TYIndexSection;
-
-// pagerView scrolling direction
-typedef NS_ENUM(NSUInteger, TYPagerScrollDirection) {
-    TYPagerScrollDirectionLeft,
-    TYPagerScrollDirectionRight,
-};
-
-@class TYCyclePagerView;
-@protocol TYCyclePagerViewDataSource <NSObject>
-
-- (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView;
-
-- (__kindof UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index;
-
-/**
- return pagerView layout,and cache layout
- */
-- (TYCyclePagerViewLayout *)layoutForPagerView:(TYCyclePagerView *)pageView;
-
-@end
-
-@protocol TYCyclePagerViewDelegate <NSObject>
-
-@optional
-
-/**
- pagerView did scroll to new index page
- */
-- (void)pagerView:(TYCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
-
-/**
- pagerView did selected item cell
- */
-- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index;
-- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndexSection:(TYIndexSection)indexSection;
-
-// custom layout
-- (void)pagerView:(TYCyclePagerView *)pageView initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
-
-- (void)pagerView:(TYCyclePagerView *)pageView applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
-
-
-// scrollViewDelegate
-
-- (void)pagerViewDidScroll:(TYCyclePagerView *)pageView;
-
-- (void)pagerViewWillBeginDragging:(TYCyclePagerView *)pageView;
-
-- (void)pagerViewDidEndDragging:(TYCyclePagerView *)pageView willDecelerate:(BOOL)decelerate;
-
-- (void)pagerViewWillBeginDecelerating:(TYCyclePagerView *)pageView;
-
-- (void)pagerViewDidEndDecelerating:(TYCyclePagerView *)pageView;
-
-- (void)pagerViewWillBeginScrollingAnimation:(TYCyclePagerView *)pageView;
-
-- (void)pagerViewDidEndScrollingAnimation:(TYCyclePagerView *)pageView;
-
-@end
-
-
-@interface TYCyclePagerView : UIView
-
-// will be automatically resized to track the size of the pagerView
-@property (nonatomic, strong, nullable) UIView *backgroundView; 
-
-@property (nonatomic, weak, nullable) id<TYCyclePagerViewDataSource> dataSource;
-@property (nonatomic, weak, nullable) id<TYCyclePagerViewDelegate> delegate;
-
-// pager view, don't set dataSource and delegate
-@property (nonatomic, weak, readonly) UICollectionView *collectionView;
-// pager view layout
-@property (nonatomic, strong, readonly) TYCyclePagerViewLayout *layout;
-
-/**
- is infinite cycle pageview
- */
-@property (nonatomic, assign) BOOL isInfiniteLoop;
-
-/**
- pagerView automatic scroll time interval, default 0,disable automatic
- */
-@property (nonatomic, assign) CGFloat autoScrollInterval;
-
-@property (nonatomic, assign) BOOL reloadDataNeedResetIndex;
-
-/**
- current page index
- */
-@property (nonatomic, assign, readonly) NSInteger curIndex;
-@property (nonatomic, assign, readonly) TYIndexSection indexSection;
-
-// scrollView property
-@property (nonatomic, assign, readonly) CGPoint contentOffset;
-@property (nonatomic, assign, readonly) BOOL tracking;
-@property (nonatomic, assign, readonly) BOOL dragging;
-@property (nonatomic, assign, readonly) BOOL decelerating;
-
-
-/**
- reload data, !!important!!: will clear layout and call delegate layoutForPagerView
- */
-- (void)reloadData;
-
-/**
- update data is reload data, but not clear layuot
- */
-- (void)updateData;
-
-/**
- if you only want update layout
- */
-- (void)setNeedUpdateLayout;
-
-/**
- will set layout nil and call delegate->layoutForPagerView
- */
-- (void)setNeedClearLayout;
-
-/**
- current index cell in pagerView
- */
-- (__kindof UICollectionViewCell * _Nullable)curIndexCell;
-
-/**
- visible cells in pageView
- */
-- (NSArray<__kindof UICollectionViewCell *> *_Nullable)visibleCells;
-
-
-/**
- visible pageView indexs, maybe repeat index
- */
-- (NSArray *)visibleIndexs;
-
-/**
- scroll to item at index
- */
-- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate;
-- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate;
-/**
- scroll to next or pre item
- */
-- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate;
-
-/**
- register pager view cell with class
- */
-- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier;
-
-/**
- register pager view cell with nib
- */
-- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
-
-/**
- dequeue reusable cell for pagerView
- */
-- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 607
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.m

@@ -1,607 +0,0 @@
-//
-//  TYCyclePagerView.m
-//  TYCyclePagerViewDemo
-//
-//  Created by tany on 2017/6/14.
-//  Copyright © 2017年 tany. All rights reserved.
-//
-
-#import "TYCyclePagerView.h"
-
-NS_INLINE BOOL TYEqualIndexSection(TYIndexSection indexSection1,TYIndexSection indexSection2) {
-    return indexSection1.index == indexSection2.index && indexSection1.section == indexSection2.section;
-}
-
-NS_INLINE TYIndexSection TYMakeIndexSection(NSInteger index, NSInteger section) {
-    TYIndexSection indexSection;
-    indexSection.index = index;
-    indexSection.section = section;
-    return indexSection;
-}
-
-@interface TYCyclePagerView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, TYCyclePagerTransformLayoutDelegate> {
-    struct {
-        unsigned int pagerViewDidScroll   :1;
-        unsigned int didScrollFromIndexToNewIndex   :1;
-        unsigned int initializeTransformAttributes   :1;
-        unsigned int applyTransformToAttributes   :1;
-    }_delegateFlags;
-    struct {
-        unsigned int cellForItemAtIndex   :1;
-        unsigned int layoutForPagerView   :1;
-    }_dataSourceFlags;
-}
-
-// UI
-@property (nonatomic, weak) UICollectionView *collectionView;
-@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
-@property (nonatomic, strong) NSTimer *timer;
-
-// Data
-@property (nonatomic, assign) NSInteger numberOfItems;
-
-@property (nonatomic, assign) NSInteger dequeueSection;
-@property (nonatomic, assign) TYIndexSection beginDragIndexSection;
-@property (nonatomic, assign) NSInteger firstScrollIndex;
-
-@property (nonatomic, assign) BOOL needClearLayout;
-@property (nonatomic, assign) BOOL didReloadData;
-@property (nonatomic, assign) BOOL didLayout;
-@property (nonatomic, assign) BOOL needResetIndex;
-
-@end
-
-#define kPagerViewMaxSectionCount 200
-#define kPagerViewMinSectionCount 18
-
-@implementation TYCyclePagerView
-
-#pragma mark - life Cycle
-
-- (instancetype)initWithFrame:(CGRect)frame {
-    if (self = [super initWithFrame:frame]) {
-        [self configureProperty];
-        
-        [self addCollectionView];
-    }
-    return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
-    if (self = [super initWithCoder:aDecoder]) {
-        [self configureProperty];
-        
-        [self addCollectionView];
-    }
-    return self;
-}
-
-- (void)configureProperty {
-    _needResetIndex = NO;
-    _didReloadData = NO;
-    _didLayout = NO;
-    _autoScrollInterval = 0;
-    _isInfiniteLoop = YES;
-    _beginDragIndexSection.index = 0;
-    _beginDragIndexSection.section = 0;
-    _indexSection.index = -1;
-    _indexSection.section = -1;
-    _firstScrollIndex = -1;
-}
-
-- (void)addCollectionView {
-    TYCyclePagerTransformLayout *layout = [[TYCyclePagerTransformLayout alloc]init];
-    UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout];
-    layout.delegate = _delegateFlags.applyTransformToAttributes ? self : nil;;
-    collectionView.backgroundColor = [UIColor clearColor];
-    collectionView.dataSource = self;
-    collectionView.delegate = self;
-    collectionView.pagingEnabled = NO;
-    collectionView.decelerationRate = 1-0.0076;
-    if ([collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) {
-        collectionView.prefetchingEnabled = NO;
-    }
-    collectionView.showsHorizontalScrollIndicator = NO;
-    collectionView.showsVerticalScrollIndicator = NO;
-    [self addSubview:collectionView];
-    _collectionView = collectionView;
-}
-
-- (void)willMoveToSuperview:(UIView *)newSuperview {
-    if (!newSuperview) {
-        [self removeTimer];
-    }else {
-        [self removeTimer];
-        if (_autoScrollInterval > 0) {
-            [self addTimer];
-        }
-    }
-}
-
-
-#pragma mark - timer
-
-- (void)addTimer {
-    if (_timer || _autoScrollInterval <= 0) {
-        return;
-    }
-    _timer = [NSTimer timerWithTimeInterval:_autoScrollInterval target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
-    [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
-}
-
-- (void)removeTimer {
-    if (!_timer) {
-        return;
-    }
-    [_timer invalidate];
-    _timer = nil;
-}
-
-- (void)timerFired:(NSTimer *)timer {
-    if (!self.superview || !self.window || _numberOfItems == 0 || self.tracking) {
-        return;
-    }
-    
-    [self scrollToNearlyIndexAtDirection:TYPagerScrollDirectionRight animate:YES];
-}
-
-#pragma mark - getter
-
-- (TYCyclePagerViewLayout *)layout {
-    if (!_layout) {
-        if (_dataSourceFlags.layoutForPagerView) {
-            _layout = [_dataSource layoutForPagerView:self];
-            _layout.isInfiniteLoop = _isInfiniteLoop;
-        }
-        if (_layout.itemSize.width <= 0 || _layout.itemSize.height <= 0) {
-            _layout = nil;
-        }
-    }
-    return _layout;
-}
-
-- (NSInteger)curIndex {
-    return _indexSection.index;
-}
-
-- (CGPoint)contentOffset {
-    return _collectionView.contentOffset;
-}
-
-- (BOOL)tracking {
-    return _collectionView.tracking;
-}
-
-- (BOOL)dragging {
-    return _collectionView.dragging;
-}
-
-- (BOOL)decelerating {
-    return _collectionView.decelerating;
-}
-
-- (UIView *)backgroundView {
-    return _collectionView.backgroundView;
-}
-
-- (__kindof UICollectionViewCell *)curIndexCell {
-    return [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:_indexSection.index inSection:_indexSection.section]];
-}
-
-- (NSArray<__kindof UICollectionViewCell *> *)visibleCells {
-    return _collectionView.visibleCells;
-}
-
-- (NSArray *)visibleIndexs {
-    NSMutableArray *indexs = [NSMutableArray array];
-    for (NSIndexPath *indexPath in _collectionView.indexPathsForVisibleItems) {
-        [indexs addObject:@(indexPath.item)];
-    }
-    return [indexs copy];
-}
-
-#pragma mark - setter
-
-- (void)setBackgroundView:(UIView *)backgroundView {
-    [_collectionView setBackgroundView:backgroundView];
-}
-
-- (void)setAutoScrollInterval:(CGFloat)autoScrollInterval {
-    _autoScrollInterval = autoScrollInterval;
-    [self removeTimer];
-    if (autoScrollInterval > 0 && self.superview) {
-        [self addTimer];
-    }
-}
-
-- (void)setDelegate:(id<TYCyclePagerViewDelegate>)delegate {
-    _delegate = delegate;
-    _delegateFlags.pagerViewDidScroll = [delegate respondsToSelector:@selector(pagerViewDidScroll:)];
-    _delegateFlags.didScrollFromIndexToNewIndex = [delegate respondsToSelector:@selector(pagerView:didScrollFromIndex:toIndex:)];
-    _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerView:initializeTransformAttributes:)];
-    _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerView:applyTransformToAttributes:)];
-    if (self.collectionView && self.collectionView.collectionViewLayout) {
-        ((TYCyclePagerTransformLayout *)self.collectionView.collectionViewLayout).delegate = _delegateFlags.applyTransformToAttributes ? self : nil;
-    }
-}
-
-- (void)setDataSource:(id<TYCyclePagerViewDataSource>)dataSource {
-    _dataSource = dataSource;
-    _dataSourceFlags.cellForItemAtIndex = [dataSource respondsToSelector:@selector(pagerView:cellForItemAtIndex:)];
-    _dataSourceFlags.layoutForPagerView = [dataSource respondsToSelector:@selector(layoutForPagerView:)];
-}
-
-#pragma mark - public
-
-- (void)reloadData {
-    _didReloadData = YES;
-    _needResetIndex = YES;
-    [self setNeedClearLayout];
-    [self clearLayout];
-    [self updateData];
-}
-
-// not clear layout
-- (void)updateData {
-    [self updateLayout];
-    _numberOfItems = [_dataSource numberOfItemsInPagerView:self];
-    [_collectionView reloadData];
-    if (!_didLayout && !CGRectIsEmpty(self.collectionView.frame) && _indexSection.index < 0) {
-        _didLayout = YES;
-    }
-    BOOL needResetIndex = _needResetIndex && _reloadDataNeedResetIndex;
-    _needResetIndex = NO;
-    if (needResetIndex) {
-        [self removeTimer];
-    }
-    [self resetPagerViewAtIndex:(_indexSection.index < 0 && !CGRectIsEmpty(self.collectionView.frame)) || needResetIndex ? 0 :_indexSection.index];
-    if (needResetIndex) {
-        [self addTimer];
-    }
-}
-
-- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate {
-    TYIndexSection indexSection = [self nearlyIndexPathAtDirection:direction];
-    [self scrollToItemAtIndexSection:indexSection animate:animate];
-}
-
-- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate {
-    if (!_didLayout && _didReloadData) {
-        _firstScrollIndex = index;
-    }else {
-        _firstScrollIndex = -1;
-    }
-    if (!_isInfiniteLoop) {
-        [self scrollToItemAtIndexSection:TYMakeIndexSection(index, 0) animate:animate];
-        return;
-    }
-
-    [self scrollToItemAtIndexSection:TYMakeIndexSection(index, index >= self.curIndex ? _indexSection.section : _indexSection.section+1) animate:animate];
-}
-
-- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate {
-    if (_numberOfItems <= 0 || ![self isValidIndexSection:indexSection]) {
-        //NSLog(@"scrollToItemAtIndex: item indexSection is invalid!");
-        return;
-    }
-    
-    if (animate && [_delegate respondsToSelector:@selector(pagerViewWillBeginScrollingAnimation:)]) {
-        [_delegate pagerViewWillBeginScrollingAnimation:self];
-    }
-    CGFloat offset = [self caculateOffsetXAtIndexSection:indexSection];
-    [_collectionView setContentOffset:CGPointMake(offset, _collectionView.contentOffset.y) animated:animate];
-}
-
-- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier {
-    [_collectionView registerClass:Class forCellWithReuseIdentifier:identifier];
-}
-
-- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier {
-    [_collectionView registerNib:nib forCellWithReuseIdentifier:identifier];
-}
-
-- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index {
-    UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:index inSection:_dequeueSection]];
-    return cell;
-}
-
-#pragma mark - configure layout
-
-- (void)updateLayout {
-    if (!self.layout) {
-        return;
-    }
-    self.layout.isInfiniteLoop = _isInfiniteLoop;
-    ((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).layout = self.layout;
-}
-
-- (void)clearLayout {
-    if (_needClearLayout) {
-        _layout = nil;
-        _needClearLayout = NO;
-    }
-}
-
-- (void)setNeedClearLayout {
-    _needClearLayout = YES;
-}
-
-- (void)setNeedUpdateLayout {
-    if (!self.layout) {
-        return;
-    }
-    [self clearLayout];
-    [self updateLayout];
-    [_collectionView.collectionViewLayout invalidateLayout];
-    [self resetPagerViewAtIndex:_indexSection.index < 0 ? 0 :_indexSection.index];
-}
-
-#pragma mark - pager index
-
-- (BOOL)isValidIndexSection:(TYIndexSection)indexSection {
-    return indexSection.index >= 0 && indexSection.index < _numberOfItems && indexSection.section >= 0 && indexSection.section < kPagerViewMaxSectionCount;
-}
-
-- (TYIndexSection)nearlyIndexPathAtDirection:(TYPagerScrollDirection)direction{
-    return [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
-}
-
-- (TYIndexSection)nearlyIndexPathForIndexSection:(TYIndexSection)indexSection direction:(TYPagerScrollDirection)direction {
-    if (indexSection.index < 0 || indexSection.index >= _numberOfItems) {
-        return indexSection;
-    }
-    
-    if (!_isInfiniteLoop) {
-        if (direction == TYPagerScrollDirectionRight && indexSection.index == _numberOfItems - 1) {
-            return _autoScrollInterval > 0 ? TYMakeIndexSection(0, 0) : indexSection;
-        } else if (direction == TYPagerScrollDirectionRight) {
-            return TYMakeIndexSection(indexSection.index+1, 0);
-        }
-        
-        if (indexSection.index == 0) {
-            return _autoScrollInterval > 0 ? TYMakeIndexSection(_numberOfItems - 1, 0) : indexSection;
-        }
-        return TYMakeIndexSection(indexSection.index-1, 0);
-    }
-    
-    if (direction == TYPagerScrollDirectionRight) {
-        if (indexSection.index < _numberOfItems-1) {
-            return TYMakeIndexSection(indexSection.index+1, indexSection.section);
-        }
-        if (indexSection.section >= kPagerViewMaxSectionCount-1) {
-            return TYMakeIndexSection(indexSection.index, kPagerViewMaxSectionCount-1);
-        }
-        return TYMakeIndexSection(0, indexSection.section+1);
-    }
-    
-    if (indexSection.index > 0) {
-        return TYMakeIndexSection(indexSection.index-1, indexSection.section);
-    }
-    if (indexSection.section <= 0) {
-        return TYMakeIndexSection(indexSection.index, 0);
-    }
-    return TYMakeIndexSection(_numberOfItems-1, indexSection.section-1);
-}
-
-- (TYIndexSection)caculateIndexSectionWithOffsetX:(CGFloat)offsetX {
-    if (_numberOfItems <= 0) {
-        return TYMakeIndexSection(0, 0);
-    }
-     UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
-    CGFloat leftEdge = _isInfiniteLoop ? _layout.sectionInset.left : _layout.onlyOneSectionInset.left;
-    CGFloat width = CGRectGetWidth(_collectionView.frame);
-    CGFloat middleOffset = offsetX + width/2;
-    CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
-    NSInteger curIndex = 0;
-    NSInteger curSection = 0;
-    if (middleOffset - leftEdge >= 0) {
-        NSInteger itemIndex = (middleOffset - leftEdge+layout.minimumInteritemSpacing/2)/itemWidth;
-        if (itemIndex < 0) {
-            itemIndex = 0;
-        }else if (itemIndex >= _numberOfItems*kPagerViewMaxSectionCount) {
-            itemIndex = _numberOfItems*kPagerViewMaxSectionCount-1;
-        }
-        curIndex = itemIndex%_numberOfItems;
-        curSection = itemIndex/_numberOfItems;
-    }
-    return TYMakeIndexSection(curIndex, curSection);
-}
-
-- (CGFloat)caculateOffsetXAtIndexSection:(TYIndexSection)indexSection{
-    if (_numberOfItems == 0) {
-        return 0;
-    }
-    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
-    UIEdgeInsets edge = _isInfiniteLoop ? _layout.sectionInset : _layout.onlyOneSectionInset;
-    CGFloat leftEdge = edge.left;
-    CGFloat rightEdge = edge.right;
-    CGFloat width = CGRectGetWidth(_collectionView.frame);
-    CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
-    CGFloat offsetX = 0;
-    if (!_isInfiniteLoop && !_layout.itemHorizontalCenter && indexSection.index == _numberOfItems - 1) {
-        offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - (width - itemWidth) -  layout.minimumInteritemSpacing + rightEdge;
-    }else {
-        offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - layout.minimumInteritemSpacing/2 - (width - itemWidth)/2;
-    }
-    return MAX(offsetX, 0);
-}
-
-- (void)resetPagerViewAtIndex:(NSInteger)index {
-    if (_didLayout && _firstScrollIndex >= 0) {
-        index = _firstScrollIndex;
-        _firstScrollIndex = -1;
-    }
-    if (index < 0) {
-        return;
-    }
-    if (index >= _numberOfItems) {
-        index = 0;
-    }
-    [self scrollToItemAtIndexSection:TYMakeIndexSection(index, _isInfiniteLoop ? kPagerViewMaxSectionCount/3 : 0) animate:NO];
-    if (!_isInfiniteLoop && _indexSection.index < 0) {
-        [self scrollViewDidScroll:_collectionView];
-    }
-}
-
-- (void)recyclePagerViewIfNeed {
-    if (!_isInfiniteLoop) {
-        return;
-    }
-    if (_indexSection.section > kPagerViewMaxSectionCount - kPagerViewMinSectionCount || _indexSection.section < kPagerViewMinSectionCount) {
-        [self resetPagerViewAtIndex:_indexSection.index];
-    }
-}
-
-#pragma mark - UICollectionViewDataSource
-
-- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
-    return _isInfiniteLoop ? kPagerViewMaxSectionCount : 1;
-}
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
-    _numberOfItems = [_dataSource numberOfItemsInPagerView:self];
-    return _numberOfItems;
-}
-
-- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
-    _dequeueSection = indexPath.section;
-    if (_dataSourceFlags.cellForItemAtIndex) {
-       return [_dataSource pagerView:self cellForItemAtIndex:indexPath.row];
-    }
-    NSAssert(NO, @"pagerView cellForItemAtIndex: is nil!");
-    return nil;
-}
-
-#pragma mark - UICollectionViewDelegateFlowLayout
-
-- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
-    if (!_isInfiniteLoop) {
-        return _layout.onlyOneSectionInset;
-    }
-    if (section == 0 ) {
-        return _layout.firstSectionInset;
-    }else if (section == kPagerViewMaxSectionCount -1) {
-        return _layout.lastSectionInset;
-    }
-    return _layout.middleSectionInset;
-}
-
-- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
-    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
-    if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndex:)]) {
-        [_delegate pagerView:self didSelectedItemCell:cell atIndex:indexPath.item];
-    }
-    if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndexSection:)]) {
-        [_delegate pagerView:self didSelectedItemCell:cell atIndexSection:TYMakeIndexSection(indexPath.item, indexPath.section)];
-    }
-}
-
-#pragma mark - UIScrollViewDelegate
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
-    if (!_didLayout) {
-        return;
-    }
-    TYIndexSection newIndexSection =  [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
-    if (_numberOfItems <= 0 || ![self isValidIndexSection:newIndexSection]) {
-        NSLog(@"inVlaidIndexSection:(%ld,%ld)!",(long)newIndexSection.index,(long)newIndexSection.section);
-        return;
-    }
-    TYIndexSection indexSection = _indexSection;
-    _indexSection = newIndexSection;
-    
-    if (_delegateFlags.pagerViewDidScroll) {
-        [_delegate pagerViewDidScroll:self];
-    }
-    
-    if (_delegateFlags.didScrollFromIndexToNewIndex && !TYEqualIndexSection(_indexSection, indexSection)) {
-        //NSLog(@"curIndex %ld",(long)_indexSection.index);
-        [_delegate pagerView:self didScrollFromIndex:MAX(indexSection.index, 0) toIndex:_indexSection.index];
-    }
-}
-
-- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
-    if (_autoScrollInterval > 0) {
-        [self removeTimer];
-    }
-    _beginDragIndexSection = [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
-    if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDragging:)]) {
-        [_delegate pagerViewWillBeginDragging:self];
-    }
-}
-
-- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
-    if (fabs(velocity.x) < 0.35 || !TYEqualIndexSection(_beginDragIndexSection, _indexSection)) {
-        targetContentOffset->x = [self caculateOffsetXAtIndexSection:_indexSection];
-        return;
-    }
-    TYPagerScrollDirection direction = TYPagerScrollDirectionRight;
-    if ((scrollView.contentOffset.x < 0 && targetContentOffset->x <= 0) || (targetContentOffset->x < scrollView.contentOffset.x && scrollView.contentOffset.x < scrollView.contentSize.width - scrollView.frame.size.width)) {
-        direction = TYPagerScrollDirectionLeft;
-    }
-    TYIndexSection indexSection = [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
-    targetContentOffset->x = [self caculateOffsetXAtIndexSection:indexSection];
-}
-
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
-    if (_autoScrollInterval > 0) {
-        [self addTimer];
-    }
-    if ([_delegate respondsToSelector:@selector(pagerViewDidEndDragging:willDecelerate:)]) {
-        [_delegate pagerViewDidEndDragging:self willDecelerate:decelerate];
-    }
-}
-
-- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
-    if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDecelerating:)]) {
-        [_delegate pagerViewWillBeginDecelerating:self];
-    }
-}
-
-- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
-    [self recyclePagerViewIfNeed];
-    if ([_delegate respondsToSelector:@selector(pagerViewDidEndDecelerating:)]) {
-        [_delegate pagerViewDidEndDecelerating:self];
-    }
-}
-
-- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
-    [self recyclePagerViewIfNeed];
-    if ([_delegate respondsToSelector:@selector(pagerViewDidEndScrollingAnimation:)]) {
-        [_delegate pagerViewDidEndScrollingAnimation:self];
-    }
-}
-
-#pragma mark - TYCyclePagerTransformLayoutDelegate
-
-- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes {
-    if (_delegateFlags.initializeTransformAttributes) {
-        [_delegate pagerView:self initializeTransformAttributes:attributes];
-    }
-}
-
-- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
-    if (_delegateFlags.applyTransformToAttributes) {
-        [_delegate pagerView:self applyTransformToAttributes:attributes];
-    }
-}
-
-- (void)layoutSubviews {
-    [super layoutSubviews];
-    BOOL needUpdateLayout = !CGRectEqualToRect(_collectionView.frame, self.bounds);
-    _collectionView.frame = self.bounds;
-    if ((_indexSection.section < 0 || needUpdateLayout) && (_numberOfItems > 0 || _didReloadData)) {
-        _didLayout = YES;
-        [self setNeedUpdateLayout];
-    }
-}
-
-- (void)dealloc {
-    ((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).delegate = nil;
-    _collectionView.delegate = nil;
-    _collectionView.dataSource = nil;
-}
-
-@end
-
-

+ 0 - 47
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.h

@@ -1,47 +0,0 @@
-//
-//  TYPageControl.h
-//  TYCyclePagerViewDemo
-//
-//  Created by tany on 2017/6/20.
-//  Copyright © 2017年 tany. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface TYPageControl : UIControl
-
-@property (nonatomic, assign) NSInteger numberOfPages;          // default is 0
-@property (nonatomic, assign) NSInteger currentPage;            // default is 0. value pinned to 0..numberOfPages-1
-
-@property (nonatomic, assign) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO
-
-@property (nonatomic, assign) CGFloat pageIndicatorSpaing;
-@property (nonatomic, assign) UIEdgeInsets contentInset; // center will ignore this
-@property (nonatomic, assign ,readonly) CGSize contentSize; // real content size
-
-// override super 
-//@property (nonatomic, assign) UIControlContentVerticalAlignment contentVerticalAlignment;     // how to position content vertically inside control. default is center
-//@property (nonatomic, assign) UIControlContentHorizontalAlignment contentHorizontalAlignment; // how to position content hozontally inside control. default is center
-
-// indicatorTint color
-@property (nullable, nonatomic,strong) UIColor *pageIndicatorTintColor;
-@property (nullable, nonatomic,strong) UIColor *currentPageIndicatorTintColor;
-
-// indicator image
-@property (nullable, nonatomic,strong) UIImage *pageIndicatorImage;
-@property (nullable, nonatomic,strong) UIImage *currentPageIndicatorImage;
-
-@property (nonatomic, assign) UIViewContentMode indicatorImageContentMode; // default is UIViewContentModeCenter
-
-@property (nonatomic, assign) CGSize pageIndicatorSize; // indicator size
-@property (nonatomic, assign) CGSize currentPageIndicatorSize; // default pageIndicatorSize
-
-@property (nonatomic, assign) CGFloat animateDuring; // default 0.3
-
-- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate;
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 285
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.m

@@ -1,285 +0,0 @@
-//
-//  TYPageControl.m
-//  TYCyclePagerViewDemo
-//
-//  Created by tany on 2017/6/20.
-//  Copyright © 2017年 tany. All rights reserved.
-//
-
-#import "TYPageControl.h"
-
-@interface TYPageControl ()
-// UI
-@property (nonatomic, strong) NSArray<UIImageView *> *indicatorViews;
-
-// Data
-@property (nonatomic, assign) BOOL forceUpdate;
-
-@end
-
-@implementation TYPageControl
-
-#pragma mark - life cycle
-
-- (instancetype)initWithFrame:(CGRect)frame {
-    if (self = [super initWithFrame:frame]) {
-        [self configurePropertys];
-    }
-    return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
-    if (self = [super initWithCoder:aDecoder]) {
-        [self configurePropertys];
-    }
-    return self;
-}
-
-- (void)configurePropertys {
-    self.userInteractionEnabled = NO;
-    _forceUpdate = NO;
-    _animateDuring = 0.3;
-    _pageIndicatorSpaing = 10;
-    _indicatorImageContentMode = UIViewContentModeCenter;
-    _pageIndicatorSize = CGSizeMake(6,6);
-    _currentPageIndicatorSize = _pageIndicatorSize;
-    _pageIndicatorTintColor = [UIColor colorWithRed:128/255. green:128/255. blue:128/255. alpha:1];
-    _currentPageIndicatorTintColor = [UIColor whiteColor];
-}
-
-- (void)willMoveToSuperview:(UIView *)newSuperview {
-    [super willMoveToSuperview:newSuperview];
-    if (newSuperview) {
-        _forceUpdate = YES;
-        [self updateIndicatorViews];
-        _forceUpdate = NO;
-    }
-}
-
-#pragma mark - getter setter
-
-- (CGSize)contentSize {
-    CGFloat width = (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _pageIndicatorSize.width + _contentInset.left +_contentInset.right;
-    CGFloat height = _currentPageIndicatorSize.height + _contentInset.top + _contentInset.bottom;
-    return CGSizeMake(width, height);
-}
-
-- (void)setNumberOfPages:(NSInteger)numberOfPages {
-    if (numberOfPages == _numberOfPages) {
-        return;
-    }
-    _numberOfPages = numberOfPages;
-    if (_currentPage >= numberOfPages) {
-        _currentPage = 0;
-    }
-    [self updateIndicatorViews];
-    if (_indicatorViews.count > 0) {
-        [self setNeedsLayout];
-    }
-}
-
-- (void)setCurrentPage:(NSInteger)currentPage {
-    if (_currentPage == currentPage || _indicatorViews.count <= currentPage) {
-        return;
-    }
-    _currentPage = currentPage;
-    if (!CGSizeEqualToSize(_currentPageIndicatorSize, _pageIndicatorSize)) {
-        [self setNeedsLayout];
-    }
-    [self updateIndicatorViewsBehavior];
-    if (self.userInteractionEnabled) {
-        [self sendActionsForControlEvents:UIControlEventValueChanged];
-    }
-}
-
-- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate {
-    if (animate) {
-        [UIView animateWithDuration:_animateDuring animations:^{
-            [self setCurrentPage:currentPage];
-        }];
-    }else {
-        [self setCurrentPage:currentPage];
-    }
-}
-
-- (void)setPageIndicatorImage:(UIImage *)pageIndicatorImage {
-    _pageIndicatorImage = pageIndicatorImage;
-    [self updateIndicatorViewsBehavior];
-}
-
-- (void)setCurrentPageIndicatorImage:(UIImage *)currentPageIndicatorImage {
-    _currentPageIndicatorImage = currentPageIndicatorImage;
-    [self updateIndicatorViewsBehavior];
-}
-
-- (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor {
-    _pageIndicatorTintColor = pageIndicatorTintColor;
-    [self updateIndicatorViewsBehavior];
-}
-
-- (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor {
-    _currentPageIndicatorTintColor = currentPageIndicatorTintColor;
-    [self updateIndicatorViewsBehavior];
-}
-
-- (void)setPageIndicatorSize:(CGSize)pageIndicatorSize {
-    if (CGSizeEqualToSize(_pageIndicatorSize, pageIndicatorSize)) {
-        return;
-    }
-    _pageIndicatorSize = pageIndicatorSize;
-    if (CGSizeEqualToSize(_currentPageIndicatorSize, CGSizeZero) || (_currentPageIndicatorSize.width < pageIndicatorSize.width && _currentPageIndicatorSize.height < pageIndicatorSize.height)) {
-        _currentPageIndicatorSize = pageIndicatorSize;
-    }
-    if (_indicatorViews.count > 0) {
-        [self setNeedsLayout];
-    }
-}
-
-- (void)setPageIndicatorSpaing:(CGFloat)pageIndicatorSpaing {
-    _pageIndicatorSpaing = pageIndicatorSpaing;
-    if (_indicatorViews.count > 0) {
-        [self setNeedsLayout];
-    }
-}
-
-- (void)setCurrentPageIndicatorSize:(CGSize)currentPageIndicatorSize {
-    if (CGSizeEqualToSize(_currentPageIndicatorSize, currentPageIndicatorSize)) {
-        return;
-    }
-    _currentPageIndicatorSize = currentPageIndicatorSize;
-    if (_indicatorViews.count > 0) {
-        [self setNeedsLayout];
-    }
-}
-
-- (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment {
-    [super setContentHorizontalAlignment:contentHorizontalAlignment];
-    if (_indicatorViews.count > 0) {
-        [self setNeedsLayout];
-    }
-}
-
-- (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment {
-    [super setContentVerticalAlignment:contentVerticalAlignment];
-    if (_indicatorViews.count > 0) {
-        [self setNeedsLayout];
-    }
-}
-
-#pragma mark - update indicator
-
-- (void)updateIndicatorViews {
-    if (!self.superview && !_forceUpdate) {
-        return;
-    }
-    if (_indicatorViews.count == _numberOfPages) {
-        [self updateIndicatorViewsBehavior];
-        return;
-    }
-    NSMutableArray *indicatorViews = _indicatorViews ? [_indicatorViews mutableCopy] :[NSMutableArray array];
-    if (indicatorViews.count < _numberOfPages) {
-        for (NSInteger idx = indicatorViews.count; idx < _numberOfPages; ++idx) {
-            UIImageView *indicatorView = [[UIImageView alloc]init];
-            indicatorView.contentMode = _indicatorImageContentMode;
-            [self addSubview:indicatorView];
-            [indicatorViews addObject:indicatorView];
-        }
-    }else if (indicatorViews.count > _numberOfPages) {
-        for (NSInteger idx = indicatorViews.count - 1; idx >= _numberOfPages; --idx) {
-            UIImageView *indicatorView = indicatorViews[idx];
-            [indicatorView removeFromSuperview];
-            [indicatorViews removeObjectAtIndex:idx];
-        }
-    }
-    _indicatorViews = [indicatorViews copy];
-    [self updateIndicatorViewsBehavior];
-}
-
-- (void)updateIndicatorViewsBehavior {
-    if (_indicatorViews.count == 0 || (!self.superview && !_forceUpdate)) {
-        return;
-    }
-    if (_hidesForSinglePage && _indicatorViews.count == 1) {
-        UIImageView *indicatorView = _indicatorViews.lastObject;
-        indicatorView.hidden = YES;
-        return;
-    }
-    NSInteger index = 0;
-    for (UIImageView *indicatorView in _indicatorViews) {
-        if (_pageIndicatorImage) {
-            indicatorView.contentMode = _indicatorImageContentMode;
-            indicatorView.image = _currentPage == index ? _currentPageIndicatorImage : _pageIndicatorImage;
-        }else {
-            indicatorView.image = nil;
-            indicatorView.backgroundColor = _currentPage == index ? _currentPageIndicatorTintColor : _pageIndicatorTintColor;
-        }
-        indicatorView.hidden = NO;
-        ++index;
-    }
-}
-
-#pragma mark - layout
-
-- (void)layoutIndicatorViews {
-    if (_indicatorViews.count == 0) {
-        return;
-    }
-    CGFloat orignX = 0;
-    CGFloat centerY = 0;
-    CGFloat pageIndicatorSpaing = _pageIndicatorSpaing;
-    switch (self.contentHorizontalAlignment) {
-        case UIControlContentHorizontalAlignmentCenter:
-            // ignore contentInset
-            orignX = (CGRectGetWidth(self.frame) - (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) - _currentPageIndicatorSize.width)/2;
-            break;
-        case UIControlContentHorizontalAlignmentLeft:
-            orignX = _contentInset.left;
-            break;
-        case UIControlContentHorizontalAlignmentRight:
-            orignX = CGRectGetWidth(self.frame) - ((_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _currentPageIndicatorSize.width) - _contentInset.right;
-            break;
-        case UIControlContentHorizontalAlignmentFill:
-            orignX = _contentInset.left;
-            if (_indicatorViews.count > 1) {
-                pageIndicatorSpaing = (CGRectGetWidth(self.frame) - _contentInset.left - _contentInset.right - _pageIndicatorSize.width - (_indicatorViews.count - 1) * _pageIndicatorSize.width)/(_indicatorViews.count - 1);
-            }
-            break;
-        default:
-            break;
-    }
-    switch (self.contentVerticalAlignment) {
-        case UIControlContentVerticalAlignmentCenter:
-            centerY = CGRectGetHeight(self.frame)/2;
-            break;
-        case UIControlContentVerticalAlignmentTop:
-            centerY = _contentInset.top + _currentPageIndicatorSize.height/2;
-            break;
-        case UIControlContentVerticalAlignmentBottom:
-            centerY = CGRectGetHeight(self.frame) - _currentPageIndicatorSize.height/2 - _contentInset.bottom;
-            break;
-        case UIControlContentVerticalAlignmentFill:
-            centerY = (CGRectGetHeight(self.frame) - _contentInset.top - _contentInset.bottom)/2 + _contentInset.top;
-            break;
-        default:
-            break;
-    }
-    NSInteger index = 0;
-    for (UIImageView *indicatorView in _indicatorViews) {
-        if (_pageIndicatorImage) {
-            indicatorView.layer.cornerRadius = 0;
-        }else {
-            indicatorView.layer.cornerRadius = _currentPage == index ? _currentPageIndicatorSize.height/2 : _pageIndicatorSize.height/2;
-        }
-        CGSize size = index == _currentPage ? _currentPageIndicatorSize : _pageIndicatorSize;
-        indicatorView.frame = CGRectMake(orignX, centerY - size.height/2, size.width, size.height);
-        orignX += size.width + pageIndicatorSpaing;
-        ++index;
-    }
-}
-
-- (void)layoutSubviews {
-    [super layoutSubviews];
-    [self layoutIndicatorViews];
-}
-
-@end

+ 0 - 136
TSLiveWallpaper/Common/ThirdParty/Util/AVAssetExtension.swift

@@ -1,136 +0,0 @@
-import AVKit
-
-extension AVAsset {
-    func countFrames(exact:Bool) -> Int {
-        
-        var frameCount = 0
-        
-        if let videoReader = try? AVAssetReader(asset: self)  {
-            
-            if let videoTrack = self.tracks(withMediaType: .video).first {
-                
-                frameCount = Int(CMTimeGetSeconds(self.duration) * Float64(videoTrack.nominalFrameRate))
-                
-                
-                if exact {
-                    
-                    frameCount = 0
-                    
-                    let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: nil)
-                    videoReader.add(videoReaderOutput)
-                    
-                    videoReader.startReading()
-                    
-                    // count frames
-                    while true {
-                        let sampleBuffer = videoReaderOutput.copyNextSampleBuffer()
-                        if sampleBuffer == nil {
-                            break
-                        }
-                        frameCount += 1
-                    }
-                    
-                    videoReader.cancelReading()
-                }
-                
-                
-            }
-        }
-        
-        return frameCount
-    }
-    
-    func stillImageTime() -> CMTime?  {
-        
-        var stillTime:CMTime? = nil
-        
-        if let videoReader = try? AVAssetReader(asset: self)  {
-            
-            if let metadataTrack = self.tracks(withMediaType: .metadata).first {
-                
-                let videoReaderOutput = AVAssetReaderTrackOutput(track: metadataTrack, outputSettings: nil)
-                
-                videoReader.add(videoReaderOutput)
-                
-                videoReader.startReading()
-                
-                let keyStillImageTime = "com.apple.quicktime.still-image-time"
-                let keySpaceQuickTimeMetadata = "mdta"
-                
-                var found = false
-                
-                while found == false {
-                    if let sampleBuffer = videoReaderOutput.copyNextSampleBuffer() {
-                        if CMSampleBufferGetNumSamples(sampleBuffer) != 0 {
-                            let group = AVTimedMetadataGroup(sampleBuffer: sampleBuffer)
-                            for item in group?.items ?? [] {
-                                if item.key as? String == keyStillImageTime && item.keySpace!.rawValue == keySpaceQuickTimeMetadata {
-                                    stillTime = group?.timeRange.start
-                                    //print("stillImageTime = \(CMTimeGetSeconds(stillTime!))")
-                                    found = true
-                                    break
-                                }
-                            }
-                        }
-                    }
-                    else {
-                        break;
-                    }
-                }
-                
-                videoReader.cancelReading()
-                
-            }
-        }
-        
-        return stillTime
-    }
-    
-    func makeStillImageTimeRange(percent:Float, inFrameCount:Int = 0) -> CMTimeRange {
-        
-        var time = self.duration
-        
-        var frameCount = inFrameCount
-        
-        if frameCount == 0 {
-            frameCount = self.countFrames(exact: true)
-        }
-        
-        let frameDuration = Int64(Float(time.value) / Float(frameCount))
-        
-        time.value = Int64(Float(time.value) * percent)
-        
-        //print("stillImageTime = \(CMTimeGetSeconds(time))")
-        
-        return CMTimeRangeMake(start: time, duration: CMTimeMake(value: frameDuration, timescale: time.timescale))
-    }
-    
-    func getAssetFrame(percent:Float) -> UIImage?
-    {
-        
-        let imageGenerator = AVAssetImageGenerator(asset: self)
-        imageGenerator.appliesPreferredTrackTransform = true
-        
-        imageGenerator.requestedTimeToleranceAfter = CMTimeMake(value: 1,timescale: 100)
-        imageGenerator.requestedTimeToleranceBefore = CMTimeMake(value: 1,timescale: 100)
-        
-        var time = self.duration
-        
-        time.value = Int64(Float(time.value) * percent)
-        
-        do {
-            var actualTime = CMTime.zero
-            let imageRef = try imageGenerator.copyCGImage(at: time, actualTime:&actualTime)
-            
-            let img = UIImage(cgImage: imageRef)
-            
-            return img
-        }
-        catch let error as NSError
-        {
-            print("Image generation failed with error \(error)")
-            return nil
-        }
-    }
-}
-

+ 0 - 57
TSLiveWallpaper/Common/ThirdParty/Util/Converter4Image.swift

@@ -1,57 +0,0 @@
-import UIKit
-import UniformTypeIdentifiers
-import CoreServices
-import ImageIO
-import Photos
-
-@objc class Converter4Image : NSObject {
-    private let kFigAppleMakerNote_AssetIdentifier = "17"
-    private let image : UIImage
-
-    @objc init(image : UIImage) {
-        self.image = image
-    }
-
-    @objc func read() -> String? {
-        guard let makerNote = metadata(index: 0)?.object(forKey: kCGImagePropertyMakerAppleDictionary) as? NSDictionary else {
-            return nil
-        }
-        return makerNote.object(forKey: kFigAppleMakerNote_AssetIdentifier) as? String
-    }
-
-    @objc func write(dest : String, assetIdentifier : String) {
-        guard let destURL = URL(fileURLWithPath: dest) as CFURL?,
-              let dest = CGImageDestinationCreateWithURL(destURL, UTType.heic.identifier as CFString, 1, nil) else { return }
-        defer { CGImageDestinationFinalize(dest) }
-        for i in 0...0 {
-            guard let imageSource = self.imageSource() else { return }
-            guard let metadata = self.metadata(index: i)?.mutableCopy() as? NSMutableDictionary else { return }
-            
-            let makerNote = NSMutableDictionary()
-            makerNote.setObject(assetIdentifier, forKey: kFigAppleMakerNote_AssetIdentifier as NSCopying)
-            metadata.setObject(makerNote, forKey: kCGImagePropertyMakerAppleDictionary as NSString)
-//            metadata.setObject("sRGB IEC61966-2.1", forKey: kCGImagePropertyProfileName as NSString)
-            CGImageDestinationAddImageFromSource(dest, imageSource, i, metadata as CFDictionary)
-        }
-    }
-
-    private func metadata(index: Int) -> NSDictionary? {
-        return self.imageSource().flatMap {
-            CGImageSourceCopyPropertiesAtIndex($0, index, nil) as NSDictionary?
-        }
-    }
-
-    private func imageSource() -> CGImageSource? {
-        return self.data().flatMap {
-            CGImageSourceCreateWithData($0 as CFData, nil)
-        }
-    }
-
-    private func data() -> Data? {
-        if #available(iOS 17.0, *) {
-            return image.heicData()
-        } else {
-            return image.pngData()
-        }
-    }
-}

+ 0 - 663
TSLiveWallpaper/Common/ThirdParty/Util/Converter4Video.swift

@@ -1,663 +0,0 @@
-import Foundation
-import AVFoundation
-import UIKit
-
-@objc class Converter4Video : NSObject {
-    private let kKeyContentIdentifier =  "com.apple.quicktime.content.identifier"
-    private let kKeyStillImageTime = "com.apple.quicktime.still-image-time"
-    private let kKeySpaceQuickTimeMetadata = "mdta"
-    private let path : String
-
-    private lazy var asset : AVURLAsset = {
-        let url = NSURL(fileURLWithPath: self.path)
-        return AVURLAsset(url: url as URL)
-    }()
-
-    @objc init(path : String) {
-        self.path = path
-    }
-
-    @objc func readAssetIdentifier() -> String? {
-        for item in metadata() {
-            if item.key as? String == kKeyContentIdentifier &&
-                item.keySpace?.rawValue == kKeySpaceQuickTimeMetadata {
-                return item.value as? String
-            }
-        }
-        return nil
-    }
-    
-    private func reader(track: AVAssetTrack, settings: [String:AnyObject]?) throws -> (AVAssetReader, AVAssetReaderOutput) {
-        let output = AVAssetReaderTrackOutput(track: track, outputSettings: settings)
-        let reader = try AVAssetReader(asset: asset)
-        reader.add(output)
-        return (reader, output)
-    }
-
-//    func readStillImageTime() -> NSNumber? {
-//        if let track = track(mediaType: AVMediaType.metadata.rawValue) {
-//            let (reader, output) = try! self.reader(track: track, settings: nil)
-//            reader.startReading()
-//
-//            while true {
-//                guard let buffer = output.copyNextSampleBuffer() else { return nil }
-//                if CMSampleBufferGetNumSamples(buffer) != 0 {
-//                    let group = AVTimedMetadataGroup(sampleBuffer: buffer)
-//                    for item in group?.items ?? [] {
-//                        if item.key as? String == kKeyStillImageTime &&
-//                            item.keySpace?.rawValue == kKeySpaceQuickTimeMetadata {
-//                                return item.numberValue
-//                        }
-//                    }
-//                }
-//            }
-//        }
-//        return nil
-//    }
-    
-    private func createMetadataAdaptorForStillImageTime() -> AVAssetWriterInputMetadataAdaptor {
-        let keyStillImageTime = "com.apple.quicktime.still-image-time"
-        let keySpaceQuickTimeMetadata = "mdta"
-        let spec : NSDictionary = [
-            kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier as NSString:
-            "\(keySpaceQuickTimeMetadata)/\(keyStillImageTime)",
-            kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType as NSString:
-            "com.apple.metadata.datatype.int8"            ]
-        var desc : CMFormatDescription? = nil
-        CMMetadataFormatDescriptionCreateWithMetadataSpecifications(allocator: kCFAllocatorDefault, metadataType: kCMMetadataFormatType_Boxed, metadataSpecifications: [spec] as CFArray, formatDescriptionOut: &desc)
-        let input = AVAssetWriterInput(mediaType: .metadata,
-                                       outputSettings: nil, sourceFormatHint: desc)
-        return AVAssetWriterInputMetadataAdaptor(assetWriterInput: input)
-    }
-    
-    private func metadataForAssetID(_ assetIdentifier: String) -> AVMetadataItem {
-        let item = AVMutableMetadataItem()
-        let keyContentIdentifier =  "com.apple.quicktime.content.identifier"
-        let keySpaceQuickTimeMetadata = "mdta"
-        item.key = keyContentIdentifier as (NSCopying & NSObjectProtocol)?
-        item.keySpace = AVMetadataKeySpace(rawValue: keySpaceQuickTimeMetadata)
-        item.value = assetIdentifier as (NSCopying & NSObjectProtocol)?
-        item.dataType = "com.apple.metadata.datatype.UTF-8"
-        return item
-    }
-
-    private func metadataForStillImageTime() -> AVMetadataItem {
-        let item = AVMutableMetadataItem()
-        item.key = kKeyStillImageTime as any NSCopying & NSObjectProtocol
-        item.keySpace = AVMetadataKeySpace.quickTimeMetadata
-        item.value = 0 as (NSCopying & NSObjectProtocol)?
-        item.dataType = kCMMetadataBaseDataType_SInt8 as String
-        return item.copy() as! AVMetadataItem
-    }
-
-    @objc func write(dest: String, assetIdentifier: String, metaURL: URL, completion: @escaping (Bool, Error?) -> Void) {
-        do {
-            let metadataAsset = AVURLAsset(url: metaURL)
-            
-            let readerVideo = try AVAssetReader(asset: asset)
-            let readerMetadata = try AVAssetReader(asset: metadataAsset)
-            
-            let writer = try AVAssetWriter(outputURL: URL(fileURLWithPath: dest), fileType: .mov)
-            
-            let writingGroup = DispatchGroup()
-            
-            var videoIOs = [(AVAssetWriterInput, AVAssetReaderTrackOutput)]()
-            var metadataIOs = [(AVAssetWriterInput, AVAssetReaderTrackOutput)]()
-            
-            self.loadTracks(asset: self.asset, type: .video) { videoTracks in
-                for track in videoTracks {
-                    let trackReaderOutput = AVAssetReaderTrackOutput(track: track, outputSettings: [kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_32BGRA as UInt32)])
-                    readerVideo.add(trackReaderOutput)
-                    
-                    let videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: [AVVideoCodecKey : AVVideoCodecType.h264, AVVideoWidthKey : track.naturalSize.width, AVVideoHeightKey : track.naturalSize.height])
-                    videoInput.transform = track.preferredTransform
-                    videoInput.expectsMediaDataInRealTime = true
-                    writer.add(videoInput)
-                    
-                    videoIOs.append((videoInput, trackReaderOutput))
-                }
-                
-                self.loadTracks(asset: metadataAsset, type: .metadata) { metadataTracks in
-                    for track in metadataTracks {
-                        let trackReaderOutput = AVAssetReaderTrackOutput(track: track, outputSettings: nil)
-                        readerMetadata.add(trackReaderOutput)
-                        
-                        let metadataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil)
-                        writer.add(metadataInput)
-                        
-                        metadataIOs.append((metadataInput, trackReaderOutput))
-                    }
-                    
-                    writer.metadata = [self.metadataForAssetID(assetIdentifier)]
-//                    let stillImageTimeMetadataAdapter = self.createMetadataAdaptorForStillImageTime()
-//                    writer.add(stillImageTimeMetadataAdapter.assetWriterInput)
-                    
-                    writer.startWriting()
-                    readerVideo.startReading()
-                    readerMetadata.startReading()
-                    writer.startSession(atSourceTime: .zero)
-                    
-//                    let _stillImagePercent: Float = 0.2
-//                    stillImageTimeMetadataAdapter.append(AVTimedMetadataGroup(items: [self.metadataForStillImageTime()],timeRange: self.asset.makeStillImageTimeRange(percent: _stillImagePercent, inFrameCount: self.asset.countFrames(exact: false))))
-                    
-                    for (videoInput, videoOutput) in videoIOs {
-                        writingGroup.enter()
-                        videoInput.requestMediaDataWhenReady(on: DispatchQueue(label: "assetWriterQueue.video")) {
-                            while videoInput.isReadyForMoreMediaData {
-                                if let sampleBuffer = videoOutput.copyNextSampleBuffer() {
-                                    videoInput.append(sampleBuffer)
-                                } else {
-                                    videoInput.markAsFinished()
-                                    writingGroup.leave()
-                                    break
-                                }
-                            }
-                        }
-                    }
-                    for (metadataInput, metadataOutput) in metadataIOs {
-                        writingGroup.enter()
-                        metadataInput.requestMediaDataWhenReady(on: DispatchQueue(label: "assetWriterQueue.metadata")) {
-                            while metadataInput.isReadyForMoreMediaData {
-                                if let sampleBuffer = metadataOutput.copyNextSampleBuffer() {
-                                    metadataInput.append(sampleBuffer)
-                                } else {
-                                    metadataInput.markAsFinished()
-                                    writingGroup.leave()
-                                    break
-                                }
-                            }
-                        }
-                    }
-                    
-                    writingGroup.notify(queue: .main) {
-                        if
-                            readerVideo.status == .completed &&
-                            readerMetadata.status == .completed &&
-                            writer.status == .writing {
-                            writer.finishWriting {
-                                completion(writer.status == .completed, writer.error)
-                            }
-                        } else {
-                            if let readerError = readerVideo.error {
-                                completion(false, readerError)
-                            } else if let readerError = readerMetadata.error {
-                                completion(false, readerError)
-                            } else if let writerError = writer.error {
-                                completion(false, writerError)
-                            } else {
-                                completion(false, NSError(domain: "VideoProcessing", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unkown error"]))
-                            }
-                        }
-                    }
-                }
-            }
-        } catch {
-            completion(false, error)
-        }
-    }
-
-    private func metadata() -> [AVMetadataItem] {
-        return asset.metadata(forFormat: AVMetadataFormat.quickTimeMetadata)
-    }
-
-    private func degressFromVideoFileWithURL(videoTrack: AVAssetTrack)->Int {
-        var degress = 0
-     
-        let t: CGAffineTransform = videoTrack.preferredTransform
-        if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
-            // Portrait
-            degress = 90
-        }else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
-            // PortraitUpsideDown
-            degress = 270
-        }else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
-            // LandscapeRight
-            degress = 0
-        }else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
-            // LandscapeLeft
-            degress = 180
-        }
-        return degress
-    }
-
-    @objc public func cleanTransformVideo(at inputPath: String, outputPath: String, completion: @escaping (Bool, Error?) -> Void) {
-        let inputURL = URL(fileURLWithPath: inputPath)
-        let outputURL = URL(fileURLWithPath: outputPath)
-        
-        let asset = AVAsset(url: inputURL)
-        self.loadTracks(asset: asset, type: .video) { videoTracks in
-            guard let videoTrack = videoTracks.first else {
-                completion(false, NSError(domain: "Clean Transform", code: -1, userInfo: [NSLocalizedDescriptionKey: "Video track is not available"]))
-                return
-            }
-            
-            let videoComposition = AVMutableComposition()
-            guard let track = videoComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) else {
-                return
-            }
-            do {
-                try track.insertTimeRange(CMTimeRangeMake(start: .zero, duration: asset.duration),
-                                      of: videoTrack,
-                                      at: .zero)
-                track.preferredTransform = .identity
-                
-                let exportSession = AVAssetExportSession(asset: videoComposition, presetName: AVAssetExportPresetPassthrough)!
-                exportSession.outputURL = outputURL
-                exportSession.outputFileType = .mov
-                
-                exportSession.exportAsynchronously {
-                    DispatchQueue.main.async {
-                        switch exportSession.status {
-                        case .completed:
-                            completion(true, nil)
-                        case .failed:
-                            completion(false, exportSession.error)
-                        default:
-                            break
-                        }
-                    }
-                }
-            } catch {
-                print("\(error)")
-            }
-        }
-    }
-    
-    @objc public func accelerateVideo(at inputPath: String, to duration: CMTime, outputPath: String, completion: @escaping (Bool, Error?) -> Void) {
-        let videoURL = URL(fileURLWithPath: inputPath)
-        let asset = AVAsset(url: videoURL)
-
-        let composition = AVMutableComposition()
-        self.loadTracks(asset: asset, type: .video) { videoTracks in
-            do {
-                guard let videoTrack = videoTracks.first else {
-                    completion(false, NSError(domain: "Accelerate", code: -1, userInfo: [NSLocalizedDescriptionKey: "Video track is not available"]))
-                    return
-                }
-                
-                let compositionVideoTrack = composition.addMutableTrack(withMediaType: .video,
-                                                                         preferredTrackID: kCMPersistentTrackID_Invalid)
-                
-                try compositionVideoTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: asset.duration),
-                                                            of: videoTrack,
-                                                            at: .zero)
-                let targetDuration = duration
-                
-                compositionVideoTrack?.scaleTimeRange(CMTimeRangeMake(start: .zero, duration: asset.duration),
-                                                       toDuration: targetDuration)
-                compositionVideoTrack?.preferredTransform = videoTrack.preferredTransform
-                
-                guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {
-                    return
-                }
-                
-                let outputFileURL = URL(fileURLWithPath: outputPath)
-                exportSession.outputURL = outputFileURL
-                exportSession.outputFileType = .mov
-                exportSession.exportAsynchronously {
-                    switch exportSession.status {
-                    case .completed:
-                        completion(true, nil)
-                    case .failed:
-                        completion(false, exportSession.error)
-                    default:
-                        completion(false, NSError(domain: "VideoProcessing", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown error"]))
-                    }
-                }
-
-            } catch {
-                completion(false, error)
-            }
-        }
-    }
-    
-    
-    @objc public func resizeVideo(at inputPath: String, outputPath: String, outputSize: CGSize, completion: @escaping (Bool, Error?) -> Void) {
-        let inputURL = URL(fileURLWithPath: inputPath)
-        let outputURL = URL(fileURLWithPath: outputPath)
-        
-        let asset = AVAsset(url: inputURL)
-        self.loadTracks(asset: asset, type: .video) { videoTracks in
-            guard let videoTrack = videoTracks.first else {
-                completion(false, NSError(domain: "Resize", code: -1, userInfo: [NSLocalizedDescriptionKey: "Video track is not available"]))
-                return
-            }
-            
-            let originDegree = self.degressFromVideoFileWithURL(videoTrack: videoTrack)
-            if originDegree != 0 {
-                let tmpPath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first! + "/tmp.mp4"
-                try? FileManager.default.removeItem(atPath: tmpPath)
-                self.cleanTransformVideo(at: inputPath, outputPath: tmpPath) { success, error in
-                    self.rotateVideo(at: tmpPath, outputPath: outputPath, degree: originDegree, completion: completion)
-                }
-                return
-            }
-            
-            let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)!
-            exportSession.outputURL = outputURL
-            exportSession.outputFileType = .mov
-            exportSession.shouldOptimizeForNetworkUse = true
-            
-            let videoComposition = AVMutableVideoComposition()
-            videoComposition.renderSize = outputSize
-            videoComposition.frameDuration = CMTime(value: 1, timescale: 60)
-            
-            let instruction = AVMutableVideoCompositionInstruction()
-            instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
-            
-            let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
-            
-            let preferredTransform = videoTrack.preferredTransform
-
-            let originalSize = CGSize(width: videoTrack.naturalSize.width, height: videoTrack.naturalSize.height)
-            let transformedSize = originalSize.applying(preferredTransform)
-            let absoluteSize = CGSize(width: abs(transformedSize.width), height: abs(transformedSize.height))
-            
-            let widthRatio = outputSize.width / absoluteSize.width
-            let heightRatio = outputSize.height / absoluteSize.height
-            let scaleFactor = max(widthRatio, heightRatio)
-
-            let newWidth = absoluteSize.width * scaleFactor
-            let newHeight = absoluteSize.height * scaleFactor
-
-            let translateX = (outputSize.width - newWidth) / 2
-            let translateY = (outputSize.height - newHeight) / 2
-
-            let translateTransform = CGAffineTransform(translationX: translateX, y: translateY).scaledBy(x: scaleFactor, y: scaleFactor)
-
-            layerInstruction.setTransform(translateTransform, at: .zero)
-            
-            instruction.layerInstructions = [layerInstruction]
-            videoComposition.instructions = [instruction]
-            
-            exportSession.videoComposition = videoComposition
-            
-            exportSession.exportAsynchronously {
-                DispatchQueue.main.async {
-                    switch exportSession.status {
-                    case .completed:
-                        completion(true, nil)
-                    case .failed:
-                        completion(false, exportSession.error)
-                    default:
-                        break
-                    }
-                }
-            }
-        }
-    }
-    
-    @objc public func rotateVideo(at inputPath: String, outputPath: String, degree: Int, completion: @escaping (Bool, Error?) -> Void) {
-        let inputURL = URL(fileURLWithPath: inputPath)
-        let outputURL = URL(fileURLWithPath: outputPath)
-        
-        let asset = AVAsset(url: inputURL)
-        self.loadTracks(asset: asset, type: .video) { videoTracks in
-            guard let videoTrack = videoTracks.first else {
-                completion(false, NSError(domain: "Resize", code: -1, userInfo: [NSLocalizedDescriptionKey: "Video track is not available"]))
-                return
-            }
-            
-            let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)!
-            exportSession.outputURL = outputURL
-            exportSession.outputFileType = .mov
-            exportSession.shouldOptimizeForNetworkUse = true
-            
-            let videoComposition = AVMutableVideoComposition()
-            videoComposition.renderSize =  abs(degree) == 90 ? CGSizeMake(videoTrack.naturalSize.height, videoTrack.naturalSize.width) : videoTrack.naturalSize
-            videoComposition.frameDuration = CMTime(value: 1, timescale: 60)
-            
-            let instruction = AVMutableVideoCompositionInstruction()
-            instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
-            
-            let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
-
-            let translateTransform = CGAffineTransform(rotationAngle: Double.pi / 2)
-
-            if (degree == 90) {
-                layerInstruction.setTransform(CGAffineTransform(translationX: videoTrack.naturalSize.height, y: 0).rotated(by: .pi / 2), at: .zero)
-            } else if (degree == -90) {
-                layerInstruction.setTransform(CGAffineTransform(translationX: 0, y: videoTrack.naturalSize.width).rotated(by: -.pi / 2), at: .zero)
-            } else {
-                layerInstruction.setTransform(CGAffineTransform(translationX: videoTrack.naturalSize.width, y: videoTrack.naturalSize.height).rotated(by: .pi), at: .zero)
-            }
-            
-            instruction.layerInstructions = [layerInstruction]
-            videoComposition.instructions = [instruction]
-            
-            exportSession.videoComposition = videoComposition
-            
-            exportSession.exportAsynchronously {
-                DispatchQueue.main.async {
-                    switch exportSession.status {
-                    case .completed:
-                        completion(true, nil)
-                    case .failed:
-                        completion(false, exportSession.error)
-                    default:
-                        break
-                    }
-                }
-            }
-        }
-    }
-    
-    private func loadTracks(asset: AVAsset, type: AVMediaType, completion: @escaping ([AVAssetTrack]) -> Void) {
-        let tracksKey = #keyPath(AVAsset.tracks)
-        if #available(iOS 15.0, *) {
-            asset.loadTracks(withMediaType: type) { tracks, error in
-                if let error = error {
-                    print(error)
-                }
-                DispatchQueue.main.async {
-                    completion(tracks ?? [])
-                }
-            }
-        } else {
-            asset.loadValuesAsynchronously(forKeys: [tracksKey]) {
-                let status = asset.statusOfValue(forKey: "tracks", error: nil)
-                if (status == .loaded) {
-                    DispatchQueue.main.async {
-                        print(asset) // <-- amazing trick
-                        completion(asset.tracks(withMediaType: type))
-                    }
-                } else if (status == .cancelled) {
-                    print("load tracks cancelled")
-                } else if (status == .unknown) {
-                    print("load tracks unknown")
-                } else if (status == .failed) {
-                    print("load tracks failed")
-                }
-            }
-        }
-    }
-
-    @objc public func durationVideo(at inputPath: String, outputPath: String, targetDuration: Double, completion: @escaping (Bool, Error?) -> Void) {
-        let asset = AVURLAsset(url: URL(fileURLWithPath: inputPath))
-        let duration = asset.duration
-        let timeScale = Int32(duration.timescale)
-        
-        let length = CMTimeGetSeconds(asset.duration)
-        if length <= targetDuration {
-            let composition = AVMutableComposition()
-            
-            guard let compositionTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) else {
-                return
-            }
-
-            guard let assetTrack = asset.tracks(withMediaType: .video).first else {
-                return
-            }
-            
-            compositionTrack.preferredTransform = assetTrack.preferredTransform
-
-            do {
-                try compositionTrack.insertTimeRange(CMTimeRange(start: .zero, duration: duration),
-                                                     of: assetTrack,
-                                                     at: .zero)
-            } catch {
-                print("Failed to insert time range: \(error)")
-                completion(false, error)
-                return
-            }
-            
-            guard let firstFrame = getFrame(from: asset, at: CMTime(value: 0, timescale: timeScale)) else {
-                print("Failed to insert getFrame firstFrame")
-                completion(false, NSError(domain: "Failed to insert getFrame firstFrame", code: 0))
-                return
-            }
-            guard let lastFrame = getFrame(from: asset, at: CMTimeSubtract(duration, CMTime(value: 1, timescale: timeScale))) else {
-                print("Failed to insert getFrame lastFrame")
-                completion(false, NSError(domain: "Failed to insert getFrame lastFrame", code: 0))
-                return
-            }
-            
-            let firstPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/first.mp4"
-            let lastPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/last.mp4"
-            let firstURL = URL(fileURLWithPath: firstPath)
-            let lastURL = URL(fileURLWithPath: lastPath)
-            try? FileManager.default.removeItem(atPath: firstPath)
-            try? FileManager.default.removeItem(atPath: lastPath)
-            
-            let prefixDuration = CMTime(seconds: (targetDuration - duration.seconds) / 2, preferredTimescale: timeScale)
-            let suffixDuration = CMTime(seconds: (targetDuration - duration.seconds) / 2, preferredTimescale: timeScale)
-            
-            self.createVideo(from: firstFrame, duration: CMTime(value: Int64(1 * timeScale), timescale: timeScale), outputURL: firstURL) { success in
-                self.appendToComposition(compositionTrack, asset: AVAsset(url: firstURL), duration: prefixDuration, at: .zero)
-                self.createVideo(from: lastFrame, duration: CMTime(value: Int64(1 * timeScale), timescale: timeScale), outputURL: lastURL) { success in
-                    self.appendToComposition(compositionTrack, asset: AVAsset(url: lastURL), duration: suffixDuration, at: CMTimeAdd(prefixDuration, duration))
-                    let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality)
-                    exporter?.outputURL = URL(fileURLWithPath: outputPath)
-                    exporter?.outputFileType = .mp4
-                    exporter?.exportAsynchronously {
-                        switch exporter?.status {
-                        case .completed:
-                            completion(true, nil)
-                        default:
-                            completion(false, exporter?.error)
-                        }
-                    }
-                }
-            }
-        } else {
-            
-            let startTime = length / 2 - targetDuration / 2
-            let endTime = length / 2 + targetDuration / 2
-            
-            let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)!
-            exportSession.outputURL = URL(fileURLWithPath: outputPath)
-            exportSession.outputFileType = .mp4
-            exportSession.timeRange = CMTimeRangeFromTimeToTime(start: CMTimeMakeWithSeconds(startTime, preferredTimescale: timeScale), end: CMTimeMakeWithSeconds(endTime, preferredTimescale: timeScale))
-            exportSession.exportAsynchronously {
-                switch exportSession.status {
-                case .completed:
-                    completion(true, nil)
-                default:
-                    completion(false, exportSession.error)
-                }
-            }
-        }
-    }
-
-    func getFrame(from asset: AVAsset, at timestamp: CMTime) -> UIImage? {
-        let imageGenerator = AVAssetImageGenerator(asset: asset)
-        imageGenerator.requestedTimeToleranceBefore = .zero
-        imageGenerator.requestedTimeToleranceAfter = .zero
-
-        var actualTime = CMTime.zero
-        let cgImage = try? imageGenerator.copyCGImage(at: timestamp, actualTime: &actualTime)
-        return cgImage.map(UIImage.init)
-    }
-
-    func appendToComposition(_ compositionTrack: AVMutableCompositionTrack, asset: AVAsset, duration: CMTime, at: CMTime) {
-        guard let assetTrack = asset.tracks(withMediaType: .video).first else { return }
-        
-        let frameDuration = CMTime(value: 1, timescale: 30)
-        var currentTime = at
-        let endTime = CMTimeAdd(currentTime, duration)
-
-        while currentTime < endTime {
-            let nextTime = CMTimeAdd(currentTime, frameDuration)
-            do {
-                try compositionTrack.insertTimeRange(CMTimeRange(start: .zero, duration: frameDuration),
-                                                     of: assetTrack,
-                                                     at: currentTime)
-            } catch {
-                print("Error inserting time range: \(error)")
-                return
-            }
-            currentTime = nextTime
-        }
-    }
-
-    @objc func createVideo(from image: UIImage, duration: CMTime, outputURL: URL, completion: @escaping (Bool) -> Void) {
-        let writer = try? AVAssetWriter(outputURL: outputURL, fileType: .mov)
-
-        let writerInput = AVAssetWriterInput(mediaType: .video, outputSettings: [
-            AVVideoCodecKey: AVVideoCodecType.h264,
-            AVVideoWidthKey: NSNumber(value: Float(image.size.width)),
-            AVVideoHeightKey: NSNumber(value: Float(image.size.height))
-        ])
-
-        let adaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: writerInput, sourcePixelBufferAttributes: nil)
-
-        writer?.add(writerInput)
-
-        writer?.startWriting()
-        writer?.startSession(atSourceTime: .zero)
-
-        let buffer = pixelBuffer(from: image)
-
-        var frameCount = 0.0
-        let frameDuration = CMTime(value: 1, timescale: 30) // Example frame rate: 30 fps
-        var presentTime = CMTime.zero
-
-        writerInput.requestMediaDataWhenReady(on: DispatchQueue(label: "mediaInputQueue")) {
-            while frameCount < duration.seconds * 30 { // 30 fps * duration in seconds
-                if writerInput.isReadyForMoreMediaData {
-                    if let buffer = buffer {
-                        adaptor.append(buffer, withPresentationTime: presentTime)
-                    }
-                    presentTime = CMTimeAdd(presentTime, frameDuration)
-                    frameCount += 1
-                }
-            }
-            writerInput.markAsFinished()
-            writer?.finishWriting {
-                switch writer?.status {
-                case .completed:
-                    print("Video file created successfully.")
-                    completion(true)
-                default:
-                    print("Failed to write video file: \(writer?.error?.localizedDescription ?? "Unknown error")")
-                    completion(false)
-                }
-            }
-        }
-    }
-
-    func pixelBuffer(from image: UIImage) -> CVPixelBuffer? {
-        let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
-        var pixelBuffer: CVPixelBuffer?
-        let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(image.size.width), Int(image.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer)
-        guard status == kCVReturnSuccess else {
-            return nil
-        }
-
-        CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
-        let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!)
-
-        let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
-        let context = CGContext(data: pixelData, width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
-
-        context?.translateBy(x: 0, y: image.size.height)
-        context?.scaleBy(x: 1.0, y: -1.0)
-
-        UIGraphicsPushContext(context!)
-        image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
-        UIGraphicsPopContext()
-        CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
-
-        return pixelBuffer
-    }
-}

+ 0 - 279
TSLiveWallpaper/Common/ThirdParty/Util/LivePhotoConverter.swift

@@ -1,279 +0,0 @@
-//
-//  LivePhotoTool.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/31.
-//
-
-import Foundation
-import AVFoundation
-import UIKit
-import Photos
-
-class LivePhotoConverter {
-    
-    static func convertVideo(
-        _ videoURL: URL,
-        imageURL:URL? = nil,
-        completion: @escaping (Bool, URL?, URL?, String?) -> Void
-    ) {
-        print("Start converting...")
-        
-        guard let metaURL = Bundle.main.url(forResource: "metadata", withExtension: "mov") else {
-//        guard let metaURL = Bundle.main.url(forResource: "output", withExtension: "mov") else {
-            completion(false, nil, nil, "Metadata file not found")
-            return
-        }
-        
-        
-        let fileManager = FileManager.default
-        let eidtVideoPathURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("livePhoto").appendingPathComponent("editVideo")
-
-        
-        
-        let documentPath = eidtVideoPathURL.path
-        let durationPath = "\(documentPath)/duration.mp4"
-        let acceleratePath = "\(documentPath)/accelerate.mp4"
-        let resizePath = "\(documentPath)/resize.mp4"
-        
-        let destinationDirectory = eidtVideoPathURL
-        // 如果目标文件夹不存在,创建文件夹
-        if !fileManager.fileExists(atPath: destinationDirectory.path) {
-            do {
-                try fileManager.createDirectory(at: destinationDirectory, withIntermediateDirectories: true, attributes: nil)
-                debugPrint("创建文件夹成功")
-            } catch {
-                debugPrint("尝试创建文件夹失败: \(error.localizedDescription)")
-            }
-        }
-        
-        try? FileManager.default.removeItem(atPath: durationPath)
-        try? FileManager.default.removeItem(atPath: acceleratePath)
-        try? FileManager.default.removeItem(atPath: resizePath)
-        
-        let asset = AVURLAsset(url: videoURL)
-        let targetDuration = CMTimeGetSeconds(asset.duration)
-//        let videoSize = asset.tracks(withMediaType: .video).first?.naturalSize ?? CGSize(width: 1080, height: 1920)
-//        let videoSize = CGSize(width: 1080, height: 1920)
-        
-        let videoSize = CGSize(width: 1080, height: 1920)
-//        let livePhotoDuration = CMTimeMake(value: 550, timescale: 600)
-        let livePhotoDuration = CMTimeMake(value: 550, timescale: 600)
-        let assetIdentifier = UUID().uuidString
-        let finalPath = resizePath
-        let converter = Converter4Video(path: finalPath)
-        
-        converter.durationVideo(at: videoURL.path, outputPath: durationPath, targetDuration: targetDuration) { success, error in
-            guard success else {
-                completion(false, nil, nil, error?.localizedDescription)
-                return
-            }
-            
-            converter.accelerateVideo(at: durationPath, to: livePhotoDuration, outputPath: acceleratePath) { success, error in
-                guard success else {
-                    completion(false, nil, nil, error?.localizedDescription)
-                    return
-                }
-
-                converter.resizeVideo(at: acceleratePath, outputPath: resizePath, outputSize: videoSize) { success, error in
-                    guard success else {
-                        completion(false, nil, nil, error?.localizedDescription)
-                        return
-                    }
-
-                    let picturePath = "\(documentPath)/live.heic"
-                    let videoPath = "\(documentPath)/live.mov"
-                    
-                    try? FileManager.default.removeItem(atPath: picturePath)
-                    try? FileManager.default.removeItem(atPath: videoPath)
-                    
-                    let asset = AVURLAsset(url:URL(fileURLWithPath: finalPath))
-                    var image:UIImage? = nil
-                    if let imageURL = imageURL {
-                        image = UIImage(contentsOfFile: imageURL.path)
-                    }else{
-                        if let imageData = self.generateKeyPhoto(from: asset) {
-                            image = UIImage(data: imageData)
-                        }
-                    }
-                    
-                    guard let image = image else {
-                        completion(false, nil, nil, "image nil")
-                        return
-                    }
-                    
-                    let imageConverter = Converter4Image(image:image)
-                    imageConverter.write(dest: picturePath, assetIdentifier: assetIdentifier)
-                    converter.write(dest: videoPath, assetIdentifier: assetIdentifier, metaURL: metaURL) { success, error in
-                        guard success else {
-                            completion(false, nil, nil, error?.localizedDescription)
-                            return
-                        }
-                        
-                        let photoURL = URL(fileURLWithPath: picturePath)
-                        let pairedVideoURL = URL(fileURLWithPath: videoPath)
-                        
-                        debugPrint("picturePath=\(picturePath)")
-                        debugPrint("videoPath=\(videoPath)")
-                        
-                        DispatchQueue.main.async {
-                            completion(success, photoURL, pairedVideoURL, error?.localizedDescription)
-                        }
-                    }
-                }
-            }
-        }
-    }
-    
-    
-    
-//    static func convertVideo(
-//        _ videoURL: URL,
-//        imageURL:URL? = nil,
-//        completion: @escaping (Bool, URL?, URL?, String?) -> Void
-//    ) {
-//        print("Start converting...")
-//        
-//        guard let metaURL = Bundle.main.url(forResource: "metadata", withExtension: "mov") else {
-//            completion(false, nil, nil, "Metadata file not found")
-//            return
-//        }
-//        
-//        
-//        let fileManager = FileManager.default
-//        let eidtVideoPathURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("livePhoto").appendingPathComponent("editVideo")
-//
-//        
-//        
-//        let documentPath = eidtVideoPathURL.path
-//        let durationPath = "\(documentPath)/duration.mp4"
-//        let acceleratePath = "\(documentPath)/accelerate.mp4"
-//        let resizePath = "\(documentPath)/resize.mp4"
-//        
-//        let destinationDirectory = eidtVideoPathURL
-//        // 如果目标文件夹不存在,创建文件夹
-//        if !fileManager.fileExists(atPath: destinationDirectory.path) {
-//            do {
-//                try fileManager.createDirectory(at: destinationDirectory, withIntermediateDirectories: true, attributes: nil)
-//                debugPrint("创建文件夹成功")
-//            } catch {
-//                debugPrint("尝试创建文件夹失败: \(error.localizedDescription)")
-//            }
-//        }
-//        
-//        try? FileManager.default.removeItem(atPath: durationPath)
-//        try? FileManager.default.removeItem(atPath: acceleratePath)
-//        try? FileManager.default.removeItem(atPath: resizePath)
-//        
-//        let asset = AVURLAsset(url: videoURL)
-//        let targetDuration = CMTimeGetSeconds(asset.duration)
-////        let videoSize = asset.tracks(withMediaType: .video).first?.naturalSize ?? CGSize(width: 1080, height: 1920)
-//        let videoSize = CGSize(width: 1080, height: 1920)
-//        let livePhotoDuration = CMTimeMake(value: 550, timescale: 600)
-//        let assetIdentifier = UUID().uuidString
-//        let finalPath = resizePath
-//        let converter = Converter4Video(path: finalPath)
-//        
-//        converter.durationVideo(at: videoURL.path, outputPath: durationPath, targetDuration: targetDuration) { success, error in
-//            guard success else {
-//                completion(false, nil, nil, error?.localizedDescription)
-//                return
-//            }
-//            
-//            converter.accelerateVideo(at: durationPath, to: livePhotoDuration, outputPath: acceleratePath) { success, error in
-//                guard success else {
-//                    completion(false, nil, nil, error?.localizedDescription)
-//                    return
-//                }
-//                
-//                converter.resizeVideo(at: acceleratePath, outputPath: resizePath, outputSize: videoSize) { success, error in
-//                    guard success else {
-//                        completion(false, nil, nil, error?.localizedDescription)
-//                        return
-//                    }
-//
-//                    let picturePath = "\(documentPath)/live.heic"
-//                    let videoPath = "\(documentPath)/live.mov"
-//                    
-//                    try? FileManager.default.removeItem(atPath: picturePath)
-//                    try? FileManager.default.removeItem(atPath: videoPath)
-//                    
-//                    let asset = AVURLAsset(url:URL(fileURLWithPath: finalPath))
-//                    var image:UIImage? = nil
-//                    if let imageURL = imageURL {
-//                        image = UIImage(contentsOfFile: imageURL.path)
-//                    }else{
-//                        if let imageData = self.generateKeyPhoto(from: asset) {
-//                            image = UIImage(data: imageData)
-//                        }
-//                    }
-//                    
-//                    guard let image = image else {
-//                        completion(false, nil, nil, "image nil")
-//                        return
-//                    }
-//                    
-//                    let imageConverter = Converter4Image(image:image)
-//                    imageConverter.write(dest: picturePath, assetIdentifier: assetIdentifier)
-//                    converter.write(dest: videoPath, assetIdentifier: assetIdentifier, metaURL: metaURL) { success, error in
-//                        guard success else {
-//                            completion(false, nil, nil, error?.localizedDescription)
-//                            return
-//                        }
-//                        
-//                        let photoURL = URL(fileURLWithPath: picturePath)
-//                        let pairedVideoURL = URL(fileURLWithPath: videoPath)
-//                        
-//                        debugPrint("picturePath=\(picturePath)")
-//                        debugPrint("videoPath=\(videoPath)")
-//                        
-//                        DispatchQueue.main.async {
-//                            completion(success, photoURL, pairedVideoURL, error?.localizedDescription)
-//                        }
-//                    }
-//                }
-//            }
-//        }
-//    }
-    
-
-    private static func generateKeyPhoto(from videoAsset: AVAsset) -> Data? {
-        var percent:Float = 0.5
-        if let stillImageTime = videoAsset.stillImageTime() {
-            percent = Float(stillImageTime.value) / Float(videoAsset.duration.value)
-        }
-        guard let imageFrame = videoAsset.getAssetFrame(percent: percent) else { return nil }
-        guard let jpegData = imageFrame.jpegData(compressionQuality: 1.0) else { return nil }
-        return jpegData
-    }
-    
-    static func livePhotoRequest(videoURL:URL,imageURL:URL,completion: @escaping (PHLivePhoto?) -> Void){
-        _ = PHLivePhoto.request(withResourceFileURLs: [videoURL, imageURL], placeholderImage: nil, targetSize: CGSize.zero, contentMode: PHImageContentMode.aspectFill, resultHandler: { (livePhoto: PHLivePhoto?, info: [AnyHashable : Any]) -> Void in
-            if let isDegraded = info[PHLivePhotoInfoIsDegradedKey] as? Bool, isDegraded {
-                return
-            }
-            DispatchQueue.main.async {
-                completion(livePhoto)
-            }
-        })
-    }
-    
-
-    static func saveToLibrary(videoURL:URL,imageURL:URL,completion: @escaping (Bool) -> Void){
-        PHPhotoLibrary.shared().performChanges({
-            let creationRequest = PHAssetCreationRequest.forAsset()
-            let options = PHAssetResourceCreationOptions()
-            creationRequest.addResource(with: PHAssetResourceType.pairedVideo, fileURL: videoURL, options: options)
-            creationRequest.addResource(with: PHAssetResourceType.photo, fileURL: imageURL, options: options)
-        }, completionHandler: { (success, error) in
-            if error != nil {
-                print(error as Any)
-            }
-            DispatchQueue.main.async {
-                completion(success)
-            }
-        })
-    }
-    
-}
-

+ 0 - 7
TSLiveWallpaper/Common/ThirdParty/Util/LivePhotoUtil.h

@@ -1,7 +0,0 @@
-#import <Foundation/Foundation.h>
-
-@interface LivePhotoUtil : NSObject
-
-+ (void)convertVideo:(NSString*)path complete:(void(^)(BOOL, NSString*))complete;
-
-@end

+ 0 - 168
TSLiveWallpaper/Common/ThirdParty/Util/LivePhotoUtil.m

@@ -1,168 +0,0 @@
-#import <TSLiveWallpaper-Swift.h>
-#import "LivePhotoUtil.h"
-#import <Photos/Photos.h>
-#import <UIKit/UIKit.h>
-#import <ImageIO/ImageIO.h>
-#import <MobileCoreServices/MobileCoreServices.h>
-
-@implementation LivePhotoUtil
-
-
-
-+ (void)convertVideo:(NSString*)path complete:(void(^)(BOOL, NSString*))complete{
-    NSLog(@"start converting");
-    
-    NSURL *metaURL = [NSBundle.mainBundle URLForResource:@"metadata" withExtension:@"mov"];
-    CGSize livePhotoSize = CGSizeMake(1080, 1920);
-    CMTime livePhotoDuration = CMTimeMake(550, 600);
-    NSString *assetIdentifier = NSUUID.UUID.UUIDString;
-    
-    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
-    NSString *durationPath = [documentPath stringByAppendingString:@"/duration.mp4"];
-    NSString *acceleratePath = [documentPath stringByAppendingString:@"/accelerate.mp4"];
-    NSString *resizePath = [documentPath stringByAppendingString:@"/resize.mp4"];
-    [NSFileManager.defaultManager removeItemAtPath:durationPath error:nil];
-    [NSFileManager.defaultManager removeItemAtPath:acceleratePath error:nil];
-    [NSFileManager.defaultManager removeItemAtPath:resizePath error:nil];
-    NSString *finalPath = resizePath;
-    
-    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path] options:nil];
-    CGFloat targetDuration = 3;
-//    targetDuration = CMTimeGetSeconds(asset.duration);
-//    livePhotoSize = asset.tracks.firstObject.naturalSize;
-    
-
-    Converter4Video *converter = [[Converter4Video alloc] initWithPath:finalPath];
-    [converter durationVideoAt:path outputPath:durationPath targetDuration:targetDuration completion:^(BOOL success, NSError * error) {
-        [converter accelerateVideoAt:durationPath to:livePhotoDuration outputPath:acceleratePath completion:^(BOOL success, NSError * error) {
-            [converter resizeVideoAt:acceleratePath outputPath:resizePath outputSize:livePhotoSize completion:^(BOOL success, NSError * error) {
-                
-                AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:finalPath] options:nil];
-                AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
-                generator.appliesPreferredTrackTransform = YES;
-                generator.requestedTimeToleranceAfter = kCMTimeZero;
-                generator.requestedTimeToleranceBefore = kCMTimeZero;
-                    NSMutableArray *times = @[].mutableCopy;
-            //        for (int i=0; i<10; i++) {
-            //            if (i!=5) {
-            //                continue;
-            //            }
-                        CMTime time = CMTimeMakeWithSeconds(0.5, asset.duration.timescale);
-                        [times addObject:[NSValue valueWithCMTime:time]];
-            //        }
-                    dispatch_queue_t q = dispatch_queue_create("image", DISPATCH_QUEUE_SERIAL);
-                    __block int index = 0;
-                [generator generateCGImagesAsynchronouslyForTimes:times completionHandler:^(CMTime requestedTime, CGImageRef  _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
-                    if (image){
-                        NSString *picturePath = [documentPath stringByAppendingFormat:@"/%@%d.heic", @"live", index, nil];
-                        NSString *videoPath = [documentPath stringByAppendingFormat:@"/%@%d.mov", @"live", index, nil];
-                        index += 1;
-                        [NSFileManager.defaultManager removeItemAtPath:picturePath error:nil];
-                        [NSFileManager.defaultManager removeItemAtPath:videoPath error:nil];
-                        
-                        Converter4Image *converter4Image = [[Converter4Image alloc] initWithImage:[UIImage imageWithCGImage:image]];
-                        dispatch_async(q, ^{
-                            [converter4Image writeWithDest:picturePath assetIdentifier:assetIdentifier];
-                            [converter writeWithDest:videoPath assetIdentifier:assetIdentifier metaURL:metaURL completion:^(BOOL success, NSError * error) {
-                                if (!success) {
-                                    NSLog(@"merge failed: %@", error);
-                                    complete(NO, error.localizedDescription);
-                                    return;
-                                }
-                                [PHPhotoLibrary.sharedPhotoLibrary performChanges:^{
-                                    PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
-                                    NSURL *photoURL = [NSURL fileURLWithPath:picturePath];
-                                    NSURL *pairedVideoURL = [NSURL fileURLWithPath:videoPath];
-                                    [request addResourceWithType:PHAssetResourceTypePhoto fileURL:photoURL options:[PHAssetResourceCreationOptions new]];
-                                    [request addResourceWithType:PHAssetResourceTypePairedVideo fileURL:pairedVideoURL options:[PHAssetResourceCreationOptions new]];
-                                } completionHandler:^(BOOL success, NSError * _Nullable error) {
-                                    dispatch_async(dispatch_get_main_queue(), ^{
-                                        complete(error==nil, error.localizedDescription);
-                                    });
-                                }];
-                            }];
-                        });
-                    }
-                }];
-            }];
-        }];
-    }];
-}
-
-
-//+ (void)convertVideo:(NSString*)path complete:(void(^)(BOOL, NSString*))complete{
-//    NSLog(@"start converting");
-//    
-//    NSURL *metaURL = [NSBundle.mainBundle URLForResource:@"metadata" withExtension:@"mov"];
-//    CGSize livePhotoSize = CGSizeMake(1080, 1920);
-//    CMTime livePhotoDuration = CMTimeMake(550, 600);
-//    NSString *assetIdentifier = NSUUID.UUID.UUIDString;
-//    
-//    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
-//    NSString *durationPath = [documentPath stringByAppendingString:@"/duration.mp4"];
-//    NSString *acceleratePath = [documentPath stringByAppendingString:@"/accelerate.mp4"];
-//    NSString *resizePath = [documentPath stringByAppendingString:@"/resize.mp4"];
-//    [NSFileManager.defaultManager removeItemAtPath:durationPath error:nil];
-//    [NSFileManager.defaultManager removeItemAtPath:acceleratePath error:nil];
-//    [NSFileManager.defaultManager removeItemAtPath:resizePath error:nil];
-//    NSString *finalPath = resizePath;
-//
-//    Converter4Video *converter = [[Converter4Video alloc] initWithPath:finalPath];
-//    
-//    [converter durationVideoAt:path outputPath:durationPath targetDuration:3 completion:^(BOOL success, NSError * error) {
-//        [converter accelerateVideoAt:durationPath to:livePhotoDuration outputPath:acceleratePath completion:^(BOOL success, NSError * error) {
-//            [converter resizeVideoAt:acceleratePath outputPath:resizePath outputSize:livePhotoSize completion:^(BOOL success, NSError * error) {
-//                
-//                AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:finalPath] options:nil];
-//                AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
-//                generator.appliesPreferredTrackTransform = YES;
-//                generator.requestedTimeToleranceAfter = kCMTimeZero;
-//                generator.requestedTimeToleranceBefore = kCMTimeZero;
-//                    NSMutableArray *times = @[].mutableCopy;
-//            //        for (int i=0; i<10; i++) {
-//            //            if (i!=5) {
-//            //                continue;
-//            //            }
-//                        CMTime time = CMTimeMakeWithSeconds(0.5, asset.duration.timescale);
-//                        [times addObject:[NSValue valueWithCMTime:time]];
-//            //        }
-//                    dispatch_queue_t q = dispatch_queue_create("image", DISPATCH_QUEUE_SERIAL);
-//                    __block int index = 0;
-//                [generator generateCGImagesAsynchronouslyForTimes:times completionHandler:^(CMTime requestedTime, CGImageRef  _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
-//                    if (image){
-//                        NSString *picturePath = [documentPath stringByAppendingFormat:@"/%@%d.heic", @"live", index, nil];
-//                        NSString *videoPath = [documentPath stringByAppendingFormat:@"/%@%d.mov", @"live", index, nil];
-//                        index += 1;
-//                        [NSFileManager.defaultManager removeItemAtPath:picturePath error:nil];
-//                        [NSFileManager.defaultManager removeItemAtPath:videoPath error:nil];
-//                        
-//                        Converter4Image *converter4Image = [[Converter4Image alloc] initWithImage:[UIImage imageWithCGImage:image]];
-//                        dispatch_async(q, ^{
-//                            [converter4Image writeWithDest:picturePath assetIdentifier:assetIdentifier];
-//                            [converter writeWithDest:videoPath assetIdentifier:assetIdentifier metaURL:metaURL completion:^(BOOL success, NSError * error) {
-//                                if (!success) {
-//                                    NSLog(@"merge failed: %@", error);
-//                                    complete(NO, error.localizedDescription);
-//                                    return;
-//                                }
-//                                [PHPhotoLibrary.sharedPhotoLibrary performChanges:^{
-//                                    PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
-//                                    NSURL *photoURL = [NSURL fileURLWithPath:picturePath];
-//                                    NSURL *pairedVideoURL = [NSURL fileURLWithPath:videoPath];
-//                                    [request addResourceWithType:PHAssetResourceTypePhoto fileURL:photoURL options:[PHAssetResourceCreationOptions new]];
-//                                    [request addResourceWithType:PHAssetResourceTypePairedVideo fileURL:pairedVideoURL options:[PHAssetResourceCreationOptions new]];
-//                                } completionHandler:^(BOOL success, NSError * _Nullable error) {
-//                                    dispatch_async(dispatch_get_main_queue(), ^{
-//                                        complete(error==nil, error.localizedDescription);
-//                                    });
-//                                }];
-//                            }];
-//                        });
-//                    }
-//                }];
-//            }];
-//        }];
-//    }];
-//}
-
-@end

二進制
TSLiveWallpaper/Common/ThirdParty/Util/metadata.mov


+ 0 - 450
TSLiveWallpaper/Common/ThirdParty/VideoRecorder.swift

@@ -1,450 +0,0 @@
-//
-//  LivePhotoMaker.swift
-//  MediaManagerKit
-//
-//  Created by Max Mg on 2024/7/20.
-//
-
-import Foundation
-import AVFoundation
-//import ExtensionsKit
-
-public class VideoRecorder: NSObject {
-    public static let shared = VideoRecorder()
-    
-    public typealias LivePhotoCompletionHandler = (URL?, URL?, String?) -> Void
-    
-    class RecordConfig {
-        var duration: TimeInterval = 1
-        var frameRate: Int = 30
-        var captureView: UIView!
-        var completion: ((Error?) -> Void)?
-        var recordedDuration: TimeInterval = 0
-        var startTime: CFTimeInterval = CACurrentMediaTime()
-        var reqiureFrames: Int = 0
-        var recordFrames: Int = 0
-    }
-    
-    lazy var recordConfig = RecordConfig()
-    
-    var assetWriter: AVAssetWriter!
-    var assetWriterInput: AVAssetWriterInput!
-    var pixelBufferAdaptor: AVAssetWriterInputPixelBufferAdaptor!
-    
-    var timer: Timer?
-    lazy var isRecording = false
-    var displayLink: CADisplayLink?
-    let queue = DispatchQueue(label: "xxxxxx", attributes: .concurrent)
-    
-    var videoOutuptURL: URL {
-        let temp = FileManager.default.temporaryDirectory
-        return temp.appendingPathComponent("livePhotoOutput.mov")
-    }
-    
-    override init() {
-        super.init()
-    }
-    
-    public func capture(in view: UIView,
-                        duration: TimeInterval,
-                        outputFinder: URL,
-                        completion: LivePhotoCompletionHandler?) {
-        
-        captureVideo(in: view, duration: duration, frameRate: 30) { [weak self] videoURL, error in
-            guard let videoURL = videoURL else {
-                completion?(nil, nil, error?.localizedDescription)
-                return
-            }
-            LivePhotoCreater.shared.saveLivePhoto(from: videoURL, outputDirectory: outputFinder) { videoURL, imageURL, msg in
-                completion?(videoURL, imageURL, msg)
-            }
-        }
-    }
-    
-    /// 录制一个view生成视频
-    /// - Parameters:
-    ///   - view: 目标view
-    ///   - duration: 时长
-    ///   - frameRate: 帧率
-    ///   - completion: URL: 视频temp文件夹地址
-    public func captureVideo(in view: UIView,
-                             duration: TimeInterval,
-                             frameRate: Int,
-                             completion: ((URL?, Error?) -> Void)?) {
-        
-        guard !isRecording else {
-            recordConfig.completion?(NSError(domain: "Video is Recording, try again later", code: 401))
-            return
-        }
-        
-        recordConfig.duration = duration
-        recordConfig.frameRate = frameRate
-        recordConfig.reqiureFrames = Int(Double(frameRate) * duration)
-        recordConfig.recordFrames = 0
-        recordConfig.captureView = view
-        recordConfig.recordedDuration = 0
-        recordConfig.completion = { [weak self] error in
-            if let error = error {
-                completion?(nil, error)
-            } else {
-                completion?(self?.videoOutuptURL, nil)
-            }
-        }
-        
-        startRecordVideo()
-    }
-}
-
-// MARK: -- 视频录制
-extension VideoRecorder {
-    func startRecordVideo() {
-        guard !isRecording, let view = recordConfig.captureView else {
-            recordConfig.completion?(NSError(domain: "Video is Recording, try again later", code: 401))
-            return
-        }
-        
-        if FileManager.default.fileExists(atPath: videoOutuptURL.path) {
-            try? FileManager.default.removeItem(atPath: videoOutuptURL.path)
-        }
-        
-        do {
-            assetWriter = try AVAssetWriter(outputURL: videoOutuptURL, fileType: .mov)
-        } catch {
-            print("Error creating AVAssetWriter: \(error)")
-            recordConfig.completion?(error)
-        }
-        
-        let size = CGSize(width: view.bounds.width * UIScreen.main.scale, height: view.bounds.height * UIScreen.main.scale)
-//        let size = CGSize(width: view.bounds.width, height: view.bounds.height)
-        let outputSettings: [String: Any] = [
-            AVVideoCodecKey: AVVideoCodecType.h264,
-            AVVideoWidthKey: size.width,
-            AVVideoHeightKey: size.height
-        ]
-        assetWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: outputSettings)
-        assetWriterInput.expectsMediaDataInRealTime = true
-        assetWriter.add(assetWriterInput)
-        
-        let pixelBufferAttributes: [String: Any] = [
-            kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32ARGB,
-            kCVPixelBufferWidthKey as String: size.width,
-            kCVPixelBufferHeightKey as String: size.height
-        ]
-        pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: assetWriterInput, sourcePixelBufferAttributes: pixelBufferAttributes)
-        
-        assetWriter.startWriting()
-        assetWriter.startSession(atSourceTime: .zero)
-        isRecording = true
-        recordConfig.startTime = CACurrentMediaTime()
-        
-        // 第一帧
-        let layer = self.recordConfig.captureView.layer
-        let cgImage = layer.contents
-//        snapshotView(afterScreenUpdates: false)?.layer ?? self.recordConfig.captureView.layer
-        let videoSize = self.recordConfig.captureView.bounds.size
-//        queue.async {
-//            let image = self.drawViewHierarchyToImage(layer: layer)
-            if let pixelBuffer = self.createPixelBuffer(from: self.recordConfig.captureView, videoSize: videoSize) {
-                for _ in 0..<5 {
-                    while true {
-                        if self.pixelBufferAdaptor.assetWriterInput.isReadyForMoreMediaData {
-                            let presentationTime = CMTime(seconds: Double(recordConfig.recordedDuration), preferredTimescale: 600)
-                            self.pixelBufferAdaptor.append(pixelBuffer, withPresentationTime: presentationTime)
-                            
-                            recordConfig.recordFrames += 1
-                            recordConfig.recordedDuration += 1.0 / CGFloat(recordConfig.frameRate)
-                            Log("append===\(recordConfig.recordFrames)")
-                            break
-                        }
-                    }
-                }
-            }
-        
-//        appendPixelBuffer(at: CMTime.zero)
-        timer = Timer.scheduledTimer(withTimeInterval: 1.0 / CGFloat(recordConfig.frameRate), repeats: true) { [weak self] _ in
-            self?.timerHandler()
-        }
-//        displayLink = CADisplayLink(target: self, selector: #selector(timerHandler))
-//        displayLink?.preferredFramesPerSecond = 10
-//        displayLink?.add(to: .current, forMode: .common)
-    }
-    
-    func stopRecording() {
-        timer?.invalidate()
-        timer = nil
-        displayLink?.invalidate()
-        displayLink = nil
-        
-        assetWriterInput.markAsFinished()
-        assetWriter.finishWriting { [weak self] in
-            guard let self = self else { return }
-            self.isRecording = false
-            if self.assetWriter.status == .completed {
-                self.recordConfig.completion?(nil)
-            } else {
-                self.recordConfig.completion?(assetWriter.error)
-            }
-        }
-    }
-    
-    @objc func timerHandler() {
-        if recordConfig.recordFrames >= recordConfig.reqiureFrames {
-//        if recordConfig.recordedDuration >= recordConfig.duration {
-            stopRecording()
-            return
-        }
-        let presentationTime = CMTime(seconds: Double(recordConfig.recordedDuration), preferredTimescale: 600)
-        self.appendPixelBuffer(at: presentationTime)
-        recordConfig.recordFrames += 1
-        recordConfig.recordedDuration += 1.0 / CGFloat(recordConfig.frameRate)
-        Log("===\(recordConfig.recordedDuration)")
-    }
-}
-
-extension VideoRecorder {
-    func appendPixelBuffer(at time: CMTime) {
-        let layer = self.recordConfig.captureView.layer
-        let cgImage = layer.contents
-//        snapshotView(afterScreenUpdates: false)?.layer ?? self.recordConfig.captureView.layer
-        let size = self.recordConfig.captureView.bounds.size
-//        queue.async {
-//            let image = self.drawViewHierarchyToImage(layer: layer)
-            if let pixelBuffer = self.createPixelBuffer(from: self.recordConfig.captureView, videoSize: size),
-               self.pixelBufferAdaptor.assetWriterInput.isReadyForMoreMediaData {
-                self.pixelBufferAdaptor.append(pixelBuffer, withPresentationTime: time)
-            }
-//        }
-    }
-    
-    /// 获取Buffer
-    func createPixelBuffer(from view: UIView, videoSize: CGSize) -> CVPixelBuffer? {
-//        let videoSize = view.frame.size
-//        var contextSize = videoSize
-        var contextSize = CGSize(width: videoSize.width*UIScreen.main.scale, height: videoSize.height*UIScreen.main.scale)
-        
-        let pixelBufferAttributes: [String: Any] = [
-            kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32ARGB,
-            kCVPixelBufferWidthKey as String: contextSize.width,
-            kCVPixelBufferHeightKey as String: contextSize.height
-        ]
-        
-        var pixelBuffer: CVPixelBuffer?
-        let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(contextSize.width), Int(contextSize.height), kCVPixelFormatType_32ARGB, pixelBufferAttributes as CFDictionary, &pixelBuffer)
-        
-        if status != kCVReturnSuccess || pixelBuffer == nil {
-            print("Error creating pixel buffer")
-            return nil
-        }
-        
-        CVPixelBufferLockBaseAddress(pixelBuffer!, .init(rawValue: 0))
-        guard let context = CGContext(data: CVPixelBufferGetBaseAddress(pixelBuffer!),
-                                width: Int(contextSize.width),
-                                height: Int(contextSize.height),
-                                bitsPerComponent: 8,
-                                bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!),
-                                space: CGColorSpaceCreateDeviceRGB(),
-                                      bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue) else {
-            return nil
-        }
-        
-        context.translateBy(x: contextSize.width / 2, y: contextSize.height / 2)
-        context.scaleBy(x: 1, y: -1) // Flip vertically
-        context.translateBy(x: -contextSize.width / 2, y: -contextSize.height / 2)
-        
-        UIGraphicsPushContext(context)
-//        context.saveGState()
-//        CGContextSaveGState(context)
-//        layer.render(in: context)
-//        context.restoreGState()
-//        image.draw(in: CGRect(origin: .zero, size: contextSize))
-        
-        view.drawHierarchy(in: CGRect(origin: .zero, size: contextSize), afterScreenUpdates: false)
-        UIGraphicsPopContext()
-        
-        CVPixelBufferUnlockBaseAddress(pixelBuffer!, .init(rawValue: 0))
-        
-        return pixelBuffer
-    }
-    
-    func drawViewHierarchyToImage(layer: CALayer) -> UIImage? {
-        // 创建绘制上下文
-        UIGraphicsBeginImageContextWithOptions(UIScreen.main.bounds.size, false, UIScreen.main.scale)
-        defer { UIGraphicsEndImageContext() }
-
-        guard let context = UIGraphicsGetCurrentContext() else { return nil }
-
-        // 在绘制上下文中绘制视图内容
-        layer.render(in: context)
-
-        // 获取绘制完成的图片
-        let image = UIGraphicsGetImageFromCurrentImageContext()
-        return image
-    }
-
-}
-
-extension VideoRecorder {
-    func generateVideoFromAnimation(view: UIView, size: CGSize, duration: Double, completion: ((URL?) -> Void)?) {
-        // 设置视频的参数
-        let framePerSecond = 30
-        let totalFrames = Int(duration * Double(framePerSecond))
-        
-        let mainComposition = AVMutableComposition()
-        let compositionVideoTrack = mainComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
-        try? compositionVideoTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: CMTime(value: 1, timescale: CMTimeScale(framePerSecond))), of: mainComposition.tracks.first!, at: CMTime.zero)
-        
-        let videoComposition = AVMutableVideoComposition()
-        videoComposition.frameDuration = CMTime(value: 1, timescale: CMTimeScale(framePerSecond))
-        videoComposition.renderSize = size
-        let tool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: view.layer, in: view.layer)
-        videoComposition.animationTool = tool
-        
-        let videoInstruction = AVMutableVideoCompositionInstruction()
-        videoInstruction.timeRange = CMTimeRange(start: .zero, duration: CMTime(value: 1, timescale: CMTimeScale(framePerSecond)))
-        videoComposition.instructions = [videoInstruction]
-        
-        // 设置导出的路径和文件名
-        let outputPath = NSTemporaryDirectory() + "output.mp4"
-        let outputURL = URL(fileURLWithPath: outputPath)
-        
-        let fileManager = FileManager.default
-        if fileManager.fileExists(atPath: outputPath) {
-            try? fileManager.removeItem(atPath: outputPath)
-        }
-        
-        guard let exporter = AVAssetExportSession(asset: mainComposition, presetName: AVAssetExportPresetHighestQuality) else {
-            return
-        }
-        exporter.outputURL = outputURL
-        exporter.outputFileType = .mp4
-        exporter.shouldOptimizeForNetworkUse = true
-        exporter.videoComposition = videoComposition
-        exporter.audioMix = AVAudioMix()
-        
-        exporter.exportAsynchronously {
-            switch exporter.status {
-            case .completed:
-                print("视频生成成功: \(outputURL)")
-                completion?(outputURL)
-            case .failed:
-                print("视频生成失败: \(String(describing: exporter.error))")
-            case .cancelled:
-                print("视频生成取消")
-            default:
-                break
-            }
-        }
-    }
-}
-
-
-//import ImageIO
-//import MobileCoreServices
-import ReplayKit
-
-typealias StartRecordHandler = () -> Void
-extension VideoRecorder {
-    
-    /*
-     LivePhoto制作
-     1. 录屏生成视频
-     2. 从视频中获取最后一帧图片,并给图片添加livePhoto信息
-     3. 视频转为mov格式并添加livePhoto信息
-     4. 将拥有相同livePhoto信息的图片和视频合并生成livePhoto保存至相册
-     */
-    /// 录制生成LivePhoto并保存相册
-    func saveLivePhoto(duration: TimeInterval, outputDirectory: URL,
-                       prepearHandler: ((StartRecordHandler?) -> Void)?,
-                       completion: ((URL?, URL?, String?) -> Void)?) {
-        
-        startRecording(duration: duration, prepearHandler: prepearHandler) { videoURL, erMsg in
-            guard let videoURL = videoURL else {
-                completion?(nil, nil, erMsg ?? "Record Failure~")
-                return
-            }
-            LivePhotoCreater.shared.saveLivePhoto(from: videoURL, outputDirectory: outputDirectory, completion: completion)
-        }
-    }
-    
-    /// 开始录屏任务
-    /// - Parameters:
-    ///   - duration: 时长
-    ///   - prepearHandler: 录制前回调,用于业务层倒计时、清屏等操作
-    ///   - completion: (URL: 录制结果视频URL,String: 报错信息)
-    func startRecording(duration: TimeInterval,
-                        prepearHandler: (((StartRecordHandler)?) -> Void)?,
-                        completion: ((URL?, String?) -> Void)?) {
-        guard RPScreenRecorder.shared().isAvailable else {
-            Log("RPScreenRecorder isAvailable = false")
-            completion?(nil, "ScreenRecorder unAvailable".localized)
-            return
-        }
-        
-        let livePhotoQueue = DispatchQueue(label: "queue_recording_video")
-//        let semaphore = DispatchSemaphore(value: 0)
-        
-        livePhotoQueue.async {
-            Log("==点击开始")
-            
-            // 1. 录制视频
-            // 获取RPScreenRecorder
-            let recorder = RPScreenRecorder.shared()
-            recorder.isMicrophoneEnabled = false
-            recorder.isCameraEnabled = false
-//            recorder.delegate = self
-            
-            let duration = min(5, duration)
-            // 开始录制
-            recorder.startRecording { error in
-                if let error = error {
-                    Log(error.localizedDescription)
-                    if recorder.isRecording {
-                        recorder.stopRecording()
-                    }
-                    completion?(nil, error.localizedDescription)
-                } else {
-                    Log("已经获取权限")
-//                    recorder.stopRecording()
-                    
-                    // 开始录制操作
-                    let handler = {
-                        Log("==开始录制")
-                        recorder.startRecording { _ in
-//                            semaphore.signal()
-                        }
-                    }
-                    prepearHandler?(handler)
-                }
-            }
-            
-//            semaphore.wait()
-            
-            DispatchQueue.global().asyncAfter(deadline: .now()+duration) {
-                let ts = Date().timeIntervalSince1970
-                let tempDirectoryPath =  NSTemporaryDirectory()
-                let path = (tempDirectoryPath as NSString).appendingPathComponent("\(Int(ts)).mov")
-                
-                let documentURL = TSFileManagerTool.documentsDirectory.appendingPathComponent("\(Int(ts)).mov")
-                
-                let recorder = RPScreenRecorder.shared()
-                
-                // 停止录制
-                let pathURL = URL(fileURLWithPath: path)
-                recorder.stopRecording(withOutput: pathURL) { (error) in
-                    Log("==录制结束")
-                    
-                    TSFileManagerTool.copyFileWithOverwrite(from: pathURL, to: documentURL)
-                    
-                    if let error = error {
-                        Log(error)
-                        completion?(nil, error.localizedDescription)
-                    }
-                    else {
-                        completion?(pathURL, nil)
-                    }
-                }
-            }
-        }
-    }
-}
-

+ 0 - 562
TSLiveWallpaper/Common/Tool/PhotoTools.swift

@@ -1,562 +0,0 @@
-//
-//  PhotoTools.swift
-//  照片选择器-Swift
-//
-//  Created by Silence on 2019/6/29.
-//  Copyright © 2019年 Silence. All rights reserved.
-//
-
-import UIKit
-import Photos
-#if canImport(Kingfisher)
-import Kingfisher
-#endif
-import ImageIO
-
-public struct PhotoTools {
-    
-    /// 转换视频时长为 mm:ss 格式的字符串
-    public static func transformVideoDurationToString(
-        duration: TimeInterval
-    ) -> String {
-        let time = Int(round(Double(duration)))
-        if time < 10 {
-            return String.init(format: "00:0%d", arguments: [time])
-        }else if time < 60 {
-            return String.init(format: "00:%d", arguments: [time])
-        }else {
-            var min = Int(time / 60)
-            let sec = time - (min * 60)
-            if min < 60 {
-                if sec < 10 {
-                    return String(format: "%d:0%d", arguments: [min, sec])
-                }else {
-                    return String(format: "%d:%d", arguments: [min, sec])
-                }
-            }else {
-                let hour = Int(min / 60)
-                min -= hour * 60
-                if hour < 10 {
-                    if min < 10 {
-                        if sec < 10 {
-                            return String(format: "0%d:0%d:0%d", arguments: [hour, min, sec])
-                        }else {
-                            return String(format: "0%d:0%d:%d", arguments: [hour, min, sec])
-                        }
-                    }else {
-                        if sec < 10 {
-                            return String(format: "0%d:%d:0%d", arguments: [hour, min, sec])
-                        }else {
-                            return String(format: "0%d:%d:%d", arguments: [hour, min, sec])
-                        }
-                    }
-                }
-                if min < 10 {
-                    if sec < 10 {
-                        return String(format: "%d:0%d:0%d", arguments: [hour, min, sec])
-                    }else {
-                        return String(format: "%d:0%d:%d", arguments: [hour, min, sec])
-                    }
-                }else {
-                    if sec < 10 {
-                        return String(format: "%d:%d:0%d", arguments: [hour, min, sec])
-                    }else {
-                        return String(format: "%d:%d:%d", arguments: [hour, min, sec])
-                    }
-                }
-            }
-        }
-    }
-    
-    /// 根据视频地址获取视频时长
-    public static func getVideoDuration(
-        videoURL: URL?
-    ) -> TimeInterval {
-        guard let videoURL = videoURL else {
-            return 0
-        }
-        let options = [AVURLAssetPreferPreciseDurationAndTimingKey: false]
-        let urlAsset = AVURLAsset.init(url: videoURL, options: options)
-//        let second = TimeInterval(urlAsset.duration.value) / TimeInterval(urlAsset.duration.timescale)
-        return TimeInterval(round(urlAsset.duration.seconds))
-    }
-    
-    /// 根据视频时长(00:00:00)获取秒
-    static func getVideoTime(forVideo duration: String) -> TimeInterval {
-        var m = 0
-        var s = 0
-        var ms = 0
-        let components = duration.components(
-            separatedBy: CharacterSet.init(charactersIn: ":.")
-        )
-        if components.count >= 2 {
-            if let i = Int(components[0]) {
-                m = i
-            }else {
-                m = 0
-            }
-            if let i = Int(components[1]) {
-                s = i
-            }else {
-                s = 0
-            }
-            if components.count == 3 {
-                if let i = Int(components[2]) {
-                    ms = i
-                }else {
-                    ms = 0
-                }
-            }
-        }else {
-            s = Int(INT_MAX)
-        }
-        return TimeInterval(CGFloat(m * 60) + CGFloat(s) + CGFloat(ms) * 0.001)
-    }
-    
-    /// 根据视频地址获取视频封面
-    public static func getVideoThumbnailImage(
-        videoURL: URL?,
-        atTime: TimeInterval
-    ) -> UIImage? {
-        guard let videoURL = videoURL else {
-            return nil
-        }
-        return getVideoThumbnailImage(avAsset: .init(url: videoURL), atTime: atTime)
-    }
-    
-    /// 根据视频地址获取视频封面
-    public static func getVideoThumbnailImage(
-        avAsset: AVAsset?,
-        atTime: TimeInterval
-    ) -> UIImage? {
-        guard let avAsset = avAsset else {
-            return nil
-        }
-        return avAsset.getImage(at: atTime)
-    }
-    
-    /// 获视频缩略图
-    @discardableResult
-    public static func getVideoThumbnailImage(
-        url: URL,
-        atTime: TimeInterval,
-        imageGenerator: ((AVAssetImageGenerator) -> Void)? = nil,
-        completion: @escaping (URL, UIImage?, AVAssetImageGenerator.Result) -> Void
-    ) -> AVAsset {
-        let asset = AVURLAsset(url: url)
-        asset.loadValuesAsynchronously(forKeys: ["duration"]) {
-            if asset.statusOfValue(forKey: "duration", error: nil) != .loaded {
-                DispatchQueue.main.async {
-                    completion(url, nil, .failed)
-                }
-                return
-            }
-            let generator = AVAssetImageGenerator(asset: asset)
-            generator.appliesPreferredTrackTransform = true
-            let time = CMTime(value: CMTimeValue(atTime), timescale: asset.duration.timescale)
-            let array = [NSValue(time: time)]
-            generator.generateCGImagesAsynchronously(
-                forTimes: array
-            ) { (_, cgImage, _, result, _) in
-                if let image = cgImage, result == .succeeded {
-                    var image = UIImage(cgImage: image)
-                    if image.imageOrientation != .up,
-                       let img = image.normalizedImage() {
-                        image = img
-                    }
-                    DispatchQueue.main.async {
-                        completion(url, image, result)
-                    }
-                }else {
-                    DispatchQueue.main.async {
-                        completion(url, nil, result)
-                    }
-                }
-            }
-            DispatchQueue.main.async {
-                imageGenerator?(generator)
-            }
-        }
-        return asset
-    }
-    
-    #if canImport(Kingfisher)
-    public static func downloadNetworkImage(
-        with url: URL,
-        cancelOrigianl: Bool = true,
-        options: KingfisherOptionsInfo,
-        progressBlock: DownloadProgressBlock? = nil,
-        completionHandler: ((UIImage?) -> Void)? = nil
-    ) {
-        let key = url.cacheKey
-        if ImageCache.default.isCached(forKey: key) {
-            ImageCache.default.retrieveImage(
-                forKey: key,
-                options: options
-            ) { (result) in
-                switch result {
-                case .success(let value):
-                    completionHandler?(value.image)
-                case .failure:
-                    completionHandler?(nil)
-                }
-            }
-            return
-        }
-        ImageDownloader.default.downloadImage(
-            with: url,
-            options: options,
-            progressBlock: progressBlock
-        ) { (result) in
-            switch result {
-            case .success(let value):
-                DispatchQueue.global().async {
-                    if let gifImage = DefaultImageProcessor.default.process(
-                        item: .data(value.originalData),
-                        options: .init([])
-                    ) {
-                        if cancelOrigianl {
-                            ImageCache.default.store(
-                                gifImage,
-                                original: value.originalData,
-                                forKey: key
-                            )
-                        }
-                        DispatchQueue.main.async {
-                            completionHandler?(gifImage)
-                        }
-                        return
-                    }
-                    if cancelOrigianl {
-                        ImageCache.default.store(
-                            value.image,
-                            original: value.originalData,
-                            forKey: key
-                        )
-                    }
-                    DispatchQueue.main.async {
-                        completionHandler?(value.image)
-                    }
-                }
-            case .failure:
-                completionHandler?(nil)
-            }
-        }
-    }
-    #endif
-    
-    static func transformImageSize(
-        _ imageSize: CGSize,
-        to view: UIView
-    ) -> CGRect {
-        return transformImageSize(
-            imageSize,
-            toViewSize: view.size
-        )
-    }
-    
-    public static func transformImageSize(
-        _ imageSize: CGSize,
-        toViewSize viewSize: CGSize,
-        directions: [PhotoToolsTransformImageSizeDirections] = [.horizontal, .vertical]
-    ) -> CGRect {
-        var size: CGSize = .zero
-        var center: CGPoint = .zero
-        
-        func handleVertical(
-            _ imageSize: CGSize,
-            _ viewSize: CGSize
-        ) -> (CGSize, CGPoint) {
-            let aspectRatio = viewSize.width / imageSize.width
-            let contentWidth = viewSize.width
-            let contentHeight = imageSize.height * aspectRatio
-            let _size = CGSize(width: contentWidth, height: contentHeight)
-            if contentHeight < viewSize.height {
-                let center = CGPoint(x: viewSize.width * 0.5, y: viewSize.height * 0.5)
-                return (_size, center)
-            }
-            return (_size, .zero)
-        }
-        func handleHorizontal(
-            _ imageSize: CGSize,
-            _ viewSize: CGSize
-        ) -> (CGSize, CGPoint) {
-            let aspectRatio = viewSize.height / imageSize.height
-            var contentWidth = imageSize.width * aspectRatio
-            var contentHeight = viewSize.height
-            if contentWidth > viewSize.width {
-                contentHeight = viewSize.width / contentWidth * contentHeight
-                contentWidth = viewSize.width
-            }
-            let _size = CGSize(width: contentWidth, height: contentHeight)
-            if contentHeight < viewSize.height {
-                let center = CGPoint(x: viewSize.width * 0.5, y: viewSize.height * 0.5)
-                return (_size, center)
-            }
-            return (_size, .zero)
-        }
-        
-        if directions.contains(.horizontal) && directions.contains(.vertical) {
-            if UIDevice.isPortrait {
-                let content = handleVertical(imageSize, viewSize)
-                size = content.0
-                center = content.1
-            }else {
-                let content = handleHorizontal(imageSize, viewSize)
-                size = content.0
-                if !content.1.equalTo(.zero) {
-                    center = content.1
-                }
-            }
-        }else if directions.contains(.horizontal) {
-            let content = handleHorizontal(imageSize, viewSize)
-            size = content.0
-            center = content.1
-        }else if directions.contains(.vertical) {
-            let content = handleVertical(imageSize, viewSize)
-            size = content.0
-            center = content.1
-        }
-        var rectY: CGFloat
-        if center.equalTo(.zero) {
-            rectY = 0
-        }else {
-            rectY = (viewSize.height - size.height) * 0.5
-        }
-        return CGRect(x: (viewSize.width - size.width) * 0.5, y: rectY, width: size.width, height: size.height)
-    }
-    
-    static func exportSessionFileLengthLimit(
-        seconds: Double,
-        maxSize: Int? = nil,
-        exportPreset: ExportPreset,
-        videoQuality: Int
-    ) -> Int64 {
-        if videoQuality > 0 {
-            let quality = Double(min(videoQuality, 10))
-            if let maxSize = maxSize {
-                return Int64(Double(maxSize) * (quality / 10))
-            }
-            var ratioParam: Double = 0
-            if exportPreset == .ratio_640x480 {
-                ratioParam = 0.02
-            }else if exportPreset == .ratio_960x540 {
-                ratioParam = 0.04
-            }else if exportPreset == .ratio_1280x720 {
-                ratioParam = 0.08
-            }
-            return Int64(seconds * ratioParam * quality * 1000 * 1000)
-        }
-        return 0
-    }
-    
-    static func imageCompress(
-        _ data: Data,
-        compressionQuality: CGFloat
-    ) -> Data? {
-        guard var resultImage = UIImage(data: data)?.normalizedImage() else {
-            return nil
-        }
-        let compression = max(0, min(1, compressionQuality))
-        let maxLength = Int(CGFloat(data.count) * compression)
-        let widthHeightRatio = resultImage.width / resultImage.height
-        var data = data
-        
-        var lastDataLength = 0
-        while data.count > maxLength && data.count != lastDataLength {
-            let dataCount = data.count
-            lastDataLength = dataCount
-            let maxRatio: CGFloat
-            if widthHeightRatio < 0.2 {
-                maxRatio = 1
-            }else {
-                maxRatio = min(5000 / resultImage.width, 5000 / resultImage.height)
-            }
-            let ratio = min(max(CGFloat(maxLength) / CGFloat(dataCount), compression), maxRatio)
-            let size = CGSize(
-                width: Int(resultImage.width * ratio),
-                height: Int(resultImage.height * ratio)
-            )
-            guard let image = resultImage.scaleToFillSize(size: size),
-                  let imageData = image.jpegData(compressionQuality: 0.5) else {
-                return data
-            }
-            resultImage = image
-            data = imageData
-        }
-        return data
-    }
-    
-    static func compressImageData(
-        _ imageData: Data,
-        compressionQuality: CGFloat?,
-        queueLabel: String,
-        completion: @escaping (Data?) -> Void
-    ) {
-        guard let compressionQuality else {
-            completion(imageData)
-            return
-        }
-        guard let resultImage = UIImage(data: imageData)?.normalizedImage() else {
-            completion(imageData)
-            return
-        }
-        let serialQueue = DispatchQueue(
-            label: queueLabel,
-            qos: .userInitiated,
-            attributes: [],
-            autoreleaseFrequency: .workItem,
-            target: nil
-        )
-        let compression = max(0, min(1, compressionQuality))
-        let maxLength = Int(CGFloat(imageData.count) * compression)
-        let widthHeightRatio = resultImage.width / resultImage.height
-        let data = imageData
-        
-        serialQueue.async {
-            compressImageData(
-                data,
-                resultImage: resultImage,
-                compression: compressionQuality,
-                maxLength: maxLength,
-                widthHeightRatio: widthHeightRatio
-            ) {
-                completion($0)
-            }
-        }
-    }
-     
-    private static func compressImageData(
-        _ data: Data,
-        resultImage: UIImage,
-        compression: CGFloat,
-        maxLength: Int,
-        lastDataLength: Int = 0,
-        widthHeightRatio: CGFloat,
-        completionHandler: @escaping (Data) -> Void
-    ) {
-        autoreleasepool {
-            var lastDataLength = lastDataLength
-            let dataCount = data.count
-            lastDataLength = dataCount
-            let maxRatio: CGFloat
-            if widthHeightRatio < 0.2 {
-                maxRatio = 1
-            }else {
-                maxRatio = min(5000 / resultImage.width, 5000 / resultImage.height)
-            }
-            let ratio = min(max(CGFloat(maxLength) / CGFloat(dataCount), compression), maxRatio)
-            let size = CGSize(
-                width: Int(resultImage.width * ratio),
-                height: Int(resultImage.height * ratio)
-            )
-            guard let image = resultImage.scaleToFillSize(size: size),
-                  let imageData = image.jpegData(compressionQuality: 0.5) else {
-                completionHandler(data)
-                return
-            }
-            if data.count > maxLength && data.count != lastDataLength {
-                self.compressImageData(
-                    imageData,
-                    resultImage: image,
-                    compression: compression,
-                    maxLength: maxLength,
-                    lastDataLength: lastDataLength,
-                    widthHeightRatio: widthHeightRatio,
-                    completionHandler: completionHandler
-                )
-                return
-            }
-            completionHandler(imageData)
-        }
-    }
-    
-    static func getBasicAnimation(
-        _ keyPath: String,
-        _ fromValue: Any?,
-        _ toValue: Any?,
-        _ duration: TimeInterval,
-        _ timingFunctionName: CAMediaTimingFunctionName = .linear
-    ) -> CABasicAnimation {
-        let animation = CABasicAnimation(keyPath: keyPath)
-        animation.fromValue = fromValue
-        animation.toValue = toValue
-        animation.duration = duration
-        animation.fillMode = .backwards
-        animation.timingFunction = .init(name: timingFunctionName)
-        return animation
-    }
-    
-    static func getGradientShadowLayer(
-        _ isTop: Bool,
-        colors: [CGColor] = [UIColor.black.withAlphaComponent(0).cgColor,
-                             UIColor.black.withAlphaComponent(0.2).cgColor,
-                             UIColor.black.withAlphaComponent(0.3).cgColor,
-                             UIColor.black.withAlphaComponent(0.4).cgColor,
-                             UIColor.black.withAlphaComponent(0.5).cgColor],
-        locations: [NSNumber] = [0.1, 0.3, 0.5, 0.7, 0.9]
-    ) -> CAGradientLayer {
-        getGradientShadowLayer(
-            startPoint: isTop ? CGPoint(x: 0, y: 1) : CGPoint(x: 0, y: 0),
-            endPoint: isTop ? CGPoint(x: 0, y: 0) : CGPoint(x: 0, y: 1),
-            colors: colors,
-            locations: locations
-        )
-    }
-    
-    static func getGradientShadowLayer(
-        startPoint: CGPoint,
-        endPoint: CGPoint,
-        colors: [CGColor] = [UIColor.black.withAlphaComponent(0).cgColor,
-                             UIColor.black.withAlphaComponent(0.2).cgColor,
-                             UIColor.black.withAlphaComponent(0.3).cgColor,
-                             UIColor.black.withAlphaComponent(0.4).cgColor,
-                             UIColor.black.withAlphaComponent(0.5).cgColor],
-        locations: [NSNumber] = [0.1, 0.3, 0.5, 0.7, 0.9]
-    ) -> CAGradientLayer {
-        let layer = CAGradientLayer()
-        layer.contentsScale = UIScreen._scale
-        layer.colors = colors
-        layer.startPoint = startPoint
-        layer.endPoint = endPoint
-        layer.locations = locations
-        layer.borderWidth = 0.0
-        return layer
-    }
-    
-    #if HXPICKER_ENABLE_EDITOR || HXPICKER_ENABLE_EDITOR_VIEW || HXPICKER_ENABLE_CAMERA
-    static func getColor(red: Int, green: Int, blue: Int, alpha: Int = 255) -> CIColor {
-        return CIColor(red: CGFloat(Double(red) / 255.0),
-                       green: CGFloat(Double(green) / 255.0),
-                       blue: CGFloat(Double(blue) / 255.0),
-                       alpha: CGFloat(Double(alpha) / 255.0))
-    }
-    
-    static func getColorImage(red: Int, green: Int, blue: Int, alpha: Int = 255, rect: CGRect) -> CIImage {
-        let color = self.getColor(red: red, green: green, blue: blue, alpha: alpha)
-        return CIImage(color: color).cropped(to: rect)
-    }
-    
-    
-    static func createPixelBuffer(_ size: CGSize) -> CVPixelBuffer? {
-        var pixelBuffer: CVPixelBuffer?
-        let pixelBufferAttributes = [kCVPixelBufferIOSurfacePropertiesKey: [:] as [String: Any]]
-        CVPixelBufferCreate(
-            nil,
-            Int(size.width),
-            Int(size.height),
-            kCVPixelFormatType_32BGRA,
-            pixelBufferAttributes as CFDictionary,
-            &pixelBuffer
-        )
-        return pixelBuffer
-    }
-    #endif
-     
-    private init() { }
-}
-
-public enum PhotoToolsTransformImageSizeDirections {
-    case horizontal
-    case vertical
-}

+ 0 - 81
TSLiveWallpaper/DataManger/TSHomeDataModel.swift

@@ -1,81 +0,0 @@
-//
-//  TSHomeDataModel.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/23.
-//
-import ObjectMapper
-
-
-class TSHomeBannerDataSectionModel: TSBaseModel {
-    
-    var style:ImageDataStyple = .homeLiveList {
-        didSet{
-            for itemModel in itemModels {
-                itemModel.style = style
-            }
-        }
-    }
-    
-    var itemModels:[TSHomeBannerDataItemModel] = [TSHomeBannerDataItemModel]()
-    
-    override func mapping(map: ObjectMapper.Map) {
-        style <- map["style"]
-        itemModels <- map["itemModels"]
-    }
-}
-
-
-extension TSHomeBannerDataSectionModel : TSCollectionViewSectionComponent{
-    var sectionInset: UIEdgeInsets {
-        return style.sectionInset
-    }
-    
-    var lineSpacing: CGFloat {
-        return style.lineSpacing
-    }
-    
-    var itemSpacing: CGFloat {
-        return style.itemSpacing
-    }
-    var headerComponent: TSCollectionViewReuseViewComponent? {
-        nil
-    }
-    var cells: [TSCollectionViewCellComponent] {
-        return itemModels
-    }
-}
-
-//MARK: TSHomeBannerDataItemModel
-class TSHomeBannerDataItemModel: TSBaseModel {
-    
-    var style:ImageDataStyple = .homeLiveList {
-        didSet{
-            for itemModel in items {
-                itemModel.style = style
-            }
-        }
-    }
-    
-    var type:String = ""
-    var items:[TSImageDataItemModel] = [TSImageDataItemModel]()
-    var vip:Bool = false
-    override func mapping(map: ObjectMapper.Map) {
-        type    <- map["type"]
-        items   <- map["items"]
-        vip     <- map["vip"]
-        style    <- map["style"]
-    }
-    
-}
-
-extension TSHomeBannerDataItemModel : TSCollectionViewCellComponent {
-    
-    var cellClass: UICollectionViewCell.Type {
-        style.cellClass
-    }
-    
-    func cellSize(with attrubites: [String : Any]?) -> CGSize {
-        style.cellSize
-    }
-}

+ 0 - 355
TSLiveWallpaper/DataManger/TSImageDataCenter.swift

@@ -1,355 +0,0 @@
-//
-//  TSImageDataTool.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/23.
-//
-
-import ObjectMapper
-
-
-let columns = UIDevice.isPad ? 3.0 : 2.0
-let itemMargin = columns*2//item的宽之间不能太精准,否则还是放不下,稍微去掉
-private let liveBannerW = k_ScreenWidth
-private let liveBannerH = 486.5
-
-private let liveItemW = (k_ScreenWidth - 16 - 16 - 17)/columns - itemMargin
-private let liveItemH =  kGetUIWdith(designSize: CGSize(width: 163.0, height: 352.0), currentW: liveItemW)
-
-private let randomBannerW:CGFloat = k_ScreenWidth - 16.0
-private let randowBannerH:CGFloat = kGetUIWdith(designSize:CGSize(width: 343, height: 117), currentW: randomBannerW)
-
-private let randowItemW:CGFloat = (k_ScreenWidth - 13 - 16 - 16) / columns - itemMargin
-private let randowItemH:CGFloat = kGetUIWdith(designSize:CGSize(width: 165, height: 278) , currentW: randowItemW)
-
-
-enum ImageDataStyple : Int {
-    case homeLiveBanner
-    case homeLiveList
-    case randomBanner
-    case randomList
-    
-    
-    var sectionInset: UIEdgeInsets {
-        switch self {
-        case .homeLiveBanner:
-            return UIEdgeInsets(top: 24, left: 0, bottom: 17, right: 0)
-        case .homeLiveList:
-            return UIEdgeInsets(top: 0, left: 16, bottom: 10, right: 16)
-        case .randomBanner:
-            return UIEdgeInsets(top: 16, left: 16, bottom: 24, right: 16)
-        case .randomList:
-            return UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
-        }
-    }
-    
-    var lineSpacing: CGFloat {
-        switch self {
-        case .homeLiveBanner:
-            return 0
-        case .homeLiveList:
-            return 17
-        case .randomBanner:
-            return 0
-        case .randomList:
-            return 16
-        }
-    }
-    
-    var itemSpacing: CGFloat {
-        switch self {
-        case .homeLiveBanner:
-            return 0
-        case .homeLiveList:
-            return 16
-        case .randomBanner:
-            return 0
-        case .randomList:
-            return 13
-        }
-    }
-    
-    var cellSize:CGSize {
-        switch self {
-        case .homeLiveBanner:
-            return CGSize(width: liveBannerW, height: liveBannerH)
-        case .homeLiveList:
-            return CGSize(width: liveItemW, height: liveItemH)
-        case .randomBanner:
-            return CGSize(width: randomBannerW, height: randowBannerH)
-        case .randomList:
-            return CGSize(width: randowItemW, height: randowItemH)
-        }
-    }
-    
-    var cellClass: UICollectionViewCell.Type {
-        switch self {
-        case .homeLiveBanner:
-            return TSHomeTopBannerCell.self
-        case .homeLiveList:
-            return TSHomeCollectionCell.self
-        case .randomBanner:
-            return TSRandomWallpaperBannerCell.self
-        case .randomList:
-            return TSRandomWallpaperCell.self
-        }
-    }
-    
-    var headerViewSize:CGSize {
-        switch self {
-        case .homeLiveBanner:
-            return CGSize.zero
-        case .homeLiveList:
-            return CGSizeMake(k_ScreenWidth, 48)
-        case .randomBanner:
-            return CGSize.zero
-        case .randomList:
-            return CGSize.zero
-        }
-    }
-}
-
-let kImageDataCenterShared = TSImageDataCenter.shared
-class TSImageDataCenter{
-
-    static var shared = TSImageDataCenter()
-    
-    @UserDefault(key: "editLiveHistoryList", defaultValue: "")
-    private var editLiveHistoryListString: String
-    
-    var editLiveHistoryListArray:[TSImageDataSectionModel]{
-        get{
-            if let totalArray = Mapper<TSImageDataSectionModel>().mapArray(JSONString: editLiveHistoryListString){
-                return totalArray
-            }else{
-                let sectionModel = TSImageDataSectionModel()
-                sectionModel.name = "History".localized
-                return [sectionModel]
-            }
-        }
-        
-        set{
-            if let jsonString = newValue.toJSONString() {
-                editLiveHistoryListString = jsonString
-            }
-        }
-    }
-    
-    
-    
-
-    //所有数据
-    var totalArray:[TSImageDataSectionModel] = [TSImageDataSectionModel]()
-    
-    //banner 图片
-    var liveBannerArray:[TSHomeBannerDataSectionModel] = [TSHomeBannerDataSectionModel]()
-    //live 图片
-    var liveListArray:[TSImageDataSectionModel] = [TSImageDataSectionModel]()
-    
-    
-    //壁纸Banner
-    var randomBannerArray:[TSRandomWallpaperDataSectionModel] = [TSRandomWallpaperDataSectionModel]()
-    //壁纸组
-    var randomListArray:[TSRandomWallpaperDataSectionModel] = [TSRandomWallpaperDataSectionModel]()
-    
-    init() {
-    
-        totalArray = [TSImageDataSectionModel]()
-        
-        liveListArray = [TSImageDataSectionModel]()
-        randomListArray = [TSRandomWallpaperDataSectionModel]()
-   
-        if let totalArray = Mapper<TSImageDataSectionModel>().mapArray(JSONfile: "response.json"){
-            
-            self.totalArray = totalArray
-
-            var randomItemListArray = [TSRandomWallpaperDataItemModel]()
-            
-            for sectionModel in totalArray {
-                if sectionModel.type == "live" {
-                    if let newModel = setSectionModelStype(sectionModel: sectionModel, style: .homeLiveList) {
-                        liveListArray.append(newModel)
-                    }
-                }else{
-                    if let newModel = getRandomWallpaperDataItemModel(sctionModel: sectionModel, style: .randomList) {
-                        randomItemListArray.append(newModel)
-                    }
-                }
-            }
-
-            //首页顶部
-            liveBannerArray = {
-                let itemModel = TSHomeBannerDataItemModel()
-                let randomInts = [16, 50, 27, 1, 57, 26, 31, 32, 15, 44]
-                if liveBannerArray.count < 9 {
-                    if let fistModel = liveListArray.first {
-                        if let newModel = setSectionModelStype(sectionModel: fistModel, style: .homeLiveBanner) {
-                            
-                            var items = [TSImageDataItemModel]()
-                            for randomInt in randomInts {
-                                if let item = newModel.items.safeObj(At: randomInt) {
-                                    items.append(item)
-                                }
-                            }
-                            itemModel.items = items
-                        }
-                    }
-                }
-
-                let sectionModel = TSHomeBannerDataSectionModel()
-                sectionModel.itemModels = [itemModel]
-                sectionModel.style = .homeLiveBanner
-                return [sectionModel]
-            }()
-            
-            
-            //随机壁纸 头
-            randomBannerArray = {
-                let sectionModel = TSRandomWallpaperDataSectionModel()
-                sectionModel.itemModels = [TSRandomWallpaperDataItemModel()]
-                sectionModel.style = .randomBanner
-                return [sectionModel]
-            }()
-            
-            //随机壁纸 list
-            randomListArray = {
-                let sectionModel = TSRandomWallpaperDataSectionModel()
-                sectionModel.itemModels = randomItemListArray
-                sectionModel.style = .randomList
-                return  [sectionModel]
-            }()
-            
-        }
-    }
-    
-    func setSectionModelStype(sectionModel:TSImageDataSectionModel,style:ImageDataStyple) -> TSImageDataSectionModel?{
-        if let newModel = sectionModel.copy() as? TSImageDataSectionModel{
-            newModel.style = style
-            return newModel
-        }
-        return nil
-    }
-    
-    
-    func getRandomWallpaperDataItemModel(sctionModel:TSImageDataSectionModel,style:ImageDataStyple) -> TSRandomWallpaperDataItemModel?{
-        if let model = Mapper<TSRandomWallpaperDataItemModel>().map(JSON: sctionModel.toJSON()){
-            model.style = style
-            return model
-        }
-        return nil
-    }
-}
-
-class TSImageDataSectionModel: TSBaseModel {
-    var style:ImageDataStyple = .homeLiveList {
-        didSet{
-            for itemModel in items {
-                itemModel.style = style
-            }
-        }
-    }
-    
-    var type:String = ""
-    var items:[TSImageDataItemModel] = [TSImageDataItemModel]()
-    var name:String = "Recommend"
-    var vip:Bool = false
-    override func mapping(map: ObjectMapper.Map) {
-        type    <- map["type"]
-        items   <- map["items"]
-        vip     <- map["vip"]
-        style    <- map["style"]
-    }
-    
-}
-
-extension TSImageDataSectionModel : TSCollectionViewSectionComponent{
-    
-    var sectionInset: UIEdgeInsets {
-        return style.sectionInset
-    }
-    
-    var lineSpacing: CGFloat {
-        return style.lineSpacing
-    }
-    
-    var itemSpacing: CGFloat {
-        return style.itemSpacing
-    }
-    var headerComponent: TSCollectionViewReuseViewComponent? {
-        return TSComponentReuseViewModel(sectionModel: self)
-    }
-    
-    var cells: [TSCollectionViewCellComponent] {
-        
-        if style == .homeLiveBanner {//用分区头来展示 banner
-            return []
-        }
-        return items
-    }
-}
- 
-
-
-class TSImageDataItemModel: TSBaseModel {
-    var style:ImageDataStyple = .homeLiveList
-    
-    var imageUrl:String = ""
-    var videoUrl:String = ""
-    var vip:Bool = false
-    override func mapping(map: ObjectMapper.Map) {
-        imageUrl    <- map["imageUrl"]
-        videoUrl    <- map["videoUrl"]
-        vip         <- map["vip"]
-        
-        style    <- map["style"]
-    }
-    
-}
-
-extension TSImageDataItemModel: TSCollectionViewCellComponent {
-    var cellClass: UICollectionViewCell.Type {
-        style.cellClass
-    }
-    
-    func cellSize(with attrubites: [String : Any]?) -> CGSize {
-        style.cellSize
-    }
-}
-
-
-// 头部标题
-class TSComponentReuseViewModel : TSBaseModel ,TSCollectionViewReuseViewComponent {
-    var sectionModel:TSImageDataSectionModel
-
-    init(sectionModel:TSImageDataSectionModel) {
-        self.sectionModel = sectionModel
-    }
-    
-    required convenience init?(json: [String : Any]) {
-        fatalError("init(json:) has not been implemented")
-    }
-    
-    required convenience init?(map: ObjectMapper.Map) {
-        fatalError("init(map:) has not been implemented")
-    }
-    
-    override func mapping(map: ObjectMapper.Map) {
-        sectionModel    <- map["sectionModel"]
-    }
-    
-    var viewClass: UICollectionReusableView.Type {
-        return TSHomeCollectionReusableView.self
-    }
-    
-    var reuseIdentifier: String{
-        return viewClass.description()
-    }
-    
-    var viewSize: CGSize {
-        return sectionModel.style.headerViewSize
-    }
-    
-    var viewType: TSCollectionViewReuseViewType {
-        return .header
-    }
-}

+ 0 - 82
TSLiveWallpaper/DataManger/TSRandomWallpaperModel.swift

@@ -1,82 +0,0 @@
-//
-//  TSRandomWallpaperModel.swift
-//  TSLiveWallpaper
-//
-//  Created by 100Years on 2024/12/23.
-//
-
-import ObjectMapper
-
-
-class TSRandomWallpaperDataSectionModel: TSBaseModel {
-    
-    var style:ImageDataStyple = .homeLiveList {
-        didSet{
-            for itemModel in itemModels {
-                itemModel.style = style
-            }
-        }
-    }
-    
-    var itemModels:[TSRandomWallpaperDataItemModel] = [TSRandomWallpaperDataItemModel]()
-    
-    override func mapping(map: ObjectMapper.Map) {
-        style <- map["style"]
-        itemModels <- map["itemModels"]
-    }
-}
-
-
-extension TSRandomWallpaperDataSectionModel : TSCollectionViewSectionComponent{
-    var sectionInset: UIEdgeInsets {
-        return style.sectionInset
-    }
-    
-    var lineSpacing: CGFloat {
-        return style.lineSpacing
-    }
-    
-    var itemSpacing: CGFloat {
-        return style.itemSpacing
-    }
-    var headerComponent: TSCollectionViewReuseViewComponent? {
-        nil
-    }
-    var cells: [TSCollectionViewCellComponent] {
-        return itemModels
-    }
-}
-
-
-class TSRandomWallpaperDataItemModel: TSBaseModel {
-    
-    var style:ImageDataStyple = .homeLiveList {
-        didSet{
-            for itemModel in items {
-                itemModel.style = style
-            }
-        }
-    }
-    
-    var type:String = ""
-    var items:[TSImageDataItemModel] = [TSImageDataItemModel]()
-    var vip:Bool = false
-    override func mapping(map: ObjectMapper.Map) {
-        type    <- map["type"]
-        items   <- map["items"]
-        vip     <- map["vip"]
-        style    <- map["style"]
-    }
-    
-}
-
-extension TSRandomWallpaperDataItemModel : TSCollectionViewCellComponent {
-    
-    var cellClass: UICollectionViewCell.Type {
-        style.cellClass
-    }
-    
-    func cellSize(with attrubites: [String : Any]?) -> CGSize {
-        style.cellSize
-    }
-}