// // V2TIMConversation+Extension.swift // Lanu // // Created by OneeChan on 2025/12/14. // import Foundation extension V2TIMConversation { var lastDisplayDate: Date? { if draftText?.isEmpty == false { draftTimestamp } else if let lastMessage { lastMessage.timestamp } else { Date.distantPast } } var lastDisplayString: NSMutableAttributedString? { let atStr = groupAtTipString let attrString = NSMutableAttributedString(string: atStr) attrString.setAttributes([.foregroundColor: UIColor.systemRed], range: .init(location: 0, length: atStr.count)) let hasRisk = lastMessage?.hasRiskContent == true let isRevoked = lastMessage?.status == .MSG_STATUS_LOCAL_REVOKED if draftText?.count ?? 0 > 0 { let draft = NSAttributedString(string: TIMLocalizedText.shared.commonText("TUIKitMessageTypeDraftFormat"), attributes: [.foregroundColor: UIColor(hex: "#FA5151")]) attrString.append(draft) let draftContentStr = draftContent.getEmojiDescContent let draftContent = NSAttributedString(string: draftContentStr, attributes: [.foregroundColor: UIColor.systemGray]) attrString.append(draftContent) } else { if let lastMessage { let imMessage = LNIMMessageData(imMessage: lastMessage) if case .official = imMessage.type { if let message: LNIMOfficialMessage = imMessage.decodeCustomMessage() { attrString.append(.init(string: message.title)) } else { attrString.append(.init(string: .init(key: "A00019"))) } } else if case .order = imMessage.type { attrString.append(.init(string: .init(key: "A00020"))) } else if case .call = imMessage.type { attrString.append(.init(string: .init(key: "C00012"))) } else if case .autoReply = imMessage.type { attrString.append(.init(string: .init(key: "B00128"))) } else { let lastMsgStr = lastMessage.displayString guard let lastMsgStr else { return nil } if hasRisk, !isRevoked { attrString.append(.init(string: lastMsgStr, attributes: [.foregroundColor: UIColor(hex: "#E94444")])) } else { attrString.append(.init(string: lastMsgStr)) } } } } if groupType == GroupType_Meeting, recvOpt == .RECEIVE_NOT_NOTIFY_MESSAGE, unreadCount > 0 { let unreadStr = NSAttributedString(string: String(format: "[%d %@]", unreadCount, TIMLocalizedText.shared.commonText("TUIKitMessageTypeLastMsgCountFormat"))) attrString.insert(unreadStr, at: 0) } if draftText == nil, let lastMessage, lastMessage.status == .MSG_STATUS_SENDING || lastMessage.status == .MSG_STATUS_SEND_FAIL || hasRisk, !isRevoked { let font = UIFont.systemFont(ofSize: 14) let spaceStr = NSAttributedString(string: " ", attributes: [.font: font]) attrString.insert(spaceStr, at: 0) let image: UIImage = if lastMessage.status == .MSG_STATUS_SENDING { .msgSendingForConv } else { .msgErrorForConv } let attachment = NSTextAttachment(image: image) attachment.bounds = .init(x: 0, y: -(font.lineHeight - font.pointSize) / 2, width: font.pointSize, height: font.pointSize) let imageStr = NSAttributedString(attachment: attachment) attrString.insert(imageStr, at: 0) } return attrString } } extension V2TIMConversation { private var groupAtTipString: String { var atMe = false var atAll = false self.groupAtInfolist?.forEach { switch ($0.atType) { case .AT_ME: atMe = true case .AT_ALL: atAll = true case .AT_ALL_AT_ME: atMe = true atAll = true default: break } } var atTipsStr = "" if atMe, !atAll { atTipsStr = TIMLocalizedText.shared.commonText("TUIKitConversationTipsAtMe") } if !atMe, atAll { atTipsStr = TIMLocalizedText.shared.commonText("TUIKitConversationTipsAtAll") } if atMe, atAll { atTipsStr = TIMLocalizedText.shared.commonText("TUIKitConversationTipsAtMeAndAll") } return atTipsStr } private var draftContent: String { guard let draftText, !draftText.isEmpty else { return "" } guard let data = draftText.data(using: .utf8) else { return "" } let jsonDic = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [String: String] return jsonDic?["content"] ?? "" } } private var extraInfoKey: UInt8 = 0 class LNIMConversationExtraInfo { var userInfo: LNUserProfileVO? var remark: String? } extension V2TIMConversation { var extraInfo: LNIMConversationExtraInfo? { get { objc_getAssociatedObject(self, &extraInfoKey) as? LNIMConversationExtraInfo } set { objc_setAssociatedObject(self, &extraInfoKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } var displayName: String? { return if let remark = extraInfo?.remark, !remark.isEmpty { remark } else { extraInfo?.userInfo?.nickname } } }