Procházet zdrojové kódy

feal:解决一批报错,app 可正常运行

100Years před 2 měsíci
rodič
revize
7590dbc66a

+ 72 - 0
TSLiveWallpaper.xcodeproj/project.pbxproj

@@ -171,6 +171,12 @@
 		A86857982DF846FE0089D222 /* TSDynamicBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857972DF846FB0089D222 /* TSDynamicBlurView.swift */; };
 		A868579A2DF915950089D222 /* TSPurchaseEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857992DF9158C0089D222 /* TSPurchaseEnum.swift */; };
 		A868579E2DF915E90089D222 /* TSPurchaseBusiness.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868579D2DF915DD0089D222 /* TSPurchaseBusiness.swift */; };
+		A86857A12DF91EB90089D222 /* TSAIListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857A02DF91EB80089D222 /* TSAIListVC.swift */; };
+		A86857A32DF91F690089D222 /* TSAILIstCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857A22DF91F680089D222 /* TSAILIstCell.swift */; };
+		A86857A82DF9204B0089D222 /* TSPhotoPickerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857A62DF9204B0089D222 /* TSPhotoPickerManager.swift */; };
+		A86857AC2DF921160089D222 /* TSAIListHintBaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857AA2DF921160089D222 /* TSAIListHintBaseVC.swift */; };
+		A86857B02DF921970089D222 /* TSAppBtnView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857AE2DF921970089D222 /* TSAppBtnView.swift */; };
+		A86857B22DF921F90089D222 /* TSView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857B12DF921F90089D222 /* TSView.swift */; };
 		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 */; };
