增加换肤功能
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// TUICallRecordCallsCellViewModel.swift
|
||||
// TUICallKit
|
||||
//
|
||||
// Created by vincepzhang on 2023/8/28.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import TUICallEngine
|
||||
import ImSDK_Plus
|
||||
import TUICore
|
||||
|
||||
class TUICallRecordCallsCellViewModel {
|
||||
|
||||
var avatarImage: UIImage = UIImage()
|
||||
var faceURL: Observable<String> = Observable("")
|
||||
|
||||
var titleLabelStr: Observable<String> = Observable("")
|
||||
var mediaTypeImageStr: String = ""
|
||||
var resultLabelStr: String = ""
|
||||
var timeLabelStr: String = ""
|
||||
|
||||
var callRecord: TUICallRecords
|
||||
|
||||
init(_ record: TUICallRecords) {
|
||||
callRecord = record
|
||||
|
||||
configAvatarImage(callRecord)
|
||||
configResult(callRecord.result)
|
||||
configMediaTypeImageName(callRecord.mediaType)
|
||||
configTitle(callRecord)
|
||||
configTime(callRecord)
|
||||
}
|
||||
|
||||
private func configAvatarImage(_ callRecord: TUICallRecords) {
|
||||
if callRecord.scene == .group {
|
||||
|
||||
var inviteList = callRecord.inviteList
|
||||
inviteList.insert(callRecord.inviter, at: 0)
|
||||
guard let inviteList = inviteList as? [String] else { return }
|
||||
configGroupAvatarImage(inviteList)
|
||||
|
||||
} else if callRecord.scene == .single {
|
||||
configSingleAvatarImage(callRecord)
|
||||
} else {
|
||||
avatarImage = TUICoreDefineConvert.getDefaultGroupAvatarImage()
|
||||
}
|
||||
}
|
||||
|
||||
private func configGroupAvatarImage(_ inviteList: [String]) {
|
||||
if inviteList.isEmpty {
|
||||
avatarImage = TUICoreDefineConvert.getDefaultGroupAvatarImage()
|
||||
return
|
||||
}
|
||||
|
||||
let inviteStr = inviteList.joined(separator: "#")
|
||||
|
||||
getCacheAvatarForInviteStr(inviteStr) { [weak self] avatar in
|
||||
guard let self = self else { return }
|
||||
if let avatar = avatar {
|
||||
self.avatarImage = avatar
|
||||
} else {
|
||||
V2TIMManager.sharedInstance()?.getUsersInfo(inviteList, succ: { infoList in
|
||||
var avatarsList = [String]()
|
||||
|
||||
infoList?.forEach { userFullInfo in
|
||||
if let faceURL = userFullInfo.faceURL, !faceURL.isEmpty {
|
||||
avatarsList.append(faceURL)
|
||||
} else {
|
||||
avatarsList.append("http://placeholder")
|
||||
}
|
||||
}
|
||||
TUIGroupAvatar.createGroupAvatar(avatarsList, finished: { [weak self] image in
|
||||
guard let self = self else { return }
|
||||
self.avatarImage = image
|
||||
self.cacheGroupCallAvatar(image, inviteStr: inviteStr)
|
||||
})
|
||||
}, fail: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func configSingleAvatarImage(_ callRecord: TUICallRecords) {
|
||||
avatarImage = TUICoreDefineConvert.getDefaultAvatarImage()
|
||||
var useId = callRecord.inviter
|
||||
|
||||
if callRecord.role == .call {
|
||||
guard let firstInvite = callRecord.inviteList.first as? String else { return }
|
||||
useId = firstInvite
|
||||
}
|
||||
|
||||
if !useId.isEmpty {
|
||||
V2TIMManager.sharedInstance()?.getUsersInfo([useId], succ: { [weak self] infoList in
|
||||
guard let self = self else { return }
|
||||
if let userFullInfo = infoList?.first {
|
||||
if let faceURL = userFullInfo.faceURL, !faceURL.isEmpty, faceURL.hasPrefix("http") {
|
||||
self.faceURL.value = faceURL
|
||||
}
|
||||
}
|
||||
}, fail: nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func configResult(_ callResultType: TUICallResultType) {
|
||||
switch callResultType {
|
||||
case .missed:
|
||||
resultLabelStr = TUICallKitLocalize(key: "TUICallKit.Recents.missed") ?? "Missed"
|
||||
case .incoming:
|
||||
resultLabelStr = TUICallKitLocalize(key: "TUICallKit.Recents.incoming") ?? "Incoming"
|
||||
case .outgoing:
|
||||
resultLabelStr = TUICallKitLocalize(key: "TUICallKit.Recents.outgoing") ?? "Outgoing"
|
||||
case .unknown:
|
||||
break
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func configMediaTypeImageName(_ callMediaType: TUICallMediaType) {
|
||||
if callMediaType == .audio {
|
||||
mediaTypeImageStr = "ic_recents_audio"
|
||||
} else if callMediaType == .video {
|
||||
mediaTypeImageStr = "ic_recents_video"
|
||||
}
|
||||
}
|
||||
|
||||
func configTitle(_ callRecord: TUICallRecords) {
|
||||
titleLabelStr.value = ""
|
||||
var allUsers: [String] = []
|
||||
|
||||
switch callRecord.scene {
|
||||
case .single:
|
||||
if callRecord.role == .call {
|
||||
guard let inviteList = callRecord.inviteList as? [String] else { return }
|
||||
allUsers = inviteList
|
||||
} else if callRecord.role == .called {
|
||||
let inviter = callRecord.inviter
|
||||
allUsers.append(inviter)
|
||||
}
|
||||
case .group:
|
||||
guard let inviteList = callRecord.inviteList as? [String] else { return }
|
||||
allUsers = inviteList
|
||||
case .multi:
|
||||
break
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
|
||||
User.getUserInfosFromIM(userIDs: allUsers) { [weak self] infoList in
|
||||
guard let self = self else { return }
|
||||
let titleArray = infoList.map { $0.remark.value.count > 0
|
||||
? $0.remark.value
|
||||
: $0.nickname.value.count > 0 ? $0.nickname.value : $0.id.value }
|
||||
self.titleLabelStr.value = titleArray.joined(separator: ",")
|
||||
}
|
||||
}
|
||||
|
||||
private func configTime(_ callRecord: TUICallRecords) {
|
||||
let beginTime: TimeInterval = callRecord.beginTime / 1_000
|
||||
if beginTime <= 0 {
|
||||
return
|
||||
}
|
||||
timeLabelStr = TUITool.convertDate(toStr: Date(timeIntervalSince1970: beginTime))
|
||||
}
|
||||
|
||||
// MARK: - Cache
|
||||
private func getCacheAvatarForInviteStr(_ inviteStr: String, completion: @escaping (UIImage?) -> Void) {
|
||||
let cacheKey = "group_call_avatar_\(inviteStr)"
|
||||
let cachePath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first ?? ""
|
||||
let filePath = "\(cachePath)/\(cacheKey)"
|
||||
let fileManager = FileManager.default
|
||||
|
||||
if fileManager.fileExists(atPath: filePath) {
|
||||
if let data = fileManager.contents(atPath: filePath), let image = UIImage(data: data) {
|
||||
completion(image)
|
||||
return
|
||||
}
|
||||
}
|
||||
completion(nil)
|
||||
}
|
||||
|
||||
private func cacheGroupCallAvatar(_ avatar: UIImage, inviteStr: String) {
|
||||
let cacheKey = "group_call_avatar_\(inviteStr)"
|
||||
let cachePath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first ?? ""
|
||||
let filePath = "\(cachePath)/\(cacheKey)"
|
||||
let fileManager = FileManager.default
|
||||
|
||||
if let data = avatar.pngData() {
|
||||
fileManager.createFile(atPath: filePath, contents: data, attributes: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// TUICallRecordCallsViewModel.swift
|
||||
//
|
||||
//
|
||||
// Created by vincepzhang on 2023/8/28.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import TUICallEngine
|
||||
import TUICore
|
||||
|
||||
enum TUICallRecordCallsType: Int {
|
||||
case all
|
||||
case missed
|
||||
}
|
||||
|
||||
enum TUICallKitRecordCallsUIStyle: Int {
|
||||
case classic
|
||||
case minimalist
|
||||
}
|
||||
|
||||
class TUICallRecordCallsViewModel {
|
||||
|
||||
var dataSource: Observable<[TUICallRecordCallsCellViewModel]> = Observable(Array())
|
||||
var allDataSource: [TUICallRecordCallsCellViewModel] = []
|
||||
var missedDataSource: [TUICallRecordCallsCellViewModel] = []
|
||||
|
||||
var recordCallsUIStyle: TUICallKitRecordCallsUIStyle = .minimalist
|
||||
var recordCallsType: TUICallRecordCallsType = .all
|
||||
|
||||
typealias SuccClosureType = @convention(block) (UIViewController) -> Void
|
||||
typealias FailClosureType = @convention(block) (Int, String) -> Void
|
||||
|
||||
func queryRecentCalls() {
|
||||
let filter = TUICallRecentCallsFilter()
|
||||
TUICallEngine.createInstance().queryRecentCalls(filter: filter, succ: { [weak self] callRecords in
|
||||
guard let self = self else { return }
|
||||
var viewModelList: [TUICallRecordCallsCellViewModel] = []
|
||||
callRecords.forEach { callRecord in
|
||||
let viewModel = TUICallRecordCallsCellViewModel(callRecord)
|
||||
viewModelList.append(viewModel)
|
||||
}
|
||||
self.updateDataSource(viewModelList)
|
||||
}, fail: {})
|
||||
}
|
||||
|
||||
func updateDataSource(_ viewModelList: [TUICallRecordCallsCellViewModel]) {
|
||||
if viewModelList.isEmpty {
|
||||
return
|
||||
}
|
||||
cleanAllSource()
|
||||
allDataSource = viewModelList
|
||||
viewModelList.forEach { viewModel in
|
||||
if viewModel.callRecord.result == .missed {
|
||||
missedDataSource.append(viewModel)
|
||||
}
|
||||
}
|
||||
reloadDataSource()
|
||||
}
|
||||
|
||||
func switchRecordCallsType(_ type: TUICallRecordCallsType) {
|
||||
recordCallsType = type
|
||||
reloadDataSource()
|
||||
}
|
||||
|
||||
func reloadDataSource() {
|
||||
switch recordCallsType {
|
||||
case .all:
|
||||
dataSource.value = allDataSource
|
||||
case .missed:
|
||||
dataSource.value = missedDataSource
|
||||
}
|
||||
}
|
||||
|
||||
func cleanAllSource() {
|
||||
dataSource.value.removeAll()
|
||||
allDataSource.removeAll()
|
||||
missedDataSource.removeAll()
|
||||
}
|
||||
|
||||
func cleanSource(viewModel: TUICallRecordCallsCellViewModel) {
|
||||
allDataSource.removeAll() { $0.callRecord.callId == viewModel.callRecord.callId }
|
||||
missedDataSource.removeAll() { $0.callRecord.callId == viewModel.callRecord.callId }
|
||||
}
|
||||
|
||||
func cleanSource(callId: String) {
|
||||
allDataSource.removeAll() { $0.callRecord.callId == callId }
|
||||
missedDataSource.removeAll() { $0.callRecord.callId == callId }
|
||||
}
|
||||
|
||||
|
||||
func repeatCall(_ indexPath: IndexPath) {
|
||||
let cellViewModel = dataSource.value[indexPath.row]
|
||||
|
||||
if cellViewModel.callRecord.scene == .single {
|
||||
repeatSingleCall(cellViewModel.callRecord)
|
||||
}
|
||||
}
|
||||
|
||||
func repeatSingleCall(_ callRecord: TUICallRecords) {
|
||||
var userId = callRecord.inviteList.first
|
||||
if callRecord.role == .called {
|
||||
userId = callRecord.inviter
|
||||
}
|
||||
|
||||
guard let userId = userId as? String else { return }
|
||||
|
||||
TUICallKit.createInstance().call(userId: userId, callMediaType: callRecord.mediaType)
|
||||
}
|
||||
|
||||
func deleteAllRecordCalls() {
|
||||
var callIdList: [String] = []
|
||||
|
||||
if recordCallsType == .all {
|
||||
callIdList = getCallIdList(allDataSource)
|
||||
} else if recordCallsType == .missed {
|
||||
callIdList = getCallIdList(missedDataSource)
|
||||
}
|
||||
|
||||
TUICallEngine.createInstance().deleteRecordCalls(callIdList, succ: { [weak self] succList in
|
||||
guard let self = self else { return }
|
||||
|
||||
succList.forEach { callId in
|
||||
self.cleanSource(callId: callId)
|
||||
}
|
||||
|
||||
self.reloadDataSource()
|
||||
}, fail: {})
|
||||
}
|
||||
|
||||
func getCallIdList(_ cellViewModelArray: [TUICallRecordCallsCellViewModel]) -> [String] {
|
||||
var callIdList: [String] = []
|
||||
|
||||
if cellViewModelArray.isEmpty {
|
||||
return callIdList
|
||||
}
|
||||
|
||||
cellViewModelArray.forEach { obj in
|
||||
callIdList.append(obj.callRecord.callId)
|
||||
}
|
||||
|
||||
return callIdList
|
||||
}
|
||||
|
||||
func deleteRecordCall(_ indexPath: IndexPath) {
|
||||
if indexPath.row < 0 || indexPath.row >= dataSource.value.count {
|
||||
return
|
||||
}
|
||||
let viewModel = dataSource.value[indexPath.row]
|
||||
|
||||
TUICallEngine.createInstance().deleteRecordCalls([viewModel.callRecord.callId], succ: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.cleanSource(viewModel: viewModel)
|
||||
self.reloadDataSource()
|
||||
|
||||
}, fail: {})
|
||||
}
|
||||
|
||||
func jumpUserInfoController(indexPath: IndexPath, navigationController: UINavigationController) {
|
||||
if indexPath.row < 0 || indexPath.row >= dataSource.value.count {
|
||||
return
|
||||
}
|
||||
let cellViewModel = dataSource.value[indexPath.row]
|
||||
|
||||
let groupId = cellViewModel.callRecord.groupId
|
||||
var userId = cellViewModel.callRecord.inviter
|
||||
|
||||
if cellViewModel.callRecord.role == .call {
|
||||
guard let firstUserId = cellViewModel.callRecord.inviteList.first as? String else { return }
|
||||
userId = firstUserId
|
||||
}
|
||||
|
||||
if !groupId.isEmpty {
|
||||
let param: [String: Any] = [TUICore_TUIContactObjectFactory_GetGroupInfoVC_GroupID: groupId]
|
||||
if TUICallKitRecordCallsUIStyle.classic == recordCallsUIStyle {
|
||||
navigationController.push(TUICore_TUIContactObjectFactory_GetGroupInfoVC_Classic, param: param, forResult: nil)
|
||||
} else {
|
||||
navigationController.push(TUICore_TUIContactObjectFactory_GetGroupInfoVC_Minimalist, param: param, forResult: nil)
|
||||
}
|
||||
} else if !userId.isEmpty {
|
||||
getUserOrFriendProfileVCWithUserID(userId: userId) { viewController in
|
||||
navigationController.pushViewController(viewController, animated: true)
|
||||
} fail: { code, desc in
|
||||
TUITool.makeToastError(Int(code), msg: desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getUserOrFriendProfileVCWithUserID(userId: String, succ: @escaping SuccClosureType, fail: @escaping FailClosureType) {
|
||||
let param: NSDictionary = [
|
||||
TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_UserIDKey: userId,
|
||||
TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_SuccKey: succ,
|
||||
TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod_FailKey: fail,
|
||||
]
|
||||
|
||||
if TUICallKitRecordCallsUIStyle.classic == self.recordCallsUIStyle {
|
||||
TUICore.createObject(TUICore_TUIContactObjectFactory,
|
||||
key: TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod, param: param as? [AnyHashable : Any])
|
||||
} else {
|
||||
TUICore.createObject(TUICore_TUIContactObjectFactory_Minimalist,
|
||||
key: TUICore_TUIContactObjectFactory_GetUserOrFriendProfileVCMethod, param: param as? [AnyHashable : Any])
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user