// // LNCountrySelectPanel.swift // Gami // // Created by OneeChan on 2026/1/15. // import Foundation import UIKit import SnapKit class LNCountrySelectPanel: LNPopupView { private let tableView = UITableView(frame: .zero, style: .grouped) private var sections: [(code: String, list: [LNCountryCodeVO])] = [] private let sectionIndex = UIStackView() var handler: ((LNCountryCodeVO) -> Void)? override init(frame: CGRect) { super.init(frame: frame) setupViews() } func update(_ sections: [(code: String, list: [LNCountryCodeVO])]) { self.sections = sections tableView.reloadData() sectionIndex.arrangedSubviews.forEach { sectionIndex.removeArrangedSubview($0) $0.removeFromSuperview() } for (index, section) in sections.enumerated() { let item = buildSectionIndexItem(section.code) sectionIndex.addArrangedSubview(item) item.onTap { [weak self] in guard let self else { return } let indexPath = IndexPath(row: 0, section: index) tableView.scrollToRow(at: indexPath, at: .top, animated: false) } } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNCountrySelectPanel: UITableViewDataSource, UITableViewDelegate { func numberOfSections(in tableView: UITableView) -> Int { sections.count } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { sections[section].list.count } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 56 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: LNCountryCodeCell.className, for: indexPath) as! LNCountryCodeCell let item = sections[indexPath.section].list[indexPath.row] cell.update(item) return cell } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 30 } func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let container = UIView() let titleLabel = UILabel() titleLabel.font = .body_l titleLabel.textColor = .text_3 titleLabel.text = sections[section].code container.addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalToSuperview().offset(16) } return container } func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { 0 } func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { nil } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: false) let item = sections[indexPath.section].list[indexPath.row] dismiss() handler?(item) } } extension LNCountrySelectPanel { private func setupViews() { let titleView = buildTitleView() container.addSubview(titleView) titleView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalToSuperview() } let listView = buildListView() container.addSubview(listView) listView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalTo(titleView.snp.bottom) make.bottom.equalToSuperview() } let sectionIndex = buildSectionIndex() container.addSubview(sectionIndex) sectionIndex.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview() } let closeButton = UIButton() closeButton.setImage(.init(systemName: "xmark")?.withRenderingMode(.alwaysTemplate), for: .normal) closeButton.tintColor = .text_2 closeButton.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } dismiss() }), for: .touchUpInside) container.addSubview(closeButton) closeButton.snp.makeConstraints { make in make.top.equalToSuperview().offset(13) make.trailing.equalToSuperview().offset(-13) make.width.height.equalTo(24) } } private func buildTitleView() -> UIView { let container = UIView() container.snp.makeConstraints { make in make.height.equalTo(50) } let titleLabel = UILabel() titleLabel.text = .init(key: "B00024") titleLabel.font = .heading_h3 titleLabel.textColor = .text_5 container.addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.center.equalToSuperview() } return container } private func buildListView() -> UIView { tableView.dataSource = self tableView.delegate = self tableView.separatorStyle = .none tableView.backgroundColor = .fill tableView.register(LNCountryCodeCell.self, forCellReuseIdentifier: LNCountryCodeCell.className) tableView.contentInset = .init(top: 0, left: 0, bottom: -commonBottomInset, right: 0) return tableView } private func buildSectionIndex() -> UIView { sectionIndex.axis = .vertical sectionIndex.snp.makeConstraints { make in make.width.equalTo(32) make.height.equalTo(0).priority(.low) } return sectionIndex } private func buildSectionIndexItem(_ title: String) -> UIView { let container = UIView() container.backgroundColor = .fill container.snp.makeConstraints { make in make.width.equalTo(32) make.height.equalTo(30) } let label = UILabel() label.text = title label.font = .body_l label.textColor = .text_3 container.addSubview(label) label.snp.makeConstraints { make in make.center.equalToSuperview() } return container } } private class LNCountryCodeCell: UITableViewCell { private let icon = UIImageView() private let nameLabel = UILabel() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupViews() } func update(_ item: LNCountryCodeVO) { icon.sd_setImage(with: URL(string: item.icon)) nameLabel.text = "\(item.name) \(item.num)" } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupViews() { icon.layer.cornerRadius = 12 icon.clipsToBounds = true contentView.addSubview(icon) icon.snp.makeConstraints { make in make.leading.equalToSuperview().offset(16) make.centerY.equalToSuperview() make.width.height.equalTo(24) } nameLabel.font = .body_l nameLabel.textColor = .text_5 contentView.addSubview(nameLabel) nameLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(icon.snp.trailing).offset(12) } } } #if DEBUG import SwiftUI struct LNCountrySelectPanelPreview: UIViewRepresentable { func makeUIView(context: Context) -> some UIView { let container = UIView() container.backgroundColor = .lightGray let view = LNCountrySelectPanel() view.containerHeight = .percent(0.7) view.popup(container) return container } func updateUIView(_ uiView: UIViewType, context: Context) { } } #Preview(body: { LNCountrySelectPanelPreview() }) #endif