Prechádzať zdrojové kódy

启动页开发完毕

100Years 2 mesiacov pred
rodič
commit
62925e54a0
23 zmenil súbory, kde vykonal 781 pridanie a 6 odobranie
  1. 24 0
      TSLiveWallpaper.xcodeproj/project.pbxproj
  2. 30 6
      TSLiveWallpaper/AppDelegate.swift
  3. 6 0
      TSLiveWallpaper/Assets.xcassets/Boot/Contents.json
  4. 22 0
      TSLiveWallpaper/Assets.xcassets/Boot/boot_bottom_shadow.imageset/Contents.json
  5. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_bottom_shadow.imageset/boot_bottom_shadow@2x.png
  6. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_bottom_shadow.imageset/boot_bottom_shadow@3x.png
  7. 21 0
      TSLiveWallpaper/Assets.xcassets/Boot/boot_new_0.imageset/Contents.json
  8. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_new_0.imageset/boot_new_0.png
  9. 21 0
      TSLiveWallpaper/Assets.xcassets/Boot/boot_new_1.imageset/Contents.json
  10. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_new_1.imageset/boot_new_1.png
  11. 21 0
      TSLiveWallpaper/Assets.xcassets/Boot/boot_new_2.imageset/Contents.json
  12. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_new_2.imageset/boot_new_2.png
  13. 21 0
      TSLiveWallpaper/Assets.xcassets/Boot/boot_old_0.imageset/Contents.json
  14. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_old_0.imageset/boot_old_0.png
  15. 21 0
      TSLiveWallpaper/Assets.xcassets/Boot/boot_old_1.imageset/Contents.json
  16. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_old_1.imageset/boot_old_1.png
  17. 21 0
      TSLiveWallpaper/Assets.xcassets/Boot/boot_old_2.imageset/Contents.json
  18. BIN
      TSLiveWallpaper/Assets.xcassets/Boot/boot_old_2.imageset/boot_old_2.png
  19. 308 0
      TSLiveWallpaper/Business/BusinessView/TSImageProComparisonView.swift
  20. 120 0
      TSLiveWallpaper/Business/TSBootVC/TSBootCell.swift
  21. 27 0
      TSLiveWallpaper/Business/TSBootVC/TSBootModel.swift
  22. 117 0
      TSLiveWallpaper/Business/TSBootVC/TSBootVC.swift
  23. 1 0
      TSLiveWallpaper/LaunchVC/TSLaunchVC.swift

+ 24 - 0
TSLiveWallpaper.xcodeproj/project.pbxproj

@@ -196,6 +196,10 @@
 		A8E56BF62D1520EC003C54AF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8E56BEC2D1520EC003C54AF /* AppDelegate.swift */; };
 		A8E56BF92D1520EC003C54AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A8E56BED2D1520EC003C54AF /* Assets.xcassets */; };
 		A8E56BFB2D1520EC003C54AF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A8E56BF02D1520EC003C54AF /* LaunchScreen.storyboard */; };
