123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- //
- // IMChatMessageViewCell.swift
- // O2Platform
- //
- // Created by FancyLou on 2020/6/8.
- // Copyright © 2020 zoneland. All rights reserved.
- //
- import UIKit
- import CocoaLumberjack
- protocol IMChatMessageDelegate {
- func playAudio(info: IMMessageBodyInfo, id: String?)
- func openImageOrFileMessage(info: IMMessageBodyInfo)
- func openLocatinMap(info: IMMessageBodyInfo)
- func openApplication(storyboard: String)
- func openWork(workId: String)
- }
- class IMChatMessageViewCell: UITableViewCell {
- @IBOutlet weak var avatarImage: UIImageView!
- @IBOutlet weak var titleLabel: UILabel!
- @IBOutlet weak var timeLabel: UILabel!
- @IBOutlet weak var messageBackgroundView: UIView!
- @IBOutlet weak var messageBackgroundWidth: NSLayoutConstraint!
- @IBOutlet weak var messageBackgroundHeight: NSLayoutConstraint!
-
- private lazy var audioView: IMAudioView = {
- let view = Bundle.main.loadNibNamed("IMAudioView", owner: self, options: nil)?.first as! IMAudioView
- view.frame = CGRect(x: 0, y: 0, width: IMAudioView.IMAudioView_width, height: IMAudioView.IMAudioView_height)
- return view
- }()
- //位置消息 主体view
- private lazy var locationView: IMLocationView = {
- let view = Bundle.main.loadNibNamed("IMLocationView", owner: self, options: nil)?.first as! IMLocationView
- view.frame = CGRect(x: 0, y: 0, width: IMLocationView.IMLocationViewWidth, height: IMLocationView.IMLocationViewHeight)
- return view
- }()
-
- //文件消息
- private lazy var fileView: IMFileView = {
- let view = Bundle.main.loadNibNamed("IMFileView", owner: self, options: nil)?.first as! IMFileView
- view.frame = CGRect(x: 0, y: 0, width: IMFileView.IMFileView_width, height: IMFileView.IMFileView_height)
- return view
- }()
-
- // 流程消息卡片
- private lazy var processView: IMProcessCardView = {
- let view = Bundle.main.loadNibNamed("IMProcessCardView", owner: self, options: nil)?.first as! IMProcessCardView
- view.frame = CGRect(x: 0, y: 0, width: IMProcessCardView.IMProcessCardView_width, height: IMProcessCardView.IMProcessCardView_height)
- return view
- }()
- var delegate: IMChatMessageDelegate?
- //是否正在播放音频 音频消息使用
- private var isPlayingAudio = false
-
- var msgInfo: IMMessageInfo? = nil
- override func awakeFromNib() {
- super.awakeFromNib()
- }
- override func setSelected(_ selected: Bool, animated: Bool) {
- super.setSelected(selected, animated: animated)
- }
-
- // UIMenuController菜单弹出 这个参数很重要
- override var canBecomeFirstResponder: Bool {
- return true
- }
- //普通通知消息
- func setInstantContent(item: InstantMessage) {
- if let time = item.createTime {
- let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
- self.timeLabel.text = date.friendlyTime()
- }
- self.messageBackgroundView.removeSubviews()
- if let msg = item.title {
- let msgLabel = textMsgRender(msg: msg)
- setColorAndClickEvent(item: item, label: msgLabel)
- }
- if let type = item.type {
- if type.starts(with: "task_") {
- self.avatarImage.image = UIImage(named: "icon_daiban")
- self.titleLabel.text = "待办消息"
- } else if type.starts(with: "taskCompleted_") {
- self.avatarImage.image = UIImage(named: "icon_taskcompleted")
- self.titleLabel.text = "已办消息"
- } else if type.starts(with: "read_") {
- self.avatarImage.image = UIImage(named: "icon_read")
- self.titleLabel.text = "待阅消息"
- } else if type.starts(with: "readCompleted_") {
- self.avatarImage.image = UIImage(named: "icon_readcompleted")
- self.titleLabel.text = "已阅消息"
- } else if type.starts(with: "review_") || type.starts(with: "work_") || type.starts(with: "process_") {
- self.avatarImage.image = UIImage(named: "icon_daiban")
- self.titleLabel.text = "工作消息"
- } else if type.starts(with: "meeting_") {
- self.avatarImage.image = UIImage(named: "icon_meeting")
- self.titleLabel.text = "会议消息"
- } else if type.starts(with: "attachment_") {
- self.avatarImage.image = UIImage(named: "icon_yunpan")
- self.titleLabel.text = "云盘消息"
- } else if type.starts(with: "calendar_") {
- self.avatarImage.image = UIImage(named: "icon_calendar")
- self.titleLabel.text = "日历消息"
- } else if type.starts(with: "cms_") {
- self.avatarImage.image = UIImage(named: "icon_cms")
- self.titleLabel.text = "信息中心消息"
- } else if type.starts(with: "bbs_") {
- self.avatarImage.image = UIImage(named: "icon_bbs")
- self.titleLabel.text = "论坛消息"
- } else if type.starts(with: "mind_") {
- self.avatarImage.image = UIImage(named: "icon_mindMap")
- self.titleLabel.text = "脑图消息"
- } else {
- self.avatarImage.image = UIImage(named: "icon_email")
- self.titleLabel.text = "其他消息"
- }
- }
- }
-
- private func setcc(label:UILabel, clickEvent: ((UITapGestureRecognizer)->Void)?) {
- if let textString = label.text {
- let attributedString = NSMutableAttributedString(string: textString)
- attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: attributedString.length))
- attributedString.addAttribute(.foregroundColor, value: base_blue_color, range: NSRange(location: 0, length: attributedString.length))
- label.attributedText = attributedString
- label.addTapGesture(action: clickEvent)
- }
- }
-
- private func setColorAndClickEvent(item: InstantMessage, label:UILabel) {
-
- func parseWorkId(body: String) -> String? {
- if let jsonData = String(body).data(using: .utf8) {
- let dicArr = try! JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as! [String:AnyObject]
- if let work = dicArr["work"] as? String {
- return work
- }
- if let workCompleted = dicArr["workCompleted"] as? String {
- return workCompleted
- }
- }
- return nil
- }
-
- if let type = item.type {
- if type.starts(with: "task_") {
- if !type.contains("_delete") {
- guard let body = item.body else {
- return
- }
- guard let workId = parseWorkId(body: body) else {
- return
- }
- setcc(label: label) { tap in
- //打开工作 ?
- self.delegate?.openWork(workId: workId)
- }
- }
- } else if type.starts(with: "taskCompleted_") {
- if !type.contains("_delete") {
- guard let body = item.body else {
- return
- }
- guard let workId = parseWorkId(body: body) else {
- return
- }
- setcc(label: label) { tap in
- //打开已办
- self.delegate?.openWork(workId: workId)
- }
- }
- } else if type.starts(with: "read_") {
- if !type.contains("_delete") {
- guard let body = item.body else {
- return
- }
- guard let workId = parseWorkId(body: body) else {
- return
- }
- setcc(label: label) { tap in
- //打开待阅
- self.delegate?.openWork(workId: workId)
- }
- }
- } else if type.starts(with: "readCompleted_") {
- if !type.contains("_delete") {
- guard let body = item.body else {
- return
- }
- guard let workId = parseWorkId(body: body) else {
- return
- }
- setcc(label: label) { tap in
- //打开已阅
- self.delegate?.openWork(workId: workId)
- }
- }
- } else if type.starts(with: "review_") || type.starts(with: "work_") || type.starts(with: "process_") {
- if !type.contains("_delete") {
- guard let body = item.body else {
- return
- }
- guard let workId = parseWorkId(body: body) else {
- return
- }
- setcc(label: label) { tap in
- //打开 其他工作
- self.delegate?.openWork(workId: workId)
- }
- }
- } else if type.starts(with: "meeting_") {
- setcc(label: label) { tap in
- //打开会议模块
- self.delegate?.openApplication(storyboard: "meeting")
- }
- } else if type.starts(with: "attachment_") {
- setcc(label: label) { tap in
- //打开云盘
- self.delegate?.openApplication(storyboard: "CloudFile")
- }
- } else if type.starts(with: "calendar_") {
- setcc(label: label) { tap in
- //打开日历
- self.delegate?.openApplication(storyboard: "calendar")
- }
- } else if type.starts(with: "cms_") {
- setcc(label: label) { tap in
- //打开cms
- self.delegate?.openApplication(storyboard: "information")
- }
- } else if type.starts(with: "bbs_") {
- setcc(label: label) { tap in
- //打开论坛
- self.delegate?.openApplication(storyboard: "bbs")
- }
- } else if type.starts(with: "mind_") {
- setcc(label: label) { tap in
- //打开脑图
- self.delegate?.openApplication(storyboard: "mind")
- }
- } else {
-
- }
- }
- }
-
-
- //聊天消息
- func setContent(item: IMMessageInfo, isPlayingAudio: Bool) {
- self.msgInfo = item
- self.isPlayingAudio = isPlayingAudio
- //time
- if let time = item.createTime {
- let date = time.toDate(formatter: "yyyy-MM-dd HH:mm:ss")
- self.timeLabel.text = date.friendlyTime()
- }
- //name avatart
- if let person = item.createPerson {
- let urlstr = AppDelegate.o2Collect.generateURLWithAppContextKey(ContactContext.contactsContextKeyV2, query: ContactContext.personIconByNameQueryV2, parameter: ["##name##": person as AnyObject], generateTime: false)
- if let u = URL(string: urlstr!) {
- self.avatarImage.hnk_setImageFromURL(u)
- } else {
- self.avatarImage.image = UIImage(named: "icon_men")
- }
- //姓名
- self.titleLabel.text = person.split("@").first ?? ""
- } else {
- self.avatarImage.image = UIImage(named: "icon_men")
- self.titleLabel.text = ""
- }
- self.messageBackgroundView.removeSubviews()
- if let jsonBody = item.body, let body = parseJson(msg: jsonBody) {
- if body.type == o2_im_msg_type_emoji {
- emojiMsgRender(emoji: body.body!)
- } else if body.type == o2_im_msg_type_image {
- imageMsgRender(info: body)
- } else if o2_im_msg_type_audio == body.type {
- audioMsgRender(info: body, id: item.id)
- } else if o2_im_msg_type_location == body.type {
- locationMsgRender(info: body)
- } else if o2_im_msg_type_file == body.type {
- fileMsgRender(info: body)
- } else if o2_im_msg_type_process == body.type {
- processMsgRender(info: body)
- } else {
- _ = textMsgRender(msg: body.body ?? "")
- }
- }
- }
-
- // 流程工作卡片消息
- private func processMsgRender(info: IMMessageBodyInfo) {
- self.messageBackgroundWidth.constant = IMProcessCardView.IMProcessCardView_width + 20
- self.messageBackgroundHeight.constant = IMProcessCardView.IMProcessCardView_height + 20
- self.processView.translatesAutoresizingMaskIntoConstraints = false
- self.messageBackgroundView.addSubview(self.processView)
- self.processView.setCardInfo(info: info)
- self.constraintWithContent(contentView: self.processView)
- self.processView.addTapGesture { tap in
- self.delegate?.openWork(workId: info.work ?? "")
- }
- }
-
- //文件消息
- private func fileMsgRender(info: IMMessageBodyInfo) {
- self.messageBackgroundWidth.constant = IMFileView.IMFileView_width + 20
- self.messageBackgroundHeight.constant = IMFileView.IMFileView_height + 20
- self.fileView.translatesAutoresizingMaskIntoConstraints = false
- self.messageBackgroundView.addSubview(self.fileView)
- if let fileId = info.fileId {
- self.fileView.setFile(name: info.fileName ?? fileId, fileExt: info.fileExtension)
- }else if let filePath = info.fileTempPath {
- let ext = filePath.pathExtension
- let fileName = filePath.pathFileName
- self.fileView.setFile(name: fileName, fileExt: ext)
- }
- self.fileView.addTapGesture { (tap) in
- self.delegate?.openImageOrFileMessage(info: info)
- }
- //点击事件
- self.constraintWithContent(contentView: self.fileView)
- }
- //位置消息
- private func locationMsgRender(info: IMMessageBodyInfo) {
- self.messageBackgroundWidth.constant = IMLocationView.IMLocationViewWidth + 20
- self.messageBackgroundHeight.constant = IMLocationView.IMLocationViewHeight + 20
- self.locationView.translatesAutoresizingMaskIntoConstraints = false
- self.messageBackgroundView.addSubview(self.locationView)
- self.locationView.setLocationAddress(address: info.address ?? "")
- //点击打开地址
- self.locationView.addTapGesture { (tap) in
- //open map view
- self.delegate?.openLocatinMap(info: info)
- }
- self.constraintWithContent(contentView: self.locationView)
- }
- //音频消息
- private func audioMsgRender(info: IMMessageBodyInfo, id: String?) {
- let width = IMAudioView.IMAudioView_width + 20
- let height = IMAudioView.IMAudioView_height + 20
- self.messageBackgroundWidth.constant = width
- self.messageBackgroundHeight.constant = height
- //背景图片
- let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
- let insets = UIEdgeInsets(top: 28, left: 10, bottom: 5, right: 5); // 上、左、下、右
- var bubble = UIImage(named: "chat_bubble_incomming")
- bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
- bgImg.image = bubble
- self.messageBackgroundView.addSubview(bgImg)
-
- self.audioView.translatesAutoresizingMaskIntoConstraints = false
- self.messageBackgroundView.addSubview(self.audioView)
- self.audioView.setDuration(duration: info.audioDuration ?? "0")
- if self.isPlayingAudio {
- self.audioView.playAudioGif()
- }else {
- self.audioView.stopPlayAudioGif()
- }
- self.audioView.addTapGesture { (tap) in
- self.delegate?.playAudio(info: info, id: id)
- }
- self.constraintWithContent(contentView: self.audioView)
- }
- private func constraintWithContent(contentView: UIView) {
- let top = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: contentView.superview!, attribute: .top, multiplier: 1, constant: 10)
- let bottom = NSLayoutConstraint(item: contentView.superview!, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: 10)
- let left = NSLayoutConstraint(item: contentView, attribute: .leading, relatedBy: .equal, toItem: contentView.superview!, attribute: .leading, multiplier: 1, constant: 10)
- let right = NSLayoutConstraint(item: contentView.superview!, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 10)
- NSLayoutConstraint.activate([top, bottom, left, right])
- }
- //图片消息
- private func imageMsgRender(info: IMMessageBodyInfo) {
- let width: CGFloat = 144
- let height: CGFloat = 192
- self.messageBackgroundWidth.constant = width + 20
- self.messageBackgroundHeight.constant = height + 20
- //图片
- let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
- if let fileId = info.fileId {
- DDLogDebug("file id :\(fileId)")
- let urlStr = AppDelegate.o2Collect.generateURLWithAppContextKey(
- CommunicateContext.communicateContextKey,
- query: CommunicateContext.imDownloadImageWithSizeQuery,
- parameter: ["##id##": fileId as AnyObject,
- "##width##": "144" as AnyObject,
- "##height##": "192" as AnyObject], generateTime: false)
- if let url = URL(string: urlStr!) {
- imageView.hnk_setImageFromURL(url)
- } else {
- imageView.image = UIImage(named: "chat_image")
- }
- } else if let filePath = info.fileTempPath {
- DDLogDebug("filePath :\(filePath)")
- imageView.hnk_setImageFromFile(filePath)
- } else {
- imageView.image = UIImage(named: "chat_image")
- }
- imageView.translatesAutoresizingMaskIntoConstraints = false
- self.messageBackgroundView.addSubview(imageView)
- imageView.addTapGesture { (tap) in
- self.delegate?.openImageOrFileMessage(info: info)
- }
- self.constraintWithContent(contentView: imageView)
- }
- private func emojiMsgRender(emoji: String) {
- let emojiSize = 36
- let width = CGFloat(emojiSize + 20)
- let height = CGFloat(emojiSize + 20)
- self.messageBackgroundWidth.constant = width
- self.messageBackgroundHeight.constant = height
- //背景图片
- let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
- let insets = UIEdgeInsets(top: 28, left: 10, bottom: 5, right: 5); // 上、左、下、右
- var bubble = UIImage(named: "chat_bubble_incomming")
- bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
- bgImg.image = bubble
- self.messageBackgroundView.addSubview(bgImg)
- //表情图
- let emojiImage = UIImageView(frame: CGRect(x: 0, y: 0, width: emojiSize, height: emojiSize))
- let bundle = Bundle().o2EmojiBundle(anyClass: IMChatMessageViewCell.self)
- let path = o2ImEmojiPath(emojiBody: emoji)
- emojiImage.image = UIImage(named: path, in: bundle, compatibleWith: nil)
- emojiImage.translatesAutoresizingMaskIntoConstraints = false
- self.messageBackgroundView.addSubview(emojiImage)
- self.constraintWithContent(contentView: emojiImage)
- }
- private func textMsgRender(msg: String) -> UILabel {
- let size = msg.getSizeWithMaxWidth(fontSize: 16, maxWidth: messageWidth)
- self.messageBackgroundWidth.constant = size.width + 28
- self.messageBackgroundHeight.constant = size.height + 28
- //背景图片
- let bgImg = UIImageView(frame: CGRect(x: 0, y: 0, width: size.width + 28, height: size.height + 28))
- let insets = UIEdgeInsets(top: 28, left: 10, bottom: 5, right: 5); // 上、左、下、右
- var bubble = UIImage(named: "chat_bubble_incomming")
- bubble = bubble?.resizableImage(withCapInsets: insets, resizingMode: .stretch)
- bgImg.image = bubble
- self.messageBackgroundView.addSubview(bgImg)
- //文字
- let label = generateMessagelabel(str: msg, size: size)
- label.translatesAutoresizingMaskIntoConstraints = false
- self.messageBackgroundView.addSubview(label)
- self.constraintWithContent(contentView: label)
- return label
- // let top = NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: label.superview!, attribute: .top, multiplier: 1, constant: 10)
- // let left = NSLayoutConstraint(item: label, attribute: .leading, relatedBy: .equal, toItem: label.superview!, attribute: .leading, multiplier: 1, constant: 10)
- // let right = NSLayoutConstraint(item: label.superview!, attribute: .trailing, relatedBy: .equal, toItem: label, attribute: .trailing, multiplier: 1, constant: 10)
- // NSLayoutConstraint.activate([top, left, right])
- }
- private func generateMessagelabel(str: String, size: CGSize) -> UILabel {
- let label = UILabel(frame: CGRect(x: 0, y: 0, width: size.width + 8, height: size.height + 8))
- label.text = str
- label.font = UIFont.systemFont(ofSize: 16)
- label.numberOfLines = 0
- label.lineBreakMode = .byCharWrapping
- label.preferredMaxLayoutWidth = size.width
- return label
- }
- // private func calTextSize(str: String) -> CGSize {
- // let size = CGSize(width: messageWidth.toCGFloat, height: CGFloat(MAXFLOAT))
- // return str.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], context: nil).size
- // }
- //解析json为消息对象
- private func parseJson(msg: String) -> IMMessageBodyInfo? {
- return IMMessageBodyInfo.deserialize(from: msg)
- }
- }
|