TSChatInputBarVC.swift 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. //
  2. // TSChatInputBarVC.swift
  3. // AIEmoji
  4. //
  5. // Created by 100Years on 2025/2/14.
  6. //
  7. import UIKit
  8. class TSChatInputBarVC: TSBaseVC, UITextViewDelegate {
  9. var sendComplete:(([Any])->Void)?
  10. //AI是否正在回答问题
  11. var isAIAnswering:Bool = false{
  12. didSet{
  13. sendEnabled(enabled: !isAIAnswering)
  14. setBtnHidden()
  15. }
  16. }
  17. lazy var InputBarView:UIView = {
  18. let InputBarView = UIView()
  19. InputBarView.backgroundColor = "#222222".uiColor
  20. InputBarView.cornerRadius = 28.0
  21. return InputBarView
  22. }()
  23. lazy var sendBtn: UIButton = {
  24. let sendBtn = UIButton.createButton(image: UIImage(named: "chat_send")) { [weak self] in
  25. guard let self = self else { return }
  26. sendMsg()
  27. }
  28. sendBtn.isEnabled = false
  29. return sendBtn
  30. }()
  31. lazy var stopBtn: UIButton = {
  32. let stopBtn = UIButton.createButton(image: UIImage(named: "chat_stop")) { [weak self] in
  33. guard let self = self else { return }
  34. NotificationCenter.default.post(name: .kAIStopRespondNotification, object: nil, userInfo: nil)
  35. }
  36. stopBtn.isHidden = true
  37. return stopBtn
  38. }()
  39. lazy var magnifyBtn: UIButton = {
  40. let magnifyBtn = UIButton.createButton(image: UIImage(named: "chat_send_magnify")) { [weak self] in
  41. guard let self = self else { return }
  42. let vc = TSChatInputFullScreenVC()
  43. vc.text = textView.text
  44. vc.sendComplete = { [weak self] date in
  45. guard let self = self else { return }
  46. if let text = date.first as? String {
  47. textView.text = text
  48. textView.resignFirstResponder()
  49. textDidChange()
  50. scrollTextViewToBottom()
  51. sendComplete?(date)
  52. }
  53. }
  54. vc.closeComplete = { [weak self] text in
  55. guard let self = self else { return }
  56. textView.text = text
  57. textView.resignFirstResponder()
  58. textDidChange()
  59. scrollTextViewToBottom()
  60. }
  61. kPresentModalVC(target: self, modelVC: vc)
  62. }
  63. magnifyBtn.isHidden = true
  64. return magnifyBtn
  65. }()
  66. private let minHeight: CGFloat = 56//24
  67. private let maxHeight: CGFloat = 154
  68. lazy var textView: TSPlaceholderTextView = {
  69. let textView = TSPlaceholderTextView()
  70. textView.backgroundColor = .clear
  71. textView.textColor = .white
  72. textView.delegate = self
  73. textView.font = .font(size: 16)
  74. textView.clipsToBounds = true
  75. textView.isScrollEnabled = false
  76. textView.tintColor = .themeColor
  77. textView.returnKeyType = .send
  78. textView.placeholder = "Send a message".localized
  79. textView.placeholderColor = .white.withAlphaComponent(0.4)
  80. textView.placeholderLabel.font = .font(size: 16.0)
  81. textView.textInsets = UIEdgeInsets(top: 18, left: 16, bottom: 14, right: 0)
  82. return textView
  83. }()
  84. override func createView() {
  85. setNavBarViewHidden(true)
  86. view.backgroundColor = .clear
  87. contentView.addSubview(InputBarView)
  88. InputBarView.addSubview(textView)
  89. InputBarView.addSubview(magnifyBtn)
  90. InputBarView.addSubview(stopBtn)
  91. InputBarView.addSubview(sendBtn)
  92. InputBarView.snp.makeConstraints { make in
  93. make.leading.equalTo(16)
  94. make.trailing.equalTo(-16)
  95. make.top.equalTo(12)
  96. make.bottom.equalTo(-12)
  97. }
  98. textView.snp.makeConstraints { make in
  99. make.leading.equalTo(0)
  100. make.trailing.equalTo(-60)
  101. make.top.equalTo(0)
  102. make.bottom.equalTo(0)
  103. make.height.equalTo(minHeight)
  104. }
  105. stopBtn.snp.makeConstraints { make in
  106. make.trailing.equalTo(-16)
  107. make.bottom.equalTo(-16)
  108. make.width.equalTo(24)
  109. make.height.equalTo(24)
  110. }
  111. sendBtn.snp.makeConstraints { make in
  112. make.trailing.equalTo(-16)
  113. make.bottom.equalTo(-16)
  114. make.width.equalTo(24)
  115. make.height.equalTo(24)
  116. }
  117. magnifyBtn.snp.makeConstraints { make in
  118. make.trailing.equalTo(-16)
  119. make.top.equalTo(16)
  120. make.width.equalTo(24)
  121. make.height.equalTo(24)
  122. }
  123. }
  124. override func dealThings() {
  125. // 监听文本变化事件
  126. NotificationCenter.default.addObserver(self, selector: #selector(textDidChange), name: UITextView.textDidChangeNotification, object: textView)
  127. NotificationCenter.default.addObserver(self, selector: #selector(handleAIAnsweringNotification(_:)), name: .kAIAnsweringNotification, object: nil)
  128. }
  129. func sendMsg(){
  130. if sendBtn.isEnabled == false {
  131. return
  132. }
  133. // if textView.text.replacingOccurrences(of: " ", with: "").count <= 0 {
  134. // return
  135. // }
  136. if let string = textView.text {
  137. sendComplete?([string])
  138. textView.resignFirstResponder()
  139. }
  140. }
  141. func sendEnabled(enabled:Bool){
  142. if enabled == true,
  143. isAIAnswering == false,
  144. textView.text.replacingOccurrences(of: " ", with: "").count > 0 {
  145. sendBtn.isEnabled = true
  146. }else{
  147. sendBtn.isEnabled = false
  148. }
  149. }
  150. func emptyInput() {
  151. textView.text = ""
  152. textDidChange()
  153. magnifyBtn.isHidden = true
  154. }
  155. @objc func handleAIAnsweringNotification(_ notification: Notification) {
  156. if let userInfo = notification.userInfo, let boolValue = userInfo[kIsAIAnswering] as? Bool {
  157. isAIAnswering = boolValue
  158. }
  159. }
  160. func setBtnHidden() {
  161. if isAIAnswering {
  162. sendBtn.isHidden = true
  163. stopBtn.isHidden = false
  164. }else{
  165. sendBtn.isHidden = false
  166. stopBtn.isHidden = true
  167. }
  168. }
  169. deinit {
  170. // 移除通知监听
  171. NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView)
  172. }
  173. }
  174. extension TSChatInputBarVC {
  175. @objc private func textDidChange() {
  176. // 计算输入框的内容高度
  177. let sizeToFit = CGSize(width: textView.bounds.width, height: .greatestFiniteMagnitude)
  178. let estimatedSize = textView.sizeThatFits(sizeToFit)
  179. // 根据内容高度调整输入框的高度
  180. var newHeight = estimatedSize.height
  181. if newHeight <= minHeight {
  182. newHeight = minHeight
  183. textView.isScrollEnabled = false
  184. magnifyBtn.isHidden = true
  185. } else if newHeight > maxHeight {
  186. newHeight = maxHeight
  187. textView.isScrollEnabled = true
  188. magnifyBtn.isHidden = false
  189. } else {
  190. textView.isScrollEnabled = false
  191. magnifyBtn.isHidden = true
  192. }
  193. sendEnabled(enabled: textView.text.count > 0)
  194. // 更新输入框的高度
  195. textView.snp.updateConstraints { make in
  196. make.height.equalTo(newHeight)
  197. }
  198. }
  199. private func scrollTextViewToBottom() {
  200. let bottomOffset = CGPoint(x: 0, y: textView.contentSize.height - textView.bounds.size.height)
  201. textView.setContentOffset(bottomOffset, animated: true)
  202. }
  203. }
  204. extension TSChatInputBarVC {
  205. // 实现 UITextViewDelegate 协议方法,控制 return 键行为
  206. func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
  207. if text == "\n" {
  208. // 当输入为换行符(即按下 return 键)时,执行相应操作
  209. sendMsg()
  210. return false
  211. }
  212. return true
  213. }
  214. }