+		A8E590392DFFAE4400C2533F /* TSBootVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8E590382DFFAE4400C2533F /* TSBootVC.swift */; };
+		A8EE92C02DFFC3B50077DFFD /* TSImageProComparisonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EE92BF2DFFC39C0077DFFD /* TSImageProComparisonView.swift */; };
+		A8EE92C22DFFC54C0077DFFD /* TSBootModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EE92C12DFFC54A0077DFFD /* TSBootModel.swift */; };
+		A8EE92C42DFFC5830077DFFD /* TSBootCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EE92C32DFFC5820077DFFD /* TSBootCell.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 */; };
@@ -419,6 +423,10 @@
 		A8E56BED2D1520EC003C54AF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		A8E56BEE2D1520EC003C54AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		A8E56BEF2D1520EC003C54AF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		A8E590382DFFAE4400C2533F /* TSBootVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBootVC.swift; sourceTree = "<group>"; };
+		A8EE92BF2DFFC39C0077DFFD /* TSImageProComparisonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSImageProComparisonView.swift; sourceTree = "<group>"; };
+		A8EE92C12DFFC54A0077DFFD /* TSBootModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBootModel.swift; sourceTree = "<group>"; };
+		A8EE92C32DFFC5820077DFFD /* TSBootCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBootCell.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>"; };
@@ -842,6 +850,7 @@
 		A81CA48C2D15855300A3AAC8 /* Business */ = {
 			isa = PBXGroup;
 			children = (
+				A8E590372DFFAE3100C2533F /* TSBootVC */,
 				A86857AD2DF9218C0089D222 /* General */,
 				A86857A92DF9210D0089D222 /* TSAIListVC */,
 				A868578D2DF845D00089D222 /* BusinessView */,
@@ -1110,6 +1119,7 @@
 		A868578D2DF845D00089D222 /* BusinessView */ = {
 			isa = PBXGroup;
 			children = (
+				A8EE92BF2DFFC39C0077DFFD /* TSImageProComparisonView.swift */,
 				A86857DC2DF99C200089D222 /* TSImageIPanComparisonView.swift */,
 				A8FD8F422DFC1656008CAACF /* TSImageComparisonView.swift */,
 				A8FD8F402DFC138A008CAACF /* TYCycleImageComparisonView.swift */,
@@ -1281,6 +1291,16 @@
 			path = TSLiveWallpaper;
 			sourceTree = "<group>";
 		};
+		A8E590372DFFAE3100C2533F /* TSBootVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8EE92C12DFFC54A0077DFFD /* TSBootModel.swift */,
+				A8E590382DFFAE4400C2533F /* TSBootVC.swift */,
+				A8EE92C32DFFC5820077DFFD /* TSBootCell.swift */,
+			);
+			path = TSBootVC;
+			sourceTree = "<group>";
+		};
 		A8F76C3A2D35022300AA6E93 /* TSPurchaseMembershipVC */ = {
 			isa = PBXGroup;
 			children = (
@@ -1506,6 +1526,7 @@
 				A81CA4B82D16A6BD00A3AAC8 /* View+Ex.swift in Sources */,
 				A8F76C422D350A9600AA6E93 /* TSPurchaseManager.swift in Sources */,
 				60553FDD2D3B84E700BAAD7F /* UIScrollView+Ext.swift in Sources */,
+				A8EE92C42DFFC5830077DFFD /* TSBootCell.swift in Sources */,
 				A81CA4852D1582A600A3AAC8 /* UIButton+Ex.swift in Sources */,
 				606372E72D5705F4005C82CF /* MusicPlaylistContainerViewController.swift in Sources */,
 				A81CA47F2D15789C00A3AAC8 /* TSConfig.swift in Sources */,
@@ -1533,6 +1554,7 @@
 				60553F7D2D3B528A00BAAD7F /* PlayDetailTopView.swift in Sources */,
 				60553F7E2D3B528A00BAAD7F /* CWOperateViewController+Ext.swift in Sources */,
 				A868577E2DF81A940089D222 /* TSDBActionInfoModel.swift in Sources */,
+				A8EE92C22DFFC54C0077DFFD /* TSBootModel.swift in Sources */,
 				A86857B72DF9258D0089D222 /* TSAIUploadPhotoVC.swift in Sources */,
 				60553F7F2D3B528A00BAAD7F /* OperateTopView.swift in Sources */,
 				A86857822DF81AD40089D222 /* TSActionInfoModel.swift in Sources */,
@@ -1625,6 +1647,7 @@
 				A839463C2D1D6E3600ABFF0D /* TSRandomWallpaperCopyrightVC.swift in Sources */,
 				A81CA4952D1652B500A3AAC8 /* TSEditLiveVC.swift in Sources */,
 				A86857D12DF977980089D222 /* TSAIListPhotoGeneratorVM.swift in Sources */,
+				A8E590392DFFAE4400C2533F /* TSBootVC.swift in Sources */,
 				A86857982DF846FE0089D222 /* TSDynamicBlurView.swift in Sources */,
 				A83946332D1D66A900ABFF0D /* TSPrivacyPolicyVC.swift in Sources */,
 				A86857C22DF926ED0089D222 /* TSPhotoSizeHelper.swift in Sources */,
@@ -1639,6 +1662,7 @@
 				A81CA4972D1652BD00A3AAC8 /* TSRandomWallpaperVC.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 */,
 				A81F5B5F2D1A909300740085 /* TSRandomWallpaperModel.swift in Sources */,

+ 30 - 6
TSLiveWallpaper/AppDelegate.swift

@@ -24,16 +24,35 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         return true
     }
 
+
+    func goToLoadVC() {
+        let luanch = TSLaunchVC()
+        luanch.dismissHandler = { [weak self] in
+            guard let self = self else { return }
+            JudgmentSkipPage()
+        }
+        window?.rootViewController = luanch
+    }
+    
     func goToTab() {
         window?.rootViewController = TSTabBarController()
     }
 
-    func goToLoadVC() {
-        _ = TSImageDataCenter.shared
-        window?.rootViewController = TSLaunchVC()
-        
+    func JudgmentSkipPage() {
+        if AppDelegate.isFirstInstallApp() {
+            let bootPageVC = TSBootVC { [weak self] in
+                guard let self = self else { return }
+//                UserDefaults.standard.set("1", forKey: "isFirstInstallApp")
+//                UserDefaults.standard.synchronize()
+                goToTab()
+            }
+            let navi = TSBaseNavigationC(rootViewController: bootPageVC)
+            window?.rootViewController = navi
+        } else {
+            goToTab()
+        }
     }
-
+    
     func initBaseDatas() {
         var config = TSConfiguration.default
         config.configurePath = "http://p.100yearslater.com/live/config"
@@ -78,10 +97,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 }
 
 extension AppDelegate {
+    
+    static func isFirstInstallApp() -> Bool {
+        return UserDefaults.standard.string(forKey: "isFirstInstallApp") == nil
+    }
+    
     func initPlatform() {
         dePrint("TSRMShared.aiListDB.listModels.count=\(TSRMShared.aiListDB.listModels.count)")
         TSColorConfigShared.naviMianTextColor = .white
-
+        _ = TSImageDataCenter.shared
         
         let cache = ImageCache(name: "permanent_image_cache")
         cache.diskStorage.config.expiration = .never    // 永不过期

+ 6 - 0
TSLiveWallpaper/Assets.xcassets/Boot/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 22 - 0
TSLiveWallpaper/Assets.xcassets/Boot/boot_bottom_shadow.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "boot_bottom_shadow@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "boot_bottom_shadow@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_bottom_shadow.imageset/boot_bottom_shadow@2x.png


BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_bottom_shadow.imageset/boot_bottom_shadow@3x.png


+ 21 - 0
TSLiveWallpaper/Assets.xcassets/Boot/boot_new_0.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "boot_new_0.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_new_0.imageset/boot_new_0.png


+ 21 - 0
TSLiveWallpaper/Assets.xcassets/Boot/boot_new_1.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "boot_new_1.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_new_1.imageset/boot_new_1.png


+ 21 - 0
TSLiveWallpaper/Assets.xcassets/Boot/boot_new_2.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "boot_new_2.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_new_2.imageset/boot_new_2.png


+ 21 - 0
TSLiveWallpaper/Assets.xcassets/Boot/boot_old_0.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "boot_old_0.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_old_0.imageset/boot_old_0.png


+ 21 - 0
TSLiveWallpaper/Assets.xcassets/Boot/boot_old_1.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "boot_old_1.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_old_1.imageset/boot_old_1.png


+ 21 - 0
TSLiveWallpaper/Assets.xcassets/Boot/boot_old_2.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "boot_old_2.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Boot/boot_old_2.imageset/boot_old_2.png


+ 308 - 0
TSLiveWallpaper/Business/BusinessView/TSImageProComparisonView.swift

@@ -0,0 +1,308 @@
+//
+//  TSImageProComparisonView.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/15.
+//
+
+import UIKit
+
+class TSImageProComparisonView: UIView {
+    // MARK: - 属性
+    private let oldImageView = UIImageView()
+    private let newImageView = UIImageView()
+    private let lineView = UIView()
+    private var displayLink: CADisplayLink?
+    private var animationStartTime: CFTimeInterval = 0
+    var duration: TimeInterval = 3.0
+    
+    // 动画方向枚举
+    enum AnimationDirection {
+        case leftToRight  // 从左到右(默认)
+        case rightToLeft  // 从右到左
+        case topToBottom  // 从上到下
+        case bottomToTop  // 从下到上
+    }
+    
+    // 动画曲线枚举
+    enum AnimationCurve {
+        case linear       // 线性
+        case easeIn       // 缓入
+        case easeOut      // 缓出
+        case easeInOut    // 缓入缓出
+    }
+    
+    // 线条样式枚举
+    enum LineStyle: Equatable {
+        case straight    // 直线(默认)
+        case curved(curveWidth: CGFloat) // 弧线,可以指定弧线宽度
+    }
+    
+    var direction: AnimationDirection = .leftToRight
+    var curve: AnimationCurve = .linear
+    var lineStyle: LineStyle = .straight
+    var lineWidth: CGFloat = 2.0
+    var lineColor: UIColor = .white
+    
+    // 当前进度(0.0-1.0)
+    private var currentProgress: CGFloat = 0.0
+    
+    // MARK: - 初始化
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        setupViews()
+    }
+    
+    required init?(coder: NSCoder) {
+        super.init(coder: coder)
+        setupViews()
+    }
+    
+    // MARK: - 视图设置
+    private func setupViews() {
+        // 旧图片视图(初始显示)
+        oldImageView.contentMode = .scaleAspectFill
+        oldImageView.clipsToBounds = true
+        addSubview(oldImageView)
+        
+        // 新图片视图(初始隐藏)
+        newImageView.contentMode = .scaleAspectFill
+        newImageView.clipsToBounds = true
+        newImageView.alpha = 0
+        addSubview(newImageView)
+        
+        // 分割线样式
+        lineView.backgroundColor = .clear
+        lineView.alpha = 0 // 初始隐藏
+        addSubview(lineView)
+    }
+    
+    // MARK: - 布局
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        oldImageView.frame = bounds
+        newImageView.frame = bounds
+    }
+    
+    // MARK: - 公开方法
+    func configure(oldImage: UIImage?, newImage: UIImage?) {
+        oldImageView.image = oldImage
+        newImageView.image = newImage
+        reset()
+    }
+    
+    func startAnimation(duration: TimeInterval = 3.0,
+                        direction: AnimationDirection = .leftToRight,
+                        curve: AnimationCurve = .linear) {
+        reset()
+        self.duration = duration
+        self.direction = direction
+        self.curve = curve
+        
+        // 初始状态
+        oldImageView.alpha = 1
+        newImageView.alpha = 0
+        lineView.alpha = 1
+        
+        // 启动动画
+        animationStartTime = CACurrentMediaTime()
+        displayLink = CADisplayLink(target: self, selector: #selector(updateAnimation))
+        displayLink?.add(to: .main, forMode: .common)
+    }
+    
+    private func stopAnimation() {
+        displayLink?.invalidate()
+        displayLink = nil
+    }
+    
+    func animationComplete() {
+        self.stopAnimation()
+        self.newImageView.alpha = 1
+        self.oldImageView.alpha = 0
+        self.lineView.alpha = 0
+    }
+ 
+    func reset() {
+        stopAnimation()
+        oldImageView.alpha = 1
+        newImageView.alpha = 0
+        lineView.alpha = 0
+        currentProgress = 0
+        lineView.frame = bounds // 重置为完整框架
+        lineView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
+    }
+    
+    // MARK: - 动画更新
+    @objc private func updateAnimation() {
+        guard displayLink != nil else { return }
+        
+        let elapsed = CACurrentMediaTime() - animationStartTime
+        let rawProgress = min(CGFloat(elapsed / duration), 1.0)
+        
+        // 应用动画曲线
+        let progress: CGFloat
+        switch curve {
+        case .linear:
+            progress = rawProgress
+        case .easeIn:
+            progress = rawProgress * rawProgress  // 缓入效果
+        case .easeOut:
+            progress = rawProgress * (2 - rawProgress)
+        case .easeInOut:
+            if rawProgress < 0.5 {
+                progress = 2 * rawProgress * rawProgress
+            } else {
+                progress = -1 + (4 - 2 * rawProgress) * rawProgress
+            }
+        }
+        
+        currentProgress = progress
+        updateViews(with: progress)
+        
+        if rawProgress >= 1.0 {
+            animationComplete()
+        }
+    }
+    
+    private func updateViews(with progress: CGFloat) {
+        // 更新遮罩和线条
+        updateMaskAndLine(with: progress)
+        newImageView.alpha = 1
+    }
+    
+    private func updateMaskAndLine(with progress: CGFloat) {
+        // 清除之前的图层
+        lineView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
+        lineView.backgroundColor = .clear
+        
+        // 创建遮罩层
+        let maskLayer = CAShapeLayer()
+        
+        // 创建线条图层
+        let lineLayer = CAShapeLayer()
+        lineLayer.strokeColor = lineColor.cgColor
+        lineLayer.fillColor = UIColor.clear.cgColor
+        lineLayer.lineWidth = lineWidth
+        
+        switch (direction, lineStyle) {
+        // 直线样式
+        case (_, .straight):
+            let path = UIBezierPath()
+            
+            switch direction {
+            case .leftToRight:
+                let x = bounds.width * progress
+                path.move(to: CGPoint(x: x, y: 0))
+                path.addLine(to: CGPoint(x: x, y: bounds.height))
+                
+                maskLayer.path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: x, height: bounds.height)).cgPath
+                
+            case .rightToLeft:
+                let x = bounds.width * (1 - progress)
+                path.move(to: CGPoint(x: x, y: 0))
+                path.addLine(to: CGPoint(x: x, y: bounds.height))
+                
+                maskLayer.path = UIBezierPath(rect: CGRect(x: x, y: 0, width: bounds.width - x, height: bounds.height)).cgPath
+                
+            case .topToBottom:
+                let y = bounds.height * progress
+                path.move(to: CGPoint(x: 0, y: y))
+                path.addLine(to: CGPoint(x: bounds.width, y: y))
+                
+                maskLayer.path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: bounds.width, height: y)).cgPath
+                
+            case .bottomToTop:
+                let y = bounds.height * (1 - progress)
+                path.move(to: CGPoint(x: 0, y: y))
+                path.addLine(to: CGPoint(x: bounds.width, y: y))
+                
+                maskLayer.path = UIBezierPath(rect: CGRect(x: 0, y: y, width: bounds.width, height: bounds.height - y)).cgPath
+            }
+            
+            lineLayer.path = path.cgPath
+            
+        // 弧线样式
+        case (.leftToRight, .curved(let curveWidth)):
+            let x = bounds.width * progress
+            let path = UIBezierPath()
+            path.move(to: CGPoint(x: x, y: 0))
+            path.addQuadCurve(to: CGPoint(x: x, y: bounds.height),
+                             controlPoint: CGPoint(x: x + curveWidth, y: bounds.height / 2))
+            
+            lineLayer.path = path.cgPath
+            
+            // 弧形遮罩
+            let maskPath = UIBezierPath()
+            maskPath.move(to: .zero)
+            maskPath.addLine(to: CGPoint(x: x, y: 0))
+            maskPath.addQuadCurve(to: CGPoint(x: x, y: bounds.height),
+                                 controlPoint: CGPoint(x: x + curveWidth, y: bounds.height / 2))
+            maskPath.addLine(to: CGPoint(x: 0, y: bounds.height))
+            maskPath.close()
+            maskLayer.path = maskPath.cgPath
+            
+        case (.rightToLeft, .curved(let curveWidth)):
+            let x = bounds.width * (1 - progress)
+            let path = UIBezierPath()
+            path.move(to: CGPoint(x: x, y: 0))
+            path.addQuadCurve(to: CGPoint(x: x, y: bounds.height),
+                             controlPoint: CGPoint(x: x - curveWidth, y: bounds.height / 2))
+            
+            lineLayer.path = path.cgPath
+            
+            // 弧形遮罩
+            let maskPath = UIBezierPath()
+            maskPath.move(to: CGPoint(x: bounds.width, y: 0))
+            maskPath.addLine(to: CGPoint(x: x, y: 0))
+            maskPath.addQuadCurve(to: CGPoint(x: x, y: bounds.height),
+                                 controlPoint: CGPoint(x: x - curveWidth, y: bounds.height / 2))
+            maskPath.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
+            maskPath.close()
+            maskLayer.path = maskPath.cgPath
+            
+        case (.topToBottom, .curved(let curveWidth)):
+            let y = bounds.height * progress
+            let path = UIBezierPath()
+            path.move(to: CGPoint(x: 0, y: y))
+            path.addQuadCurve(to: CGPoint(x: bounds.width, y: y),
+                             controlPoint: CGPoint(x: bounds.width / 2, y: y + curveWidth))
+            
+            lineLayer.path = path.cgPath
+            
+            // 弧形遮罩
+            let maskPath = UIBezierPath()
+            maskPath.move(to: .zero)
+            maskPath.addLine(to: CGPoint(x: 0, y: y))
+            maskPath.addQuadCurve(to: CGPoint(x: bounds.width, y: y),
+                                 controlPoint: CGPoint(x: bounds.width / 2, y: y + curveWidth))
+            maskPath.addLine(to: CGPoint(x: bounds.width, y: 0))
+            maskPath.close()
+            maskLayer.path = maskPath.cgPath
+            
+        case (.bottomToTop, .curved(let curveWidth)):
+            let y = bounds.height * (1 - progress)
+            let path = UIBezierPath()
+            path.move(to: CGPoint(x: 0, y: y))
+            path.addQuadCurve(to: CGPoint(x: bounds.width, y: y),
+                             controlPoint: CGPoint(x: bounds.width / 2, y: y - curveWidth))
+            
+            lineLayer.path = path.cgPath
+            
+            // 弧形遮罩
+            let maskPath = UIBezierPath()
+            maskPath.move(to: CGPoint(x: 0, y: bounds.height))
+            maskPath.addLine(to: CGPoint(x: 0, y: y))
+            maskPath.addQuadCurve(to: CGPoint(x: bounds.width, y: y),
+                                 controlPoint: CGPoint(x: bounds.width / 2, y: y - curveWidth))
+            maskPath.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
+            maskPath.close()
+            maskLayer.path = maskPath.cgPath
+        }
+        
+        // 应用遮罩
+        newImageView.layer.mask = maskLayer
+        
+        // 应用线条
+        lineView.layer.addSublayer(lineLayer)
+    }
+}

