Kaynağa Gözat

feat:增加生成图片的代码

100Years 2 ay önce
ebeveyn
işleme
d5b856a813

+ 24 - 0
TSLiveWallpaper.xcodeproj/project.pbxproj

@@ -185,6 +185,10 @@
 		A86857C22DF926ED0089D222 /* TSPhotoSizeHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857C12DF926EB0089D222 /* TSPhotoSizeHelper.swift */; };
 		A86857C42DF92AEB0089D222 /* UIFont+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857C32DF92AE30089D222 /* UIFont+Ex.swift */; };
 		A86857C62DF92BE70089D222 /* ZillaSlab-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A86857C52DF92BE70089D222 /* ZillaSlab-Bold.ttf */; };
+		A86857CF2DF977640089D222 /* TSAIListPhotoGeneratorVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857CE2DF977630089D222 /* TSAIListPhotoGeneratorVC.swift */; };
+		A86857D12DF977980089D222 /* TSAIListPhotoGeneratorVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857D02DF9778B0089D222 /* TSAIListPhotoGeneratorVM.swift */; };
+		A86857D32DF978740089D222 /* TSProgressState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857D22DF978730089D222 /* TSProgressState.swift */; };
+		A86857D52DF97A2A0089D222 /* TSAIExpandChangeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857D42DF97A2A0089D222 /* TSAIExpandChangeView.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 */; };
@@ -398,6 +402,10 @@
 		A86857C12DF926EB0089D222 /* TSPhotoSizeHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPhotoSizeHelper.swift; sourceTree = "<group>"; };
 		A86857C32DF92AE30089D222 /* UIFont+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Ex.swift"; sourceTree = "<group>"; };
 		A86857C52DF92BE70089D222 /* ZillaSlab-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ZillaSlab-Bold.ttf"; sourceTree = "<group>"; };
+		A86857CE2DF977630089D222 /* TSAIListPhotoGeneratorVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListPhotoGeneratorVC.swift; sourceTree = "<group>"; };
+		A86857D02DF9778B0089D222 /* TSAIListPhotoGeneratorVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListPhotoGeneratorVM.swift; sourceTree = "<group>"; };
+		A86857D22DF978730089D222 /* TSProgressState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSProgressState.swift; sourceTree = "<group>"; };
+		A86857D42DF97A2A0089D222 /* TSAIExpandChangeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIExpandChangeView.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>"; };
@@ -1080,6 +1088,7 @@
 			isa = PBXGroup;
 			children = (
 				A86857812DF81ACF0089D222 /* TSActionInfoModel.swift */,
