jsdw_ios/QuickLocation/Section/Home/HomeViewModel.swift

183 lines
5.6 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.

//
// HomeViewModel.swift
// QuickLocation
//
// Created by 八条 on 2026/5/30.
//
import RxSwift
import RxDataSources
import ObjectMapper
typealias GroupMemberListSectionModel = SectionModel<String, GroupMemberModel>
class HomeViewModel {
struct Output {
var sectionedItems: Observable<[GroupMemberListSectionModel]>
}
let output: Output
private var disposeBag = DisposeBag()
private let sectionedItems = PublishSubject<[GroupMemberListSectionModel]>()
lazy var cellAction: Action<GroupMemberModel, Void> = { this in
return Action { model in
return .empty()
}
}(self)
var targetUid: String = ""
var groupModel: GroupModel?
// 当前选中的圈子
var groupInfo: [String: Any] {
get {
guard let model = groupModel,
let groupInfoModel = model.groups.first(where: { $0.group_key == model.default_group_key }) else { return [:] }
return groupInfoModel.toJSON()
}
}
// 圈子名字
var groupName: String {
get {
guard let model = groupModel else { return "我的圈子" }
return model.groups.first(where: { $0.group_key == model.default_group_key })?.name ?? ""
}
}
var currentGroupInfo: GroupInfoModel? {
guard let model = groupModel else { return nil }
return model.groups.first(where: { $0.group_key == model.default_group_key })
}
var isCoupleGroup: Bool {
currentGroupInfo?.isCoupleGroup == true
}
// 圈子成员数
var memberCount: Int {
memberList.count
}
// 圈子成员在线数
var memberOnlineCount: Int {
memberList.filter(\.is_online).count
}
// 是否当前用户
func isCurrentUser(id: String) -> Bool {
let memberId = id.trimmingCharacters(in: .whitespacesAndNewlines)
let selfId = AppContextManager.shared.userId.trimmingCharacters(in: .whitespacesAndNewlines)
return !memberId.isEmpty && memberId == selfId
}
// 是否圈主
func isGroupOwn(id: String) -> Bool {
guard let model = groupModel else { return false }
return GroupOwnerMatcher.matches(userId: id, groupKey: model.default_group_key)
}
func getUserNickName(id: String) -> String {
memberList.first { $0.user_id == id }?.showName ?? ""
}
private(set) var memberList: [GroupMemberModel] = []
func markMemberInBubble(userId: String) {
updateMemberStatus(userId: userId, status: 2)
}
func isInBubble(userId: String) -> Bool {
let ids = canonicalUserIds(userId)
if let member = memberList.first(where: { ids.contains($0.user_id) }) {
return member.status == 2
}
if ids.contains(where: { $0 == "current" || isCurrentUser(id: $0) }) {
return AppContextManager.shared.status == 2
}
return false
}
func updateMembers(_ list: [GroupMemberModel]) {
memberList = GroupMemberSorter.sorted(
list,
groupKey: groupModel?.default_group_key ?? "",
currentUserId: AppContextManager.shared.userId
)
sectionedItems.onNext(memberList.mapSection())
}
func updateGroupUsers(_ list: [GroupMemberModel]) {
updateMembers(list)
}
func clearMembers() {
updateMembers([])
}
private func canonicalUserIds(_ userId: String) -> Set<String> {
var ids: Set<String> = [userId]
if userId == "current" || isCurrentUser(id: userId) {
ids.insert("current")
let mine = AppContextManager.shared.userId
if !mine.isEmpty {
ids.insert(mine)
}
}
return ids
}
/// 标记成员离线(保留 last_active_time 用于显示"X分钟前")
func setMemberOffline(userId: String) {
guard let idx = memberList.firstIndex(where: { $0.user_id == userId }) else { return }
guard memberList[idx].is_online else { return }
memberList[idx].is_online = false
updateMembers(memberList)
}
/// MQTT 位置更新后刷新成员的地址、电量、在线状态。
/// 列表 cell 不展示这些字段,在线状态没变时不要整表 reload。
func updateMemberLocation(userId: String, lat: Double, lon: Double, address: String, battery: String, isOnline: Bool, lastUpdateTime: Int64) {
guard let idx = memberList.firstIndex(where: { $0.user_id == userId }) else { return }
let onlineChanged = memberList[idx].is_online != isOnline
memberList[idx].last_position = "\(lat):\(lon):\(address)"
memberList[idx].battery = battery
memberList[idx].is_online = isOnline
memberList[idx].last_active_time = lastUpdateTime
if onlineChanged {
updateMembers(memberList)
}
}
/// 成员是否存在
func memberIsExist(userId: String) -> Bool {
(memberList.first(where: { $0.user_id == userId }) != nil)
}
/// 移除成员
func removeMember(userId: String) {
guard let idx = memberList.firstIndex(where: { $0.user_id == userId }) else { return }
var updated = memberList
updated.remove(at: idx)
updateMembers(updated)
}
func updateMemberStatus(userId: String, status: Int) {
guard let index = memberList.firstIndex(where: { $0.user_id == userId }) else { return }
memberList[index].status = status
sectionedItems.onNext(memberList.mapSection())
}
// MARK: - Init
init() {
output = Output(
sectionedItems: sectionedItems.asObservable()
)
}
}