+ 120 - 0
TSLiveWallpaper/Business/TSBootVC/TSBootCell.swift

@@ -0,0 +1,120 @@
+//
+//  TSBootCell.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/15.
+//
+
+class TSBootBaseCell: TSBaseCollectionCell {
+    var model:TSBootModel = TSBootModel()
+    var complete:(()->Void)?
+}
+
+class TSBootCell: TSBootBaseCell {
+    
+
+    
+    override var model:TSBootModel{
+        didSet{
+            titleLabel.text = model.title
+            comparisonView.configure(
+                oldImage: model.oldImage,
+                newImage: model.newImage
+            )
+            
+            setContinueBtn(state: model.state)
+        }
+    }
+
+    lazy var comparisonView: TSImageProComparisonView = {
+       let comparisonView = TSImageProComparisonView(frame: CGRect(x: 0, y: 0, width: k_ScreenWidth, height: 678*kDesignScale))
+       comparisonView.lineStyle = .curved(curveWidth: 100)
+       comparisonView.lineWidth = 1.0
+       comparisonView.lineColor = .white
+       return comparisonView
+    }()
+
+    lazy var titleLabel: UILabel = {
+       let titleLabel = UILabel.createLabel(text: "",font: .font(size: 20,weight: .semibold),textColor: .white,textAlignment:.center,numberOfLines: 0)
+       return titleLabel
+    }()
+    
+    lazy var shadowImageView : UIImageView = {
+        let shadowImageView = UIImageView.createImageView(image: .bootBottomShadow)
+        return shadowImageView
+    }()
+        
+    lazy var btnBgAnimationColor:UIColor = "#F1D3AB".uiColor
+    lazy var btnBgNextColor:UIColor = "#E4A858".uiColor
+    lazy var continueBtn: UIButton = {
+       let continueBtn = UIButton.createButton(backgroundColor:btnBgAnimationColor,font: .font(size: 18,weight: .medium),titleColor: "#111111".uiColor,corner: 25){ [weak self]  in
+           guard let self = self else { return }
+           clickContinue()
+       }
+
+       let imageView = UIImageView.createImageView(imageName: "launch_rightArrow",contentMode: .scaleToFill)
+       continueBtn.addSubview(imageView)
+       imageView.snp.makeConstraints { make in
+           make.width.height.equalTo(24)
+           make.centerY.equalToSuperview()
+           make.trailing.equalTo(-24)
+       }
+       
+       return continueBtn
+    }()
+   
+   
+   func clickContinue(){
+       model.state += 1
+       setContinueBtn(state: model.state)
+   }
+   
+    func setContinueBtn(state:Int){
+        if state == 0 {
+            continueBtn.backgroundColor = btnBgAnimationColor
+            self.continueBtn.setTitle(model.btnTitle, for: .normal)
+        }else if state == 1 {
+            let duration = 0.5;
+            self.comparisonView.startAnimation(duration: duration,direction: .bottomToTop,curve: .easeIn)
+            UIView.animate(withDuration: duration, delay: 0.0, options: .curveEaseIn, animations: {
+                self.continueBtn.backgroundColor = self.btnBgNextColor
+                self.continueBtn.setTitle("Continue".localized, for: .normal)
+            }, completion: { end in
+                
+            })
+        }else if state == 2 {
+            complete?()
+        }
+    }
+    
+   override func creatUI() {
+       super.creatUI()
+       bgContentView.addSubview(comparisonView)
+       
+       bgContentView.addSubview(shadowImageView)
+       shadowImageView.snp.makeConstraints { make in
+           make.bottom.equalTo(0)
+           make.height.equalTo(407*kDesignScale)
+           make.leading.equalTo(0)
+           make.trailing.equalTo(0)
+       }
+       
+
+       bgContentView.addSubview(continueBtn)
+       continueBtn.snp.makeConstraints { make in
+           make.leading.equalTo(16)
+           make.trailing.equalTo(-16)
+           make.height.equalTo(50)
+           make.bottom.equalTo(-26-k_Height_safeAreaInsetsBottom())
+       }
+       
+       bgContentView.addSubview(titleLabel)
+       titleLabel.snp.makeConstraints { make in
+           make.bottom.equalTo(continueBtn.snp.top).offset(-24)
+           make.height.equalTo(56)
+           make.leading.equalTo(16)
+           make.trailing.equalTo(-16)
+       }
+       
+   }
+}

