104 lines
3.0 KiB
Swift
104 lines
3.0 KiB
Swift
//
|
||
// GroupMemberListVM.swift
|
||
// QuickLocation
|
||
//
|
||
// Created by 八条 on 2026/6/29.
|
||
//
|
||
|
||
import RxSwift
|
||
import RxRelay
|
||
import RxDataSources
|
||
|
||
// Used by the itinerary detail page in this module.
|
||
struct DrivingEventItem: IdentifiableType, Equatable {
|
||
typealias Identity = String
|
||
|
||
let identity: String
|
||
let title: String
|
||
let iconName: String
|
||
let count: Int
|
||
|
||
init(title: String, iconName: String, count: Int = 0) {
|
||
self.identity = title
|
||
self.title = title
|
||
self.iconName = iconName
|
||
self.count = count
|
||
}
|
||
}
|
||
|
||
struct GroupMemberDirectorySection {
|
||
let title: String
|
||
let members: [GroupMemberModel]
|
||
}
|
||
|
||
extension GroupMemberDirectorySection: SectionModelType {
|
||
typealias Item = GroupMemberModel
|
||
|
||
init(original: GroupMemberDirectorySection, items: [GroupMemberModel]) {
|
||
self.init(title: original.title, members: items)
|
||
}
|
||
|
||
var items: [GroupMemberModel] { members }
|
||
}
|
||
|
||
final class GroupMemberListVM {
|
||
|
||
struct Output {
|
||
let directoryItems: Observable<[GroupMemberDirectorySection]>
|
||
}
|
||
|
||
let groupKey: String
|
||
let output: Output
|
||
|
||
private let directoryItemsRelay = BehaviorRelay<[GroupMemberDirectorySection]>(value: [])
|
||
private var owner: GroupMemberModel?
|
||
private var members: [GroupMemberModel] = []
|
||
private var searchKeyword = ""
|
||
|
||
init(groupKey: String) {
|
||
self.groupKey = groupKey
|
||
output = Output(directoryItems: directoryItemsRelay.asObservable())
|
||
}
|
||
|
||
func loadData(group: GroupInfoModel, members: [GroupMemberModel]) {
|
||
let sortedMembers = GroupMemberSorter.sorted(
|
||
members,
|
||
groupKey: group.group_key,
|
||
currentUserId: AppContextManager.shared.userId
|
||
)
|
||
let owner = resolvedOwner(group: group, members: sortedMembers)
|
||
self.owner = owner
|
||
self.members = sortedMembers.filter { $0.user_id != owner?.user_id }
|
||
publishDirectory()
|
||
}
|
||
|
||
func updateSearchKeyword(_ keyword: String) {
|
||
searchKeyword = keyword.trimmingCharacters(in: .whitespacesAndNewlines)
|
||
publishDirectory()
|
||
}
|
||
|
||
private func resolvedOwner(group: GroupInfoModel, members: [GroupMemberModel]) -> GroupMemberModel? {
|
||
members.first {
|
||
GroupOwnerMatcher.matches(userId: $0.user_id, groupKey: group.group_key)
|
||
}
|
||
}
|
||
|
||
private func publishDirectory() {
|
||
let matches: (GroupMemberModel) -> Bool = { [searchKeyword] member in
|
||
searchKeyword.isEmpty || member.nick_name.localizedCaseInsensitiveContains(searchKeyword)
|
||
}
|
||
|
||
var sections: [GroupMemberDirectorySection] = []
|
||
if let owner, matches(owner) {
|
||
sections.append(GroupMemberDirectorySection(title: "圈主(1人)", members: [owner]))
|
||
}
|
||
|
||
let visibleMembers = members.filter(matches)
|
||
if !visibleMembers.isEmpty {
|
||
sections.append(GroupMemberDirectorySection(title: "圈成员(\(visibleMembers.count)人)", members: visibleMembers))
|
||
}
|
||
|
||
directoryItemsRelay.accept(sections)
|
||
}
|
||
}
|