Browse Source

1.解决回答问题时上下滑动卡顿问题
2.优化回答问题时,可以自动滚动和手动翻看记录问题
3.解决AI 回答问题时,可以再次发送的问题

100Years 1 month ago
parent
commit
3181e9e79a

+ 4 - 4
AIEmoji.xcodeproj/project.pbxproj

@@ -40,7 +40,7 @@
 		A80E73E62D5348D000C64288 /* SettingPurchaseTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80E73E52D5348CF00C64288 /* SettingPurchaseTopView.swift */; };
 		A89EA64B2D59A588000EB181 /* MessageKit in Frameworks */ = {isa = PBXBuildFile; productRef = A89EA64A2D59A588000EB181 /* MessageKit */; };
 		A89EA6542D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */; };
-		A89EA6552D59A9F4000EB181 /* MockMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6502D59A9F4000EB181 /* MockMessage.swift */; };
+		A89EA6552D59A9F4000EB181 /* TSChatMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6502D59A9F4000EB181 /* TSChatMessage.swift */; };
 		A89EA6562D59A9F4000EB181 /* TSChatUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6522D59A9F4000EB181 /* TSChatUser.swift */; };
 		A89EA6582D59A9F4000EB181 /* TSLayoutSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA64E2D59A9F4000EB181 /* TSLayoutSizeCalculator.swift */; };
 		A89EA6592D59A9F4000EB181 /* CustomMessageFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA64C2D59A9F4000EB181 /* CustomMessageFlowLayout.swift */; };
@@ -162,7 +162,7 @@
 		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>"; };
 		A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextLayoutSizeCalculator.swift; sourceTree = "<group>"; };
-		A89EA6502D59A9F4000EB181 /* MockMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMessage.swift; sourceTree = "<group>"; };
+		A89EA6502D59A9F4000EB181 /* TSChatMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatMessage.swift; sourceTree = "<group>"; };
 		A89EA6522D59A9F4000EB181 /* TSChatUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatUser.swift; sourceTree = "<group>"; };
 		A89EA65E2D59AA11000EB181 /* TSChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatViewController.swift; sourceTree = "<group>"; };
 		A89EA6632D59AA31000EB181 /* CameraInputBarAccessoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraInputBarAccessoryView.swift; sourceTree = "<group>"; };
@@ -448,7 +448,7 @@
 				A89EA6C02D5ED278000EB181 /* TSChatCellConfig.swift */,
 				A89EA64E2D59A9F4000EB181 /* TSLayoutSizeCalculator.swift */,
 				A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */,
-				A89EA6502D59A9F4000EB181 /* MockMessage.swift */,
+				A89EA6502D59A9F4000EB181 /* TSChatMessage.swift */,
 				A89EA6522D59A9F4000EB181 /* TSChatUser.swift */,
 			);
 			path = Models;
@@ -1083,7 +1083,7 @@
 				A80E72532D3F985E00C64288 /* TSWallpaperVC.swift in Sources */,
 				A8FB02B32D3E39A40031A396 /* TSEmojisModel.swift in Sources */,
 				A89EA6542D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift in Sources */,
-				A89EA6552D59A9F4000EB181 /* MockMessage.swift in Sources */,
+				A89EA6552D59A9F4000EB181 /* TSChatMessage.swift in Sources */,
 				A89EA6562D59A9F4000EB181 /* TSChatUser.swift in Sources */,
 				A89EA6582D59A9F4000EB181 /* TSLayoutSizeCalculator.swift in Sources */,
 				A89EA6592D59A9F4000EB181 /* CustomMessageFlowLayout.swift in Sources */,

+ 66 - 0
AIEmoji/Business/AIChat/TSChatViewController/Models/TSChatMessage.swift

