jsdw_ios/QuickLocation/Section/Group/GroupViewModel.swift

152 lines
5.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

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.

//
// GroupViewModel.swift
// QuickLocation
//
import Foundation
import RxSwift
import RxCocoa
import RxDataSources
import OpenIMSDK
import ObjectMapper
typealias HotGroupListSectionModel = SectionModel<String, GroupInfoModel>
typealias CircleListSectionModel = SectionModel<String, GroupCellData>
/// cell `groups` IM //
struct GroupCellData {
let group: GroupInfoModel
let unreadCount: Int
let lastMsgTime: Int // ms timestamp
let lastMsgPreview: String
var tags: [String] { Array(group.labels.prefix(2)) }
var iconURL: String { group.groupIconURL }
var localIcon: UIImage { group.groupIcon }
}
final class GroupViewModel {
struct Output {
let hotGroups: Observable<[HotGroupListSectionModel]>
let createdSections: Observable<[CircleListSectionModel]>
let joinedSections: Observable<[CircleListSectionModel]>
let segmentTitles: Driver<[String]>
}
let output: Output
private let hotGroupSectionedItems = PublishSubject<[HotGroupListSectionModel]>()
private let createdSectionsSubject = PublishSubject<[CircleListSectionModel]>()
private let joinedSectionsSubject = PublishSubject<[CircleListSectionModel]>()
let segmentTitles = BehaviorRelay<[String]>(value: ["我创建的圈子", "我加入的圈子"])
private(set) var groupList: [GroupInfoModel] = []
private var cachedConversations: [OIMConversationInfo] = []
///
func loadHotGroupData(_ list: [GroupInfoModel]) {
hotGroupSectionedItems.onNext(list.mapSection())
}
lazy var hotGroupCellAction: Action<GroupInfoModel, Void> = { this in
return Action { model in
AppRouter.push(Route.groupInfo, userInfo: ["groupInfo": model.toJSON()])
return .empty()
}
}(self)
/// `groups`
func applyBusinessGroups(_ list: [GroupInfoModel]) {
groupList = list
reloadData()
}
/// IM
func loadConversations(_ conversations: [OIMConversationInfo]) {
cachedConversations = conversations
reloadData()
}
/// -
func updateConversations(_ conversations: [OIMConversationInfo]) {
var merged: [String: OIMConversationInfo] = [:]
for c in cachedConversations { if let gid = c.groupID { merged[gid] = c } }
for c in conversations { if let gid = c.groupID { merged[gid] = c } }
cachedConversations = Array(merged.values)
reloadData()
}
private func reloadData() {
let convMap: [String: OIMConversationInfo] = {
var m: [String: OIMConversationInfo] = [:]
for c in cachedConversations where c.groupID != nil && !(c.groupID?.isEmpty ?? true) {
m[c.groupID!] = c
}
return m
}()
func cellData(for group: GroupInfoModel) -> GroupCellData {
let conv = convMap[group.group_key]
return GroupCellData(
group: group,
unreadCount: Int(conv?.unreadCount ?? 0),
lastMsgTime: Int(conv?.latestMsgSendTime ?? 0),
lastMsgPreview: Self.previewText(from: conv?.latestMsg)
)
}
func sortedByLastMsg(_ items: [GroupCellData]) -> [GroupCellData] {
items.sorted { lhs, rhs in
if lhs.lastMsgTime != rhs.lastMsgTime {
return lhs.lastMsgTime > rhs.lastMsgTime
}
return lhs.group.group_key < rhs.group.group_key
}
}
let all = sortedByLastMsg(groupList.map(cellData(for:)))
let created = sortedByLastMsg(groupList.filter(\.is_owner).map(cellData(for:)))
createdSectionsSubject.onNext(created.mapSection())
joinedSectionsSubject.onNext(all.mapSection())
}
private static func previewText(from msg: OIMMessageInfo?) -> String {
guard let msg else { return "" }
let body: String
switch msg.contentType {
case .image: body = "[图片]"
case .audio: body = "[语音]"
case .video: body = "[视频]"
case .file: body = "[文件]"
case .location: body = "[位置]"
case .at: body = Self.displayBody(msg.atTextElem?.text ?? "[消息]")
case .quote: body = Self.displayBody(msg.quoteElem?.text ?? "[消息]")
case .face: body = "[表情]"
default:
body = Self.displayBody(msg.textElem?.content ?? msg.content ?? "")
}
let name = msg.senderNickname ?? ""
if name.isEmpty { return body }
if body.isEmpty { return name }
return "\(name): \(body)"
}
private static func displayBody(_ text: String) -> String {
if text.hasPrefix("js_emoji:") { return "[表情]" }
return text
}
// MARK: - Init
init() {
output = Output(
hotGroups: hotGroupSectionedItems.asObservable(),
createdSections: createdSectionsSubject.asObservable(),
joinedSections: joinedSectionsSubject.asObservable(),
segmentTitles: segmentTitles.asDriver()
)
}
}