瀏覽代碼

初步开发了一点

100Years 1 周之前
父節點
當前提交
ff66ae2f69

+ 4 - 0
AIEmoji.xcodeproj/project.pbxproj

@@ -155,6 +155,7 @@
 		A8BA76472DA4CC70000B6707 /* TSPTPSelectStyleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76462DA4CC6C000B6707 /* TSPTPSelectStyleView.swift */; };
 		A8BA76472DA4CC70000B6707 /* TSPTPSelectStyleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76462DA4CC6C000B6707 /* TSPTPSelectStyleView.swift */; };
 		A8BA764F2DA50B52000B6707 /* CpuMapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */; };
 		A8BA764F2DA50B52000B6707 /* CpuMapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */; };
 		A8BA76522DA51600000B6707 /* TSPTPImageHintVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.swift */; };
 		A8BA76522DA51600000B6707 /* TSPTPImageHintVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.swift */; };
+		A8BA76542DA54571000B6707 /* CollectionViewObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76532DA5456E000B6707 /* CollectionViewObserver.swift */; };
 		A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD32D3E6C610032C5A0 /* Flower💐.json */; };
 		A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD32D3E6C610032C5A0 /* Flower💐.json */; };
 		A8EEADD62D3E6CD80032C5A0 /* Fish🐠.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */; };
 		A8EEADD62D3E6CD80032C5A0 /* Fish🐠.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */; };
 		A8EEADD82D3E74D20032C5A0 /* Pink🩷.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */; };
 		A8EEADD82D3E74D20032C5A0 /* Pink🩷.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */; };
@@ -386,6 +387,7 @@
 		A8BA764C2DA4F689000B6707 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		A8BA764C2DA4F689000B6707 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CpuMapManager.swift; sourceTree = "<group>"; };
 		A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CpuMapManager.swift; sourceTree = "<group>"; };
 		A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPImageHintVC.swift; sourceTree = "<group>"; };
 		A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPImageHintVC.swift; sourceTree = "<group>"; };
+		A8BA76532DA5456E000B6707 /* CollectionViewObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewObserver.swift; sourceTree = "<group>"; };
 		A8EEADD32D3E6C610032C5A0 /* Flower💐.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Flower💐.json"; sourceTree = "<group>"; };
 		A8EEADD32D3E6C610032C5A0 /* Flower💐.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Flower💐.json"; sourceTree = "<group>"; };
 		A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Fish🐠.json"; sourceTree = "<group>"; };
 		A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Fish🐠.json"; sourceTree = "<group>"; };
 		A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Pink🩷.json"; sourceTree = "<group>"; };
 		A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Pink🩷.json"; sourceTree = "<group>"; };
@@ -1264,6 +1266,7 @@
 		A8BA76402DA4C918000B6707 /* VM */ = {
 		A8BA76402DA4C918000B6707 /* VM */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				A8BA76532DA5456E000B6707 /* CollectionViewObserver.swift */,
 				A8BA76412DA4C920000B6707 /* TSPTPInputVM.swift */,
 				A8BA76412DA4C920000B6707 /* TSPTPInputVM.swift */,
 			);
 			);
 			path = VM;
 			path = VM;
@@ -1953,6 +1956,7 @@
 				A80E724F2D3F6D7F00C64288 /* DiyFixedTextElement.swift in Sources */,
 				A80E724F2D3F6D7F00C64288 /* DiyFixedTextElement.swift in Sources */,
 				A85E478F2D67115A0018D62D /* TSTextGeneralPictureVC.swift in Sources */,
 				A85E478F2D67115A0018D62D /* TSTextGeneralPictureVC.swift in Sources */,
 				A89EA6C42D5F40CC000EB181 /* TSChatInputBarVC.swift in Sources */,
 				A89EA6C42D5F40CC000EB181 /* TSChatInputBarVC.swift in Sources */,
+				A8BA76542DA54571000B6707 /* CollectionViewObserver.swift in Sources */,
 				A8F775452D39347100AA6E93 /* TSSetingViewModel.swift in Sources */,
 				A8F775452D39347100AA6E93 /* TSSetingViewModel.swift in Sources */,
 				A80E72202D3F3A8600C64288 /* DiyElementBaseView.swift in Sources */,
 				A80E72202D3F3A8600C64288 /* DiyElementBaseView.swift in Sources */,
 				A8F776212D3A3F0200AA6E93 /* TSEmojisChildVC.swift in Sources */,
 				A8F776212D3A3F0200AA6E93 /* TSEmojisChildVC.swift in Sources */,

+ 22 - 0
AIEmoji/Assets.xcassets/Common/selected_circle.imageset/Contents.json

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