@@ -0,0 +1,66 @@
+// MIT License
+//
+// Copyright (c) 2017-2019 MessageKit
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+import Foundation
+import MessageKit
+import UIKit
+// MARK: - TSChatMessage
+internal class TSChatMessage: MessageType {
+  // MARK: Lifecycle
+
+    init(kind: MessageKind, user: TSChatUser, messageId: String, date: Date) {
+        self.kind = kind
+        self.user = user
+        self.messageId = messageId
+        sentDate = date
+    }
+
+    convenience init(custom: Any?, user: TSChatUser, messageId: String, date: Date) {
+        self.init(kind: .custom(custom), user: user, messageId: messageId, date: date)
+    }
+
+    convenience init(text: String, user: TSChatUser, messageId: String, date: Date) {
+        self.init(kind: .text(text), user: user, messageId: messageId, date: date)
+    }
+
+    convenience init(attributedText: NSAttributedString, user: TSChatUser, messageId: String, date: Date) {
+        self.init(kind: .attributedText(attributedText), user: user, messageId: messageId, date: date)
+    }
+
+    convenience init(linkItem: LinkItem, user: TSChatUser, messageId: String, date: Date) {
+        self.init(kind: .linkPreview(linkItem), user: user, messageId: messageId, date: date)
+    }
+
+    // MARK: Internal
+    var messageId: String
+    var sentDate: Date
+    var kind: MessageKind
+    var user: TSChatUser
+    var sender: SenderType {
+        user
+    }
+    var sendState: TSProgressState = .none
+    var appendDict:[String:Any] = [:]
+}
+
+//AI对话默认头View
+let kCMAppendkey_AIDefaultHeader = "kCMAppendkey_AIDefaultHeader"

+ 35 - 2
AIEmoji/Business/AIChat/TSChatViewController/TSChatInputBarVC/TSChatInputBarVC.swift

@@ -10,6 +10,13 @@ import UIKit
 class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
     
     var sendComplete:(([Any])->Void)?