+ 27 - 0
TSLiveWallpaper/Business/TSBootVC/TSBootModel.swift

@@ -0,0 +1,27 @@
+//
+//  TSBootModel.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/15.
+//
+
+class TSBootModel {
+    
+    init(){ }
+    
+    init(title: String, oldImage: UIImage, newImage: UIImage, state: Int, cellID: String,btnTitle:String) {
+        self.title = title
+        self.oldImage = oldImage
+        self.newImage = newImage
+        self.state = state
+        self.cellID = cellID
+        self.btnTitle = btnTitle
+    }
+    
+    var title:String = ""
+    var oldImage:UIImage = UIImage()
+    var newImage:UIImage = UIImage()
+    var state:Int = 0 //0 点击开始动画,1 点击下一页
+    var cellID:String = ""
+    var btnTitle:String = ""
+}

+ 117 - 0
TSLiveWallpaper/Business/TSBootVC/TSBootVC.swift

@@ -0,0 +1,117 @@
+//
+//  TSBootVC.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/15.
+//
+
+class TSBootVC: TSBaseVC {
+    
+    var closeComplete:(()->Void)
+    init(closeComplete: @escaping () -> Void) {
+        self.closeComplete = closeComplete
+        super.init()
+    }
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    lazy var dataArray: [TSBootModel] = {
+        return [
+            TSBootModel(title: "Add Color to Memories".localized,
+                        oldImage: .bootOld0,
+                        newImage: .bootNew0,
+                        state: 0,
+                        cellID: "TSBootCell",
+                        btnTitle: "Colorize Photo".localized),
+            
+            TSBootModel(title: "Your photo is now vibrantly colorized, bringing memories to life".localized,
+                        oldImage: .bootOld1,
+                        newImage: .bootNew1,
+                        state: 0,
+                        cellID: "TSBootCell",
+                        btnTitle: "Remove Scratches".localized),
+            
+            TSBootModel(title: "Erase Scratches ".localized,
+                        oldImage: .bootOld2,
+                        newImage: .bootNew2,
+                        state: 0,
+                        cellID: "TSBootCell",
+                        btnTitle: "Enhance Photo".localized),
+        ]
+    }()
+    
+    var currentIndex:Int = 0{
+        didSet{
+            if dataArray.count > 0 {
+                
+                if currentIndex >= dataArray.count {
+                    closeComplete()
+                    return
+                }
+                self.collectionView.scrollToItem(at: IndexPath(item: currentIndex, section: 0), at: .centeredHorizontally, animated: true)
+            }
+        }
+    }
+    
+    lazy var layout: UICollectionViewFlowLayout = {
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .horizontal
+        layout.itemSize = CGSize(width: k_ScreenWidth, height: k_ScreenHeight)
+        layout.minimumInteritemSpacing = 0.0
+        layout.minimumLineSpacing = 0.0
+        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
+        return layout
+    }()
+    
+    lazy var collectionView: UICollectionView = {
+        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        collectionView.isScrollEnabled = false
+        collectionView.isPagingEnabled = true
+        collectionView.showsVerticalScrollIndicator = false
+        collectionView.showsHorizontalScrollIndicator = false
+        collectionView.backgroundColor = .clear
+        collectionView.register(TSBootCell.self, forCellWithReuseIdentifier: "TSBootCell")
+        collectionView.register(TSBootBaseCell.self, forCellWithReuseIdentifier: "TSBootBaseCell")
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        return collectionView
+    }()
+
+    
+    override func createView() {
+        setNavBarViewHidden(true)
+        contentView.addSubview(collectionView)
+        collectionView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    override func dealThings() {
+
+    }
+}
+
+extension TSBootVC : UICollectionViewDataSource ,UICollectionViewDelegate {
+    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return dataArray.count
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        if let model = dataArray.safeObj(At: indexPath.item),
+           let cell = collectionView.dequeueReusableCell(withReuseIdentifier: model.cellID, for: indexPath) as? TSBootCell{
+            cell.model = model
+            cell.complete = { [weak self]  in
+                guard let self = self else { return }
+                currentIndex = currentIndex + 1
+            }
+            return cell
+        }
+        return UICollectionViewCell()
+    }
+}
+ 

+ 1 - 0
TSLiveWallpaper/LaunchVC/TSLaunchVC.swift

@@ -50,6 +50,7 @@ class TSLaunchVC: UIViewController {
     }
 
     func enterApp() {
+        dismissHandler?()
         DispatchQueue.main.async {
             let keyWindow = WindowHelper.getCurrentWindow()
             if (keyWindow?.rootViewController is TSTabBarController) == false {