二進制
AIEmoji/Assets.xcassets/Common/selected_circle.imageset/selected_circle@2x.png


二進制
AIEmoji/Assets.xcassets/Common/selected_circle.imageset/selected_circle@3x.png


+ 34 - 15
AIEmoji/Business/TSPTPGeneratorVC/TSPTPImageHintVC/TSPTPImageHintVC.swift

@@ -18,6 +18,16 @@ class TSPTPImageHintVC: TSBaseVC {
         popupContentView.cornerRadius = 20.0
         popupContentView.cornerRadius = 20.0
         return popupContentView
         return popupContentView
     }()
     }()
+    
+    
+    lazy var noPromptsBtn: UIButton = {
+        let noPromptsBtn = UIButton.createButton(title: "No more prompts".localized,image: UIImage(named: "selected_circle"),font: .font(size: 11),titleColor: .white.withAlphaComponent(0.6)){ [weak self]  in
+            guard let self = self else { return }
+            changeNoPromptsBtn()
+        }
+        noPromptsBtn.setImage(UIImage(named: "radioboxSelected"), for: .selected)
+        return noPromptsBtn
+    }()
     override func createView() {
     override func createView() {
         setNavBarViewHidden(true)
         setNavBarViewHidden(true)
         view.backgroundColor = .black.withAlphaComponent(0.7)
         view.backgroundColor = .black.withAlphaComponent(0.7)
@@ -116,23 +126,32 @@ class TSPTPImageHintVC: TSBaseVC {
             make.centerX.equalToSuperview()
             make.centerX.equalToSuperview()
             make.width.equalTo(250*kDesignScale)
             make.width.equalTo(250*kDesignScale)
             make.height.equalTo(48)
             make.height.equalTo(48)
-            make.bottom.equalTo(-24)
         }
         }
+
         
         
-//        let okBtn = UIButton.createButton(title: "Upload Photo".localized,backgroundColor: .white.withAlphaComponent(0.4),titleColor: .white,corner: 24){ [weak self]  in
-//            guard let self = self else { return }
-//            
-//            dismiss()
-//        }
-//        popupContentView.addSubview(okBtn)
-//        okBtn.snp.makeConstraints { make in
-//            make.top.equalTo(badImageView.snp.bottom).offset(35)
-//            make.centerX.equalToSuperview()
-//            make.width.equalTo(250*kDesignScale)
-//            make.height.equalTo(48*kDesignScale)
-//            make.bottom.equalTo(-24)
-//        }
-        
+        noPromptsBtn.isSelected = true
+        popupContentView.addSubview(noPromptsBtn)
+        noPromptsBtn.snp.makeConstraints { make in
+            make.top.equalTo(submitBtn.snp.bottom).offset(12)
+            make.centerX.equalToSuperview()
+            make.height.equalTo(16)
+            make.bottom.equalTo(-24)
+        }
+    }
+    
+    func changeNoPromptsBtn(){
+        noPromptsBtn.isSelected = !noPromptsBtn.isSelected
+        Self.isShowUploadImageHint = noPromptsBtn.isSelected
     }
     }
     
     
+    static var isShowUploadImageHint:Bool{
+        get {
+            return UserDefaults.standard.string(forKey: "isFirstUploadImagePTP") == nil
+        }
+        
+        set {
+            UserDefaults.standard.set(newValue ? "1" : nil, forKey: "isFirstUploadImagePTP")
+            UserDefaults.standard.synchronize()
+        }
+    }
 }
 }

+ 87 - 85
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC.swift