+    //AI是否正在回答问题
+    var isAIAnswering:Bool = false{
+        didSet{
+            sendEnabled(enabled: !isAIAnswering)
+//            chatInputFullScreenVC?.isAIAnswering = isAIAnswering
+        }
+    }
     
     lazy var InputBarView:UIView = {
         let InputBarView = UIView()
@@ -31,9 +38,13 @@ class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
         let magnifyBtn = UIButton.createButton(image: UIImage(named: "chat_send_magnify")) { [weak self]  in
             guard let self = self else { return }
             let vc = TSChatInputFullScreenVC()
+            
+//            chatInputFullScreenVC = vc
+            
             vc.text = textView.text
             vc.sendComplete = { [weak self] date in
                 guard let self = self else { return }
+//                chatInputFullScreenVC = nil
                 if let text = date.first as? String {
                     textView.text = text
                     textView.resignFirstResponder()
@@ -45,6 +56,7 @@ class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
             
             vc.closeComplete = { [weak self] text in
                 guard let self = self else { return }
+//                chatInputFullScreenVC = nil
                 textView.text = text
                 textView.resignFirstResponder()
                 textDidChange()
@@ -52,11 +64,15 @@ class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
             }
             
             kPresentModalVC(target: self, modelVC: vc)
+            
         }
         magnifyBtn.isHidden = true
         return magnifyBtn
     }()
     
+    
+//    var chatInputFullScreenVC: TSChatInputFullScreenVC?
+    
     private let minHeight: CGFloat = 56//24
     private let maxHeight: CGFloat = 154
     lazy var textView: TSCustomTextView = {
@@ -122,12 +138,19 @@ class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
     override func dealThings() {
         // 监听文本变化事件
         NotificationCenter.default.addObserver(self, selector: #selector(textDidChange), name: UITextView.textDidChangeNotification, object: textView)
+        NotificationCenter.default.addObserver(self, selector: #selector(handleAIAnsweringNotification(_:)), name: .kAIAnsweringNotification, object: nil)
     }
 
     func sendMsg(){
-        if textView.text.replacingOccurrences(of: " ", with: "").count <= 0 {
+        
+        if sendBtn.isEnabled == false {
             return
         }
+        
+//        if textView.text.replacingOccurrences(of: " ", with: "").count <= 0 {
+//            return
+//        }
+        
         if let string = textView.text {
             sendComplete?([string])
             textView.resignFirstResponder()
@@ -135,7 +158,9 @@ class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
     }
     
     func sendEnabled(enabled:Bool){
-        if enabled == true ,textView.text.replacingOccurrences(of: " ", with: "").count > 0 {
+        if enabled == true,
+           isAIAnswering == false,
+           textView.text.replacingOccurrences(of: " ", with: "").count > 0 {
             sendBtn.isEnabled = true
         }else{
             sendBtn.isEnabled = false
@@ -149,6 +174,14 @@ class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
         magnifyBtn.isHidden = true
     }
     
+    
+    @objc func handleAIAnsweringNotification(_ notification: Notification) {
+        if let userInfo = notification.userInfo, let boolValue = userInfo[kIsAIAnswering] as? Bool {
+            isAIAnswering = boolValue
+        }
+    }
+    
+    
     deinit {
         // 移除通知监听
         NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView)

+ 25 - 3
AIEmoji/Business/AIChat/TSChatViewController/TSChatInputBarVC/TSChatInputFullScreenVC.swift

@@ -12,6 +12,12 @@ class TSChatInputFullScreenVC: TSBaseVC, UITextViewDelegate {
     var sendComplete:(([Any])->Void)?
     var closeComplete:((String)->Void)?
     var text:String?
+    //AI是否正在回答问题
+    var isAIAnswering:Bool = false{
+        didSet{
+            sendEnabled(enabled: !isAIAnswering)
+        }
+    }
     
     lazy var InputBarView:UIView = {
         let InputBarView = UIView()
@@ -109,6 +115,8 @@ class TSChatInputFullScreenVC: TSBaseVC, UITextViewDelegate {
         // 监听键盘事件
         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(handleAIAnsweringNotification(_:)), name: .kAIAnsweringNotification, object: nil)
     }
 
     @objc func clickView(){
@@ -121,10 +129,15 @@ class TSChatInputFullScreenVC: TSBaseVC, UITextViewDelegate {
     
     
     func sendMsg(){
-        if textView.text.replacingOccurrences(of: " ", with: "").count <= 0 {
+
+        if sendBtn.isEnabled == false {
             return
         }
         
+//        if textView.text.replacingOccurrences(of: " ", with: "").count <= 0 {
+//            return
+//        }
+        
         if let string = textView.text {
             sendComplete?([string])
             textView.resignFirstResponder()
@@ -133,7 +146,9 @@ class TSChatInputFullScreenVC: TSBaseVC, UITextViewDelegate {
     }
     
     func sendEnabled(enabled:Bool){
-        if enabled == true ,textView.text.replacingOccurrences(of: " ", with: "").count > 0 {
+        if enabled == true,
+           isAIAnswering == false,
+            textView.text.replacingOccurrences(of: " ", with: "").count > 0 {
             sendBtn.isEnabled = true
         }else{
             sendBtn.isEnabled = false
@@ -178,9 +193,16 @@ class TSChatInputFullScreenVC: TSBaseVC, UITextViewDelegate {
         }
     }
     
+    
+    @objc func handleAIAnsweringNotification(_ notification: Notification) {
+        if let userInfo = notification.userInfo, let boolValue = userInfo[kIsAIAnswering] as? Bool {
+            isAIAnswering = boolValue
+        }
+    }
+    
     deinit {
         // 移除通知监听
-        NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView)
+        NotificationCenter.default.removeObserver(self)
     }
 }
 

+ 1 - 1
AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+Keyboard.swift

@@ -45,7 +45,7 @@ extension TSChatViewController{
         let frameHeight = scrollView.frame.size.height
         
         // 判断是否需要显示滚动到底部的按钮
-        if offsetY > contentHeight - frameHeight - 400 {
+        if offsetY > contentHeight - frameHeight + inputContainerView.frame.size.height - 10 {
             scrollToBottomButton.isHidden = true
         } else {
             scrollToBottomButton.isHidden = false

+ 48 - 10
AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController+SendMsg.swift

@@ -53,12 +53,19 @@ extension TSChatViewController {
         insertMessage(message)
         
         inputBarVC.sendEnabled(enabled: false)
+
+        NotificationCenter.default.post(name: .kAIAnsweringNotification, object: nil, userInfo: [kIsAIAnswering: true])
+        
         viewModel.sendChatMessage(message: messageString) {[weak self] string in
             guard let self = self else { return }
             debugPrint("viewModel.AiMDString=\(viewModel.AiMDString)")
             message.kind = .attributedText(kMDAttributedString(text: viewModel.AiMDString))
             message.sendState = .progress(0.5)
-            updataAIChatCellUI()
+           
+            if self.scrollToBottomButton.isHidden == true {
+                updataAIChatCellUI()
+                self.messagesCollectionView.scrollToLastItem(animated: false)
+            }
             
         } completion: {[weak self] data, error in
             guard let self = self else { return }
@@ -76,29 +83,60 @@ extension TSChatViewController {
             updataAIChatCellUI()
             
             kExecuteOnMainThread {
-                self.inputBarVC.sendEnabled(enabled: true)
+                NotificationCenter.default.post(name: .kAIAnsweringNotification, object: nil, userInfo: [kIsAIAnswering: false])
                 
                 //更新 Vip
                 if kPurchaseDefault.isVip == false{
                     self.updateVipView()
                 }
                 
-//                self.messagesCollectionView.scrollToLastItem(animated: false)
+                if self.scrollToBottomButton.isHidden == true {
+                    self.messagesCollectionView.scrollToLastItem(animated: false)
+                }
             }
         }
     }
     
     func updataAIChatCellUI(){
-        kExecuteOnMainThread {
-            if self.messageList.count >= 2 {
-                UIView.performWithoutAnimation {
-                    self.messagesCollectionView.reloadItems(at: [self.lastIndexPath])
+//        if self.scrollToBottomButton.isHidden == true {
+//        if isLastItemVisible() {
+            kExecuteOnMainThread {
+                if self.messageList.count >= 2 {
+                    UIView.performWithoutAnimation {
+                        self.messagesCollectionView.reloadItems(at: [self.lastIndexPath])
+                    }
+                }else{
+                    self.messagesCollectionView.reloadData()
                 }
-            }else{
-                self.messagesCollectionView.reloadData()
             }
-        }
+//        }
     }
     
+    
+    
+    // 判断是否显示最后一个单元格
+    func isLastItemVisible() -> Bool {
+        guard let indexPath = getIndexPathForLastItem() else { return false }
+        let visibleIndexPaths = messagesCollectionView.indexPathsForVisibleItems
+        return visibleIndexPaths.contains(lastIndexPath)
+    }
+
+
+    // 获取最后一个单元格的 indexPath
+    func getIndexPathForLastItem() -> IndexPath? {
+        let section = messagesCollectionView.numberOfSections - 1
+        if messagesCollectionView.numberOfItems(inSection: section) > 0 {
+            let item = messagesCollectionView.numberOfItems(inSection: section) - 1
+            return IndexPath(item: item, section: section)
+        }
+        return nil
+    }
+
+}
 
+public extension Notification.Name {
+    //AI 回答中通知
+    static let kAIAnsweringNotification = Self.init("kAIAnsweringNotification")
 }
+let kIsAIAnswering = "isAIAnswering"
+

+ 0 - 1
AIEmoji/Business/AIChat/TSChatViewController/TSChatViewController/TSChatViewController.swift

@@ -50,7 +50,6 @@ class TSChatViewController: MessagesViewController, MessagesDataSource {
     lazy var freeText: UILabel = creatFreeText
     lazy var upgradeVipBg: UIView = creatUpgradeVipBg
 
-    
     let formatter: DateFormatter = {
         let formatter = DateFormatter()
         formatter.dateStyle = .medium