Visual_Novel_iOS/crush/Crush/Src/Modules/Chat/Model/SessionBaseModel.swift

188 lines
6.1 KiB
Swift
Raw Normal View History

2025-10-09 10:29:35 +00:00
//
// SessionBaseModel.swift
// Crush
//
// Created by Leon on 2025/8/18.
//
import UIKit
import Foundation
import NIMSDK
protocol SessionCellContentDelegate {
/// contentView
func contentSize(model: SessionBaseModel) -> CGSize
/// cell(
func cellInsets(model: SessionBaseModel) -> UIEdgeInsets
/// contentViewbubble
func contentInsets(model: SessionBaseModel) -> UIEdgeInsets
/// contentView false true
func onlyShowContent(model: SessionBaseModel) -> Bool
/// conten View
func contentViewClass(model: SessionBaseModel) -> IMContentBaseView.Type
}
enum SessionCellType: String, Codable {
case unknown
case text //
case aimsg // AI Msg
case image //
case timeStamp //
case create //
case keyword //
case tips //
case gift //
case phonecall // im phone call
case aiLoading
}
class SessionBaseModel: CustomStringConvertible, CustomDebugStringConvertible{
/// content
static let maxBubbleContentWidth = floor(UIScreen.width * 0.65)
/// content
static let maxContentWidth = UIScreen.width - 32
var cellType: SessionCellType = .unknown
/// Seconds timestam;
var timeStamp: TimeInterval = 0
var v2msg: V2NIMMessage?
/// message
var baseRemoteInfo: IMBaseRemoteInfo?
/// model cellcell NO
var isDeriveModel = false
/// view
var shouldShowCardView = false
/// tips
var shouldShowTips = false
///
var shouldShowLeft = false
/// YES
var shouldShowBubble = true
///
var cacheCellHeight: CGFloat = 0
/// content
var config: IMContentBaseConfig!
var speechModel : SpeechModel?
var autoPlayAudioOnce: Bool = false
var autoPlayAlreadyPlayed : Bool = false //
///
public func clearCacheData() {
cacheCellHeight = 0
}
public func cellHeight() -> CGFloat {
if cacheCellHeight > 0 {
return cacheCellHeight
}
// content
let size = config.contentSize(model: self)
let cellInsets = config.cellInsets(model: self)
let contentInsets = config.contentInsets(model: self)
//
let height: CGFloat = size.height + cellInsets.top + cellInsets.bottom + contentInsets.top + contentInsets.bottom
cacheCellHeight = height
return height
}
// MARK: Audio About
func prepareAudio(info: IMAIUserInfo?, completion:((_ model: SpeechModel?)-> Void)?){
guard cellType == .aimsg, let text = v2msg?.text, text.count > 0, let voiceType = info?.voiceType else{
return
}
guard AudioPlayTool.audioChannelFreeToUse() else{
dlog("Audio Channel 不可用")
return
}
if let path = self.speechModel?.path, path.count > 0 {
completion?(self.speechModel)
return
}
let saywords = String.removeBracketContents(from: text)
guard saywords.count > 0 else{
return
}
let speechRate = info?.dialogueSpeechRate ?? "0"
let loudnessRate = info?.dialoguePitch ?? "0"
var params = [String: Any]()
params.updateValue(saywords, forKey: "text")
params.updateValue(voiceType, forKey: "voiceType")
params.updateValue(speechRate, forKey: "speechRate")
params.updateValue(loudnessRate, forKey: "pitchRate")
if let aiId = IMAIViewModel.shared.aiIMInfo?.aiId{
params.updateValue(aiId, forKey: "aiId")
}
AICowProvider.request(.voiceTts(params: params), modelType: String.self) {[weak self] result in
switch result {
case .success(let model):
if let audioString = model{
self?.speechModel = SpeechModel.modelWithBase64String(audioString)
//self?.speechModel?.refreshPath(path: audioString)
completion?(self?.speechModel)
}
case .failure:
completion?(nil)
}
}
}
// MARK: - Static
// MARK: Equatable
static func == (lhs: SessionBaseModel, rhs: SessionBaseModel) -> Bool {
return lhs === rhs
}
///
public static func getContentConfigClass(type: SessionCellType) -> IMContentBaseConfig.Type {
switch type {
case .unknown:
return IMContentBaseConfig.self
case .text:
return IMTextContentConfig.self
case .aimsg:
return IMAIMsgContentConfig.self
case .timeStamp:
return IMTimeStampContentConfig.self
case .image:
return IMImageContentConfig.self
case .tips, .create, .keyword:
return IMTipsContentConfig.self
case .gift:
return IMGiftContentConfig.self
case .phonecall:
return IMPhoneCallConfig.self
case .aiLoading:
return IMAIMsgLoadingConfig.self
// default:
// return IMContentBaseConfig.self
}
}
// MARK: - Other Debug
var description: String {
var attchmentString = ""
if let attchmentRaw = v2msg?.attachment?.raw{
attchmentString = attchmentRaw
}
var icon = (v2msg?.isSelf ?? false) ? "✉️" :"💌"
return "\(icon)[\(cellType.rawValue)] 『\(v2msg?.text ?? "-")』raw:\(attchmentString)"
}
var debugDescription: String {
return "[\(cellType.rawValue)] 『\(v2msg?.text ?? "-")"
}
}