V2TIMConversation+Extension.swift 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. //
  2. // V2TIMConversation+Extension.swift
  3. // Lanu
  4. //
  5. // Created by OneeChan on 2025/12/14.
  6. //
  7. import Foundation
  8. extension V2TIMConversation {
  9. var lastDisplayDate: Date? {
  10. if draftText?.isEmpty == false {
  11. draftTimestamp
  12. } else if let lastMessage {
  13. lastMessage.timestamp
  14. } else {
  15. Date.distantPast
  16. }
  17. }
  18. var lastDisplayString: NSMutableAttributedString? {
  19. let atStr = groupAtTipString
  20. let attrString = NSMutableAttributedString(string: atStr)
  21. attrString.setAttributes([.foregroundColor: UIColor.systemRed], range: .init(location: 0, length: atStr.count))
  22. let hasRisk = lastMessage?.hasRiskContent == true
  23. let isRevoked = lastMessage?.status == .MSG_STATUS_LOCAL_REVOKED
  24. if draftText?.count ?? 0 > 0 {
  25. let draft = NSAttributedString(string: TIMLocalizedText.shared.commonText("TUIKitMessageTypeDraftFormat"), attributes: [.foregroundColor: UIColor(hex: "#FA5151")])
  26. attrString.append(draft)
  27. let draftContentStr = draftContent.getEmojiDescContent
  28. let draftContent = NSAttributedString(string: draftContentStr, attributes: [.foregroundColor: UIColor.systemGray])
  29. attrString.append(draftContent)
  30. } else {
  31. if let lastMessage {
  32. let imMessage = LNIMMessageData(imMessage: lastMessage)
  33. if case .official = imMessage.type {
  34. if let message: LNIMOfficialMessage = imMessage.decodeCustomMessage() {
  35. attrString.append(.init(string: message.title))
  36. } else {
  37. attrString.append(.init(string: .init(key: "A00019")))
  38. }
  39. } else if case .order = imMessage.type {
  40. attrString.append(.init(string: .init(key: "A00020")))
  41. } else if case .call = imMessage.type {
  42. attrString.append(.init(string: .init(key: "C00012")))
  43. } else if case .autoReply = imMessage.type {
  44. attrString.append(.init(string: .init(key: "B00128")))
  45. } else {
  46. let lastMsgStr = lastMessage.displayString
  47. guard let lastMsgStr else { return nil }
  48. if hasRisk, !isRevoked {
  49. attrString.append(.init(string: lastMsgStr, attributes: [.foregroundColor: UIColor(hex: "#E94444")]))
  50. } else {
  51. attrString.append(.init(string: lastMsgStr))
  52. }
  53. }
  54. }
  55. }
  56. if groupType == GroupType_Meeting,
  57. recvOpt == .RECEIVE_NOT_NOTIFY_MESSAGE,
  58. unreadCount > 0 {
  59. let unreadStr = NSAttributedString(string: String(format: "[%d %@]", unreadCount, TIMLocalizedText.shared.commonText("TUIKitMessageTypeLastMsgCountFormat")))
  60. attrString.insert(unreadStr, at: 0)
  61. }
  62. if draftText == nil, let lastMessage,
  63. lastMessage.status == .MSG_STATUS_SENDING
  64. || lastMessage.status == .MSG_STATUS_SEND_FAIL
  65. || hasRisk,
  66. !isRevoked {
  67. let font = UIFont.systemFont(ofSize: 14)
  68. let spaceStr = NSAttributedString(string: " ", attributes: [.font: font])
  69. attrString.insert(spaceStr, at: 0)
  70. let image: UIImage = if lastMessage.status == .MSG_STATUS_SENDING {
  71. .msgSendingForConv
  72. } else {
  73. .msgErrorForConv
  74. }
  75. let attachment = NSTextAttachment(image: image)
  76. attachment.bounds = .init(x: 0, y: -(font.lineHeight - font.pointSize) / 2, width: font.pointSize, height: font.pointSize)
  77. let imageStr = NSAttributedString(attachment: attachment)
  78. attrString.insert(imageStr, at: 0)
  79. }
  80. return attrString
  81. }
  82. }
  83. extension V2TIMConversation {
  84. private var groupAtTipString: String {
  85. var atMe = false
  86. var atAll = false
  87. self.groupAtInfolist?.forEach {
  88. switch ($0.atType) {
  89. case .AT_ME: atMe = true
  90. case .AT_ALL: atAll = true
  91. case .AT_ALL_AT_ME:
  92. atMe = true
  93. atAll = true
  94. default:
  95. break
  96. }
  97. }
  98. var atTipsStr = ""
  99. if atMe, !atAll {
  100. atTipsStr = TIMLocalizedText.shared.commonText("TUIKitConversationTipsAtMe")
  101. }
  102. if !atMe, atAll {
  103. atTipsStr = TIMLocalizedText.shared.commonText("TUIKitConversationTipsAtAll")
  104. }
  105. if atMe, atAll {
  106. atTipsStr = TIMLocalizedText.shared.commonText("TUIKitConversationTipsAtMeAndAll")
  107. }
  108. return atTipsStr
  109. }
  110. private var draftContent: String {
  111. guard let draftText, !draftText.isEmpty else { return "" }
  112. guard let data = draftText.data(using: .utf8) else { return "" }
  113. let jsonDic = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [String: String]
  114. return jsonDic?["content"] ?? ""
  115. }
  116. }
  117. private var extraInfoKey: UInt8 = 0
  118. class LNIMConversationExtraInfo {
  119. var userInfo: LNUserProfileVO?
  120. var remark: String?
  121. }
  122. extension V2TIMConversation {
  123. var extraInfo: LNIMConversationExtraInfo? {
  124. get {
  125. objc_getAssociatedObject(self, &extraInfoKey) as? LNIMConversationExtraInfo
  126. }
  127. set {
  128. objc_setAssociatedObject(self, &extraInfoKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  129. }
  130. }
  131. var displayName: String? {
  132. return if let remark = extraInfo?.remark, !remark.isEmpty {
  133. remark
  134. } else {
  135. extraInfo?.userInfo?.nickname
  136. }
  137. }
  138. }