Эх сурвалжийг харах

图生图代码用扩展分拆-1

100Years 1 долоо хоног өмнө
parent
commit
1e1cbb143d

+ 20 - 0
AIEmoji.xcodeproj/project.pbxproj

@@ -149,6 +149,11 @@
 		A88508B62DBF142B000FBCEC /* TSGennertatorSelectStyleVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88508B52DBF142A000FBCEC /* TSGennertatorSelectStyleVC.swift */; };
 		A8990DE92DDF241500DD55FE /* TYCycleImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8990DE82DDF241300DD55FE /* TYCycleImageView.swift */; };
 		A8990E022DE1800100DD55FE /* launch.png in Resources */ = {isa = PBXBuildFile; fileRef = A8990E012DE1800100DD55FE /* launch.png */; };
+		A8990E042DE1A7E500DD55FE /* TSPTPInputVC+Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8990E032DE1A7E500DD55FE /* TSPTPInputVC+Stack.swift */; };
+		A8990E082DE1A8B100DD55FE /* TSPTPInputVC+Upload.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8990E072DE1A89F00DD55FE /* TSPTPInputVC+Upload.swift */; };
+		A8990E0A2DE1A98E00DD55FE /* TSPTPInputVC+Col.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8990E092DE1A98D00DD55FE /* TSPTPInputVC+Col.swift */; };
+		A8990E0C2DE1AA9100DD55FE /* TSPTPInputVC+TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8990E0B2DE1AA9000DD55FE /* TSPTPInputVC+TextView.swift */; };
+		A8990E0E2DE1AD2000DD55FE /* TSPTPInputVC+BtnView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8990E0D2DE1AD1E00DD55FE /* TSPTPInputVC+BtnView.swift */; };
 		A899D34A2D827A0E00AB9C1C /* TSChatThinkingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A899D3492D8279FB00AB9C1C /* TSChatThinkingModel.swift */; };
 		A89EA64B2D59A588000EB181 /* MessageKit in Frameworks */ = {isa = PBXBuildFile; productRef = A89EA64A2D59A588000EB181 /* MessageKit */; };
 		A89EA6542D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */; };
@@ -439,6 +444,11 @@
 		A88508B52DBF142A000FBCEC /* TSGennertatorSelectStyleVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGennertatorSelectStyleVC.swift; sourceTree = "<group>"; };
 		A8990DE82DDF241300DD55FE /* TYCycleImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TYCycleImageView.swift; sourceTree = "<group>"; };
 		A8990E012DE1800100DD55FE /* launch.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = launch.png; sourceTree = "<group>"; };
+		A8990E032DE1A7E500DD55FE /* TSPTPInputVC+Stack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPTPInputVC+Stack.swift"; sourceTree = "<group>"; };
+		A8990E072DE1A89F00DD55FE /* TSPTPInputVC+Upload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPTPInputVC+Upload.swift"; sourceTree = "<group>"; };
+		A8990E092DE1A98D00DD55FE /* TSPTPInputVC+Col.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPTPInputVC+Col.swift"; sourceTree = "<group>"; };
+		A8990E0B2DE1AA9000DD55FE /* TSPTPInputVC+TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPTPInputVC+TextView.swift"; sourceTree = "<group>"; };
+		A8990E0D2DE1AD1E00DD55FE /* TSPTPInputVC+BtnView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPTPInputVC+BtnView.swift"; sourceTree = "<group>"; };
 		A899D3492D8279FB00AB9C1C /* TSChatThinkingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatThinkingModel.swift; sourceTree = "<group>"; };
 		A89EA64C2D59A9F4000EB181 /* CustomMessageFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomMessageFlowLayout.swift; sourceTree = "<group>"; };
 		A89EA64E2D59A9F4000EB181 /* TSLayoutSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSLayoutSizeCalculator.swift; sourceTree = "<group>"; };
@@ -1488,6 +1498,11 @@
 				A8BA76432DA4C927000B6707 /* View */,
 				A8BA76402DA4C918000B6707 /* VM */,
 				A8BA763E2DA4C906000B6707 /* TSPTPInputVC.swift */,
+				A8990E032DE1A7E500DD55FE /* TSPTPInputVC+Stack.swift */,
+				A8990E072DE1A89F00DD55FE /* TSPTPInputVC+Upload.swift */,
+				A8990E092DE1A98D00DD55FE /* TSPTPInputVC+Col.swift */,
+				A8990E0B2DE1AA9000DD55FE /* TSPTPInputVC+TextView.swift */,
+				A8990E0D2DE1AD1E00DD55FE /* TSPTPInputVC+BtnView.swift */,
 			);
 			path = TSPTPInputVC;
 			sourceTree = "<group>";