+				A86857D22DF978730089D222 /* TSProgressState.swift */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -1162,6 +1171,8 @@
 		A86857A92DF9210D0089D222 /* TSAIListVC */ = {
 			isa = PBXGroup;
 			children = (
+				A86857D42DF97A2A0089D222 /* TSAIExpandChangeView.swift */,
+				A86857CD2DF9775D0089D222 /* TSAIPhotoGeneratorVC */,
 				A86857BA2DF926070089D222 /* TSAIListHistoryVC */,
 				A86857B82DF9259C0089D222 /* TSAIList+Enmu.swift */,
 				A86857B62DF9258D0089D222 /* TSAIUploadPhotoVC */,
@@ -1203,6 +1214,15 @@
 			path = TSAIListHistoryVC;
 			sourceTree = "<group>";
 		};
+		A86857CD2DF9775D0089D222 /* TSAIPhotoGeneratorVC */ = {
+			isa = PBXGroup;
+			children = (
+				A86857CE2DF977630089D222 /* TSAIListPhotoGeneratorVC.swift */,
+				A86857D02DF9778B0089D222 /* TSAIListPhotoGeneratorVM.swift */,
+			);
+			path = TSAIPhotoGeneratorVC;
+			sourceTree = "<group>";
+		};
 		A8C4C0A12D24218A003C46FC /* Util */ = {
 			isa = PBXGroup;
 			children = (
@@ -1554,6 +1574,7 @@
 				60553F9F2D3B528A00BAAD7F /* FilterBarView.swift in Sources */,
 				60553FA02D3B528A00BAAD7F /* SongListViewController+Target.swift in Sources */,
 				60553FA12D3B528A00BAAD7F /* ToastView.swift in Sources */,
+				A86857D32DF978740089D222 /* TSProgressState.swift in Sources */,
 				A868579A2DF915950089D222 /* TSPurchaseEnum.swift in Sources */,
 				60553FA22D3B528A00BAAD7F /* SongListViewController.swift in Sources */,
 				60553FA32D3B528A00BAAD7F /* PlayListTopItemView.swift in Sources */,
@@ -1571,6 +1592,7 @@
 				60553FAE2D3B528A00BAAD7F /* CWProgressView.swift in Sources */,
 				60553FAF2D3B528A00BAAD7F /* TipsView.swift in Sources */,
 				60553FB02D3B528A00BAAD7F /* PlayMiniBar.swift in Sources */,
+				A86857CF2DF977640089D222 /* TSAIListPhotoGeneratorVC.swift in Sources */,
 				60553FB12D3B528A00BAAD7F /* SongDownloadCell.swift in Sources */,
 				60553FB22D3B528A00BAAD7F /* LocalSearchViewModel.swift in Sources */,
 				A86857922DF845F60089D222 /* TSGeneratoringAnimationView.swift in Sources */,
@@ -1602,11 +1624,13 @@
 				A839463C2D1D6E3600ABFF0D /* TSRandomWallpaperCopyrightVC.swift in Sources */,
 				A81CA4952D1652B500A3AAC8 /* TSEditLiveVC.swift in Sources */,
 				606372E12D54BC37005C82CF /* GoogleMobileAdsConsentManager.swift in Sources */,
+				A86857D12DF977980089D222 /* TSAIListPhotoGeneratorVM.swift in Sources */,
 				A86857982DF846FE0089D222 /* TSDynamicBlurView.swift in Sources */,
 				A83946332D1D66A900ABFF0D /* TSPrivacyPolicyVC.swift in Sources */,
 				A86857C22DF926ED0089D222 /* TSPhotoSizeHelper.swift in Sources */,
 				A839463A2D1D6E3000ABFF0D /* TSRandomWallpaperTutorialsVC.swift in Sources */,
 				A84C239F2D1E88CD00B61B55 /* TSFileManagerTool.swift in Sources */,
+				A86857D52DF97A2A0089D222 /* TSAIExpandChangeView.swift in Sources */,
 				A81F5B562D1982BF00740085 /* TSImageDataCenter.swift in Sources */,
 				A86857A82DF9204B0089D222 /* TSPhotoPickerManager.swift in Sources */,
 				A839462F2D1D64BF00ABFF0D /* TSAboutUsVC.swift in Sources */,

+ 145 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIExpandChangeView.swift

@@ -0,0 +1,145 @@
+//
+//  TSAIExpandChangeView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/22.
+//
+
+class TSAIExpandChangeView: TSBaseView {
+    
+    
+    var clickAddViewBlock:(()->Void)?
+    
+    lazy var maxSize: CGSize = {
+        let maxSize = CGSizeMake(k_ScreenWidth, 465*kDesignScale)
+        return maxSize
+    }()
+    
+    
+    lazy var bgImageView: UIImageView = {
+        let imageView = UIImageView.createImageView(imageName: "clear_Bg",contentMode: .scaleAspectFill)
+        return imageView
+    }()
+    
+    lazy var boardView: UIView = {
+        let boardView = UIView()
+        boardView.layer.borderColor = UIColor.white.cgColor
+        boardView.layer.borderWidth = 1.5
+        return boardView
+    }()
+    
+    lazy var expandAreaView: UIView = {
+        let view = UIView()
+        
+        view.addSubview(bgImageView)
+        bgImageView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        view.addSubview(showImageView)
+        showImageView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(maxSize.width)
+            make.height.equalTo(maxSize.height)
+        }
+        
+        view.addSubview(uploadImageBgView)
+        uploadImageBgView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        view.addSubview(boardView)
+        boardView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        return view
+    }()
+    
+    lazy var showImageView: UIImageView = {
+        let imageView = UIImageView()
+        imageView.isUserInteractionEnabled = true
+        imageView.contentMode = .scaleAspectFit
+        return imageView
+    }()
+    
+    lazy var uploadImageBgView: UIView = {
+        let bgView = UIView()
+        bgView.addGestureRecognizer(UITapGestureRecognizer(target: self, action:#selector(clickAddBgView)))
+        bgView.addSubview(upLoadView)
+        bgView.isHidden = true
+        upLoadView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+        }
+        return bgView
+    }()
+    
+    lazy var upLoadView: UIView = {
+        let bgView = UIView()
+        
+        let addImageView = UIImageView.createImageView(imageName: "add")
+        bgView.addSubview(addImageView)
+        addImageView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.centerX.equalToSuperview()
+            make.width.height.equalTo(24)
+        }
+        
+        let textLabel = UILabel.createLabel(text: "Upload Photo".localized,font: .font(size: 16),textColor: .white)
+        bgView.addSubview(textLabel)
+        textLabel.snp.makeConstraints { make in
+            make.top.equalTo(addImageView.snp.bottom).offset(16)
+            make.centerX.equalToSuperview()
+            make.bottom.equalToSuperview()
+        }
+        return bgView
+    }()
+    
+    override func creatUI() {
+        contentView.addSubview(expandAreaView)
+        expandAreaView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(maxSize.width)
+            make.height.equalTo(maxSize.height)
+        }
+        
+    }
+    
+    
+    func updateExpandAreaView(width:CGFloat,height:CGFloat){
+        expandAreaView.snp.updateConstraints { make in
+            make.width.equalTo(width)
+            make.height.equalTo(height)
+        }
+    }
+    
+    func updateImageView(width:CGFloat,height:CGFloat){
+        showImageView.snp.updateConstraints { make in
+            make.width.equalTo(width)
+            make.height.equalTo(height)
+        }
+    }
+    
+    func setImage(showImage:UIImage?,bgImage:UIImage? = nil){
+        showImageView.image = showImage
+        bgImageView.image = bgImage ?? UIImage(named: "clear_Bg")
+        uploadImageBgView.isHidden = showImageView.image==nil ? false : true
+        boardView.isHidden = !uploadImageBgView.isHidden
+    }
+    
+    func onlyBgImage(only:Bool) {
+        if only {
+            bgImageView.isHidden = false
+            showImageView.isHidden = true
+        }else{
+            bgImageView.isHidden = true
+            showImageView.isHidden = false
+        }
+    }
+    
+    
+    @objc func clickAddBgView() {
+        clickAddViewBlock?()
+    }
+    
+}

+ 4 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIList+Enmu.swift

@@ -57,4 +57,8 @@ enum TSGeneratorImageStyle {
     var advance:Bool{
         return false
     }
+    //服务器生成图片所用的模型
+    var aiModel:String {
+        return "kie"
+    }
 }

+ 410 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoGeneratorVC/TSAIListPhotoGeneratorVC.swift

@@ -0,0 +1,410 @@
+//
+//  TSAIPhotoGeneratorVC.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/11.
+//
+
+import Kingfisher
+struct TSAIListPhotoGeneratorModel {
+    var upLoadImage:UIImage
+    var generatorStyle:TSGeneratorImageStyle
+    var expandEdge:UIEdgeInsets
+    var expandViewSizes:(CGSize,CGSize)?
+    var additionalPrompt:String//追加的提示词
+    
+    //预测宝宝
+    var upLoadImages:[UIImage]?
+    
+    
+    init(upLoadImage: UIImage,
+         generatorStyle: TSGeneratorImageStyle,
+         expandEdge:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0),
+         expandViewSizes:(CGSize,CGSize)? = nil,
+         additionalPrompt:String = "",
+         upLoadImages:[UIImage]? = nil
+    ) {
+        self.upLoadImage = upLoadImage
+        self.generatorStyle = generatorStyle
+        self.expandEdge = expandEdge
+        self.expandViewSizes = expandViewSizes
+        self.additionalPrompt = additionalPrompt
+        self.upLoadImages = upLoadImages
+    }
+}
+
+class TSAIListPhotoGeneratorVC: TSBaseVC {
+
+    init(generatorModel:TSAIListPhotoGeneratorModel,complete:@escaping ((TSActionInfoModel)->Void)) {
+        self.complete = complete
+        self.viewModel = TSAIListPhotoGeneratorBaseVM(generatorModel: generatorModel)
+        super.init()
+    }
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    var imageModel:TSActionInfoModel?
+    var complete:((TSActionInfoModel)->Void)
+    var progressState = TSProgressState.none
+    
+    var isSavePhotoMark:Bool = false
+    var isNeedSavePhoto:Bool {
+        if isSavePhotoMark == false,let _ = imageModel {
+            return true
+        }
+        return false
+    }
+    
+    var viewModel: TSAIListPhotoGeneratorBaseVM!
+//    var videoPlayerVC: TSAIListVideoPlayerVC = TSAIListVideoPlayerVC(videoURL: URL(string: "www.baidu.com")!)
+    lazy var bottomViewH = 60+k_Height_safeAreaInsetsBottom()
+    lazy var netWorkImageView: UIImageView = {
+        let netWorkImageView = UIImageView(frame: CGRectMake(0, 0, k_ScreenWidth, k_ScreenHeight-bottomViewH))
+        netWorkImageView.backgroundColor = "#111111".uiColor
+        netWorkImageView.contentMode = .scaleAspectFit
+        netWorkImageView.isUserInteractionEnabled = true
+        return netWorkImageView
+    }()
+    
+    lazy var generateInView : TSGeneratorView = {
+        let generateInView = TSGeneratorView()
+        generateInView.isUploadImage = false
+        generateInView.animationView.setText(time: String(format: "~ %d min".localized, 2), info: "Lots of people are creating images right now, so this might take a bit.".localized)
+        generateInView.clickErrorBlock = { [weak self] style in
+            guard let self = self else { return }
+            
+            switch style {
+            case .netWorkError:
+                clickRegenerateBtn()
+            default:
+                self.dismiss(animated: false, completion: nil)
+                break
+            }
+        }
+        
+        
+        return generateInView
+    }()
+    
+    lazy var expandAreaView: TSAIExpandChangeView = {
+        let view = TSAIExpandChangeView()
+        return view
+    }()
+    
+    lazy var switchOriginalPictureBtn: TSUIExpandedTouchButton = {
+        let switchOriginalPictureBtn = TSUIExpandedTouchButton()
+        switchOriginalPictureBtn.setUpButton(image:UIImage(named: "switch_original_picture"))
+        switchOriginalPictureBtn.addTarget(self, action: #selector(switchOriginalPictureTouchDown), for: .touchDown)
+        switchOriginalPictureBtn.addTarget(self, action: #selector(switchOriginalPictureTouchUp), for: [.touchUpInside, .touchUpOutside, .touchCancel])
+        switchOriginalPictureBtn.isHidden = true
+        return switchOriginalPictureBtn
+    }()
+    
+//    lazy var rotatingPictureBtn: TSUIExpandedTouchButton = {
+//        let rotatingPictureBtn = TSUIExpandedTouchButton()
+//        rotatingPictureBtn.setUpButton(image:UIImage(named: "rotating_picture")){ [weak self]  in
+//            guard let self = self else { return }
+//            //旋转图片并储存
+//            if let image = netWorkImageView.image?.rotated(by: .degrees90) {
+//                netWorkImageView.image = image
+//                if let resultUrl = self.imageModel?.response.resultUrl,
+//                   let url = URL(string: resultUrl){
+//                    ImageCache.default.store(image, forKey: url.cacheKey)
+//                }
+//            }
+//        }
+//        rotatingPictureBtn.isHidden = true
+//        return rotatingPictureBtn
+//    }()
+    
+    
+    lazy var saveBtn: UIButton = {
+        let saveBtn = kCreateNormalSubmitBtn(title: "Save".localized) { [weak self]  in
+            guard let self = self else { return }
+            clickSaveBtn()
+        }
+        return saveBtn
+    }()
+    
+    override func createView() {
+
+        contentView.addSubview(generateInView)
+        generateInView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        super.createView()
+        
+        contentView.addSubview(switchOriginalPictureBtn)
+        switchOriginalPictureBtn.snp.makeConstraints { make in
+            make.bottom.equalTo(-k_Height_safeAreaInsetsBottom() - 76)
+            make.trailing.equalTo(-16)
+            make.width.equalTo(40)
+            make.height.equalTo(40)
+        }
+        
+//        contentView.addSubview(rotatingPictureBtn)
+//        rotatingPictureBtn.snp.makeConstraints { make in
+//            make.bottom.equalTo(-k_Height_safeAreaInsetsBottom() - 76)
+//            make.trailing.equalTo(-16)
+//            make.width.equalTo(40)
+//            make.height.equalTo(40)
+//        }
+        
+        saveBtn.setTitleImageSpace(spacing: 0)
+        
+//        if viewModel.generatorModel.generatorStyle == .photoExpand {
+//            setUpExpandAreaView()
+//        }
+
+    }
+    
+//    func setUpExpandAreaView(){
+//        netWorkImageView.addSubview(expandAreaView)
+//        expandAreaView.snp.makeConstraints { make in
+//            make.top.leading.trailing.bottom.equalTo(0)
+//        }
+//        
+//        expandAreaView.showImageView.isHidden = true
+//        expandAreaView.boardView.isHidden = true
+//        
+//        if let sizes = self.viewModel.generatorModel.expandViewSizes {
+//            expandAreaView.updateExpandAreaView(width: sizes.0.width, height: sizes.0.height)
+//            expandAreaView.updateImageView(width: sizes.1.width, height: sizes.1.height)
+//        }
+//    }
+    
+    func closePage() {
+    
+        if progressState.isResult {
+            if isNeedSavePhoto{
+                TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+                    message: "You haven't saved the photo yet. Are you sure to quit?".localized,
+                    messageColor: .white,
+                    messageFont: .systemFont(ofSize: 16),
+                    
+                    cancelTitle: "Quit".localized,
+                    cancelColor: .white,
+                    
+                    confirmTitle: "Save".localized,
+                    confirmColor: .themeColor,
+                    
+                    cancelAction: { [weak self]  in
+                        guard let self = self else { return }
+                        print("用户点击了Leave")
+                        viewModel.cancelAllRequest()
+                        self.dismiss(animated: true, completion: nil)
+                    },
+                    confirmAction: { [weak self]  in
+                        guard let self = self else { return }
+                        print("用户点击了Stay")
+                        clickSaveBtn()
+                    }
+                ))
+            }else{
+                viewModel.cancelAllRequest()
+                self.dismiss(animated: true, completion: nil)
+            }
+        }else{
+            TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+                message: "As you leave, your generation will be interrupted and no result.".localized,
+                messageColor: .white,
+                messageFont: .systemFont(ofSize: 16),
+                
+                cancelTitle: "Leave".localized,
+                cancelColor: .white,
+                
+                confirmTitle: "Wait".localized,
+                confirmColor: .themeColor,
+                
+                cancelAction: { [weak self]  in
+                    guard let self = self else { return }
+                    print("用户点击了Leave")
+                    viewModel.cancelAllRequest()
+                    self.dismiss(animated: true, completion: nil)
+                },
+                confirmAction: {
+                    print("用户点击了Stay")
+                }
+            ))
+        }
+    }
+    
+    //重新生成
+    @objc func clickRegenerateBtn(){
+        //判断 vip
+        if kJudgeVip(externalBool: kPurchaseBusiness.isVip , vc: self){ return }
+        
+        viewModel.uploadAndCreatImage()
+    }
+    
+    //保存功能
+    @objc func clickSaveBtn(){
+        guard let imageModel = imageModel else { return }
+//        if viewModel.generatorModel.generatorStyle == .photoLive{
+//            TSDownloadManager.getDownLoadVideo(urlString: imageModel.response.resultUrl) { url, success in
+//                if let url = url {
+//                    PhotoManagerShared.saveVideoToAlbum(videoURL: url) { [weak self] success, error in
+//                        guard let self = self else { return }
+//                        if success {
+//                            isSavePhotoMark = true
+//                            kSaveSuccesswShared.show(atView:self.view)
+//                        }else{
+//                            debugPrint(error)
+//                        }
+//                    }
+//                }
+//            }
+//        }else{
+            UIImageView.downloadImageWithProgress(urlString: imageModel.response.resultUrl) { image in
+                if let image = image {
+                    PhotoManagerShared.saveImageToAlbum(image) { [weak self] success, error in
+                        guard let self = self else { return }
+                        if success {
+                            isSavePhotoMark = true
+                            kSaveSuccesswShared.show(atView:self.view)
+                        }else{
+                            debugPrint(error)
+                        }
+                    }
+                }
+            }
+//        }
+    }
+    
+    override func dealThings() {
+        viewModel.uploadAndCreatImage()
+        viewModel.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self]  (state,model) in
+            guard let self = self else { return }
+            self.upDateView(state: state, model: model)
+        }.store(in: &cancellable)
+    }
+    
+}
+
+extension TSAIListPhotoGeneratorVC {
+    
+    func getSuccessImage()->UIImage?{
+        if let image = netWorkImageView.image {
+            return image.pngImage
+        }
+        return nil
+    }
+    
+}
+extension TSAIListPhotoGeneratorVC {
+    
+    func upDateView(state:TSProgressState,model:TSActionInfoModel?){
+        progressState = state
+        switch state {
+            case .failed(let errorStr,let code):
+                showError(text: errorStr,code:code)
+            case .success:
+                if let model = model {
+                    showSuccess(model: model)
+                }else{
+                    showError(text: "")
+                }
+            case .progressString(let string):
+                showProgress(text: string)
+            default:
+                showLoading()
+        }
+    }
+    
+    func showProgress(text:String) {
+        generateInView.updateShowProgress(text: text)
+        
+        netWorkImageView.isHidden = true
+        switchOriginalPictureBtn.isHidden = true
+        
+        setVideoHidden()
+    }
+    
+    func showLoading(){
+        generateInView.updateShowLoading(text: "Generating".localized + " ...".localized)
+
+    }
+    
+    func showError(text:String,code:Int = 0){
+        generateInView.updateShowError(text: text,code: code)
+
+        
+    }
+    
+    func showSuccess(model:TSActionInfoModel){
+        generateInView.updateShowSuccess()
+
+        imageModel = model
+        
+
+        netWorkImageView.isHidden = false
+        
+//        if viewModel.generatorModel.generatorStyle == .futureBaby {
+//            rotatingPictureBtn.isHidden = false
+//        }else{
+            switchOriginalPictureBtn.isHidden = false
+//        }
+        
+        isSavePhotoMark = false
+        self.netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder:kPlaceholderImage,backgroundColor:netWorkImageView.backgroundColor!)
+        
+        if let model = imageModel {
+            complete(model)
+        }
+        
+//        setVideoURL()
+        setExpandAreaImage()
+    }
+    
+    @objc func switchOriginalPictureTouchDown() {
+//        if viewModel.generatorModel.generatorStyle == .photoExpand {
+//            expandAreaView.onlyBgImage(only: false)
+//        }else{
+            self.netWorkImageView.image = self.viewModel.generatorModel.upLoadImage
+//        }
+    }
+    
+    @objc func switchOriginalPictureTouchUp() {
+        guard let imageModel = imageModel else { return }
+        
+//        if viewModel.generatorModel.generatorStyle == .photoExpand {
+//            expandAreaView.onlyBgImage(only: true)
+//        }else{
+            self.netWorkImageView.setAsyncImage(urlString: imageModel.response.resultUrl,placeholder:kPlaceholderImage,backgroundColor:netWorkImageView.backgroundColor!)
+//        }
+    }
+}
+
+extension TSAIListPhotoGeneratorVC {
+    func setVideoHidden(){
+//        if viewModel.generatorModel.generatorStyle == .photoLive {
+//            videoPlayerVC.removeFromParent()
+//            videoPlayerVC.view.removeFromSuperview()
+//        }
+    }
+    
+    func setVideoURL(){
+//        if viewModel.generatorModel.generatorStyle == .photoLive {
+//            if let model = imageModel {
+//                switchOriginalPictureBtn.isHidden = true
+//                self.videoPlayerVC = TSAIListVideoPlayerVC(videoURL: model.videoURL)
+//                self.addChild(self.videoPlayerVC)
+//                self.videoPlayerVC.view.frame = self.netWorkImageView.bounds
+//                self.netWorkImageView.addSubview(self.videoPlayerVC.view)
+//                self.videoPlayerVC.setControlsBottom(bottem: -20)
+//            }
+//        }
+    }
+}
+extension TSAIListPhotoGeneratorVC {
+    
+    func setExpandAreaImage(){
+//        if viewModel.generatorModel.generatorStyle == .photoExpand {
+//            netWorkImageView.image = nil
+//            expandAreaView.bgImageView.setAsyncImage(urlString: imageModel?.response.resultUrl,placeholder:kPlaceholderImage,backgroundColor:netWorkImageView.backgroundColor!)
+//            expandAreaView.showImageView.image = self.viewModel.generatorModel.upLoadImage
+//        }
+    }
+}

