IMChatMessageSendViewCell.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. //
  2. // IMChatMessageSendViewCell.swift
  3. // O2Platform
  4. //
  5. // Created by FancyLou on 2020/6/10.
  6. // Copyright © 2020 zoneland. All rights reserved.
  7. //
  8. import UIKit
  9. import CocoaLumberjack
  10. class IMChatMessageSendViewCell: UITableViewCell {
  11. @IBOutlet weak var timeLabel: UILabel!
  12. @IBOutlet weak var avatarImageView: UIImageView!
  13. @IBOutlet weak var nameLabel: UILabel!
  14. @IBOutlet weak var messageBackgroundView: UIView!
  15. @IBOutlet weak var messageBgWidth: NSLayoutConstraint!
  16. @IBOutlet weak var messageBgHeight: NSLayoutConstraint!
  17. //音频消息 主体view
  18. private lazy var audioView: IMAudioViewSend = {
  19. let view = Bundle.main.loadNibNamed("IMAudioViewSend", owner: self, options: nil)?.first as! IMAudioViewSend
  20. view.frame = CGRect(x: 0, y: 0, width: IMAudioViewSend.IMAudioView_width, height: IMAudioViewSend.IMAudioView_height)
  21. return view
  22. }()
  23. //位置消息 主体view
  24. private lazy var locationView: IMLocationView = {
  25. let view = Bundle.main.loadNibNamed("IMLocationView", owner: self, options: nil)?.first as! IMLocationView
  26. view.frame = CGRect(x: 0, y: 0, width: IMLocationView.IMLocationViewWidth, height: IMLocationView.IMLocationViewHeight)
  27. return view
  28. }()
  29. //文件消息
  30. private lazy var fileView: IMFileView = {
  31. let view = Bundle.main.loadNibNamed("IMFileView", owner: self, options: nil)?.first as! IMFileView
  32. view.frame = CGRect(x: 0, y: 0, width: IMFileView.IMFileView_width, height: IMFileView.IMFileView_height)
  33. return view
  34. }()
  35. var delegate: IMChatMessageDelegate?
  36. //是否正在播放音频 音频消息使用
  37. private var isPlayingAudio = false
  38. override func awakeFromNib() {
  39. super.awakeFromNib()
  40. }
  41. override func setSelected(_ selected: Bool, animated: Bool) {
  42. super.setSelected(selected, animated: animated)
  43. }
  44. func setContent(item: IMMessageInfo, isPlayingAudio: Bool) {
  45. self.isPlayingAudio = isPlayingAudio
  46. //time
  47. if let time = item.createTime {
  48. let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
  49. self.timeLabel.text = date.friendlyTime()
  50. }
  51. //name avatart
  52. if let person = item.createPerson {
  53. let urlstr = AppDelegate.o2Collect.generateURLWithAppContextKey(ContactContext.contactsContextKeyV2, query: ContactContext.personIconByNameQueryV2, parameter: ["##name##":person as AnyObject], generateTime: false)
  54. if let u = URL(string: urlstr!) {
  55. self.avatarImageView.hnk_setImageFromURL(u)
  56. }else {
  57. self.avatarImageView.image = UIImage(named: "icon_men")
  58. }
  59. //姓名
  60. self.nameLabel.text = person.split("@").first ?? ""
  61. }else {
  62. self.avatarImageView.image = UIImage(named: "icon_men")
  63. self.nameLabel.text = ""
  64. }
  65. self.messageBackgroundView.removeSubviews()
  66. if let jsonBody = item.body, let body = parseJson(msg: jsonBody) {
  67. if o2_im_msg_type_emoji == body.type {
  68. emojiMsgRender(emoji: body.body!)
  69. }else if o2_im_msg_type_image == body.type {
  70. imageMsgRender(info: body)
  71. }else if o2_im_msg_type_audio == body.type {
  72. audioMsgRender(info: body, id: item.id)
  73. } else if o2_im_msg_type_location == body.type {
  74. locationMsgRender(info: body)
  75. } else if o2_im_msg_type_file == body.type {
  76. fileMsgRender(info: body)
  77. } else {
  78. textMsgRender(msg: body.body!)
  79. }
  80. }
  81. }
  82. //文件消息
  83. private func fileMsgRender(info: IMMessageBodyInfo) {
  84. self.messageBgWidth.constant = IMFileView.IMFileView_width + 20
  85. self.messageBgHeight.constant = IMFileView.IMFileView_height + 20
  86. self.fileView.translatesAutoresizingMaskIntoConstraints = false
  87. self.messageBackgroundView.addSubview(self.fileView)
  88. if let fileId = info.fileId {
  89. self.fileView.setFile(name: info.fileName ?? fileId, fileExt: info.fileExtension)
  90. }else if let filePath = info.fileTempPath {
  91. let ext = filePath.pathExtension
  92. let fileName = filePath.pathFileName
  93. self.fileView.setFile(name: fileName, fileExt: ext)
  94. }
  95. self.fileView.addTapGesture { (tap) in
  96. self.delegate?.openImageOrFileMessage(info: info)
  97. }
  98. //点击事件
  99. self.constraintWithContent(contentView: self.fileView)
  100. }
  101. //位置消息
  102. private func locationMsgRender(info: IMMessageBodyInfo) {
  103. self.messageBgWidth.constant = IMLocationView.IMLocationViewWidth + 20
  104. self.messageBgHeight.constant = IMLocationView.IMLocationViewHeight + 20
  105. self.locationView.translatesAutoresizingMaskIntoConstraints = false
  106. self.messageBackgroundView.addSubview(self.locationView)
  107. self.locationView.setLocationAddress(address: info.address ?? "")
  108. //点击打开地址
  109. self.locationView.addTapGesture { (tap) in
  110. //open map view//open map view
  111. self.delegate?.openLocatinMap(info: info)
  112. }
  113. self.constraintWithContent(contentView: self.locationView)
  114. }
  115. //音频消息
  116. private func audioMsgRender(info: IMMessageBodyInfo, id: String?) {
  117. let width = IMAudioViewSend.IMAudioView_width + 20
  118. let height = IMAudioViewSend.IMAudioView_height + 20
  119. self.messageBgWidth.constant = width
  120. self.messageBgHeight.constant = height
  121. //背景图片
  122. let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
  123. let insets = UIEdgeInsets(top: 28, left: 5, bottom: 5, right: 10); // 上、左、下、右
  124. var bubble = UIImage(named: "chat_bubble_outgoing")
  125. bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
  126. bgImg.image = bubble
  127. self.messageBackgroundView.addSubview(bgImg)
  128. //
  129. self.audioView.translatesAutoresizingMaskIntoConstraints = false
  130. self.messageBackgroundView.addSubview(self.audioView)
  131. self.audioView.setDuration(duration: info.audioDuration ?? "0")
  132. if self.isPlayingAudio {
  133. self.audioView.playAudioGif()
  134. }else {
  135. self.audioView.stopPlayAudioGif()
  136. }
  137. self.audioView.addTapGesture { (tap) in
  138. self.delegate?.playAudio(info: info, id: id)
  139. }
  140. self.constraintWithContent(contentView: self.audioView)
  141. }
  142. private func constraintWithContent(contentView: UIView) {
  143. let top = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: contentView.superview!, attribute: .top, multiplier: 1, constant: 10)
  144. let bottom = NSLayoutConstraint(item: contentView.superview!, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: 10)
  145. let left = NSLayoutConstraint(item: contentView, attribute: .leading, relatedBy: .equal, toItem: contentView.superview!, attribute: .leading, multiplier: 1, constant: 10)
  146. let right = NSLayoutConstraint(item: contentView.superview!, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 10)
  147. NSLayoutConstraint.activate([top, bottom, left, right])
  148. }
  149. //图片消息
  150. private func imageMsgRender(info: IMMessageBodyInfo) {
  151. let width: CGFloat = 144
  152. let height: CGFloat = 192
  153. self.messageBgWidth.constant = width + 20
  154. self.messageBgHeight.constant = height + 20
  155. //图片
  156. let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
  157. if let fileId = info.fileId {
  158. DDLogDebug("fileId :\(fileId)")
  159. let urlStr = AppDelegate.o2Collect.generateURLWithAppContextKey(
  160. CommunicateContext.communicateContextKey,
  161. query: CommunicateContext.imDownloadImageWithSizeQuery,
  162. parameter: ["##id##": fileId as AnyObject,
  163. "##width##": "144" as AnyObject,
  164. "##height##": "192" as AnyObject], generateTime: false)
  165. if let url = URL(string: urlStr!) {
  166. imageView.hnk_setImageFromURL(url)
  167. } else {
  168. imageView.image = UIImage(named: "chat_image")
  169. }
  170. } else if let filePath = info.fileTempPath {
  171. DDLogDebug("filePath :\(filePath)")
  172. imageView.hnk_setImageFromFile(filePath)
  173. } else {
  174. imageView.image = UIImage(named: "chat_image")
  175. }
  176. imageView.translatesAutoresizingMaskIntoConstraints = false
  177. self.messageBackgroundView.addSubview(imageView)
  178. imageView.addTapGesture { (tap) in
  179. self.delegate?.openImageOrFileMessage(info: info)
  180. }
  181. self.constraintWithContent(contentView: imageView)
  182. }
  183. private func emojiMsgRender(emoji: String) {
  184. let emojiSize = 36
  185. let width = CGFloat(emojiSize + 20)
  186. let height = CGFloat(emojiSize + 20)
  187. self.messageBgWidth.constant = width
  188. self.messageBgHeight.constant = height
  189. //背景图片
  190. let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
  191. let insets = UIEdgeInsets(top: 28, left: 5, bottom: 5, right: 10); // 上、左、下、右
  192. var bubble = UIImage(named: "chat_bubble_outgoing")
  193. bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
  194. bgImg.image = bubble
  195. self.messageBackgroundView.addSubview(bgImg)
  196. //表情图
  197. let emojiImage = UIImageView(frame: CGRect(x: 0, y: 0, width: emojiSize, height: emojiSize))
  198. let bundle = Bundle().o2EmojiBundle(anyClass: IMChatMessageSendViewCell.self)
  199. let path = o2ImEmojiPath(emojiBody: emoji)
  200. emojiImage.image = UIImage(named: path, in: bundle, compatibleWith: nil)
  201. emojiImage.translatesAutoresizingMaskIntoConstraints = false
  202. self.messageBackgroundView.addSubview(emojiImage)
  203. self.constraintWithContent(contentView: emojiImage)
  204. }
  205. private func textMsgRender(msg: String) {
  206. let size = msg.getSizeWithMaxWidth(fontSize: 16, maxWidth: messageWidth)
  207. self.messageBgWidth.constant = size.width + 28
  208. self.messageBgHeight.constant = size.height + 28
  209. //背景图片
  210. let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: size.width + 28, height: size.height + 28))
  211. let insets = UIEdgeInsets(top: 28, left: 5, bottom: 5, right: 10); // 上、左、下、右
  212. var bubble = UIImage(named: "chat_bubble_outgoing")
  213. bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
  214. bgImg.image = bubble
  215. self.messageBackgroundView.addSubview(bgImg)
  216. //文字
  217. let label = generateMessagelabel(str: msg, size: size)
  218. label.translatesAutoresizingMaskIntoConstraints = false
  219. self.messageBackgroundView.addSubview(label)
  220. self.constraintWithContent(contentView: label)
  221. // let top = NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: label.superview!, attribute: .top, multiplier: 1, constant: 10)
  222. // let left = NSLayoutConstraint(item: label, attribute: .leading, relatedBy: .equal, toItem: label.superview!, attribute: .leading, multiplier: 1, constant: 10)
  223. // let right = NSLayoutConstraint(item: label.superview!, attribute: .trailing, relatedBy: .equal, toItem: label, attribute: .trailing, multiplier: 1, constant: 10)
  224. // NSLayoutConstraint.activate([top, left, right])
  225. }
  226. private func generateMessagelabel(str: String, size: CGSize) -> UILabel {
  227. let label = UILabel(frame: CGRect(x: 0, y: 0, width: size.width + 8, height: size.height + 8))
  228. label.text = str
  229. label.font = UIFont.systemFont(ofSize: 16)
  230. label.numberOfLines = 0
  231. label.lineBreakMode = .byCharWrapping
  232. label.preferredMaxLayoutWidth = size.width
  233. return label
  234. }
  235. // private func calTextSize(str: String) -> CGSize {
  236. // let size = CGSize(width: 176, height: CGFloat(MAXFLOAT))
  237. // return str.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], context: nil).size
  238. // }
  239. //解析json为消息对象
  240. private func parseJson(msg: String) -> IMMessageBodyInfo? {
  241. return IMMessageBodyInfo.deserialize(from: msg)
  242. }
  243. }