// // RemoveMemberViewModel.swift // QuickLocation // // Created by 八条 on 2026/6/12. // import RxSwift import RxCocoa import RxDataSources import ObjectMapper typealias RemoveMemberListSectionModel = SectionModel class RemoveMemberViewModel { let groupId: String var groupModel: GroupInfoModel? struct Output { var sectionedItems: Observable<[ReviewMemberListSectionModel]> } let output: Output private var disposeBag = DisposeBag() private let sectionedItems = PublishSubject<[ReviewMemberListSectionModel]>() private var list: [GroupMemberModel] = [] private var searchKeyword = "" var selectedMembers = BehaviorRelay<[String]>(value: []) lazy var cellAction: Action = { this in return Action { model in let memberId = model.user_id guard !GroupOwnerMatcher.matches(userId: memberId, groupKey: self.groupId) else { return .empty() } var current = this.selectedMembers.value if let idx = current.firstIndex(of: memberId) { current.remove(at: idx) } else { current.append(memberId) } this.selectedMembers.accept(current) self.emitItems() return .empty() } }(self) func isSelected(id: String) -> Bool { (self.selectedMembers.value.first(where: { $0 == id }) != nil) } func loadData(_ list: [GroupMemberModel]) { self.list = GroupMemberSorter.sorted( list, groupKey: groupId, currentUserId: AppContextManager.shared.userId ) selectedMembers.accept(selectedMembers.value.filter { selectedId in list.contains(where: { $0.user_id == selectedId }) }) emitItems() } func updateSearchKeyword(_ keyword: String) { searchKeyword = keyword.trimmingCharacters(in: .whitespacesAndNewlines) emitItems() } private func emitItems() { let items: [GroupMemberModel] if searchKeyword.isEmpty { items = list } else { items = list.filter { $0.nick_name.localizedCaseInsensitiveContains(searchKeyword) } } sectionedItems.onNext(items.mapSection()) } init(groupId: String) { self.groupId = groupId output = Output( sectionedItems: sectionedItems.asObservable() ) } }