+ 302 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoGeneratorVC/TSAIListPhotoGeneratorVM.swift

@@ -0,0 +1,302 @@
+//
+//  TSAIListPhotoGeneratorVM.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/11.
+//
+
+import Alamofire
+
+
+
+let actionInfoDictVideo:[String:Any] = [
+    "actionType":"image_animation",
+    "comments": "Success",
+    "costTime":11,
+    "createdTimestamp":1744972580,
+    "id":32743,
+    "percent":1,
+    "request":"{\\\"imageUrl\\\": \\\"https://be-aigc.oss-cn-shanghai.aliyuncs.com/1981095e-b810-4eef-923b-5540350ae2d7.jpeg\\\", \\\"countryCode\\\": \\\"CN\\\", \\\"ip\\\": \\\"120.229.53.7\\\"}",
+    "response": "{\\\"resultUrl\\\": \\\"https://be-aigc.s3-accelerate.amazonaws.com/4e0da626-1de7-4c2e-9be2-3e6d0742a28e.mp4\\\"}",
+    "status":"success"
+]
+
+
+class TSAIListPhotoGeneratorBaseVM {
+    
+    var uploadRequest:Request?
+    var creatRequest:Request?
+    var queryRequest:Request?
+    var stopNetwork = false
+    
+    @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil)
+    
+    var imageUrl:String?
+    var imageUrls:[String]?
+    var generatorModel:TSAIListPhotoGeneratorModel
+    init(generatorModel:TSAIListPhotoGeneratorModel) {
+        self.generatorModel = generatorModel
+    }
+    
+//    //模拟数据
+//    func uploadAndCreatImage() {
+//
+//        stateDatauPblished = (.start,nil)
+//        stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
+//
+//        kDelayOnMainThread(0.2) {
+//            self.stateDatauPblished = (.progressString(self.generating(progress: 0.2)),nil)
+//        }
+//
+//        kDelayOnMainThread(0.5) {
+//            self.stateDatauPblished = (.progressString(self.generating(progress: 0.5)),nil)
+//        }
+//
+//        kDelayOnMainThread(0.8) {
+//            self.stateDatauPblished = (.progressString(self.generating(progress: 0.8)),nil)
+//        }
+//
+//        kDelayOnMainThread(2.0) {
+//            if kRandomBool() {
+//                let infoModel = TSActionInfoModel(JSON: self.generatorStyle == .photoLive ? actionInfoDictVideo : actionInfoDictPoster)
+//                self.stateDatauPblished = (.success(nil),infoModel)
+//            }else{
+//                self.stateDatauPblished = (.failed("error?.localizedDescription"),nil)
+//            }
+//        }
+//
+//    }
+    
+    func uploadAndCreatImage() {
+        //上传多个图片
+        if let _ = generatorModel.upLoadImages {
+            uploadImagesAndCreat()
+            return
+        }
+        //上传单个图片
+        if let imageUrl = imageUrl,imageUrl.contains("http") {
+            creatImage()
+            return
+        }
+  
+        stopNetwork = false
+        stateDatauPblished = (.start,nil)
+        
+        stateDatauPblished = (.progressString(uploadingPhoto(progress: 0.0)),nil)
+        uploadRequest = TSNetworkShared.uploadImage(upLoadImage: generatorModel.upLoadImage, maxKb: generatorModel.generatorStyle.imageMaxKb) { [weak self]  progress in
+            guard let self = self else { return }
+          
+            stateDatauPblished = (.progressString(uploadingPhoto(progress: progress)),nil)
+            
+        } completion: { [weak self]  data, error in
+            guard let self = self else { return }
+            if let error = error {
+                imageUrl = nil
+                self.stateDatauPblished = (TSProgressState.getFailed(error.tsDesc,error.tsCode),nil)
+            }else{
+                if let string = data as? String {
+                    imageUrl = string
+                    creatImage()
+                }
+            }
+        }
+    }
+    
+    private func uploadImagesAndCreat() {
+        
+        if let imageUrls = imageUrls{
+            creatImage()
+            return
+        }
+        guard let upLoadImages = generatorModel.upLoadImages else { return }
+        var uploadImageUrls:[String] = []
+        let progressRatio:Float = 1.0/Float(upLoadImages.count)//进度分割比例
+        var totalProgress:Float = 0.0//总进度
+        stopNetwork = false
+        stateDatauPblished = (.start,nil)
+        stateDatauPblished = (.progressString(uploadingPhoto(progress: 0.0)),nil)
+        
+        let group = DispatchGroup()
+        for image in upLoadImages {
+            group.enter()
+            uploadRequest = TSNetworkShared.uploadImage(upLoadImage: image, maxKb: generatorModel.generatorStyle.imageMaxKb) { [weak self]  progress in
+                guard let self = self else { return }
+                totalProgress+=progress*progressRatio
+                stateDatauPblished = (.progressString(uploadingPhoto(progress: totalProgress)),nil)
+            } completion: { [weak self]  data, error in
+                guard let self = self else { return }
+                if let error = error {
+                    self.imageUrls = nil
+                    self.stateDatauPblished = (TSProgressState.getFailed(error.tsDesc,error.tsCode),nil)
+                }else{
+                    if let string = data as? String {
+                        uploadImageUrls.append(string)
+                    }
+                }
+                group.leave()
+            }
+        }
+
+        group.notify(queue: .main) {
+            if uploadImageUrls.count == upLoadImages.count {
+                self.imageUrls = uploadImageUrls
+                self.imageUrl = ""
+                self.creatImage()
+            }
+        }
+    }
+    
+    
+    func creatImage() {
+        guard let imageUrl = imageUrl else { return }
+        stopNetwork = false
+        stateDatauPblished = (.start,nil)
+        stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
+        
+        var urlType:TSNeURLType = .imageRewrite
+        var postDict:[String:Any] = [
+            "device":getUserInfoJsonString(),
+            "imageUrl":imageUrl,
+            "model": generatorModel.generatorStyle.aiModel
+        ]
+        switch generatorModel.generatorStyle {
+        case .enhance:
+            urlType = .imageRewrite
+            postDict = ["prompt":"把图片变清晰"]
+        case .colorize:
+            urlType = .imageRewrite
+            postDict = ["prompt":"Add suitable colors to photos"]
+        case .descratch:
+            urlType = .imageRewrite
+            postDict = ["prompt":"Remove the photo's scratches and dirt"]
+        }
+        
+        creatRequest = TSNetworkShared.post(urlType: urlType,parameters: postDict) { [weak self] data,error in
+            guard let self = self else { return }
+            
+            if let dataDict = kNetWorkCodeSuccess(data: data),
+               let actionId = dataDict["actionId"] as? Int{
+                if stopNetwork == false {
+                    self.getActionInfo(action_id:actionId)
+                }
+            }else{
+                if let error = error {
+                    self.stateDatauPblished = (TSProgressState.getFailed(error.tsDesc,error.tsCode),nil)
+                }else{
+                    self.stateDatauPblished = (.generalNormalFailed,nil)
+                }
+            }
+        }
+    }
+    
+    func getActionInfo(action_id:Int){
+        queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
+            guard let self = self else { return }
+            if let result = kNetWorkResultSuccess(data: data) {
+                if let genmojiModel = TSActionInfoModel(JSON: result) {
+                    switch genmojiModel.actionStatus {
+                    case .success:
+                        if let _ = URL(string:genmojiModel.response.resultUrl) {
+//                            if generatorModel.generatorStyle == .photoLive {
+//                                downloadVideo(urlString: genmojiModel.response.resultUrl) { url in
+//                                    if let url = url {
+//                                        
+//                                        genmojiModel.videoPath = url.path.documentLastURLString
+//                                        if let videoImage = kGetVideoThumbnail(from: url) {
+//                                            let imageSavePath = url.deletingPathExtension().path + ".jpeg"
+//                                            videoImage.saveToFile(at:URL(fileURLWithPath:imageSavePath))
+//                                            genmojiModel.videoThumbnailPath = imageSavePath.documentLastURLString
+//                                        }
+//
+//                                        self.stateDatauPblished = (.success(nil),genmojiModel)
+//                                    }else{
+//                                        self.stateDatauPblished = (.generalNormalFailed,nil)
+//                                    }
+//                                }
+//                            }else {
+                                downloadImage(urlString: genmojiModel.response.resultUrl) { [weak self] in
+                                    guard let self = self else { return }
+                                    self.stateDatauPblished = (.success(nil),genmojiModel)
+                                }
+//                            }
+                        }else{
+                            self.stateDatauPblished = (.success(nil),genmojiModel)
+                        }
+                        
+                    case .failed:
+                        self.stateDatauPblished = (TSProgressState.getFailed(genmojiModel.response.codeErrorMsg,genmojiModel.response.code),nil)
+                    default:
+                        stateDatauPblished = (.progressString(generating(progress: genmojiModel.percent)),nil)
+                        if stopNetwork == false {
+                            kDelayOnMainThread(1.0) {
+                                self.getActionInfo(action_id: action_id)
+                            }
+                        }
+                    }
+                }
+            }else{
+                if let error = error {
+                    self.stateDatauPblished = (TSProgressState.getFailed(error.tsDesc,error.tsCode),nil)
+                }else{
+                    self.stateDatauPblished = (.generalNormalFailed,nil)
+                }
+            }
+        }
+    }
+    
+    func downloadImage(urlString:String,completion:@escaping ()->Void){
+        UIImageView.downloadImageWithProgress(urlString: urlString) { [weak self]  progress in
+            guard let self = self else { return }
+    
+            let progressInt = Int(progress*10.0)
+            let progressString = generatingText + " \(90 + progressInt)%"
+            stateDatauPblished = (.progressString(progressString),nil)
+            dePrint("生成后图片下载进度: \(progress)")
+        } completion: { image in
+            completion()
+        }
+    }
+    
+//    func downloadVideo(urlString:String,completion:@escaping (URL?)->Void){
+//        TSDownloadManager.getDownLoadVideo(urlString: urlString) { progress in
+//            let progressInt = Int(progress*10.0)
+//            let progressString = self.generatingText + " \(90 + progressInt)%"
+//            self.stateDatauPblished = (.progressString(progressString),nil)
+//            dePrint("生成后视频下载进度: \(progress)")
+//        } complete: { url, _ in
+//            completion(url)
+//        }
+//    }
+    
+    func cancelAllRequest(){
+        creatRequest?.cancel()
+        queryRequest?.cancel()
+        stopNetwork = true
+    }
+ 
+    func uploadingPhoto(progress:Float) -> String {
+        //Uploading Photo 0%-100%
+        var progressInt = Int(progress*100)
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        return "Uploading Photo".localized + " \(progressInt)%"
+    }
+    
+    func generating(progress:Float) -> String {
+        let progress = progress*(0.9) // 预留 10% 进度给图片下载
+        //Generating 0%-100%
+        var progressInt = Int(progress*100)
+
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        
+        return generatingText + " \(progressInt)%"
+    }
+    
+    
+    var generatingText:String{
+        return "Generating".localized
+    }
+}

