// // LNPotentialUserViewController.swift // Gami // // Created by OneeChan on 2026/3/10. // import Foundation import UIKit import SnapKit import MJRefresh extension UIView { func pushToPotentialUsers() { let vc = LNPotentialUserViewController() navigationController?.pushViewController(vc, animated: true) } } class LNPotentialUserViewController: LNViewController { private let emptyView = LNNoMoreDataView() private let tableView = UITableView() private var users: [LNPotentialUserVO] = [] private var isLoading = false override func viewDidLoad() { super.viewDidLoad() setupViews() tableView.mj_header?.beginRefreshing() } } extension LNPotentialUserViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { users.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell( withIdentifier: LNPotentialUserItemCell.className, for: indexPath ) as! LNPotentialUserItemCell let item = users[indexPath.row] cell.update(item) return cell } } extension LNPotentialUserViewController { private func setupViews() { title = .init(key: "B00116") emptyView.isHidden = true view.addSubview(emptyView) emptyView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.centerY.equalToSuperview().multipliedBy(0.6) } let header = MJRefreshNormalHeader { [weak self] in guard let self else { return } self.loadList() } header.lastUpdatedTimeLabel?.isHidden = true header.stateLabel?.isHidden = true tableView.mj_header = header tableView.dataSource = self tableView.separatorStyle = .none tableView.showsVerticalScrollIndicator = false tableView.backgroundColor = .clear tableView.allowsSelection = false tableView.register(LNPotentialUserItemCell.self, forCellReuseIdentifier: LNPotentialUserItemCell.className) view.addSubview(tableView) tableView.snp.makeConstraints { make in make.edges.equalToSuperview() } } private func loadList() { guard !isLoading else { return } isLoading = true LNGameMateManager.shared.getPotentialUsers { [weak self] res in guard let self else { return } isLoading = false if let list = res?.list { users = list tableView.reloadData() if users.isEmpty { emptyView.showNoData(tips: .init(key: "B00124")) } else { emptyView.hide() } } else { if users.isEmpty { emptyView.showNetworkError() } } tableView.mj_header?.endRefreshing() } } } private class LNPotentialUserItemCell: UITableViewCell { private let avatar = UIImageView() private let onlineView = LNOnlineView() private let nameLabel = UILabel() private let genderView = LNGenderView() private let newTag = UIView() private let chatButton = UIButton() private var curItem: LNPotentialUserVO? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupViews() LNEventDeliver.addObserver(self) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func update(_ item: LNPotentialUserVO) { avatar.showAvatar(item.avatar) nameLabel.text = item.nickname genderView.update(item.gender, item.age) newTag.isHidden = !item.newRegister onlineView.isHidden = !item.online if item.contacted { chatButton.setTitle(.init(key: "B00117"), for: .normal) } else { chatButton.setTitle(.init(key: "B00123"), for: .normal) } curItem = item } } extension LNPotentialUserItemCell: LNIMChatViewModelNotify { func onIMDidSendMessage(to uid: String) { guard let curItem, uid == curItem.userNo else { return } curItem.contacted = true update(curItem) } } private extension LNPotentialUserItemCell { func setupViews() { backgroundColor = .clear selectionStyle = .none let container = UIView() container.onTap { [weak self] in guard let self else { return } guard let curItem else { return } pushToProfile(uid: curItem.userNo) } contentView.addSubview(container) container.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(16) make.top.equalToSuperview().offset(16) make.bottom.equalToSuperview().offset(4) } avatar.layer.cornerRadius = 20 avatar.clipsToBounds = true container.addSubview(avatar) avatar.snp.makeConstraints { make in make.verticalEdges.equalToSuperview().inset(10) make.leading.equalToSuperview().offset(5) make.width.height.equalTo(40) } onlineView.offset = 5 container.addSubview(onlineView) onlineView.snp.makeConstraints { make in make.edges.equalTo(avatar).inset(-1) } let infoView = UIStackView() infoView.axis = .vertical infoView.spacing = 4 infoView.isUserInteractionEnabled = false infoView.alignment = .leading container.addSubview(infoView) infoView.snp.makeConstraints { make in make.leading.equalTo(avatar.snp.trailing).offset(13) make.centerY.equalToSuperview() } let nameContainer = UIView() infoView.addArrangedSubview(nameContainer) nameLabel.font = .heading_h4 nameLabel.textColor = .text_5 nameContainer.addSubview(nameLabel) nameLabel.snp.makeConstraints { make in make.leading.verticalEdges.equalToSuperview() } nameContainer.addSubview(genderView) genderView.snp.makeConstraints { make in make.leading.equalTo(nameLabel.snp.trailing).offset(4) make.centerY.equalTo(nameLabel) make.trailing.lessThanOrEqualToSuperview() } newTag.layer.cornerRadius = 7.5 newTag.clipsToBounds = true newTag.backgroundColor = .primary_3 infoView.addArrangedSubview(newTag) let newLabel = UILabel() newLabel.text = "New" newLabel.font = .body_xs newLabel.textColor = .text_1 newTag.addSubview(newLabel) newLabel.snp.makeConstraints { make in make.verticalEdges.equalToSuperview().inset(0.5) make.horizontalEdges.equalToSuperview().inset(6) } chatButton.setBackgroundImage(.primary_7, for: .normal) chatButton.setTitle(.init(key: "B00123"), for: .normal) chatButton.titleLabel?.font = .heading_h5 chatButton.setTitleColor(.text_1, for: .normal) chatButton.layer.cornerRadius = 11 chatButton.clipsToBounds = true chatButton.backgroundColor = .fill_2 chatButton.contentEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16) chatButton.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } guard let curItem else { return } LNGameMateManager.shared.fetchAutoReplyQuota(uid: curItem.userNo) { [weak self] canSend in guard let self else { return } guard canSend else { return } pushToChat(uid: curItem.userNo, scene: .autoReply) } }), for: .touchUpInside) container.addSubview(chatButton) chatButton.snp.makeConstraints { make in make.trailing.equalToSuperview() make.centerY.equalToSuperview() make.height.equalTo(22) } } }