// // LNOrderRoomInviteSeatPanel.swift // Gami // // Created by OneeChan on 2026/3/20. // import Foundation import UIKit import SnapKit import MJRefresh class LNOrderRoomInviteSeatPanel: LNPopupView { private let countLabel = UILabel() private let filterButton = UIButton() private let tableView = UITableView(frame: .zero, style: .plain) private let emptyView = LNNoMoreDataView() private weak var roomSession: LNOrderRoomViewModel? private var curSeat: LNRoomSeatItem? private var items: [LNRoomUserListItemVO] = [] private var nextTag: String? = nil private var categories: [LNGameCategoryItemVO] = [] private var curCategoryCode: String = "" private var curCategoryTitle: String = .init(key: "A00361") override init(frame: CGRect) { super.init(frame: frame) containerHeight = .percent(0.62) setupViews() } func update(_ seat: LNRoomSeatItem, room: LNOrderRoomViewModel?) { curSeat = seat roomSession = room loadList() if seat.index == LNOrderRoomSeatNum.guest.rawValue { filterButton.isHidden = true } else { filterButton.isHidden = false loadCategory() } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNOrderRoomInviteSeatPanel { private func loadList() { guard let roomSession else { return } roomSession.getRoomUserList(next: nextTag, playmete: curSeat?.index != LNOrderRoomSeatNum.guest.rawValue, filter: curCategoryCode) { [weak self] res in guard let self else { return } if let list = res?.list { if nextTag == nil { items.removeAll() } items.append(contentsOf: list) nextTag = res?.next tableView.reloadData() if items.isEmpty { emptyView.showNoData() } else { emptyView.hide() } } else { if items.isEmpty { emptyView.showNetworkError() } } tableView.mj_header?.endRefreshing() if nextTag?.isEmpty != false { tableView.mj_footer?.endRefreshingWithNoMoreData() } else { tableView.mj_footer?.endRefreshing() } if let total = res?.total { countLabel.text = .init(key: "A00334", total) } } } private func loadCategory() { roomSession?.getPlaymateCategory { [weak self] res in guard let self else { return } guard let res else { return } categories = res.list } } } extension LNOrderRoomInviteSeatPanel: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell( withIdentifier: LNOrderRoomInviteSeatCell.className, for: indexPath ) as! LNOrderRoomInviteSeatCell cell.update(room: roomSession, seat: curSeat, item: items[indexPath.row], index: indexPath.row + 1) return cell } } private extension LNOrderRoomInviteSeatPanel { func setupViews() { container.backgroundColor = .fill_7 let countView = buildHeader() container.addSubview(countView) countView.snp.makeConstraints { make in make.top.equalToSuperview() make.horizontalEdges.equalToSuperview().inset(16) } let header = MJRefreshNormalHeader { [weak self] in guard let self else { return } nextTag = nil loadList() } header.lastUpdatedTimeLabel?.isHidden = true header.stateLabel?.isHidden = true tableView.mj_header = header let footer = MJRefreshAutoNormalFooter { [weak self] in guard let self else { return } loadList() } footer.setTitle("", for: .noMoreData) footer.setTitle(.init(key: "A00046"), for: .idle) tableView.mj_footer = footer tableView.backgroundColor = .clear tableView.separatorStyle = .none tableView.showsVerticalScrollIndicator = false tableView.showsHorizontalScrollIndicator = false tableView.allowsSelection = false tableView.dataSource = self tableView.delegate = self tableView.register(LNOrderRoomInviteSeatCell.self, forCellReuseIdentifier: LNOrderRoomInviteSeatCell.className) container.addSubview(tableView) tableView.snp.makeConstraints { make in make.top.equalTo(countView.snp.bottom) make.horizontalEdges.equalToSuperview() make.bottom.equalToSuperview().offset(commonBottomInset) } emptyView.isHidden = true emptyView.tipsLabel.textColor = .text_2 tableView.addSubview(emptyView) emptyView.snp.makeConstraints { make in make.center.equalToSuperview() } updateFilterView() } func buildHeader() -> UIView { let container = UIView() container.snp.makeConstraints { make in make.height.equalTo(52) } let stackView = UIStackView() stackView.axis = .horizontal stackView.spacing = 5 stackView.alignment = .center container.addSubview(stackView) stackView.snp.makeConstraints { make in make.leading.centerY.equalToSuperview() } countLabel.font = .body_m countLabel.textColor = .text_6 container.addSubview(countLabel) stackView.addArrangedSubview(countLabel) let countDescLabel = UILabel() countDescLabel.font = .body_m countDescLabel.textColor = .text_1 countDescLabel.text = .init(key: "A00369") stackView.addArrangedSubview(countDescLabel) let config = UIImage.SymbolConfiguration(pointSize: 12) filterButton.backgroundColor = .fill.withAlphaComponent(0.15) filterButton.layer.cornerRadius = 15 filterButton.clipsToBounds = true filterButton.titleLabel?.font = .body_s filterButton.setTitleColor(.text_1, for: .normal) filterButton.setImage(.init(systemName: "chevron.backward", withConfiguration: config), for: .normal) filterButton.tintColor = .text_1 filterButton.semanticContentAttribute = .forceRightToLeft filterButton.imageEdgeInsets = .init(top: 0, left: 4, bottom: 0, right: -4) filterButton.contentEdgeInsets = .init(top: 0, left: 12, bottom: 0, right: 12) filterButton.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } let panel = LNOrderRoomGameCategoryFilterPanel() let options = buildCategoryFilterOptions() panel.update(options: options, curSelectedCode: curCategoryCode) panel.handler = { [weak self] option in guard let self else { return } curCategoryCode = option.code curCategoryTitle = option.code.isEmpty ? .init(key: "A00361") : option.name updateFilterView() nextTag = nil tableView.mj_header?.beginRefreshing() } panel.popup(self) }), for: .touchUpInside) container.addSubview(filterButton) filterButton.snp.makeConstraints { make in make.centerY.trailing.equalToSuperview() make.height.equalTo(30) } return container } func buildCategoryFilterOptions() -> [LNGameCategoryItemVO] { var options: [LNGameCategoryItemVO] = [] options.append(.init(code: "", name: .init(key: "A00360"), icon: "", categoryType: .normal)) options.append(contentsOf: categories) return options } func updateFilterView() { filterButton.setTitle(curCategoryTitle, for: .normal) } }