Visual_Novel_iOS/crush/Crush/Src/Modules/Chat/Util/SessionUtil.swift

566 lines
19 KiB
Swift
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// SessionUtil.swift
// LegendTeam
//
// Created by on 20/12/21.
//
import Foundation
import NIMSDK
class SessionUtil {
var topViewHeight: CGFloat = 0
let mssagePageSize = 50
//var session: NIMSession!
//var conversation: V2NIMConversation!
var conversationId : String!
let showTimeInterval: TimeInterval = 180
var cellModels: [SessionBaseModel]! = [SessionBaseModel]()
/// Key: messageClientId messageServerId,messageServerId
var msgIdDict: [String: SessionBaseModel]! = [String: SessionBaseModel]()
func getLastMessageModel() -> SessionBaseModel? {
var lastModel: SessionBaseModel?
for model in cellModels {
if let messageServerId = model.v2msg?.messageServerId, messageServerId.count > 0{
lastModel = model
}
}
return lastModel
}
}
// private
extension SessionUtil {
///
func firtTimeStamp() -> TimeInterval {
guard let model = cellModels.first else {
return 0
}
return model.timeStamp
}
///
func lastTimeInterval() -> TimeInterval {
return cellModels.last?.timeStamp ?? 0
}
///
func shouldAppendTimestamp(model: SessionBaseModel) -> Bool {
if model.cellType == .aiLoading{
return false
}
return model.timeStamp - lastTimeInterval() > showTimeInterval
}
///
func shouldInsertTimestamp(model: SessionBaseModel) -> Bool {
return firtTimeStamp() - model.timeStamp > showTimeInterval
}
/// model
func ignore(info: IMBaseRemoteInfo) -> Bool{
var ignore = false
if let customAttachment = info.customAttachment{
if let type = customAttachment.type{
if type == .HEARTBEAT_LEVEL_DOWN ||
type == .HEARTBEAT_LEVEL_UP ||
type == .INSUFFICIENT_BALANCE ||
type == .VOICE_CHAT_CONTENT
{
ignore = true
}
}else{
// type
ignore = true
}
}
return ignore
}
/// modelmodel
func needDeriveModel(message: V2NIMMessage) -> Bool {
if message.messageType == .MESSAGE_TYPE_CUSTOM{
if let attachment = message.attachment?.raw, attachment.count > 0 {
let model = CodableHelper.decode(IMCustomAttachment.self, from: attachment)
if let type = model?.type, type.rawValue.uppercased() == CLCustomAttchType.IMAGE.rawValue{
return true
}
}
}
if message.serverExtension == nil {
return false
}
let info = IMRemoteUtil.dealRemoteInfo(message: message)
if info.cellType == .keyword
|| info.cellType == .gift
{
return true
}
return false
}
func needDecriveModel(with: IMBaseRemoteInfo) -> Bool{
if let customAttachment = with.customAttachment, let type = customAttachment.type{
if type == .IMAGE{
return true
}
}
if with.cellType == .keyword || with.cellType == .gift{
return true
}
return false
}
/// model
func setIdIdctObject(model: SessionBaseModel) {
if model.isDeriveModel {
return
}
guard let messageID = model.v2msg?.messageClientId else { return }
msgIdDict[messageID] = model
}
/// messagemodel
func modelIsExist(model: SessionBaseModel) -> Bool {
guard let messageID = model.v2msg?.messageClientId else { return false }
return msgIdDict[messageID] != nil
}
func logAllCellModels(){
if APIConfig.environment == .test{
var string = "cellModels(\(cellModels.count):\n"
for per in cellModels {
string += "\(per)\n"
}
dlog(string)
}
}
}
// MARK: - Deal Models
/// Deal Models
extension SessionUtil {
/// cellModel
func createCellModelWith(type: SessionCellType) -> SessionBaseModel {
let model = SessionBaseModel()
let configType = SessionBaseModel.getContentConfigClass(type: type)
//
model.config = configType.init()
model.cellType = type
switch type {
case .image:
model.shouldShowBubble = false
case .gift:
//
model.shouldShowBubble = false
model.shouldShowCardView = true
case .timeStamp,.tips, .create, .keyword, .phonecall:
model.shouldShowBubble = false
model.shouldShowTips = true
default:
// bubble
model.shouldShowBubble = true
model.shouldShowTips = false
break
}
return model
}
func createCellModelWithCustom(attachment:String?) -> SessionBaseModel{
let model = SessionBaseModel()
guard let raw = attachment, let data = CodableHelper.decode(IMCustomAttachment.self, from: raw) else{
return model
}
// switch data.type{
// case .IMAGE: break
//
// }
//let configType = SessionBaseModel.getContentConfigClass(type: type)
return model
}
///
func dealMessages(messages: [V2NIMMessage]?, completion: @escaping ((_ messageDatas: [V2NIMMessage]?, _ error: Error?) -> Void)) {
var tempModels = modelWithV2(datas: messages!)
var tempMessages = messages ?? [V2NIMMessage]()
// while tempModels.count < mssagePageSize, messages!.count > 0 {
// tempMessages = NIMSDK.shared().conversationManager.messages(in: session, message: tempMessages.first, limit: mssagePageSize)!
// if Array.realEmpty(array: tempMessages) {
// break
// }
// let theModels = modelWith(messsages: tempMessages)
// tempModels.insert(contentsOf: theModels, at: 0)
// }
// let indexs = insertMessagesWith(models: tempModels.reversed())
DispatchQueue.main.async {
completion( messages, nil)
}
}
@discardableResult
func inserMessageWith(message: V2NIMMessage, atIndex: Int) -> [Int]{
let models = modelWithV2(datas: [message])
guard let model = models.first else { return [] }
self.cellModels.insert(model, at: atIndex)
return [atIndex]
}
/// model
func appendWith(models: [SessionBaseModel]) -> [Int] {
if Array.realEmpty(array: models) {
return []
}
let count = cellModels.count
for model in models {
if modelIsExist(model: model), !model.isDeriveModel {
continue
}
_ = appendWith(model: model)
}
var indexs = [Int]()
for i in count ..< cellModels.count {
indexs.append(i)
}
return indexs
}
/// model
@discardableResult
func appendWith(model: SessionBaseModel) -> [Int] {
var indexs = [Int]()
if shouldAppendTimestamp(model: model) {
addTimestamp(model: model, index: cellModels.count)
indexs.append(cellModels.count)
}
cellModels.insert(model, at: cellModels.count)
indexs.append(cellModels.count)
setIdIdctObject(model: model)
return indexs
}
/// model
func addTimestamp(model: SessionBaseModel, index: Int) {
let timeModel = createCellModelWith(type: .timeStamp)
timeModel.shouldShowBubble = false
timeModel.shouldShowTips = true
timeModel.timeStamp = model.v2msg?.createTime ?? model.timeStamp
cellModels.insert(timeModel, at: index)
}
/// model
func findCellModel(message: V2NIMMessage?) -> SessionBaseModel? {
guard let messageID = message?.messageClientId else { return nil }
// model
let model = msgIdDict[messageID]
return model
}
/// modelindex
func modelIndexWith(model: SessionBaseModel) -> Int? {
for i in 0 ..< cellModels.count {
let obj = cellModels[i]
//if obj.isEqual(model) {
if obj === model{
return i
}
}
return nil
}
/// message model
@discardableResult
func appendWith(messages: [V2NIMMessage]) -> [Int] {
let models = modelWithV2(datas: messages)
// modelWithV2
let indexs = appendWith(models: models.reversed())
return indexs
}
/// message model
func updateWith(message: V2NIMMessage) -> [Int]? {
guard let model = findCellModel(message: message) else { return nil }
guard let index = modelIndexWith(model: model) else { return nil }
var indexs = [Int]()
indexs.append(index)
if needDeriveModel(message: message) {
if index + 1 < cellModels.count {
indexs.append(index + 1)
}
}
return indexs
}
// MARK: V2
/// [V2NIMMessage] -> [SessionBaseModel]
func modelWithV2(datas:[V2NIMMessage]) -> [SessionBaseModel]{
var array = [SessionBaseModel]()
for i in 0 ..< datas.count {
let message = datas[i]
if let messageID = message.messageClientId, msgIdDict[messageID] != nil{
//
dlog("☁️⚠️⚠️\(message)已经存在了,应该更新,而不是新创建!⚠️⚠️")
continue
}
if let serverExtension = message.serverExtension, serverExtension.count > 0{
dlog("message___ext___\(serverExtension)")
}
// Step cellType
let info = IMRemoteUtil.dealRemoteInfo(message: message)
//
guard !ignore(info: info) else {
continue
}
// Step cellModel
if needDecriveModel(with: info) { // needDeriveModel(message: message)
//
// (👆cell//
let cellModel = createCellModelWith(type: info.cellType)
cellModel.baseRemoteInfo = info
cellModel.isDeriveModel = true
cellModel.shouldShowLeft = !message.isSelf
cellModel.v2msg = message
cellModel.timeStamp = message.createTime
array.append(cellModel)
if message.messageType == .MESSAGE_TYPE_TEXT {
if message.isSelf{
let cellModel = createCellModelWith(type: .text)
cellModel.baseRemoteInfo = info
cellModel.shouldShowLeft = false
cellModel.v2msg = message
cellModel.timeStamp = message.createTime
array.append(cellModel)
}else{
let cellModel = createCellModelWith(type: .aimsg)
cellModel.baseRemoteInfo = info
cellModel.shouldShowLeft = true
cellModel.v2msg = message
cellModel.timeStamp = message.createTime
array.append(cellModel)
}
} else if message.messageType == .MESSAGE_TYPE_TIP {
let cellModel = createCellModelWith(type: .tips)
cellModel.baseRemoteInfo = info
cellModel.shouldShowLeft = !message.isSelf
cellModel.v2msg = message
cellModel.timeStamp = message.createTime
array.append(cellModel)
}else if message.messageType == .MESSAGE_TYPE_CUSTOM{
//
if message.isSelf{
let cellModel = createCellModelWith(type: .text)
cellModel.baseRemoteInfo = info
cellModel.shouldShowLeft = !message.isSelf
cellModel.v2msg = message
cellModel.timeStamp = message.createTime
array.append(cellModel)
}else{
if info.cellType != .image{
let cellModel = createCellModelWith(type: .aimsg)
cellModel.baseRemoteInfo = info
cellModel.shouldShowLeft = !message.isSelf
cellModel.v2msg = message
cellModel.timeStamp = message.createTime
array.append(cellModel)
}
}
}
} else {
// cell
let cellModel = createCellModelWith(type: info.cellType)
cellModel.baseRemoteInfo = info
cellModel.shouldShowLeft = !message.isSelf
cellModel.v2msg = message
cellModel.timeStamp = message.createTime
array.append(cellModel)
}
}
return array
}
func createAnAILoadingModel(){
let cellModel = createCellModelWith(type: .aiLoading)
cellModel.isDeriveModel = true
cellModel.shouldShowLeft = true
cellModel.v2msg = nil
cellModel.timeStamp = TimeInterval(Date().timeStampInSeconds)
appendWith(model: cellModel)
}
func clearAILoadingModel(){
cellModels.removeAll(where: {$0.cellType == .aiLoading})
}
@discardableResult
func insertMessagesWith(models: [SessionBaseModel]) -> [Int] {
if Array.realEmpty(array: models) {
return []
}
let count = cellModels.count
for i in 0 ..< models.count {
let model = models[i]
if modelIsExist(model: model), !model.isDeriveModel, !model.shouldShowTips {
continue
}
insertMessageWith(model: model, needTime: cellModels.count != count)
}
var indexs = [Int]()
for i in 0 ..< cellModels.count - count {
indexs.append(i)
}
return indexs
}
/// model
func insertMessageWith(model: SessionBaseModel, needTime: Bool) {
//
let isCreateTimestampCell = (model.cellType == .create || model.cellType == .tips)
if isCreateTimestampCell {
if let theModel = cellModels.first, theModel.cellType != .timeStamp {
addTimestamp(model: theModel, index: 0)
}
} else {
if !shouldInsertTimestamp(model: model), needTime {
let model = cellModels.first
if model?.cellType == .timeStamp {
cellModels.removeFirst()
}
}
}
cellModels.insert(model, at: 0)
setIdIdctObject(model: model)
if !isCreateTimestampCell {
addTimestamp(model: model, index: 0)
}
}
func loadMessages(completion: @escaping ((_ firstPage: Bool, _ messageDatas: [V2NIMMessage]?, _ error: V2NIMError?) -> Void)){
let option = V2NIMMessageListOption()
var loadMoreMsgFlag = false
if let v2Msg = getLastMessageModel()?.v2msg{
option.anchorMessage = v2Msg
option.beginTime = v2Msg.createTime
loadMoreMsgFlag = true
}
option.conversationId = conversationId
NIMSDK.shared().v2MessageService.getMessageList(option) {[weak self] messages in
if let models = self?.modelWithV2(datas: messages){
// self?.cellModels = models
self?.insertMessagesWith(models: models)
completion(!loadMoreMsgFlag, messages,nil)
}
} failure: { error in
dlog("Get messages error:\(error)")
completion(!loadMoreMsgFlag, nil,error)
}
}
}
// MARK: - Messages
extension SessionUtil {
///
func sendMessage(message: V2NIMMessage) {
sendMessage(message: message) { error in
print(error ?? "")
}
}
///
func sendMessage(message: V2NIMMessage, completion: @escaping ((_ error: Error?) -> Void)) {
// See more params in https://doc.yunxin.163.com/messaging2/client-apis/DAxNjk0Mzc?platform=client#V2NIMSendMessageParams
let param = V2NIMSendMessageParams()
NIMSDK.shared().v2MessageService.send(message, conversationId: conversationId, params: param) { result in
dlog("✅send message ok \(message.text ?? "")")
} failure: { error in
dlog("❌send message failed: \(error)")
if error.code == 20000{
CLPurchase.shared.showChatModelsAndIAPEntrySheet()
}
}
// NIMSDK.shared().chatManager.send(message, to: session) { error in
// completion(error)
// }
}
}
// MARK: - Test
extension SessionUtil{
func testModes(completion: @escaping (() -> Void)) {
var array = [SessionBaseModel]()
do{
let cellModel = createCellModelWith(type: .aimsg)
cellModel.shouldShowLeft = true
let msg = V2NIMMessage()
msg.text = "(Watching her parents toast you respectfully, I feel very uncomfortable. After all, she has been standing on the top of the magic capital since she was a child. She has never seen her parents like this, but should I say that he is really handsome?) Are you?"
cellModel.v2msg = msg
cellModel.timeStamp = TimeInterval(Date().timeStamp - 1000)
array.append(cellModel)
}
do{
let cellModel = createCellModelWith(type: .text)
cellModel.shouldShowLeft = false
let msg = V2NIMMessage()
msg.text = "who are you"
cellModel.v2msg = msg
cellModel.timeStamp = TimeInterval(Date().timeStamp - 500)
array.append(cellModel)
}
cellModels = array
completion()
}
}