@@ -150,9 +150,7 @@ class TSPTPInputVC: TSBaseVC {
                 uploadView.upLoadImage = nil
                 uploadView.upLoadImage = nil
             }else{//添加
             }else{//添加
                 
                 
-                if UserDefaults.standard.string(forKey: "isFirstUploadImagePTP") == nil {
-                    UserDefaults.standard.set("1", forKey: "isFirstUploadImagePTP")
-                    UserDefaults.standard.synchronize()
+                if TSPTPImageHintVC.isShowUploadImageHint{
                     presentModalHintVC()
                     presentModalHintVC()
                 }else {
                 }else {
                     pickSinglePhoto()
                     pickSinglePhoto()
@@ -210,23 +208,17 @@ class TSPTPInputVC: TSBaseVC {
     
     
     //###################################### 输入框 ######################################
     //###################################### 输入框 ######################################
     private let maxLength = 200 // 最大长度限制
     private let maxLength = 200 // 最大长度限制
-    lazy var customTextView: UITextField = {
-        let customTextView = UITextField()
-        customTextView.placeholder = "Please describe your photo".localized
-        customTextView.font = .font(size: 14)
-        customTextView.textColor = .white
+    lazy var customTextView: TSPlaceholderTextView = {
+        let customTextView = TSPlaceholderTextView(
+            placeholder: "Please describe your photo".localized,
+            text: "",
+            font: .font(size: 14),
+            textColor: .white,
+            backgroundColor: .clear
+        )
+        customTextView.verticalAlignment = .center
         customTextView.delegate = self
         customTextView.delegate = self
         customTextView.returnKeyType = .send
         customTextView.returnKeyType = .send
-//        customTextView.iq.distanceFromKeyboard = 0
-        
-        customTextView.attributedPlaceholder = NSAttributedString(
-            string: "Please describe your photo".localized,
-            attributes: [
-                .foregroundColor: UIColor.white.withAlphaComponent(0.4),
-                .font: UIFont.font(size: 14)
-            ]
-        )
-        
         return customTextView
         return customTextView
     }()
     }()
     
     
@@ -259,6 +251,7 @@ class TSPTPInputVC: TSBaseVC {
         
         
         customTextView.snp.makeConstraints { make in
         customTextView.snp.makeConstraints { make in
             make.top.bottom.equalTo(0)
             make.top.bottom.equalTo(0)
+            make.centerY.equalToSuperview()
             make.leading.equalTo(12.0)
             make.leading.equalTo(12.0)
             make.trailing.equalTo(-32)
             make.trailing.equalTo(-32)
         }
         }
@@ -278,6 +271,14 @@ class TSPTPInputVC: TSBaseVC {
         let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
         let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
         cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: collectionViewBtootm, right: 0)
         cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: collectionViewBtootm, right: 0)
         
         
+        
+        // 禁用自动 contentInset 调整
+          if #available(iOS 11.0, *) {
+              cp.collectionView.contentInsetAdjustmentBehavior = .never
+          } else {
+              automaticallyAdjustsScrollViewInsets = false
+          }
+        
         cp.sectionActionHandler = { [weak self] cellCp, indexPath in
         cp.sectionActionHandler = { [weak self] cellCp, indexPath in
             guard let self = self else { return }
             guard let self = self else { return }
             if let cmd = cellCp as? String, cmd == "delete"  {
             if let cmd = cellCp as? String, cmd == "delete"  {
@@ -332,9 +333,9 @@ class TSPTPInputVC: TSBaseVC {
         }
         }
         
         
         
         
-//        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickView))
-//        tapGesture.cancelsTouchesInView = false
-//        view.addGestureRecognizer(tapGesture)
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickView))
+        tapGesture.cancelsTouchesInView = false
+        view.addGestureRecognizer(tapGesture)
 
 
         collectionComponent.clear()
         collectionComponent.clear()
         collectionComponent.reloadView(with:viewModel.colDataArray)
         collectionComponent.reloadView(with:viewModel.colDataArray)
@@ -358,8 +359,8 @@ class TSPTPInputVC: TSBaseVC {
     override func dealThings() {
     override func dealThings() {
         NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
         updateVipView()
         updateVipView()
-        
-//        // 监听键盘事件
+        collectionViewObserverHandle()
+////        // 监听键盘事件
 //        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
 //        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
 //        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
 //        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
     }
     }
@@ -373,6 +374,32 @@ class TSPTPInputVC: TSBaseVC {
 //        
 //        
 //        IQKeyboardManager.shared.isEnabled = true
 //        IQKeyboardManager.shared.isEnabled = true
 //    }
 //    }
+    
+    
+    private var collectionViewObserver: CollectionViewObserver!
+    
+    func collectionViewObserverHandle(){
+        collectionViewObserver = CollectionViewObserver(collectionView: collectionComponent.collectionView)
+        
+        collectionViewObserver.onContentSizeChange = { size in
+            print("collectionViewObserver 内容大小变化: \(size)")
+        }
+        
+        collectionViewObserver.onContentInsetChange = { inset in
+            print("collectionViewObserver 内边距变化: \(inset)")
+        }
+        
+        collectionViewObserver.onContentOffsetChange = { offset in
+            print("collectionViewObserver 偏移量变化: \(offset)")
+        }
+        
+    }
+    
+    
+    func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        print("contentOffset 变化: \(scrollView.contentOffset)")
+        // 实时监听偏移量变化
+    }
 }
 }
 
 
 extension TSPTPInputVC {
 extension TSPTPInputVC {
@@ -380,19 +407,24 @@ extension TSPTPInputVC {
     var cusStackViewH:CGFloat{
     var cusStackViewH:CGFloat{
         get {
         get {
             if cusStackView.viewH > 0{
             if cusStackView.viewH > 0{
+                dePrint("collectionViewObserver cusStackView.viewH == \(cusStackView.viewH)")
                 return cusStackView.viewH
                 return cusStackView.viewH
             }
             }
-            return 551+bannerH+bannerY//+promptTextViewH
+            dePrint("collectionViewObserver cusStackView.viewH = \(462+bannerH+bannerY+promptTextViewH)")
+            return 462+bannerH+bannerY+promptTextViewH
         }
         }
     }
     }
     
     
     func upDateCusStackViewH(){
     func upDateCusStackViewH(){
-        self.collectionComponent.collectionView.contentInset = UIEdgeInsets(top: cusStackViewH, left: 0, bottom: collectionViewBtootm, right: 0)
+        let cusH = cusStackViewH
+        self.collectionComponent.collectionView.contentInset = UIEdgeInsets(top: cusH, left: 0, bottom: collectionViewBtootm, right: 0)
         cusStackView.snp.remakeConstraints { make in
         cusStackView.snp.remakeConstraints { make in
-            make.top.equalTo(-cusStackViewH)
+            make.top.equalTo(-cusH)
             make.leading.trailing.equalTo(0)
             make.leading.trailing.equalTo(0)
-            make.height.equalTo(cusStackViewH)
+            make.height.equalTo(cusH)
         }
         }
+        self.collectionComponent.collectionView.contentOffset = CGPoint(x: 0, y: -cusH)
+        
     }
     }
     
     
     func presentModalHintVC(){
     func presentModalHintVC(){
@@ -407,12 +439,6 @@ extension TSPTPInputVC {
         
         
         collectionComponent.collectionView.addSubview(cusStackView)
         collectionComponent.collectionView.addSubview(cusStackView)
         
         
-//                cusStackView.addSubviewToStack(promptTextView)
-//                promptTextView.snp.makeConstraints { make in
-//                    make.height.equalTo(promptTextViewH)
-//                    make.width.equalTo(k_ScreenWidth)
-//                }
-        
         cusStackView.addSubviewToStack(entranceView)
         cusStackView.addSubviewToStack(entranceView)
         entranceView.snp.makeConstraints { make in
         entranceView.snp.makeConstraints { make in
             make.height.equalTo(bannerH+bannerY)
             make.height.equalTo(bannerH+bannerY)
@@ -458,55 +484,31 @@ extension TSPTPInputVC {
         }
         }
         
         
 
 
-        
+//        cusStackView.addSubviewToStack(promptTextView)
+//        promptTextView.snp.makeConstraints { make in
+//            make.height.equalTo(promptTextViewH)
+//            make.width.equalTo(k_ScreenWidth)
+//        }
+    }
+    
+    override func viewDidLayoutSubviews() {
+        super.viewDidLayoutSubviews()
     }
     }
 }
 }
 
 
 
 
 
 
-extension TSPTPInputVC: UITextFieldDelegate{
-    // MARK: - UITextFieldDelegate
-    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
-        if textField.returnKeyType == .send {
-            textField.resignFirstResponder() // 可选:收起键盘
-            
-            // 触发发送逻辑
-            
-            
-            return true
-        }
-        return false
-    }
-
-    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
-        // 获取当前文本
-        guard let currentText = textField.text else {
-            return true
-        }
-        
-        clearBtn.isHidden = currentText.count <= 0
-        
-        // 计算新文本
-        let newText = (currentText as NSString).replacingCharacters(in: range, with: string)
+extension TSPTPInputVC: UITextViewDelegate{
+    // 实现 UITextViewDelegate 协议方法,控制 return 键行为
+    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
         
         
-        // 如果新文本长度 > maxLength,截断并返回 false
-        if newText.count > maxLength {
-            textField.text = String(newText.prefix(maxLength))
+        if text == "\n" {
+            // 当输入为换行符(即按下 return 键)时,执行相应操作
+            //sendBolck?(textView.text)
             return false
             return false
         }
         }
-        
         return true
         return true
     }
     }
-    
-    func textFieldDidBeginEditing(_ textField: UITextField) {
-        print("输入框开始编辑 - 被点击了")
-        // 在这里可以通知控制器滚动到合适位置
-        
-//        DispatchQueue.main.async {
-//            let rect = self.promptTextView.convert(self.promptTextView.bounds, to: self.collectionComponent.collectionView)
-//            self.collectionComponent.collectionView.scrollRectToVisible(rect, animated: true)
-//        }
-    }
 
 
 }
 }
 
 
@@ -598,13 +600,13 @@ extension TSPTPInputVC {
         }
         }
 //        dePrint("keyboardWillShow contentInset IQKeyboardManager=\(IQKeyboardManager.shared.isEnabled)")
 //        dePrint("keyboardWillShow contentInset IQKeyboardManager=\(IQKeyboardManager.shared.isEnabled)")
         
         
-        let keyboardHeight = keyboardFrame.height
-        let contentInset = UIEdgeInsets(top:cusStackViewH, left: 0, bottom: keyboardHeight, right: 0)
-        dePrint("keyboardWillShow contentInset=\(contentInset)")
-//        UIView.animate(withDuration: animationDuration) {
-            self.collectionComponent.collectionView.contentInset = contentInset
-            self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
-//        }
+//        let keyboardHeight = keyboardFrame.height
+//        let contentInset = UIEdgeInsets(top:cusStackViewH, left: 0, bottom: keyboardHeight, right: 0)
+//        dePrint("keyboardWillShow contentInset=\(contentInset)")
+////        UIView.animate(withDuration: animationDuration) {
+//            self.collectionComponent.collectionView.contentInset = contentInset
+//            self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
+////        }
         
         
 //        kDelayMainShort {
 //        kDelayMainShort {
 //            self.collectionComponent.collectionView.scrollToLastItem(animated: false)
 //            self.collectionComponent.collectionView.scrollToLastItem(animated: false)
@@ -616,12 +618,12 @@ extension TSPTPInputVC {
             return
             return
         }
         }
 
 
-        let contentInset = UIEdgeInsets(top: cusStackViewH, left: 0, bottom: collectionViewBtootm, right: 0)
-        dePrint("keyboardWillHide contentInset=\(contentInset)")
-//        UIView.animate(withDuration: animationDuration) {
-            self.collectionComponent.collectionView.contentInset = contentInset
-            self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
-//        }
+//        let contentInset = UIEdgeInsets(top: cusStackViewH, left: 0, bottom: collectionViewBtootm, right: 0)
+//        dePrint("keyboardWillHide contentInset=\(contentInset)")
+////        UIView.animate(withDuration: animationDuration) {
+//            self.collectionComponent.collectionView.contentInset = contentInset
+//            self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
+////        }
     }
     }
     
     
     
     

