// // LNUserSearchRoomListView.swift // Lanu // // Created by OpenAI Codex on 2026/3/19. // import Foundation import UIKit import SnapKit import MJRefresh final class LNUserSearchRoomListView: UIView { private let emptyView = LNNoMoreDataView() private var items: [LNRoomItemVO] = [] private var curKeyword: String? = nil private var nextTag: String? = nil private let collectionView: UICollectionView override init(frame: CGRect) { let width = (UIScreen.main.bounds.width - 16 * 2 - 13) * 0.5 let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical layout.minimumLineSpacing = 16 layout.minimumInteritemSpacing = 13 layout.itemSize = .init(width: width, height: width * 204 / 165) self.collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) super.init(frame: frame) setupViews() } func search(keyword: String) { curKeyword = keyword nextTag = nil items.removeAll() collectionView.reloadData() emptyView.hide() collectionView.mj_footer?.resetNoMoreData() collectionView.mj_header?.beginRefreshing() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNUserSearchRoomListView { private func searchRoom() { guard let curKeyword, !curKeyword.isEmpty else { collectionView.mj_header?.endRefreshing() collectionView.mj_footer?.endRefreshingWithNoMoreData() return } collectionView.isHidden = false LNRoomManager.shared.searchRoom(keyword: curKeyword, next: nextTag) { [weak self] res in guard let self else { return } guard let list = res?.list else { collectionView.mj_header?.endRefreshing() collectionView.mj_footer?.endRefreshingWithNoMoreData() if items.isEmpty { emptyView.showNetworkError() } return } if nextTag?.isEmpty != false { items = list } else { items.append(contentsOf: list) } nextTag = res?.next collectionView.reloadData() if items.isEmpty { emptyView.showNoData(tips: .init(key: "A00244")) } else { emptyView.hide() } collectionView.mj_header?.endRefreshing() if res?.next.isEmpty != false { collectionView.mj_footer?.endRefreshingWithNoMoreData() } else { collectionView.mj_footer?.endRefreshing() } } } } extension LNUserSearchRoomListView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { items.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell( withReuseIdentifier: LNUserSearchRoomCardCell.className, for: indexPath ) as! LNUserSearchRoomCardCell cell.update(items[indexPath.item]) return cell } } extension LNUserSearchRoomListView { private func setupViews() { backgroundColor = .primary_1 let header = MJRefreshNormalHeader { [weak self] in guard let self else { return } nextTag = nil searchRoom() } header.lastUpdatedTimeLabel?.isHidden = true header.stateLabel?.isHidden = true collectionView.mj_header = header let footer = MJRefreshAutoNormalFooter { [weak self] in guard let self else { return } searchRoom() } footer.setTitle("", for: .noMoreData) footer.setTitle(.init(key: "A00046"), for: .idle) collectionView.mj_footer = footer collectionView.backgroundColor = .clear collectionView.showsVerticalScrollIndicator = false collectionView.showsHorizontalScrollIndicator = false collectionView.allowsSelection = false collectionView.dataSource = self collectionView.delegate = self collectionView.register(LNUserSearchRoomCardCell.self, forCellWithReuseIdentifier: LNUserSearchRoomCardCell.className) collectionView.contentInset = .init(top: 6, left: 0, bottom: -commonBottomInset, right: 0) addSubview(collectionView) collectionView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(16) make.verticalEdges.equalToSuperview() } collectionView.addSubview(emptyView) emptyView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.centerY.equalToSuperview().multipliedBy(0.6) } } } private final class LNUserSearchRoomCardCell: UICollectionViewCell { private let cardView = LNUserSearchRoomCardView() override init(frame: CGRect) { super.init(frame: frame) contentView.addSubview(cardView) cardView.snp.makeConstraints { make in make.edges.equalToSuperview() } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func update(_ item: LNRoomItemVO) { cardView.update(item) } }