@@ -2264,6 +2279,7 @@
 				A80E721A2D3F393A00C64288 /* DiyStickerModel.swift in Sources */,
 				A80EDDEB2D6EC014003CD332 /* TSPhotoToPhotoVC.swift in Sources */,
 				A80E726F2D40DE2B00C64288 /* TSWallpaperPreviewVC.swift in Sources */,
+				A8990E0A2DE1A98E00DD55FE /* TSPTPInputVC+Col.swift in Sources */,
 				A8F775492D3935D600AA6E93 /* TSBusinessWebVC.swift in Sources */,
 				A8F776392D3B38E600AA6E93 /* TSGenmojiGennerateVC.swift in Sources */,
 				A85E47C02D6961BB0018D62D /* TSChatMessageUIModel.swift in Sources */,
@@ -2276,6 +2292,7 @@
 				A80EDD462D6C3F82003CD332 /* MarkdownEscaping.swift in Sources */,
 				A80EDD472D6C3F82003CD332 /* MarkdownItalic.swift in Sources */,
 				A80EDD482D6C3F82003CD332 /* MarkdownBold.swift in Sources */,
+				A8990E042DE1A7E500DD55FE /* TSPTPInputVC+Stack.swift in Sources */,
 				A80EDD4A2D6C3F82003CD332 /* MarkdownLevelElement.swift in Sources */,
 				A80EDD4B2D6C3F82003CD332 /* MarkdownParser+AppKit.swift in Sources */,
 				A80EDD4C2D6C3F82003CD332 /* Typealias.swift in Sources */,
@@ -2345,6 +2362,7 @@
 				A80E72592D3FA67800C64288 /* TSWallpaperViewModel.swift in Sources */,
 				A89EA67D2D59F1AF000EB181 /* StreamPostRequest.swift in Sources */,
 				A80E722F2D3F3E1400C64288 /* TSDiyCanvasView.swift in Sources */,
+				A8990E0C2DE1AA9100DD55FE /* TSPTPInputVC+TextView.swift in Sources */,
 				A8F4134E2DA75E9E001E715A /* TSAboutDataVC.swift in Sources */,
 				A80E72672D409C7D00C64288 /* Template+More.swift in Sources */,
 				A82D60A92DBB9A6300596190 /* TSDBActionInfoModel.swift in Sources */,
@@ -2356,6 +2374,7 @@
 				A8F775172D38EB7400AA6E93 /* TSTabBarController.swift in Sources */,
 				A80E73E12D533E5800C64288 /* TSPurchaseVC.swift in Sources */,
 				A80EDDE02D6EB1B9003CD332 /* TSPTPGeneratorCell.swift in Sources */,
+				A8990E0E2DE1AD2000DD55FE /* TSPTPInputVC+BtnView.swift in Sources */,
 				A81BECA62DD1EFAF005D06A2 /* TSGeneratorloadingContentView.swift in Sources */,
 				A8F776352D3A7C2B00AA6E93 /* TSGenmojiColSectionView.swift in Sources */,
 				A80327B32D813D4900AF7878 /* TSTTPInputVC.swift in Sources */,
@@ -2424,6 +2443,7 @@
 				A8F7762D2D3A74A100AA6E93 /* TSGenmojiGennerateCell.swift in Sources */,
 				605E20552DCC90CE0069F4B6 /* SchemeHandler.swift in Sources */,
 				A89EA6BC2D5DFB12000EB181 /* TSViewController.swift in Sources */,
+				A8990E082DE1A8B100DD55FE /* TSPTPInputVC+Upload.swift in Sources */,
 				A85E479D2D6809DC0018D62D /* TSBigIconBrowseCell.swift in Sources */,
 				A89EA6832D59F4F9000EB181 /* TSChatViewController+ChatDelegate.swift in Sources */,
 				605E20592DCCAF3C0069F4B6 /* SchemeHandler+Ext.swift in Sources */,

+ 7 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC+BtnView.swift

@@ -0,0 +1,7 @@
+//
+//  TSPTPInputVC+BtnView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/5/24.
+//
+

+ 95 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC+Col.swift