+ 49 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/VM/CollectionViewObserver.swift

@@ -0,0 +1,49 @@
+//
+//  Untitled.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/8.
+//
+
+class CollectionViewObserver {
+    private weak var collectionView: UICollectionView?
+    private var observers: [NSKeyValueObservation] = []
+    
+    var onContentSizeChange: ((CGSize) -> Void)?
+    var onContentInsetChange: ((UIEdgeInsets) -> Void)?
+    var onContentOffsetChange: ((CGPoint) -> Void)?
+    
+    init(collectionView: UICollectionView) {
+        self.collectionView = collectionView
+        setupObservers()
+    }
+    
+    private func setupObservers() {
+        guard let collectionView = collectionView else { return }
+        
+        observers.append(
+            collectionView.observe(\.contentSize, options: [.new, .old]) { [weak self] (_, change) in
+                guard let newSize = change.newValue, newSize != change.oldValue else { return }
+                self?.onContentSizeChange?(newSize)
+            }
+        )
+        
+        observers.append(
+            collectionView.observe(\.contentInset, options: [.new, .old]) { [weak self] (_, change) in
+                guard let newInset = change.newValue, newInset != change.oldValue else { return }
+                self?.onContentInsetChange?(newInset)
+            }
+        )
+        
+        observers.append(
+            collectionView.observe(\.contentOffset, options: [.new]) { [weak self] (_, change) in
+                guard let newOffset = change.newValue else { return }
+                self?.onContentOffsetChange?(newOffset)
+            }
+        )
+    }
+    
+    deinit {
+        observers.forEach { $0.invalidate() }
+    }
+}

+ 1 - 1
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift

@@ -321,7 +321,7 @@ struct PurchaseView :View {
     
     
     var body: some View {
     var body: some View {
         ScrollView {
         ScrollView {
-            Spacer().frame(height: 31)
+            Spacer()//.frame(height: 31)
             
             
             VStack {
             VStack {
          
          

+ 3 - 3
AIEmoji/Common/Purchase/TSPurchaseManager.swift

@@ -143,9 +143,9 @@ public class PurchaseManager: NSObject {
     }
     }
 
 
     @objc public var isVip: Bool {
     @objc public var isVip: Bool {
-        #if DEBUG
-            return true
-        #endif
+//        #if DEBUG
+//            return true
+//        #endif
         guard let expiresDate = expiredDate else {
         guard let expiresDate = expiredDate else {
             return false
             return false
         }
         }