+ 5 - 5
TSLiveWallpaper/Business/TSAIListVC/TSAIUploadPhotoVC/TSAIUploadPhotoVC.swift

@@ -301,12 +301,12 @@ extension TSAIUploadPhotoVC {
 //        if generatorStyle != .catTohuman {
             additionalPrompt = ""
 //        }
-//        let gennerateVC = TSAIListPhotoGeneratorBaseVC(generatorModel: TSAIListPhotoGeneratorModel(upLoadImage: upLoadImage, generatorStyle: generatorStyle,additionalPrompt: additionalPrompt)){ [weak self] model in
-//            guard let self = self else { return }
-//            saveModel(model: model)
-//        }
+        let gennerateVC = TSAIListPhotoGeneratorVC(generatorModel: TSAIListPhotoGeneratorModel(upLoadImage: upLoadImage, generatorStyle: generatorStyle,additionalPrompt: additionalPrompt)){ [weak self] model in
+            guard let self = self else { return }
+            saveModel(model: model)
+        }
         
-//        kPresentModalVC(target: self, modelVC: gennerateVC,transitionStyle: .crossDissolve)
+        kPresentModalVC(target: self, modelVC: gennerateVC,transitionStyle: .crossDissolve)
     }
     
     func saveModel(model:TSActionInfoModel){

+ 115 - 0
TSLiveWallpaper/Data/Model/TSProgressState.swift

@@ -0,0 +1,115 @@
+//
+//  TSProgressState.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/11.
+//
+
+
+import Combine
+import Alamofire
+enum TSProgressState  {
+    case none
+    case start
+    case pending
+    case progress(CGFloat)
+    case progressString(String)
+    case success(Any?)
+    case failed(String,Int)
+
+    static func fromKeyValue(key string: String,value:String) -> TSProgressState {
+        if string == "none" {
+            return .none
+        } else if string == "start" {
+            return .start
+        } else if string == "pending" {
+            return .pending
+        }else if string == "progress" {
+            var progress = 0.0
+            if let doubleValue = Float(value) {
+                progress = CGFloat(doubleValue)
+            }
+            return .progress(progress)
+        }else if string == "progressString" {
+            return .progressString(value)
+        }else if string == "success" {
+            return .success(value)
+        }else if string == "failed" {
+            return .failed(value,0)
+        }else{
+            return .none
+        }
+    }
+    
+    var keyValue:(String,String){
+        switch self {
+        case .none:
+            return ("none","")
+        case .start:
+            return ("start","")
+        case .pending:
+            return ("pending","")
+        case .progress(let float):
+            return ("progress",String(Float(float)))
+        case .progressString(let string):
+            return ("progressString",string)
+        case .success(let string):
+            if let string = string as? String{
+                return ("success",string)
+            }
+            return ("success","")
+        case .failed(let string,let code):
+            return ("failed",string)
+        }
+    }
+    
+    
+    var isResult:Bool{
+        switch self {
+        case .none:
+            return false
+        case .start:
+            return false
+        case .pending:
+            return false
+        case .progress(_):
+            return false
+        case .progressString(_):
+            return false
+        case .success(_):
+            return true
+        case .failed(_,_):
+            return true
+        }
+    }
+    
+    
+    var reslutSuccess:Bool{
+        switch self {
+        case .success(_):
+            return true
+        case .failed(_,_):
+            return false
+        default:
+            return false
+        }
+    }
+    
+    
+    var reloadNewData:Bool{
+        switch self {
+        case .pending,.success(_),.failed(_,_):
+            return true
+        default:
+            return false
+        }
+    }
+    
+    static func getFailed(_ error:String,_ code:Int = 0)->TSProgressState {
+        return .failed(error, code)
+    }
+    
+    static var generalNormalFailed:TSProgressState {
+        return .failed(TSNetWorkCode.fail.errorMsg, TSNetWorkCode.fail.rawValue)
+    }
+}