@@ -370,6 +376,12 @@
 		A86857972DF846FB0089D222 /* TSDynamicBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSDynamicBlurView.swift; sourceTree = "<group>"; };
 		A86857992DF9158C0089D222 /* TSPurchaseEnum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchaseEnum.swift; sourceTree = "<group>"; };
 		A868579D2DF915DD0089D222 /* TSPurchaseBusiness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchaseBusiness.swift; sourceTree = "<group>"; };
+		A86857A02DF91EB80089D222 /* TSAIListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListVC.swift; sourceTree = "<group>"; };
+		A86857A22DF91F680089D222 /* TSAILIstCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAILIstCell.swift; sourceTree = "<group>"; };
+		A86857A62DF9204B0089D222 /* TSPhotoPickerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPhotoPickerManager.swift; sourceTree = "<group>"; };
+		A86857AA2DF921160089D222 /* TSAIListHintBaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListHintBaseVC.swift; sourceTree = "<group>"; };
+		A86857AE2DF921970089D222 /* TSAppBtnView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAppBtnView.swift; sourceTree = "<group>"; };
+		A86857B12DF921F90089D222 /* TSView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSView.swift; 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>"; };
@@ -746,6 +758,7 @@
 		A81CA4662D156A8100A3AAC8 /* Common */ = {
 			isa = PBXGroup;
 			children = (
+				A86857A52DF920400089D222 /* ViewTool */,
 				A86857832DF81B510089D222 /* TSNetWork */,
 				A8F76C452D3510E700AA6E93 /* NetworkManager */,
 				A8F76C402D350A9600AA6E93 /* Purchase */,
@@ -821,6 +834,8 @@
 		A81CA48C2D15855300A3AAC8 /* Business */ = {
 			isa = PBXGroup;
 			children = (
+				A86857AD2DF9218C0089D222 /* General */,
+				A86857A92DF9210D0089D222 /* TSAIListVC */,
 				A868578D2DF845D00089D222 /* BusinessView */,
 				606372DB2D549998005C82CF /* AdMob */,
 				60553F022D3B4DF800BAAD7F /* TSMusic */,
@@ -1081,6 +1096,8 @@
 		A868578D2DF845D00089D222 /* BusinessView */ = {
 			isa = PBXGroup;
 			children = (
+				A86857AE2DF921970089D222 /* TSAppBtnView.swift */,
+				A86857B12DF921F90089D222 /* TSView.swift */,
 				A86857972DF846FB0089D222 /* TSDynamicBlurView.swift */,
 				A868578E2DF845E40089D222 /* TSGeneratorloadingView */,
 			);
@@ -1097,6 +1114,55 @@
 			path = TSGeneratorloadingView;
 			sourceTree = "<group>";
 		};
+		A868579F2DF91EA10089D222 /* TSAIListVC */ = {
+			isa = PBXGroup;
+			children = (
+				A86857A02DF91EB80089D222 /* TSAIListVC.swift */,
+				A86857A22DF91F680089D222 /* TSAILIstCell.swift */,
+			);
+			path = TSAIListVC;
+			sourceTree = "<group>";
+		};
+		A86857A52DF920400089D222 /* ViewTool */ = {
+			isa = PBXGroup;
+			children = (
+				A86857A72DF9204B0089D222 /* TSPhotoPickerManager */,
+			);
+			path = ViewTool;
+			sourceTree = "<group>";
+		};
+		A86857A72DF9204B0089D222 /* TSPhotoPickerManager */ = {
+			isa = PBXGroup;
+			children = (
+				A86857A62DF9204B0089D222 /* TSPhotoPickerManager.swift */,
+			);
+			path = TSPhotoPickerManager;
+			sourceTree = "<group>";
+		};
+		A86857A92DF9210D0089D222 /* TSAIListVC */ = {
+			isa = PBXGroup;
+			children = (
+				A86857AB2DF921160089D222 /* TSAIAgeImageHintVC */,
+				A868579F2DF91EA10089D222 /* TSAIListVC */,
+			);
+			path = TSAIListVC;
+			sourceTree = "<group>";
+		};
+		A86857AB2DF921160089D222 /* TSAIAgeImageHintVC */ = {
+			isa = PBXGroup;
+			children = (
+				A86857AA2DF921160089D222 /* TSAIListHintBaseVC.swift */,
+			);
+			path = TSAIAgeImageHintVC;
+			sourceTree = "<group>";
+		};
+		A86857AD2DF9218C0089D222 /* General */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = General;
+			sourceTree = "<group>";
+		};
 		A8C4C0A12D24218A003C46FC /* Util */ = {
 			isa = PBXGroup;
 			children = (
@@ -1368,6 +1434,7 @@
 				606372DD2D54999C005C82CF /* ADScene.swift in Sources */,
 				A81F5B5D2D1A906C00740085 /* TSHomeDataModel.swift in Sources */,
 				A81CA49B2D1652CA00A3AAC8 /* TSHomeVC.swift in Sources */,
+				A86857B02DF921970089D222 /* TSAppBtnView.swift in Sources */,
 				A81CA4B82D16A6BD00A3AAC8 /* View+Ex.swift in Sources */,
 				A8F76C422D350A9600AA6E93 /* TSPurchaseManager.swift in Sources */,
 				60553FDD2D3B84E700BAAD7F /* UIScrollView+Ext.swift in Sources */,
@@ -1402,6 +1469,7 @@
 				60553F7F2D3B528A00BAAD7F /* OperateTopView.swift in Sources */,
 				A86857822DF81AD40089D222 /* TSActionInfoModel.swift in Sources */,
 				60553F802D3B528A00BAAD7F /* PlayDetailViewController+Ext.swift in Sources */,
+				A86857B22DF921F90089D222 /* TSView.swift in Sources */,
 				60553F812D3B528A00BAAD7F /* SJIJKMediaPlayer.m in Sources */,
 				60553F822D3B528A00BAAD7F /* SearchResultViewController.swift in Sources */,
 				60553F832D3B528A00BAAD7F /* THUD+CW.swift in Sources */,
@@ -1414,6 +1482,7 @@
 				60553F872D3B528A00BAAD7F /* PlayDetailListViewModel.swift in Sources */,
 				606372E32D55A995005C82CF /* ADLoadingViewController.swift in Sources */,
 				60553F882D3B528A00BAAD7F /* SearchViewModel.swift in Sources */,
+				A86857A32DF91F690089D222 /* TSAILIstCell.swift in Sources */,
 				60553F892D3B528A00BAAD7F /* CWOperateViewController.swift in Sources */,
 				60553F8A2D3B528A00BAAD7F /* THUDProtocol.swift in Sources */,
 				60553F8B2D3B528A00BAAD7F /* THUD.swift in Sources */,
@@ -1492,17 +1561,20 @@
 				A839463A2D1D6E3000ABFF0D /* TSRandomWallpaperTutorialsVC.swift in Sources */,
 				A84C239F2D1E88CD00B61B55 /* TSFileManagerTool.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 */,
 				A81F5B622D1AB17E00740085 /* TSRandomWallpaperBrowseVC.swift in Sources */,
 				A839463F2D1D6FB700ABFF0D /* TSLiveWallpaperTutorialsVC.swift in Sources */,
+				A86857A12DF91EB90089D222 /* TSAIListVC.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 */,
 				A8C4C0A72D24218A003C46FC /* LivePhotoUtil.m in Sources */,
+				A86857AC2DF921160089D222 /* TSAIListHintBaseVC.swift in Sources */,
 				A8C4C0A82D24218A003C46FC /* Converter4Image.swift in Sources */,
 				A83946432D1D701500ABFF0D /* TSLiveWallpaperCopyrightVC.swift in Sources */,
 				A8C4C0AB2D2427E7003C46FC /* LivePhotoConverter.swift in Sources */,

+ 206 - 0
TSLiveWallpaper/Business/BusinessView/TSAppBtnView.swift

@@ -0,0 +1,206 @@
+//
+//  TSAppBtnView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/23.
+//
+
+
+class TSAppBtn: UIButton {
+ 
+}
+
+class TSNormalSubmitBtn: TSAppBtn {
+//    override var isEnabled: Bool {
+//       didSet {
+//           // 根据 isEnabled 的值设置 alpha
+//           self.alpha = isEnabled ? 1.0 : 0.6
+//       }
+//    }
+}
+
+class TSNormalCancelBtn: TSAppBtn {
+
+}
+
+class TSAppBtnView: TSBaseView {
+    enum ViewStyle {
+        case generate   //创造类的按钮
+    }
+    
+    var viewH:CGFloat = 64
+    var style:ViewStyle = .generate
+    var vipFreeNumType:VipFreeNumType = .none{
+        didSet{
+            updateVipView()
+        }
+    }
+    var clickBlock:(()->Void)?
+    var btnFrame:CGRect?
+    var isIconVipBlock:(()->Bool)? //vip 图片显示
+    var isClickVipBlock:(()->Bool)?  //点击是,是否需要弹出 vip
+    
+    
+    
+    var loading:Bool = false{
+        willSet {
+            if loading != newValue {
+                loadingAnimation(loading: newValue)
+                
+                if loading == false {
+                    self.resetBtnText()
+                }
+            }
+        }
+    }
+    //###################################### Button ######################################
+    var button:UIButton = UIButton()
+    var title:String = ""
+    override func creatUI() {
+
+    }
+    
+    override func dealThings(){
+        
+    }
+
+    func setUpButton(style:ViewStyle,vipFreeNumType:VipFreeNumType = .none,btnFrame:CGRect? = nil,clickBlock: @escaping () -> Void) {
+        self.btnFrame = btnFrame
+        self.style = style
+        self.vipFreeNumType = vipFreeNumType
+        self.clickBlock = clickBlock
+        
+        contentView.removeAllSubViews()
+        
+        switch style {
+        case .generate:
+            title = "Generate".localized
+            setUpGenerate()
+            launchVipLogic()
+        }
+        
+    }
+    
+    
+    func setLoadingText(text:String?){
+        if loading {
+            button.setTitle(text, for: .normal)
+        }else{
+            resetBtnText()
+        }
+    }
+    
+    func resetBtnText(){
+        button.setTitle(title, for: .normal)
+    }
+}
+
+extension TSAppBtnView{
+    
+    func launchVipLogic(){
+        //监听 Vip 变化
+        NotificationCenter.default.addObserver(forName: .kPurchaseDidChanged, object: nil, queue: OperationQueue.main) { [weak self] notification in
+            guard let self = self else { return }
+            updateVipView()
+        }
+        
+        NotificationCenter.default.addObserver(forName: .kVipFreeNumChanged, object: nil, queue: OperationQueue.main) { [weak self] notification in
+            guard let self = self else { return }
+            if let userInfo = notification.userInfo as? [String: VipFreeNumType], let myEnum = userInfo["VipFreeNumType"] {
+                if myEnum == self.vipFreeNumType {
+                    self.updateVipView()
+                }
+            }
+        }
+        
+        updateVipView()
+    }
+
+    func updateVipView() {
+        switch style {
+        case .generate:
+            setVip(vip: isIconVipBlock?() ?? false)
+        }
+    }
+    
+    func setBtnEnabled(isEnabled:Bool) {
+        button.isEnabled = isEnabled
+//        button.alpha = isEnabled ? 1.0 : 0.6
+    }
+    
+    var isEnabled:Bool{
+        return button.isEnabled
+    }
+    
+    func setVip(vip:Bool) {
+        
+        if loading { //loading,正在显示转圈动画
+            return
+        }
+        
+        if vip {
+            button.setImage(UIImage(named: "btnImage_vip"), for: .normal)
+        }else{
+            button.setImage(nil, for: .normal)
+        }
+    }
+    
+}
+//创造按钮
+extension TSAppBtnView{
+
+    func setUpGenerate() {
+        button = kCreateNormalSubmitBtn(
+            title: title,
+            frame: CGRectMake(0, 0, k_ScreenWidth - 32, 48),
+            action: { [weak self]  in
+            guard let self = self else { return }
+            if let vc = WindowHelper.getCurrentViewController() {
+                if kJudgeVip(externalBool: isClickVipBlock?() ?? false, vc: vc) { return }  //判断 vip
+            }
+
+            clickBlock?()
+        })
+        contentView.addSubview(button)
+        button.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(button.width)
+            make.height.equalTo(button.height)
+        }
+   
+        
+        viewH = 48
+    }
+}
+//创造按钮
+extension TSAppBtnView{
+    
+    private func loadingAnimation(loading:Bool) {
+        if loading {
+            button.setImage(UIImage(named: "generated_loading"), for: .normal)
+            self.button.imageView?.startRotating()
+        }else {
+            button.imageView?.stopRotating()
+            updateVipView()
+        }
+    }
+    
+}
+//常用提交按钮
+func kCreateNormalSubmitBtn(title:String,frame:CGRect,action: (() -> Void)? = nil) -> UIButton {
+    let btn = TSNormalSubmitBtn()
+    btn.frame = frame
+    btn.setUpButton(title:title,font: UIFont.font(size: 16,weight: .medium),titleColor:.black,corner: frame.height/2,action: action)
+    btn.setTitleImageSpace(spacing: 8)
+
+    var buttonBgImage = UIImage(named: "submit_btn_bg")!
+    buttonBgImage = buttonBgImage.resizableImage(withCapInsets: UIEdgeInsets(top:24, left: 24, bottom: 24, right: 24), resizingMode: .stretch)
+    btn.setBackgroundImage(buttonBgImage, for: .normal)
+    
+    var buttonDisBgImage = UIImage(named: "submit_btn_dis_bg")!
+    buttonDisBgImage = buttonDisBgImage.resizableImage(withCapInsets: UIEdgeInsets(top:24, left: 24, bottom: 24, right: 24), resizingMode: .stretch)
+    btn.setBackgroundImage(buttonDisBgImage, for: .disabled)
+    
+    return btn
+}
+

+ 66 - 0
TSLiveWallpaper/Business/BusinessView/TSView.swift

@@ -0,0 +1,66 @@
+//
+//  TSViewTool.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2024/12/20.
+//
+
+
+
+func createBlurEffectView(style:UIBlurEffect.Style,backgroundColor:UIColor? = nil,alpha:CGFloat = 0.9) -> UIVisualEffectView {
+    let blurEffect = UIBlurEffect(style: style)
+    let blurEffectView = UIVisualEffectView(effect: blurEffect)
+    blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+    
+    if backgroundColor != nil {
+        blurEffectView.backgroundColor = backgroundColor
+    }
+    
+    blurEffectView.alpha = alpha
+    return blurEffectView
+}
+
+//常用提交按钮
+func kCreateNormalSubmitBtn(title:String, action: (() -> Void)? = nil) -> UIButton {
+    let btn = UIButton.createButton(title:title,font: UIFont.font(size: 16,weight: .medium),titleColor:.black,corner: 30,action: action)
+    
+    var buttonBgImage = UIImage(named: "submit_btn_bg")!
+    buttonBgImage = buttonBgImage.resizableImage(withCapInsets: UIEdgeInsets(top:24, left: 24, bottom: 24, right: 24), resizingMode: .stretch)
+    btn.setBackgroundImage(buttonBgImage, for: .normal)
+    
+    var buttonDisBgImage = UIImage(named: "submit_btn_dis_bg")!
+    buttonDisBgImage = buttonDisBgImage.resizableImage(withCapInsets: UIEdgeInsets(top:24, left: 24, bottom: 24, right: 24), resizingMode: .stretch)
+    btn.setBackgroundImage(buttonDisBgImage, for: .disabled)
+    btn.setTitleImageSpace(spacing: 8)
+    return btn
+}
+
+
+let kSubmitBtnbg = UIImage(named: "submit_btn_bg")
+let kSubmitBtnSmallBg = UIImage(named: "submit_btn_small_bg")
+let kSubmitBtnNormalbg = UIImage(named: "submit_btn_normal_bg")
+
+//常用取消按钮
+func kCreateNormalCancelBtn(title:String, action: (() -> Void)? = nil) -> UIButton {
+    let btn = UIButton.createButton(title:title,backgroundColor: .fromHex("#FFFFFF", alpha: 0.4),font: UIFont.font(size: 14,weight: .medium),titleColor:.white,corner: 30,action: action)
+    return btn
+}
+//常用确定按钮
+func kCreateNormalConfirmBtn(title:String, action: (() -> Void)? = nil) -> UIButton {
+    let btn = UIButton.createButton(title:title,backgroundImage:UIImage(named: "submit_btn_small_bg"),font: UIFont.font(size: 14,weight: .medium),titleColor:.white,corner: 30,action: action)
+    return btn
+}
+
+//给按钮设置 vip 图标
+func kSetBtnVipIcon(btn:UIButton,show:Bool){
+    btn.setImage(show ? UIImage(named:"btnImage_vip") : nil, for: .normal)
+}
+
+let kPlaceholderImage = UIImage(named: "placeholderImage")
+
+
+func kGetScaleHeight(originalSize:CGSize,width:CGFloat) -> CGFloat {
+    let originalScale = originalSize.width/originalSize.height
+    let height = width/originalScale
+    return height
+}

+ 258 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIAgeImageHintVC/TSAIListHintBaseVC.swift

@@ -0,0 +1,258 @@
+//
+//  TSAIListHintBaseVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/9.
+//
+
+//import PhotosUI
+//class TSAIListHintBaseVC: TSBaseVC {
+//    static var userDefaultsKey:String = "isFirstAIListAge"
+//    
+//    struct Config {
+//        var imageMaxBitSize:Int
+//        var goodImageNamed:String
+//        var badImageNamed:String
+//
+//        var titleText:String
+//        var titleSubText:String
+//        
+//        var goodText:String
+//        var goodInfoText:String
+//      
+//        var badText:String
+//        var badInfoText:String
+//        
+//        
+//        init(imageMaxBitSize: Int, goodImageNamed: String, badImageNamed: String, titleText: String, titleSubText: String, goodText: String, goodInfoText: String, badText: String, badInfoText: String) {
+//            self.imageMaxBitSize = imageMaxBitSize
+//            self.goodImageNamed = goodImageNamed
+//            self.badImageNamed = badImageNamed
+//            self.titleText = titleText
+//            self.titleSubText = titleSubText
+//            self.goodText = goodText
+//            self.goodInfoText = goodInfoText
+//            self.badText = badText
+//            self.badInfoText = badInfoText
+//        }
+//        
+//        static func getDefaultConfig(imageMaxBitSize:Int) -> Config {
+//            var config = defaultConfig
+//            config.imageMaxBitSize = imageMaxBitSize
+//            return config
+//        }
+//        
+//        static var defaultConfig:Config {
+//            return Config(imageMaxBitSize: kUploadImageMaxBit10Size,
+//                          goodImageNamed: "ptp_goodImage",
+//                          badImageNamed: "ptp_badImage",
+//                          titleText: "Upload your photos".localized,
+//                          titleSubText: "",
+//                          goodText: "Good photo examples".localized,
+//                          goodInfoText: "Fully clear and visible face, in good lighting".localized,
+//                          badText: "Bad photo examples".localized,
+//                          badInfoText: "Group photos, covered faces, nudes".localized)
+//        }
+//        
+//        static var changeHairConfig:Config {
+//            return Config(imageMaxBitSize: kUploadImageMaxBit5Size,
+//                          goodImageNamed: "ptp_hair_goodImage",
+//                          badImageNamed: "ptp_hair_badImage",
+//                          titleText: "Upload your photos".localized,
+//                          titleSubText: "",
+//                          goodText: "Good photo examples".localized,
+//                          goodInfoText: "Obvious hairstyle, Fully clear and visible face".localized,
+//                          badText: "Bad photo examples".localized,
+//                          badInfoText: "Group photos, covered faces, skinhead".localized)
+//        }
+//        
+//        static var catTohumanConfig:Config {
+//            return Config(imageMaxBitSize: kUploadImageMaxBit10Size,
+//                          goodImageNamed: "ptp_catTohuman_goodImage",
+//                          badImageNamed: "ptp_catTohuman_badImage",
+//                          titleText: "Upload your photos".localized,
+//                          titleSubText: "",
+//                          goodText: "Good photo examples".localized,
+//                          goodInfoText: "Select pet photos with clear faces".localized,
+//                          badText: "Bad photo examples".localized,
+//                          badInfoText: "No clear faces or group shots".localized)
+//        }
+//        
+//        
+//        static var futureBabyConfig:Config {
+//            return Config(imageMaxBitSize: kUploadImageMaxBit10Size,
+//                          goodImageNamed: "ptp_futureBaby_goodImage",
+//                          badImageNamed: "ptp_badImage",
+//                          titleText: "Upload your photos".localized,
+//                          titleSubText: "",
+//                          goodText: "Good photo examples".localized,
+//                          goodInfoText: "Fully clear and visible face, in good lighting".localized,
+//                          badText: "Bad photo examples".localized,
+//                          badInfoText: "Group photos, covered faces, nudes".localized)
+//        }
+//    }
+//    
+//    var config:Config = Config.defaultConfig
+//    init(config: Config, clickUpImageHandle: ((UIImage?) -> Void)? = nil) {
+//        self.config = config
+//        self.clickUpImageHandle = clickUpImageHandle
+//        super.init()
+//    }
+//    
+//    @MainActor required init?(coder: NSCoder) {
+//        fatalError("init(coder:) has not been implemented")
+//    }
+//    
+//    var clickUpImageHandle:((UIImage?)->Void)?
+//    lazy var popupContentView: UIView = {
+//        let popupContentView = UIView()
+//        popupContentView.backgroundColor = "#222222".uiColor
+//        popupContentView.cornerRadius = 20.0
+//        return popupContentView
+//    }()
+//    
+//    lazy var photoPickerManager: TSPhotoPickerManager = {
+//        let photoPickerManager = TSPhotoPickerManager(viewController: self)
+//        return photoPickerManager
+//    }()
+//    
+//    lazy var submitBtn: UIButton = {
+//        let submitBtn = kCreateNormalSubmitBtn(title: "Upload Photo".localized) { [weak self]  in
+//            guard let self = self else { return }
+//            pickSinglePhoto()
+//        }
+//        submitBtn.cornerRadius = 24.0
+//        return submitBtn
+//    }()
+//    
+//    override func createView() {
+//        setNavBarViewHidden(true)
+//        view.backgroundColor = .black.withAlphaComponent(0.7)
+//        
+//        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickView)))
+//        
+//        contentView.addSubview(popupContentView)
+//        popupContentView.center = view.center
+//        
+//        popupContentView.snp.makeConstraints { make in
+//            make.leading.equalTo(20)
+//            make.trailing.equalTo(-20)
+//            make.center.equalToSuperview()
+//        }
+//        
+//        setUpUI()
+//    }
+//    
+//    @objc func clickView() {
+//        dismiss(animated: true)
+//    }
+//    
+//    
+//    func setUpUI(){
+// 
+//        let fullText = config.titleText+config.titleSubText
+//        let attString = NSMutableAttributedString(string: fullText)
+//        let mainRange = NSRange(location: 0, length: config.titleText.count)
+//        attString.addAttributes([.font:UIFont.font(size: 18,weight: .semibold),.foregroundColor:UIColor.white], range: NSRange(location: 0, length: config.titleText.count))
+//        attString.addAttributes([.font:UIFont.font(size: 12),.foregroundColor:UIColor.white.withAlphaComponent(0.6)], range: NSRange(location: config.titleText.count, length: config.titleSubText.count))
+//
+//        let titleLabel = UILabel.createLabel(numberOfLines: 0)
+//        titleLabel.attributedText = attString
+//        popupContentView.addSubview(titleLabel)
+//        titleLabel.snp.makeConstraints { make in
+//            make.leading.top.equalTo(32)
+//            make.trailing.equalTo(-32)
+//        }
+//        
+//        let goodLabel = UILabel.createLabel(text: config.goodText,font: .font(size: 16,weight: .medium),textColor: .white,numberOfLines: 0)
+//        popupContentView.addSubview(goodLabel)
+//        goodLabel.snp.makeConstraints { make in
+//            make.top.equalTo(titleLabel.snp.bottom).offset(28)
+//            make.leading.equalTo(32)
+//            make.trailing.equalTo(-32)
+//        }
+//        
+//        let goodInfoLabel = UILabel.createLabel(text: config.goodInfoText,font: .font(size: 14),textColor: .white.withAlphaComponent(0.6),numberOfLines: 0)
+//        popupContentView.addSubview(goodInfoLabel)
+//        goodInfoLabel.snp.makeConstraints { make in
+//            make.top.equalTo(goodLabel.snp.bottom).offset(8)
+//            make.leading.equalTo(32)
+//            make.trailing.equalTo(-32)
+//        }
+//        
+//        let goodImageView = UIImageView.createImageView(imageName: config.goodImageNamed)
+//        popupContentView.addSubview(goodImageView)
+//        goodImageView.snp.makeConstraints { make in
+//            make.top.equalTo(goodInfoLabel.snp.bottom).offset(12)
+//            make.leading.equalTo(32)
+//            make.trailing.equalTo(-32)
+//            make.height.equalTo(108*kDesignScale)
+//        }
+//        
+//        let badLabel = UILabel.createLabel(text: config.badText,font: .font(size: 16,weight: .medium),textColor: .white,numberOfLines: 0)
+//        popupContentView.addSubview(badLabel)
+//        badLabel.snp.makeConstraints { make in
+//            make.top.equalTo(goodImageView.snp.bottom).offset(28)
+//            make.leading.equalTo(32)
+//            make.trailing.equalTo(-32)
+//        }
+//        
+//        let badInfoLabel = UILabel.createLabel(text: config.badInfoText,font: .font(size: 14),textColor: .white.withAlphaComponent(0.6),numberOfLines: 0)
+//        popupContentView.addSubview(badInfoLabel)
+//        badInfoLabel.snp.makeConstraints { make in
+//            make.top.equalTo(badLabel.snp.bottom).offset(8)
+//            make.leading.equalTo(32)
+//            make.trailing.equalTo(-32)
+//        }
+//        
+//        let badImageView = UIImageView.createImageView(imageName: config.badImageNamed)
+//        popupContentView.addSubview(badImageView)
+//        badImageView.snp.makeConstraints { make in
+//            make.top.equalTo(badInfoLabel.snp.bottom).offset(12)
+//            make.leading.equalTo(32)
+//            make.trailing.equalTo(-32)
+//            make.height.equalTo(108*kDesignScale)
+//        }
+//        
+//        popupContentView.addSubview(submitBtn)
+//        submitBtn.snp.makeConstraints { make in
+//            make.top.equalTo(badImageView.snp.bottom).offset(35)
+//            make.centerX.equalToSuperview()
+//            make.width.equalTo(250*kDesignScale)
+//            make.height.equalTo(48)
+//            make.bottom.equalTo(-24)
+//        }
+//    }
+//
+//    static var isShowUploadImageHint:Bool{
+//        get {
+//            return UserDefaults.standard.string(forKey: userDefaultsKey) == nil
+//        }
+//        
+//        set {
+//            UserDefaults.standard.set(newValue ? nil : "1", forKey: userDefaultsKey)
+//            UserDefaults.standard.synchronize()
+//        }
+//    }
+//    
+//    func pickSinglePhoto()  {
+//        self.submitBtn.isUserInteractionEnabled = false
+//        photoPickerManager.pickCustomSinglePhoto() { [weak self] image, errorString in
+//            guard let self = self else { return }
+//            self.submitBtn.isUserInteractionEnabled = true
+//            if let errorString = errorString {
+//                TSToastShared.showToast(text: errorString)
+//            }else{
+//                self.clickUpImageHandle?(image)
+//            }
+//        }
+//        
+//  
+//    }
+//    
+//    func dismissPageVC(){
+//        self.view.isHidden = true
+//        self.photoPickerManager.dismissPageVC()
+//        self.dismiss(animated: true)
+//    }
+//}

+ 67 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIListVC/TSAILIstCell.swift

@@ -0,0 +1,67 @@
+//
+//  TSAILIstCell.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/10.
+//
+
+
+import Kingfisher
+class TSAILIstCell: TSBaseCollectionCell {
+    
+    static let cellID = "TSAILIstCell"
+    var itemModel:TSBasicItemModel = TSBasicItemModel(){
+        didSet{
+            if let imageNamed = itemModel.leftImageName{
+                bgImageView.image = UIImage(named: imageNamed)
+            }
+            titleLab.text = itemModel.leftTitle
+            infoLab.text = itemModel.leftSubTitle
+        }
+    }
+    
+    lazy var bgImageView: UIImageView = {
+        let bgImageView = UIImageView()
+        bgImageView.contentMode = .scaleToFill
+        return bgImageView
+    }()
+    
+    
+    lazy var titleLab: UILabel = {
+        let titleLab = UILabel.createLabel(font: .font(size: 18,weight: .medium),textColor: .fromHex("FFFFFF"),numberOfLines: 0)
+        return titleLab
+    }()
+    
+    lazy var infoLab: UILabel = {
+        let infoLab = UILabel.createLabel(font: .font(size: 14,weight: .regular),textColor: .white.withAlphaComponent(0.8),numberOfLines: 0)
+        return infoLab
+    }()
+    
+    override func creatUI() {
+        bgContentView.clipsToBounds = true
+        bgContentView.addSubview(bgImageView)
+        bgImageView.snp.makeConstraints { make in
+            make.top.bottom.leading.trailing.equalTo(0)
+        }
+        
+        let leading = 12.0
+        let trailing = -155.0*kDesignScale
+        bgContentView.addSubview(infoLab)
+        infoLab.snp.makeConstraints { make in
+            make.trailing.equalTo(trailing)
+            make.leading.equalTo(leading)
+            make.bottom.equalTo(-12)
+            make.height.greaterThanOrEqualTo(16)
+        }
+
+        bgContentView.addSubview(titleLab)
+        titleLab.snp.makeConstraints { make in
+            make.trailing.equalTo(trailing)
+            make.leading.equalTo(leading)
+            make.bottom.equalTo(infoLab.snp.top).offset(-8)
+            make.height.greaterThanOrEqualTo(18)
+        }
+    }
+    
+}
+

+ 275 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIListVC/TSAIListVC.swift

@@ -0,0 +1,275 @@
+//
+//  TSAIListVC.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/10.
+//
+
+
+//class TSAILIstVC: TSBaseVC {
+//    
+//    lazy var dataArray: [TSBasicSectionModel] = {
+//        var dataArray = [TSBasicSectionModel]()
+//        let sectionModel = TSBasicSectionModel()
+//        dataArray.append(sectionModel)
+//        
+//        //照片高清修复
+//        sectionModel.addSubItemModel(
+//            createItemModel(
+//                leftImageName:"aiList_quality",
+//                leftTitle: "Photo Enhancer".localized,
+//                leftSubTitle: "Enhance photo's quality".localized,
+//                rightViewStyle: 0,
+//                tapBlock: { [weak self] model, _, _ in
+//                   guard let self = self else { return }
+//                    enterSelectPhotos(
+//                        userDefaultsKey: "",,
+//                        maxBitSize: kUploadImageMaxBit10Size,
+//                        config:.defaultConfig
+//                    ) { image in
+//                    let baseVc = TSAIUploadPhotoBaseVC(titleString: model.leftTitle ?? "",upLoadImage: nil,imageMaxBitSize: kUploadImageMaxBit10Size, generatorStyle: .photoQuality)
+//                        kPushVC(target: self, modelVC: baseVc)
+//                    }
+//        }))
+//        //老照片修复
+//        sectionModel.addSubItemModel(
+//            createItemModel(
+//                leftImageName:"aiList_restOldPhoto",
+//                leftTitle: "Restoring Photo".localized,
+//                leftSubTitle: "AI helps you find the good moments of the past".localized,
+//                rightViewStyle: 0,
+//                tapBlock: { [weak self] model, _, _ in
+//                   guard let self = self else { return }
+//                    enterSelectPhotos(
+//                        userDefaultsKey: "isFirstAIChangeRestOldPhoto",
+//                        maxBitSize: kUploadImageMaxBit5Size,
+//                        config: .getDefaultConfig(imageMaxBitSize: kUploadImageMaxBit5Size)
+//                    ) { image in
+//                        let baseVc = TSAIUploadPhotoBaseVC(titleString: model.leftTitle ?? "",upLoadImage: nil,imageMaxBitSize: kUploadImageMaxBit5Size, generatorStyle: .oldPhoto)
+//                        kPushVC(target: self, modelVC: baseVc)
+//                    }
+//        }))
+//
+//        return dataArray
+//
+//    }()
+//    
+//    var hintBaseVC:TSAIListHintBaseVC = TSAIListHintBaseVC(config: .defaultConfig)
+//    //###################################### 导航栏 view ######################################
+//
+//    lazy var vipBtn: UIButton = {
+//       let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
+//           guard let self = self else { return }
+//           TSPurchaseVC.show(target: self) {}
+//       }
+//       return vipBtn
+//   }()
+//    
+//
+//    lazy var navBarView: TSBaseNavContentBarView = {
+//       let navBarView = TSBaseNavContentBarView()
+//       
+//       let titleImageView = UIImageView.createImageView(imageName: "nav_title_ailist",contentMode: .scaleToFill)
+//       navBarView.barView.addSubview(titleImageView)
+//       titleImageView.snp.makeConstraints { make in
+//           make.centerY.equalToSuperview()
+//           make.left.equalTo(16)
+//       }
+//       
+//       navBarView.barView.addSubview(vipBtn)
+//       vipBtn.snp.makeConstraints { make in
+//           make.centerY.equalToSuperview()
+//           make.trailing.equalTo(-16)
+//           make.width.height.equalTo(24)
+//       }
+//       
+//       return navBarView
+//   }()
+//    
+//    //###################################### 导航栏 ######################################
+//    lazy var layout: UICollectionViewFlowLayout = {
+//        let layout = UICollectionViewFlowLayout()
+//        layout.scrollDirection = .vertical
+//        let w = k_ScreenWidth-32
+//        let h = kGetScaleHeight(originalSize: CGSizeMake(343, 124), width: w)
+//        layout.itemSize = CGSize(width: w, height: h)
+//        layout.minimumInteritemSpacing = 9.0
+//        layout.minimumLineSpacing = 16.0
+//        
+//        layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
+//        return layout
+//    }()
+//    lazy var collectionView: UICollectionView = {
+//        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+//        collectionView.delegate = self
+//        collectionView.dataSource = self
+//        collectionView.showsVerticalScrollIndicator = false
+//        collectionView.showsHorizontalScrollIndicator = false
+//        collectionView.backgroundColor = .clear
+//        collectionView.register(TSAILIstCell.self, forCellWithReuseIdentifier: TSAILIstCell.cellID)
+//        if #available(iOS 11.0, *) {
+//            collectionView.contentInsetAdjustmentBehavior = .never
+//        }
+//        return collectionView
+//    }()
+//
+//    lazy var photoPickerManager: TSPhotoPickerManager = {
+//        let photoPickerManager = TSPhotoPickerManager(viewController: self)
+//        return photoPickerManager
+//    }()
+//    
+//    override func createView() {
+//        
+//        navBarContentView.addSubview(navBarView)
+//        navBarView.snp.makeConstraints { make in
+//            make.edges.equalToSuperview()
+//        }
+//
+//        contentView.addSubview(collectionView)
+//        collectionView.snp.makeConstraints { make in
+//            make.edges.equalToSuperview()
+//        }
+//    }
+//    
+//    override func dealThings() {
+//        NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil)
+//        updateVipView()
+//        
+//        NotificationCenter.default.addObserver(forName: .kOpenMotherDayVC, object: nil, queue: OperationQueue.main) { [weak self] _ in
+//            guard let self = self else { return }
+//            DispatchQueue.main.async {
+//                let baseVc = TSAIUploadPhotoBaseVC(titleString: "Happy Mother's Day".localized,upLoadImage: nil,imageMaxBitSize: kUploadImageMaxBit10Size, generatorStyle: .motherDay)
+//                kPushVC(target: self, modelVC: baseVc)
+//            }
+//        }
+//        
+//        NotificationCenter.default.addObserver(forName: .kOpenCatTohumanVC, object: nil, queue: OperationQueue.main) { [weak self] _ in
+//            guard let self = self else { return }
+//            DispatchQueue.main.async {
+//                let baseVc = TSAIUploadPhotoBaseVC(titleString: "Pet Humanization".localized,upLoadImage: nil,imageMaxBitSize: kUploadImageMaxBit10Size, generatorStyle: .catTohuman)
+//                kPushVC(target: self, modelVC: baseVc)
+//            }
+//        }
+//
+//    }
+//}
+//
+//
+//extension TSAILIstVC {
+//
+//    @objc func updateVipView() {
+//        kMainAsync {
+//            self.vipBtn.isHidden = PurchaseManager.default.isVip
+//        }
+//    }
+//
+//    func createItemModel(leftImageName: String,
+//                         leftTitle: String,
+//                         leftSubTitle: String,
+//                        rightViewStyle: Int,
+//                        tapBlock: @escaping ((TSBasicItemModel, Int, Any?) -> Void)) -> TSBasicItemModel {
+//        let model = TSBasicItemModel()
+//        model.leftImageName = leftImageName
+//        model.leftTitle = leftTitle
+//        model.leftSubTitle = leftSubTitle
+//        model.rightViewStyle = rightViewStyle
+//        model.tapBlock = tapBlock
+//        return model
+//    }
+//}
+//
+//extension TSAILIstVC: UICollectionViewDataSource ,UICollectionViewDelegate {
+//    
+//    public func numberOfSections(in collectionView: UICollectionView) -> Int {
+//        return dataArray.count
+//    }
+//    
+//    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+//        if let sectionModel = dataArray.safeObj(At: section){
+//            return sectionModel.itemsArray.count
+//        }
+//        return 0
+//    }
+//    
+//    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+//        
+//        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TSAILIstCell.cellID, for: indexPath)
+//        if let cell = cell as? TSAILIstCell {
+//            if let sectionModel = dataArray.safeObj(At: indexPath.section),let itemModel = sectionModel.itemsArray.safeObj(At: indexPath.row){
+//                cell.itemModel = itemModel
+//            }
+//        }
+//        
+//        return cell
+//    }
+//
+//    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+//        if let sectionModel = dataArray.safeObj(At: indexPath.section),let itemModel = sectionModel.itemsArray.safeObj(At: indexPath.row){
+//            itemModel.tapBlock?(itemModel,indexPath.row,nil)
+//        }
+//    }
+//}
+//
+//extension TSAILIstVC{
+//    
+//    func enterSelectPhotos(userDefaultsKey:String,maxBitSize:Int,config:TSAIListHintBaseVC.Config,complete: @escaping (UIImage)->Void){
+//        if userDefaultsKey.count == 0 {
+//            self.pickSinglePhoto(maxBitSize:maxBitSize,complete:complete)
+//        }else{
+//            TSAIListHintBaseVC.userDefaultsKey = userDefaultsKey
+//            if TSAIListHintBaseVC.isShowUploadImageHint{
+//                TSAIListHintBaseVC.isShowUploadImageHint = false
+//                self.presentModalHintVC(config:config,complete:complete)
+//            }else {
+//                self.pickSinglePhoto(maxBitSize:maxBitSize,complete:complete)
+//            }
+//        }
+//    }
+//    
+//    
+//    func presentModalHintVC(config:TSAIListHintBaseVC.Config,complete:@escaping (UIImage)->Void){
+//        hintBaseVC = TSAIListHintBaseVC(config: config) { [weak self] image in
+//            guard let self = self else { return }
+//            if let image = image {
+//                complete(image)
+//            }else{
+//                dePrint("图片异常")
+//            }
+//            kDelayMainShort {
+//                self.hintBaseVC.dismissPageVC()
+//            }
+//        }
+//        kPresentModalVC(target: self, modelVC: hintBaseVC,transitionStyle: .crossDissolve)
+//    }
+//    
+//    func pickSinglePhoto(maxBitSize:Int,complete: @escaping (UIImage)->Void)  {
+////        photoPickerManager.pickSinglePhoto(maxBitSize: maxBitSize) { [weak self] image, errorString in
+//        photoPickerManager.pickCustomSinglePhoto() { [weak self] image, errorString in
+//            guard let self = self else { return }
+//            if let errorString = errorString {
+//                TSToastShared.showToast(text: errorString)
+//            }else if let image = image {
+//                complete(image)
+//            }else{
+//                dePrint("图片异常")
+//            }
+//            kDelayMainShort {
+//                self.photoPickerManager.dismissPageVC()
+//            }
+//            
+//        }
+//    }
+//}
+//
+//extension TSAILIstVC{
+//    func openMotherDayVC(titleString:String){
+//        enterSelectPhotos(
+//            userDefaultsKey: "isFirstAIListMotherDayHintVC",
+//            maxBitSize: kUploadImageMaxBit10Size,
+//            config:.defaultConfig
+//        ) { image in
+//            let baseVc = TSAIUploadPhotoBaseVC(titleString: titleString,upLoadImage: image,imageMaxBitSize: kUploadImageMaxBit10Size, generatorStyle: .motherDay)
+//            kPushVC(target: self, modelVC: baseVc)
+//        }
+//    }
+//}

+ 1 - 1
TSLiveWallpaper/Business/TSEditLiveVC/TSEditLiveEidtCell.swift

@@ -124,7 +124,7 @@ class TSEditLiveEidtCell : TSBaseCollectionCell{
     }
     
     @objc func vipInfoChanged() {
-        kExecuteOnMainThread {
+        kMainAsync {
             self.diyBtn.setTitle(self.getVipText(), for: .normal)
         }
     }

+ 3 - 3
TSLiveWallpaper/Business/TSEditLiveVC/TSEditLiveVC.swift

@@ -225,7 +225,7 @@ extension TSEditLiveVC {
 //
 //                if let resources = resources {
 //                    LivePhoto.saveToLibrary(resources, completion: { (success) in
-//                        kExecuteOnMainThread {
+//                        kMainAsync {
 //                            hideLoading()
 //                            if success {
 //                                debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
@@ -253,7 +253,7 @@ extension TSEditLiveVC {
 //
 //                    if let resources = resources {
 //                        LivePhoto.saveToLibrary(resources, completion: { (success) in
-//                            kExecuteOnMainThread {
+//                            kMainAsync {
 //                                hideLoading()
 //                                if success {
 //                                    debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
@@ -384,7 +384,7 @@ extension TSEditLiveVC {
 //
 //                    try fileManager.copyItem(at: url, to: targetURL)
 //
-//                    kExecuteOnMainThread {
+//                    kMainAsync {
 //                        self.openVideoClipperVC(videoURL: targetURL)
 //                    }
 //

+ 4 - 4
TSLiveWallpaper/Business/TSHomeVC/TSLiveWallpaperBrowseVC/TSLiveWallpaperBrowseVC.swift

@@ -587,7 +587,7 @@ class TSLiveWallpaperBrowseCell : TSBaseCollectionCell,PHLivePhotoViewDelegate{
     func saveLivePhoto(completion: @escaping (Bool) -> Void){
 //        if let resources = itemModel?.livePhotoResources {
 //            LivePhoto.saveToLibrary(resources, completion: { (success) in
-//                kExecuteOnMainThread {
+//                kMainAsync {
 //                    if success {
 //                        debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
 //                        completion(true)
@@ -601,7 +601,7 @@ class TSLiveWallpaperBrowseCell : TSBaseCollectionCell,PHLivePhotoViewDelegate{
         
 //        if let resources = itemModel?.livePhotoResources {
 //            LivePhotoConverter.saveToLibrary(videoURL: resources.pairedVideo, imageURL: resources.pairedImage) { success in
-//                kExecuteOnMainThread {
+//                kMainAsync {
 //                    if success {
 //                        debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
 //                        completion(true)
@@ -621,7 +621,7 @@ class TSLiveWallpaperBrowseCell : TSBaseCollectionCell,PHLivePhotoViewDelegate{
         TSToastShared.showLoading()
         if videoCacheUrl.path.contains("/saveVideo/") {
             LivePhotoConverter.saveToLibrary(videoURL: videoCacheUrl, imageURL: imageCacheUrl) { success in
-                kExecuteOnMainThread {
+                kMainAsync {
                     TSToastShared.hideLoading()
                     if success {
                         debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
@@ -641,7 +641,7 @@ class TSLiveWallpaperBrowseCell : TSBaseCollectionCell,PHLivePhotoViewDelegate{
                 TSToastShared.hideLoading()
                 if success {
                     LivePhotoConverter.saveToLibrary(videoURL: videoURL!, imageURL: photoURL!) { success in
-                        kExecuteOnMainThread {
+                        kMainAsync {
                             if success {
                                 debugPrint("Live Photo Saved,The live photo was successfully saved to Photos.")
                                 completion(true)

+ 1 - 4
TSLiveWallpaper/Business/TSPurchaseMembershipVC/TSViewTool/TSViewTool.swift

@@ -56,9 +56,6 @@ class TSViewTool: UIView {
 }
 
 
-let kSubmitBtnbg = UIImage(named: "submit_btn_bg")
-let kSubmitBtnSmallBg = UIImage(named: "submit_btn_small_bg")
-let kSubmitBtnNormalbg = UIImage(named: "submit_btn_normal_bg")
 let kWapppaperPlaceholderImage = UIImage(named: "wapppaper_placeholder")
 let KIconLiveImage = UIImage(named: "icon_live")
 
@@ -142,7 +139,7 @@ class TSSavePhotoSuccessTool {
     
     func show(atView:UIView,text:String = "Save Successfully".localized) {
         
-        kExecuteOnMainThread {
+        kMainAsync {
             self.textLabel.text = text
             atView.addSubview(self.saveSuccessBg)
             self.saveSuccessBg.snp.remakeConstraints { make in

+ 1 - 1
TSLiveWallpaper/Business/TSRandomWallpaperVC/TSRandomWallpaperBrowseVC/TSRandomWallpaperBrowseVC.swift

@@ -160,7 +160,7 @@ class TSRandomWallpaperBrowseVC: TSBaseVC {
             
             group.notify(queue: .main) {
                 PhotoManagerShared.saveImagesToUniqueAlbum(images: images, baseAlbumName: self.dataModel.type) { success, error in
-                    kExecuteOnMainThread {
+                    kMainAsync {
                         TSToastShared.hideLoading()
                         if success {
                             kSavePhotoSuccesswShared.show(atView: self.view)

+ 0 - 3
TSLiveWallpaper/Common/GlobalImports/GlobalImports.swift

@@ -5,9 +5,6 @@
 //  Created by 100Years on 2024/12/20.
 //
 @_exported import TSSmalCoacopods
-@_exported import Foundation
-@_exported import UIKit
-@_exported import SnapKit
 
 import AVFoundation
 

+ 16 - 0
TSLiveWallpaper/Common/Purchase/TSPurchaseBusiness.swift

@@ -158,3 +158,19 @@ extension TSPurchaseBusiness{
     }
 }
 
+func kJudgeVip(externalBool:Bool,
+               vc:UIViewController? = nil,
+               closePageBlock:(()->Void)? = nil) -> Bool {
+    //判断 vip
+    if externalBool,
+       PurchaseManager.default.isVip == false
+    {
+        if let vc = vc {
+            TSPurchaseVC.show(target: vc, closePageBlock: nil)
+        }else if let rootVC = WindowHelper.getRootViewController() {
+            TSPurchaseVC.show(target: rootVC, closePageBlock: nil)
+        }
+        return true
+    }
+    return false
+}

+ 7 - 10
TSLiveWallpaper/Common/Tool/TSCommonTool/TSCommonTool.swift

@@ -192,19 +192,17 @@ class TSCommonTool {
 
 }
 
-
-
 /// 主线程延迟执行回调
 /// - Parameters:
 ///   - delay: 延迟时间(秒)
 ///   - completion: 延迟后的回调
-func kDelayOnMainThread(_ delay: TimeInterval, completion: @escaping () -> Void) {
+func kMainAfter(_ delay: TimeInterval, completion: @escaping () -> Void) {
     DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
         completion()
     }
 }
 
-func kDelayMainShort(completion: @escaping () -> Void) {
+func kMainShort(completion: @escaping () -> Void) {
     DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
         completion()
     }
@@ -212,13 +210,9 @@ func kDelayMainShort(completion: @escaping () -> Void) {
 
 /// 在主线程上执行代码
 /// - Parameter block: 要执行的代码块
-func kExecuteOnMainThread(_ block: @escaping () -> Void) {
-    if Thread.isMainThread {
+func kMainAsync(_ block: @escaping () -> Void) {
+    DispatchQueue.main.async {
         block()
-    } else {
-        DispatchQueue.main.async {
-            block()
-        }
     }
 }
 
@@ -229,3 +223,6 @@ func kPresentModalVC(target:UIViewController,modelVC:UIViewController,style:UIMo
     target.present(navi, animated: true)
 }
 
+let kAppName:String = "Picguru" //Picguru Chibii Chibi Ghiblii AI Image Picguru
+let kUploadImageMaxBit10Size:Int = 10 * 1024 * 1024 //10M
+let kUploadImageMaxBit5Size:Int = 5 * 1024 * 1024 //5M

+ 173 - 0
TSLiveWallpaper/Common/ViewTool/TSPhotoPickerManager/TSPhotoPickerManager.swift

@@ -0,0 +1,173 @@
+//
+//  TSPhotoPickerManager.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/2/25.
+//
+
+import UIKit
+import PhotosUI
+
+//class TSPhotoPickerManager: NSObject {
+//    
+//    // MARK: - Properties
+//    private weak var viewController: UIViewController?
+//    private var completionHandler: ((UIImage?,PHAsset?) -> Void)?
+//    private var completionSizeHandler: ((UIImage?,String?) -> Void)?
+//    private var imagePicker = UIImagePickerController()
+//    // MARK: - Initializers
+//    init(viewController: UIViewController) {
+//        self.viewController = viewController
+//    }
+//    
+//    // MARK: - Public Methods
+//    /// 打开照片选择器,单选一张照片
+//    func pickSinglePhoto(completion: @escaping (UIImage?,PHAsset?) -> Void) {
+//        self.completionHandler = completion
+//        // 检查相册权限
+//        checkPhotoLibraryPermission { [weak self] authorized in
+//            guard let self = self else { return }
+//            if authorized {
+//                self.openPhotoPicker()
+//            } else {
+//                self.showPermissionAlert()
+//            }
+//        }
+//    }
+//    
+//    // MARK: - Private Methods
+//    /// 检查相册权限
+//    private func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) {
+//        let status = PHPhotoLibrary.authorizationStatus()
+//        switch status {
+//        case .authorized:
+//            completion(true)
+//        case .notDetermined:
+//            PHPhotoLibrary.requestAuthorization { newStatus in
+//                DispatchQueue.main.async {
+//                    completion(newStatus == .authorized)
+//                }
+//            }
+//        default:
+//            completion(false)
+//        }
+//    }
+//    
+//    /// 打开照片选择器
+//    private func openPhotoPicker() {
+//        imagePicker = UIImagePickerController()
+//        imagePicker.sourceType = .photoLibrary
+//        imagePicker.delegate = self
+//        imagePicker.mediaTypes = ["public.image"] // 只选择照片
+////        imagePicker.modalPresentationStyle = .custom
+////        imagePicker.modalTransitionStyle = .crossDissolve
+//        if #available(iOS 13.0, *) {
+//            imagePicker.overrideUserInterfaceStyle = .dark
+//        }
+//        viewController?.present(imagePicker, animated: true, completion: nil)
+//    }
+//    
+//    /// 显示权限提示
+//    private func showPermissionAlert() {
+//        let alert = UIAlertController(
+//            title: "No photos permission".localized,
+//            message: "Please enable photo permission in settings to select photos".localized,
+//            preferredStyle: .alert
+//        )
+//        alert.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil))
+//        alert.addAction(UIAlertAction(title: "Go to Settings".localized, style: .default) { _ in
+//            if let url = URL(string: UIApplication.openSettingsURLString) {
+//                UIApplication.shared.open(url, options: [:], completionHandler: nil)
+//            }
+//        })
+//        viewController?.present(alert, animated: true, completion: nil)
+//    }
+//    
+//    deinit {
+//        debugPrint("♻️♻️♻️ TSPhotoPickerManager -> TSPhotoPickerManager deinit ♻️♻️♻️")
+//    }
+//}
+//
+//// MARK: - UIImagePickerControllerDelegate & UINavigationControllerDelegate (iOS 14 以下)
+//extension TSPhotoPickerManager: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
+//    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
+////        picker.dismiss(animated: true) {
+//            if let image = info[.originalImage] as? UIImage {
+//                self.completionHandler?(image,info[.phAsset] as? PHAsset )
+//            } else {
+//                self.completionHandler?(nil,nil)
+//            }
+////        }
+//        
+//        if completionSizeHandler == nil {
+//            picker.dismiss(animated: true, completion: nil)
+//        }
+//
+//    }
+//    
+//    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
+////        self.completionHandler?(nil,nil)
+////        if completionSizeHandler == nil {
+//            picker.dismiss(animated: true, completion: nil)
+////        }
+//    }
+//}
+//
+//
+//
+//extension TSPhotoPickerManager{
+//    
+//    func pickCustomSinglePhoto(completion: @escaping (UIImage?,String?) -> Void) {
+//        self.completionSizeHandler = completion
+//        pickSinglePhoto { [weak self] image,phAsset in
+//            guard let self = self else { return }
+//            self.completionSizeHandler?(image,nil)
+//            self.completionSizeHandler = nil
+//        }
+//    }
+//    
+//    // MARK: - Public Methods
+//    /// 打开照片选择器,单选一张照片
+//    func pickSinglePhoto(maxBitSize:Int, completion: @escaping (UIImage?,String?) -> Void) {
+//        self.completionSizeHandler = completion
+//
+//        let maxmbSize = Int(Double(maxBitSize) / (1024 * 1024))
+//        pickSinglePhoto { [weak self] image,phAsset in
+//            guard let self = self else { return }
+//            if let image = image,let phAsset = phAsset {
+//                // 方法2:异步获取详细大小(不阻塞主线程)
+//                TSPhotoSizeHelper.getImageFileSizeAsync(asset: phAsset) {[weak self] size in
+//                    guard let self = self else { return }
+//                    
+//                    let mbSize = Double(size) / (1024 * 1024)
+//                    print("精确大小: \(mbSize) MB,size = \(size)")
+//                    if size > maxBitSize {
+//                        self.completionSizeHandler?(nil,String(format: "Photo must be smaller than %dMB.".localized, maxmbSize))
+//                    }else{
+//                        self.completionSizeHandler?(image,nil)
+//                        self.completionSizeHandler = nil
+////                        imagePicker.dismiss(animated: true)
+//                    }
+//                }
+//            }else{
+//                if let image = image {
+//                    if image.isLargerThan(byteSize: maxBitSize) {
+//                        self.completionSizeHandler?(nil,String(format: "Photo must be smaller than %dMB.".localized, maxmbSize))
+//                    }else{
+//                        self.completionSizeHandler?(image,nil)
+//                        self.completionSizeHandler = nil
+////                        imagePicker.dismiss(animated: true)
+//                    }
+//                }else{
+//                    self.completionSizeHandler?(nil,nil)
+////                    imagePicker.dismiss(animated: true)
+//                }
+//            }
+//        }
+//    }
+//    
+//    func dismissPageVC(){
+//        self.imagePicker.view.isHidden = true
+//        self.imagePicker.dismiss(animated: true)
+//    }
+//}