@@ -0,0 +1,95 @@
+//
+//  TSPTPInputVC+Col.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/5/24.
+//
+
+extension TSPTPInputVC {
+    
+    func creatCollectionComponent() -> TSCollectionViewComponent {
+        let layout = UICollectionViewFlowLayout()
+        let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
+        cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: collectionViewBtootm, right: 0)
+        cp.collectionView.isScrollEnabled = false
+
+        // 禁用自动 contentInset 调整
+        if #available(iOS 11.0, *) {
+            cp.collectionView.contentInsetAdjustmentBehavior = .never
+        } else {
+            automaticallyAdjustsScrollViewInsets = false
+        }
+
+        cp.sectionActionHandler = { [weak self] cellCp, _ in
+            guard let self = self else { return }
+            if let cmd = cellCp as? String {
+                if cmd == "delete" {
+                    showCustomAlert(message: "Are you sure to delete all histories?".localized, rightActionString: "Delete All".localized , deleteHandler: {
+                        self.viewModel.removeAllHistoryList()
+                        self.updataCollectionView()
+                    })
+                } else if cmd == "more" {
+                    let historyVC = TSPTPHistoryVC(style: .ptp)
+                    kPushVC(target: self, modelVC: historyVC)
+                }
+            }
+        }
+
+        cp.itemActionHandler = { [weak self] object, indexPath in
+            guard let self = self else { return }
+            // 删除过期的任务
+            if let cmd = object as? String{
+                if cmd == "delete_task_expired" {
+                    if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel,
+                       let currentActionInfoModel = sections.items.safeObj(At: indexPath.item) {
+                        TSRMShared.ptpDBHistory.deleteListModel(id: currentActionInfoModel.dataModel.id)
+                        updataCollectionView()
+                    }
+                }else if cmd == "delete_task_sensitive" {
+                    showDeleteErrorAlert(message: "Delete this error history?".localized, deleteHandler:  { [weak self]  in
+                        guard let self = self else { return }
+                        if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel,
+                           let currentActionInfoModel = sections.items.safeObj(At: indexPath.item) {
+                            TSRMShared.ptpDBHistory.deleteListModel(id: currentActionInfoModel.dataModel.id)
+                            updataCollectionView()
+                        }
+                    })
+                }
+            }
+        }
+
+        cp.itemDidSelectedHandler = { [weak self] _, indexPath in
+            guard let self = self else { return }
+            if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel,
+               let dataModel = sections.items.safeObj(At: indexPath.item)?.dataModel {
+                var dataModelArray: [TSActionInfoModel] = []
+                for itemModel in sections.items {
+                    if itemModel.dataModel.status == "success" || itemModel.dataModel.modelType == .example {
+                        dataModelArray.append(itemModel.dataModel)
+                    }
+                }
+
+                let browseVC = TSAIPhotoBrowseVC()
+                browseVC.dataModelArray = dataModelArray
+                browseVC.currentIndex = dataModelArray.firstIndex(of: dataModel) ?? 0
+                browseVC.deleteComplete = { [weak self]  deleteModel in
+                    guard let self = self else { return }
+                    TSRMShared.ptpDBHistory.deleteListModel(id: deleteModel.id)
+                    updataCollectionView()
+                }
+                kPresentModalVC(target: self, modelVC: browseVC,transitionStyle: .crossDissolve)
+            }
+        }
+        cp.collectionView.keyboardDismissMode = .interactive
+        return cp
+    }
+    
+    
+    
+    func updataCollectionView() {
+        viewModel.updateRecentData()
+        collectionComponent.clear()
+        collectionComponent.reloadView(with: viewModel.colDataArray)
+    }
+    
+}

+ 83 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC+Stack.swift

