IMChatViewController.swift 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //
  2. // IMChatViewController.swift
  3. // O2Platform
  4. //
  5. // Created by FancyLou on 2020/6/8.
  6. // Copyright © 2020 zoneland. All rights reserved.
  7. //
  8. import UIKit
  9. import CocoaLumberjack
  10. import O2OA_Auth_SDK
  11. class IMChatViewController: UIViewController {
  12. // MARK: - IBOutlet
  13. //消息列表
  14. @IBOutlet weak var tableView: UITableView!
  15. //消息输入框
  16. @IBOutlet weak var messageInputView: UITextField!
  17. //底部工具栏的高度约束
  18. @IBOutlet weak var bottomBarHeightConstraint: NSLayoutConstraint!
  19. //底部工具栏
  20. @IBOutlet weak var bottomBar: UIView!
  21. private let emojiBarHeight = 256
  22. //表情窗口
  23. private lazy var emojiBar: IMChatEmojiBarView = {
  24. let view = Bundle.main.loadNibNamed("IMChatEmojiBarView", owner: self, options: nil)?.first as! IMChatEmojiBarView
  25. view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: emojiBarHeight.toCGFloat)
  26. return view
  27. }()
  28. private lazy var viewModel: IMViewModel = {
  29. return IMViewModel()
  30. }()
  31. // MARK: - properties
  32. var conversation: IMConversationInfo? = nil
  33. private var chatMessageList: [IMMessageInfo] = []
  34. private var page = 1
  35. private var isShowEmoji = false
  36. private var bottomBarHeight = 64
  37. // MARK: - functions
  38. override func viewDidLoad() {
  39. super.viewDidLoad()
  40. self.tableView.delegate = self
  41. self.tableView.dataSource = self
  42. self.tableView.register(UINib(nibName: "IMChatMessageViewCell", bundle: nil), forCellReuseIdentifier: "IMChatMessageViewCell")
  43. self.tableView.register(UINib(nibName: "IMChatMessageSendViewCell", bundle: nil), forCellReuseIdentifier: "IMChatMessageSendViewCell")
  44. self.tableView.separatorStyle = .none
  45. self.tableView.rowHeight = UITableView.automaticDimension
  46. self.tableView.estimatedRowHeight = 144
  47. self.messageInputView.delegate = self
  48. //底部安全距离 老机型没有
  49. self.bottomBarHeight = Int(iPhoneX ? 64 + IPHONEX_BOTTOM_SAFE_HEIGHT: 64)
  50. self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
  51. self.bottomBar.topBorder(width: 1, borderColor: base_gray_color.alpha(0.5))
  52. self.messageInputView.backgroundColor = base_gray_color
  53. //标题
  54. if self.conversation?.type == o2_im_conversation_type_single {
  55. if let c = self.conversation {
  56. var person = ""
  57. c.personList?.forEach({ (p) in
  58. if p != O2AuthSDK.shared.myInfo()?.distinguishedName {
  59. person = p
  60. }
  61. })
  62. if !person.isEmpty {
  63. self.title = person.split("@").first ?? ""
  64. }
  65. }
  66. }else {
  67. self.title = self.conversation?.title
  68. }
  69. //获取聊天数据
  70. self.loadMsgList(page: page)
  71. //阅读
  72. self.viewModel.readConversation(conversationId: self.conversation?.id)
  73. }
  74. override func viewWillAppear(_ animated: Bool) {
  75. NotificationCenter.default.addObserver(self, selector: #selector(receiveMessageFromWs(notice:)), name: OONotification.websocket.notificationName, object: nil)
  76. }
  77. override func viewWillDisappear(_ animated: Bool) {
  78. NotificationCenter.default.removeObserver(self)
  79. }
  80. @objc private func receiveMessageFromWs(notice: Notification) {
  81. DDLogDebug("接收到websocket im 消息")
  82. if let message = notice.object as? IMMessageInfo {
  83. if message.conversationId == self.conversation?.id {
  84. self.chatMessageList.append(message)
  85. self.scrollMessageToBottom()
  86. self.viewModel.readConversation(conversationId: self.conversation?.id)
  87. }
  88. }
  89. }
  90. //获取消息
  91. private func loadMsgList(page: Int) {
  92. if let c = self.conversation, let id = c.id {
  93. self.viewModel.myMsgPageList(page: page, conversationId: id).then { (list) in
  94. self.chatMessageList = list
  95. self.scrollMessageToBottom()
  96. }
  97. } else {
  98. self.showError(title: "参数错误!!!")
  99. }
  100. }
  101. //刷新tableview 滚动到底部
  102. private func scrollMessageToBottom() {
  103. DispatchQueue.main.async {
  104. self.tableView.reloadData()
  105. if self.chatMessageList.count > 0 {
  106. self.tableView.scrollToRow(at: IndexPath(row: self.chatMessageList.count-1, section: 0), at: .bottom, animated: true)
  107. }
  108. }
  109. }
  110. //发送文本消息
  111. private func sendTextMessage() {
  112. guard let msg = self.messageInputView.text else {
  113. return
  114. }
  115. self.messageInputView.text = ""
  116. let body = IMMessageBodyInfo()
  117. body.type = o2_im_msg_type_text
  118. body.body = msg
  119. sendMessage(body: body)
  120. }
  121. //发送表情消息
  122. private func sendEmojiMessage(emoji: String) {
  123. let body = IMMessageBodyInfo()
  124. body.type = o2_im_msg_type_emoji
  125. body.body = emoji
  126. sendMessage(body: body)
  127. }
  128. //发送消息到服务器
  129. private func sendMessage(body: IMMessageBodyInfo) {
  130. let message = IMMessageInfo()
  131. message.body = body.toJSONString()
  132. message.id = UUID().uuidString
  133. message.conversationId = self.conversation?.id
  134. message.createPerson = O2AuthSDK.shared.myInfo()?.distinguishedName
  135. message.createTime = Date().formatterDate(formatter: "yyyy-MM-dd HH:mm:ss")
  136. //添加到界面
  137. self.chatMessageList.append(message)
  138. self.scrollMessageToBottom()
  139. //发送消息到服务器
  140. self.viewModel.sendMsg(msg: message)
  141. .then { (result) in
  142. DDLogDebug("发送消息成功 \(result)")
  143. self.viewModel.readConversation(conversationId: self.conversation?.id)
  144. }.catch { (error) in
  145. DDLogError(error.localizedDescription)
  146. self.showError(title: "发送消息失败!")
  147. }
  148. }
  149. // MARK: - IBAction
  150. //点击表情按钮
  151. @IBAction func clickEmojiBtn(_ sender: UIButton) {
  152. self.isShowEmoji.toggle()
  153. self.view.endEditing(true)
  154. if self.isShowEmoji {
  155. self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat + self.emojiBarHeight.toCGFloat
  156. self.emojiBar.delegate = self
  157. self.emojiBar.translatesAutoresizingMaskIntoConstraints = false
  158. self.bottomBar.addSubview(self.emojiBar)
  159. let top = NSLayoutConstraint(item: self.emojiBar, attribute: .top, relatedBy: .equal, toItem: self.emojiBar.superview!, attribute: .top, multiplier: 1, constant: CGFloat(self.bottomBarHeight))
  160. let width = NSLayoutConstraint(item: self.emojiBar, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: SCREEN_WIDTH)
  161. let height = NSLayoutConstraint(item: self.emojiBar, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: self.emojiBarHeight.toCGFloat)
  162. NSLayoutConstraint.activate([top, width, height])
  163. } else {
  164. self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
  165. self.emojiBar.removeFromSuperview()
  166. }
  167. self.view.layoutIfNeeded()
  168. }
  169. }
  170. // MARK: - 表情点击 delegate
  171. extension IMChatViewController: IMChatEmojiBarClickDelegate {
  172. func clickEmoji(emoji: String) {
  173. DDLogDebug("发送表情消息 \(emoji)")
  174. self.sendEmojiMessage(emoji: emoji)
  175. }
  176. }
  177. // MARK: - tableview delegate
  178. extension IMChatViewController: UITableViewDelegate, UITableViewDataSource {
  179. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  180. return self.chatMessageList.count
  181. }
  182. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  183. let msg = self.chatMessageList[indexPath.row]
  184. if msg.createPerson == O2AuthSDK.shared.myInfo()?.distinguishedName { //发送者
  185. if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageSendViewCell", for: indexPath) as? IMChatMessageSendViewCell {
  186. cell.setContent(item: self.chatMessageList[indexPath.row])
  187. return cell
  188. }
  189. }else {
  190. if let cell = tableView.dequeueReusableCell(withIdentifier: "IMChatMessageViewCell", for: indexPath) as? IMChatMessageViewCell {
  191. cell.setContent(item: self.chatMessageList[indexPath.row])
  192. return cell
  193. }
  194. }
  195. return UITableViewCell()
  196. }
  197. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  198. tableView.deselectRow(at: indexPath, animated: false)
  199. }
  200. }
  201. // MARK: - textField delegate
  202. extension IMChatViewController: UITextFieldDelegate {
  203. func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
  204. DDLogDebug("准备开始输入......")
  205. closeEmoji()
  206. return true
  207. }
  208. private func closeEmoji() {
  209. self.isShowEmoji = false
  210. self.bottomBarHeightConstraint.constant = self.bottomBarHeight.toCGFloat
  211. self.view.layoutIfNeeded()
  212. }
  213. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  214. DDLogDebug("回车。。。。")
  215. self.sendTextMessage()
  216. return true
  217. }
  218. }