@@ -0,0 +1,83 @@
+//
+//  Untitled.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/5/24.
+//
+
+extension TSPTPInputVC {
+    
+    func creatStackView() -> TSCustomStackView {
+        let cusStackView = TSCustomStackView(axis: .vertical, spacing: 0)
+        cusStackView.scrollView.isScrollEnabled = true
+        return cusStackView
+    }
+    
+
+    
+    func setUpCusStackView() {
+//        let uploadPhotoTitleView = TSTitleView.creatTitleView(title: "Upload Photo".localized, subTitle: "")
+//        cusStackView.addSubviewToStack(uploadPhotoTitleView)
+//        uploadPhotoTitleView.snp.makeConstraints { make in
+//            make.height.equalTo(uploadPhotoTitleView.viewH)
+//            make.width.equalTo(k_ScreenWidth)
+//        }
+//
+//        let hintBtn = TSUIExpandedTouchButton()
+//        hintBtn.setUpButton(image: UIImage(named: "ptp_hint")) { [weak self] in
+//            guard let self = self else { return }
+//            presentModalHintVC()
+//        }
+//        uploadPhotoTitleView.contentView.addSubview(hintBtn)
+//        hintBtn.snp.makeConstraints { make in
+//            make.centerY.equalToSuperview().offset(kSectionTitleViewCenterYOffset)
+//            make.trailing.equalTo(-16)
+//            make.width.height.equalTo(16)
+//        }
+
+        cusStackView.addSpacing(length: 10)
+        cusStackView.addSubviewToStack(uploadView)
+        uploadView.snp.makeConstraints { make in
+            make.height.equalTo(uploadView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+
+        let selectStyleTitleView = TSTitleMoreView()
+        selectStyleTitleView.setTitle(title: "Select Style".localized) { [weak self] in
+            guard let self = self else { return }
+            let selectStyleVC = TSGennertatorSelectStyleVC()
+            selectStyleVC.currentIndexPath = IndexPath(item: viewModel.selectedStyleIndex, section: 0)
+            selectStyleVC.dataArray = viewModel.ptpStyleModels
+            selectStyleVC.selectedValueBlock = { [weak self] indexPath, _ in
+                guard let self = self else { return }
+                selectStyleView.collectionView(selectStyleView.styleCollectionView, didSelectItemAt: indexPath)
+            }
+            kPresentModalVC(target: self, modelVC: selectStyleVC, transitionStyle: .coverVertical)
+        }
+        cusStackView.addSubviewToStack(selectStyleTitleView)
+        selectStyleTitleView.snp.makeConstraints { make in
+            make.height.equalTo(selectStyleTitleView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+
+        cusStackView.addSubviewToStack(selectStyleView)
+        selectStyleView.snp.makeConstraints { make in
+            make.height.equalTo(selectStyleView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+
+        cusStackView.addSubviewToStack(promptTextView, length: promptTextViewH)
+
+        promptTextView.isHidden = !viewModel.selectedPTPStyleModel.input
+
+        cusStackView.addSubviewToStack(collectionComponent.collectionView)
+        collectionComponent.collectionView.snp.makeConstraints { make in
+            make.height.equalTo(0)
+            make.width.equalTo(k_ScreenWidth)
+        }
+
+        cusStackView.addSpacing(length: collectionViewBtootm)
+    }
+    
+    
+}

+ 123 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC+TextView.swift

@@ -0,0 +1,123 @@
+//
+//  TSPTPInputVC+TextView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/5/24.
+//
+
+extension TSPTPInputVC {
+    
+    func creatCustomTextView() -> TSPlaceholderTextView {
+        let customTextView = TSPlaceholderTextView(
+            placeholder: "Describe how you want to transform".localized,
+            text: "",
+            font: .font(size: 14),
+            textColor: .white,
+            backgroundColor: .clear
+        )
+        customTextView.delegate = self
+        customTextView.returnKeyType = .done
+        return customTextView
+    }
+    
+    
+    func creatClearBtn() -> TSUIExpandedTouchButton {
+        let clearBtn = TSUIExpandedTouchButton()
+        clearBtn.setUpButton(
+            image: UIImage(named: "clear_text")
+        ) { [weak self] in
+            guard let self = self else { return }
+            customTextView.text = ""
+            textViewDidChange(customTextView)
+        }
+        clearBtn.isHidden = true
+        return clearBtn
+    }
+    
+    
+    func creatPromptTextView() -> UIView {
+        let promptTextView = UIView()
+        promptTextView.isHidden = true
+        promptTextView.clipsToBounds = true
+        let bgView = UIView()
+        bgView.backgroundColor = "#333333".uiColor
+        bgView.cornerRadius = 16.0
+        promptTextView.addSubview(bgView)
+        bgView.snp.makeConstraints { make in
+            make.edges.equalTo(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))
+        }
+
+        bgView.addSubview(customTextView)
+        bgView.addSubview(clearBtn)
+
+        customTextView.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.leading.equalTo(12.0)
+            make.top.equalTo(12.0)
+            make.bottom.equalTo(-12.0)
+            make.trailing.equalTo(-20)
+        }
+
+        clearBtn.snp.makeConstraints { make in
+            make.width.height.equalTo(16.0)
+            make.trailing.equalTo(-12)
+            make.bottom.equalTo(-12.0)
+        }
+
+        return promptTextView
+    }
+
+}
+
+
+extension TSPTPInputVC: UITextViewDelegate {
+    // 实现 UITextViewDelegate 协议方法,控制 return 键行为
+    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
+        if text == "\n" {
+            // 当输入为换行符(即按下 return 键)时,执行相应操作
+            // sendBolck?(textView.text)
+            clickView()
+            return false
+        }
+        return true
+    }
+
+    func textViewDidChange(_ textView: UITextView) {
+        clearBtn.isHidden = textView.text.count <= 0
+        viewModel.selectedPTPStyleModel.inputText = textView.text
+        viewModel.gennerateChange()
+    }
+}
+
+
+extension TSPTPInputVC {
+    @objc func keyboardWillShow(_ notification: Notification) {
+        guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
+        let scrollView = cusStackView.scrollView
+        let keyboardHeight = keyboardFrame.height - view.safeAreaInsets.bottom
+        let textViewFrame = scrollView.convert(customTextView.frame, from: customTextView.superview)
+        let scrollDistance = textViewFrame.maxY - (scrollView.bounds.height - keyboardHeight)
+        let y = scrollDistance
+        scrollView.setContentOffset(CGPoint(x: 0, y: y), animated: true)
+    }
+
+    // MARK: - 键盘隐藏时恢复
+
+    @objc func keyboardWillHide(_ notification: Notification) {
+        cusStackView.scrollView.contentOffset = CGPoint(x: 0, y: 0)
+    }
+}
+
+extension TSPTPInputVC {
+    func updateTextFiledView() {
+        if viewModel.selectedPTPStyleModel.input {
+            promptTextView.isHidden = false
+        } else {
+            promptTextView.isHidden = true
+        }
+
+        UIView.animate(withDuration: 0.3) {
+            self.cusStackView.layoutIfNeeded()
+        }
+    }
+}

+ 59 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC+Upload.swift

@@ -0,0 +1,59 @@
+//
+//  TSPTPInputVC+Upload.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/5/24.
+//
+
+extension TSPTPInputVC {
+    
+    func creatUploadView() -> TSPTPUploadView {
+        let uploadView = TSPTPUploadView()
+        uploadView.clickHandel = { [weak self] index in
+            guard let self = self else { return }
+
+            if index == 0 { // 删除
+                viewModel.upLoadImage = nil
+                uploadView.upLoadImage = nil
+            } else { // 添加
+                if TSAIListHintBaseVC.isShowUploadImageHint {
+                    TSAIListHintBaseVC.isShowUploadImageHint = false
+                    presentModalHintVC()
+                } else {
+                    pickSinglePhoto()
+                }
+            }
+        }
+        return uploadView
+    }
+    
+    
+    
+    func pickSinglePhoto() {
+        photoPickerManager.pickCustomSinglePhoto { [weak self] image, errorString in
+            guard let self = self else { return }
+            if let errorString = errorString {
+                TSToastShared.showToast(text: errorString)
+            } else {
+                viewModel.upLoadImage = image
+                uploadView.upLoadImage = image
+            }
+            kDelayMainShort {
+                self.photoPickerManager.dismissPageVC()
+            }
+        }
+    }
+    
+    
+    func presentModalHintVC() {
+        hintBaseVC = TSAIListHintBaseVC(config: .defaultConfig) { [weak self] image in
+            guard let self = self else { return }
+            viewModel.upLoadImage = image
+            uploadView.upLoadImage = image
+            hintBaseVC.dismissPageVC()
+        }
+        kPresentModalVC(target: self, modelVC: hintBaseVC, transitionStyle: .crossDissolve)
+    }
+
+   
+}

+ 6 - 304
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC.swift

@@ -54,48 +54,9 @@ class TSPTPInputVC: TSBaseVC {
         return navBarView
     }()
 
-    // ###################################### cusStackView ######################################
-    lazy var cusStackView: TSCustomStackView = {
-        let cusStackView = TSCustomStackView(axis: .vertical, spacing: 0)
-        cusStackView.scrollView.isScrollEnabled = true
-        return cusStackView
-    }()
-
-    // ###################################### 上传图片 ######################################
-    lazy var uploadView: TSPTPUploadView = {
-        let uploadView = TSPTPUploadView()
-        uploadView.clickHandel = { [weak self] index in
-            guard let self = self else { return }
 
-            if index == 0 { // 删除
-                viewModel.upLoadImage = nil
-                uploadView.upLoadImage = nil
-            } else { // 添加
-                if TSAIListHintBaseVC.isShowUploadImageHint {
-                    TSAIListHintBaseVC.isShowUploadImageHint = false
-                    presentModalHintVC()
-                } else {
-                    pickSinglePhoto()
-                }
-            }
-        }
-        return uploadView
-    }()
-
-    func pickSinglePhoto() {
-        photoPickerManager.pickCustomSinglePhoto { [weak self] image, errorString in
-            guard let self = self else { return }
-            if let errorString = errorString {
-                TSToastShared.showToast(text: errorString)
-            } else {
-                viewModel.upLoadImage = image
-                uploadView.upLoadImage = image
-            }
-            kDelayMainShort {
-                self.photoPickerManager.dismissPageVC()
-            }
-        }
-    }
+    lazy var cusStackView: TSCustomStackView = creatStackView()
+    lazy var uploadView: TSPTPUploadView = creatUploadView()//上传图片
 
     // ###################################### 选择风格 ######################################
     lazy var selectStyleView: TSPTPSelectStyleView = {
@@ -113,144 +74,15 @@ class TSPTPInputVC: TSBaseVC {
     }()
 
     // ###################################### 输入框 ######################################
-    lazy var customTextView: TSPlaceholderTextView = {
-        let customTextView = TSPlaceholderTextView(
-            placeholder: "Describe how you want to transform".localized,
-            text: "",
-            font: .font(size: 14),
-            textColor: .white,
-            backgroundColor: .clear
-        )
-        customTextView.delegate = self
-        customTextView.returnKeyType = .done
-        return customTextView
-    }()
-
-    lazy var clearBtn: TSUIExpandedTouchButton = {
-        let clearBtn = TSUIExpandedTouchButton()
-        clearBtn.setUpButton(
-            image: UIImage(named: "clear_text")
-        ) { [weak self] in
-            guard let self = self else { return }
-            customTextView.text = ""
-            textViewDidChange(customTextView)
-        }
-        clearBtn.isHidden = true
-        return clearBtn
-    }()
-
+    lazy var customTextView: TSPlaceholderTextView = creatCustomTextView()
+    lazy var clearBtn: TSUIExpandedTouchButton = creatClearBtn()
     var promptTextViewH: CGFloat = 96.0
-    lazy var promptTextView: UIView = {
-        let promptTextView = UIView()
-        promptTextView.isHidden = true
-        promptTextView.clipsToBounds = true
-        let bgView = UIView()
-        bgView.backgroundColor = "#333333".uiColor
-        bgView.cornerRadius = 16.0
-        promptTextView.addSubview(bgView)
-        bgView.snp.makeConstraints { make in
-            make.edges.equalTo(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))
-        }
-
-        bgView.addSubview(customTextView)
-        bgView.addSubview(clearBtn)
-
-        customTextView.snp.makeConstraints { make in
-            make.centerY.equalToSuperview()
-            make.leading.equalTo(12.0)
-            make.top.equalTo(12.0)
-            make.bottom.equalTo(-12.0)
-            make.trailing.equalTo(-20)
-        }
-
-        clearBtn.snp.makeConstraints { make in
-            make.width.height.equalTo(16.0)
-            make.trailing.equalTo(-12)
-            make.bottom.equalTo(-12.0)
-        }
-
-        return promptTextView
-    }()
+    lazy var promptTextView: UIView = creatPromptTextView()
 
     // ###################################### 集合视图 ######################################
     private var collectionViewObserver: CollectionViewObserver!
     let collectionViewBtootm: CGFloat = 80
-    lazy var collectionComponent: TSCollectionViewComponent = {
-        let layout = UICollectionViewFlowLayout()
-        let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
-        cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: collectionViewBtootm, right: 0)
-        cp.collectionView.isScrollEnabled = false
-
-        // 禁用自动 contentInset 调整
-        if #available(iOS 11.0, *) {
-            cp.collectionView.contentInsetAdjustmentBehavior = .never
-        } else {
-            automaticallyAdjustsScrollViewInsets = false
-        }
-
-        cp.sectionActionHandler = { [weak self] cellCp, _ in
-            guard let self = self else { return }
-            if let cmd = cellCp as? String {
-                if cmd == "delete" {
-                    showCustomAlert(message: "Are you sure to delete all histories?".localized, rightActionString: "Delete All".localized , deleteHandler: {
-                        self.viewModel.removeAllHistoryList()
-                        self.updataCollectionView()
-                    })
-                } else if cmd == "more" {
-                    let historyVC = TSPTPHistoryVC(style: .ptp)
-                    kPushVC(target: self, modelVC: historyVC)
-                }
-            }
-        }
-
-        cp.itemActionHandler = { [weak self] object, indexPath in
-            guard let self = self else { return }
-            // 删除过期的任务
-            if let cmd = object as? String{
-                if cmd == "delete_task_expired" {
-                    if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel,
-                       let currentActionInfoModel = sections.items.safeObj(At: indexPath.item) {
-                        TSRMShared.ptpDBHistory.deleteListModel(id: currentActionInfoModel.dataModel.id)
-                        updataCollectionView()
-                    }
-                }else if cmd == "delete_task_sensitive" {
-                    showDeleteErrorAlert(message: "Delete this error history?".localized, deleteHandler:  { [weak self]  in
-                        guard let self = self else { return }
-                        if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel,
-                           let currentActionInfoModel = sections.items.safeObj(At: indexPath.item) {
-                            TSRMShared.ptpDBHistory.deleteListModel(id: currentActionInfoModel.dataModel.id)
-                            updataCollectionView()
-                        }
-                    })
-                }
-            }
-        }
-
-        cp.itemDidSelectedHandler = { [weak self] _, indexPath in
-            guard let self = self else { return }
-            if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel,
-               let dataModel = sections.items.safeObj(At: indexPath.item)?.dataModel {
-                var dataModelArray: [TSActionInfoModel] = []
-                for itemModel in sections.items {
-                    if itemModel.dataModel.status == "success" || itemModel.dataModel.modelType == .example {
-                        dataModelArray.append(itemModel.dataModel)
-                    }
-                }
-
-                let browseVC = TSAIPhotoBrowseVC()
-                browseVC.dataModelArray = dataModelArray
-                browseVC.currentIndex = dataModelArray.firstIndex(of: dataModel) ?? 0
-                browseVC.deleteComplete = { [weak self]  deleteModel in
-                    guard let self = self else { return }
-                    TSRMShared.ptpDBHistory.deleteListModel(id: deleteModel.id)
-                    updataCollectionView()
-                }
-                kPresentModalVC(target: self, modelVC: browseVC,transitionStyle: .crossDissolve)
-            }
-        }
-        cp.collectionView.keyboardDismissMode = .interactive
-        return cp
-    }()
+    lazy var collectionComponent: TSCollectionViewComponent = creatCollectionComponent()
 
     // ###################################### Button ######################################
     lazy var creatBtnView: TSAppBtnView = {
@@ -362,108 +194,8 @@ class TSPTPInputVC: TSBaseVC {
 
         NotificationCenter.default.addObserver(self, selector: #selector(autoSelectImageToImageStyle(notify:)), name: .schemeImageToImageStylePick, object: nil)
     }
-
-    func updataCollectionView() {
-        viewModel.updateRecentData()
-        collectionComponent.clear()
-        collectionComponent.reloadView(with: viewModel.colDataArray)
-    }
 }
 
-extension TSPTPInputVC {
-    func presentModalHintVC() {
-        hintBaseVC = TSAIListHintBaseVC(config: .defaultConfig) { [weak self] image in
-            guard let self = self else { return }
-            viewModel.upLoadImage = image
-            uploadView.upLoadImage = image
-            hintBaseVC.dismissPageVC()
-        }
-        kPresentModalVC(target: self, modelVC: hintBaseVC, transitionStyle: .crossDissolve)
-    }
-
-    func setUpCusStackView() {
-//        let uploadPhotoTitleView = TSTitleView.creatTitleView(title: "Upload Photo".localized, subTitle: "")
-//        cusStackView.addSubviewToStack(uploadPhotoTitleView)
-//        uploadPhotoTitleView.snp.makeConstraints { make in
-//            make.height.equalTo(uploadPhotoTitleView.viewH)
-//            make.width.equalTo(k_ScreenWidth)
-//        }
-//
-//        let hintBtn = TSUIExpandedTouchButton()
-//        hintBtn.setUpButton(image: UIImage(named: "ptp_hint")) { [weak self] in
-//            guard let self = self else { return }
-//            presentModalHintVC()
-//        }
-//        uploadPhotoTitleView.contentView.addSubview(hintBtn)
-//        hintBtn.snp.makeConstraints { make in
-//            make.centerY.equalToSuperview().offset(kSectionTitleViewCenterYOffset)
-//            make.trailing.equalTo(-16)
-//            make.width.height.equalTo(16)
-//        }
-
-        cusStackView.addSpacing(length: 10)
-        cusStackView.addSubviewToStack(uploadView)
-        uploadView.snp.makeConstraints { make in
-            make.height.equalTo(uploadView.viewH)
-            make.width.equalTo(k_ScreenWidth)
-        }
-
-        let selectStyleTitleView = TSTitleMoreView()
-        selectStyleTitleView.setTitle(title: "Select Style".localized) { [weak self] in
-            guard let self = self else { return }
-            let selectStyleVC = TSGennertatorSelectStyleVC()
-            selectStyleVC.currentIndexPath = IndexPath(item: viewModel.selectedStyleIndex, section: 0)
-            selectStyleVC.dataArray = viewModel.ptpStyleModels
-            selectStyleVC.selectedValueBlock = { [weak self] indexPath, _ in
-                guard let self = self else { return }
-                selectStyleView.collectionView(selectStyleView.styleCollectionView, didSelectItemAt: indexPath)
-            }
-            kPresentModalVC(target: self, modelVC: selectStyleVC, transitionStyle: .coverVertical)
-        }
-        cusStackView.addSubviewToStack(selectStyleTitleView)
-        selectStyleTitleView.snp.makeConstraints { make in
-            make.height.equalTo(selectStyleTitleView.viewH)
-            make.width.equalTo(k_ScreenWidth)
-        }
-
-        cusStackView.addSubviewToStack(selectStyleView)
-        selectStyleView.snp.makeConstraints { make in
-            make.height.equalTo(selectStyleView.viewH)
-            make.width.equalTo(k_ScreenWidth)
-        }
-
-        cusStackView.addSubviewToStack(promptTextView, length: promptTextViewH)
-
-        promptTextView.isHidden = !viewModel.selectedPTPStyleModel.input
-
-        cusStackView.addSubviewToStack(collectionComponent.collectionView)
-        collectionComponent.collectionView.snp.makeConstraints { make in
-            make.height.equalTo(0)
-            make.width.equalTo(k_ScreenWidth)
-        }
-
-        cusStackView.addSpacing(length: collectionViewBtootm)
-    }
-}
-
-extension TSPTPInputVC: UITextViewDelegate {
-    // 实现 UITextViewDelegate 协议方法,控制 return 键行为
-    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
-        if text == "\n" {
-            // 当输入为换行符(即按下 return 键)时,执行相应操作
-            // sendBolck?(textView.text)
-            clickView()
-            return false
-        }
-        return true
-    }
-
-    func textViewDidChange(_ textView: UITextView) {
-        clearBtn.isHidden = textView.text.count <= 0
-        viewModel.selectedPTPStyleModel.inputText = textView.text
-        viewModel.gennerateChange()
-    }
-}
 
 extension TSPTPInputVC {
     @objc func vipInfoChanged() {
@@ -531,37 +263,7 @@ extension TSPTPInputVC {
     }
 }
 
-extension TSPTPInputVC {
-    @objc func keyboardWillShow(_ notification: Notification) {
-        guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
-        let scrollView = cusStackView.scrollView
-        let keyboardHeight = keyboardFrame.height - view.safeAreaInsets.bottom
-        let textViewFrame = scrollView.convert(customTextView.frame, from: customTextView.superview)
-        let scrollDistance = textViewFrame.maxY - (scrollView.bounds.height - keyboardHeight)
-        let y = scrollDistance
-        scrollView.setContentOffset(CGPoint(x: 0, y: y), animated: true)
-    }
-
-    // MARK: - 键盘隐藏时恢复
 
-    @objc private func keyboardWillHide(_ notification: Notification) {
-        cusStackView.scrollView.contentOffset = CGPoint(x: 0, y: 0)
-    }
-}
-
-extension TSPTPInputVC {
-    func updateTextFiledView() {
-        if viewModel.selectedPTPStyleModel.input {
-            promptTextView.isHidden = false
-        } else {
-            promptTextView.isHidden = true
-        }
-
-        UIView.animate(withDuration: 0.3) {
-            self.cusStackView.layoutIfNeeded()
-        }
-    }
-}
 
 extension TSPTPInputVC {
     @objc func autoSelectImageToImageStyle(notify: Notification) {