// // SearchLocationResultView.swift // QuickLocation // import UIKit class SearchLocationResultView: UIView { let headerView = SearchLocationHeaderView() var onSelectGroup: ((String) -> Void)? private var chipButtons: [UIButton] = [] private var selectedGroupKey: String = "" private var chipHeightConstraint: NSLayoutConstraint? private var chipTopConstraint: NSLayoutConstraint? private func setupUI() { addSubview(navBgView) addSubview(navView) addSubview(scrollView) addSubview(actionBtn) actionBtn.layoutChain .edgesHorzontal(20) .height(56) .bottom(kSafeBottomMargin + 12) navBgView.layoutChain .edges(excludingEdge: .bottom) .heightToWidth(160 / 375) navView.layoutChain .edges(excludingEdge: .bottom) .height(kNaviHeight) scrollView.layoutChain .topToBottomOfView(navView) .edges(excludingEdge: .top) } func configureResult(status: String, disclaimer: String, showWarning: Bool, showGroups: Bool) { statusPillLab.text = status disclaimerLab.text = disclaimer disclaimerLab.textAlignment = showWarning ? .left : .center disclaimerIcon.isHidden = !showWarning disclaimerRow.alignment = showWarning ? .top : .center chipScrollView.isHidden = !showGroups chipTopConstraint?.constant = showGroups ? 16 : 0 chipHeightConstraint?.constant = showGroups ? 32 : 0 } func reloadGroups(_ groups: [GroupInfoModel], selectedKey: String) { selectedGroupKey = selectedKey chipButtons.forEach { $0.removeFromSuperview() } chipButtons.removeAll() chipStack.arrangedSubviews.forEach { $0.removeFromSuperview() } for group in groups { let btn = makeChip(title: group.name, groupKey: group.group_key) applyChipStyle(btn, selected: group.group_key == selectedKey) chipStack.addArrangedSubview(btn) chipButtons.append(btn) } } var currentGroupKey: String { selectedGroupKey } func updateSubViews() { normalResultContentView.isHidden = false } lazy var navBgView: UIImageView = { let iv = UIImageView() iv.image = UIImage(named: "Common/navBar_bg_2") iv.contentMode = .scaleAspectFill iv.isHidden = true return iv }() lazy var navView: BaseNavigationView = { BaseNavigationView(title: " ") }() lazy var scrollView: UIScrollView = { let view = UIScrollView() view.backgroundColor = .clear view.showsVerticalScrollIndicator = false view.bounces = false let contentView = UIView() contentView.backgroundColor = .clear view.addSubview(contentView) contentView.layoutChain.edges().widthToView(view) contentView.addSubview(headerView) headerView.layoutChain.top(12).edgesHorzontal() contentView.addSubview(resultCard) resultCard.layoutChain .topToBottomOfView(headerView, offset: 34) .edgesHorzontal(20) contentView.addSubview(areaBadgeView) areaBadgeView.layoutChain .topToView(resultCard, offset: -15) .centerX(contentView, offset: 70) .width(74) .height(30) .bottom() return view }() lazy var resultCard: UIView = { let card = UIView() card.backgroundColor = UIColor(hexStr: "#EFFAFF") card.cornerRadius = 28 card.addSubview(normalResultContentView) normalResultContentView.layoutChain .top(22) .edgesHorzontal() .bottom() return card }() private lazy var areaBadgeView: UIImageView = { let iv = UIImageView(image: UIImage(named: "SearchLocation/area_badge")) iv.contentMode = .scaleAspectFit return iv }() private lazy var normalResultContentView: UIView = { let contentView = UIView() let locationRow = UIView() contentView.addSubview(locationRow) let pinIcon = UIImageView(image: UIImage(named: "Home/member_location")) pinIcon.contentMode = .scaleAspectFit locationRow.addSubview(pinIcon) locationRow.addSubview(phoneAreaLab) pinIcon.layoutChain.left().centerY().width(18).height(18) phoneAreaLab.layoutChain .leftToRightOfView(pinIcon, offset: 6) .right() .top() .bottom() locationRow.layoutChain.top().centerX() let pillContainer = UIView() pillContainer.backgroundColor = .white pillContainer.cornerRadius = 16 contentView.addSubview(pillContainer) pillContainer.addSubview(statusPillLab) statusPillLab.layoutChain.edgesHorzontal(12).edgesVertical(14) pillContainer.layoutChain .topToBottomOfView(locationRow, offset: 14) .edgesHorzontal(16) .height(48) contentView.addSubview(disclaimerRow) disclaimerRow.layoutChain .topToBottomOfView(pillContainer, offset: 12) .edgesHorzontal(20) contentView.addSubview(chipScrollView) chipScrollView.translatesAutoresizingMaskIntoConstraints = false chipTopConstraint = chipScrollView.topAnchor.constraint(equalTo: disclaimerRow.bottomAnchor, constant: 16) chipHeightConstraint = chipScrollView.heightAnchor.constraint(equalToConstant: 32) NSLayoutConstraint.activate([ chipTopConstraint!, chipHeightConstraint!, chipScrollView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), chipScrollView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), chipScrollView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20) ]) return contentView }() lazy var phoneAreaLab: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 18, weight: .bold) label.textColor = UIColor(hexStr: "#293445") return label }() lazy var statusPillLab: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 16, weight: .medium) label.textColor = UIColor(hexStr: "#16B3FF") label.textAlignment = .center return label }() private lazy var disclaimerIcon: UIImageView = { let iv = UIImageView(image: UIImage(named: "SearchLocation/warning")) iv.contentMode = .scaleAspectFit iv.layoutChain.width(12).height(12) return iv }() lazy var disclaimerLab: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 12, weight: .regular) label.textColor = UIColor(hexStr: "#999999") label.numberOfLines = 0 return label }() private lazy var disclaimerRow: UIStackView = { let stack = UIStackView(arrangedSubviews: [disclaimerIcon, disclaimerLab]) stack.axis = .horizontal stack.alignment = .top stack.spacing = 4 return stack }() lazy var actionBtn: UIButton = { let btn = UIButton(type: .custom) btn.setTitleColor(.white, for: .normal) btn.titleLabel?.font = FontManager.boboBold(18) btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal) btn.cornerRadius = 20 btn.isHidden = true return btn }() var inviteBtn: UIButton { actionBtn } private lazy var chipScrollView: UIScrollView = { let view = UIScrollView() view.showsHorizontalScrollIndicator = false view.alwaysBounceHorizontal = true view.addSubview(chipStack) chipStack.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ chipStack.topAnchor.constraint(equalTo: view.contentLayoutGuide.topAnchor), chipStack.leadingAnchor.constraint(equalTo: view.contentLayoutGuide.leadingAnchor), chipStack.bottomAnchor.constraint(equalTo: view.contentLayoutGuide.bottomAnchor), chipStack.trailingAnchor.constraint(equalTo: view.contentLayoutGuide.trailingAnchor), chipStack.heightAnchor.constraint(equalTo: view.frameLayoutGuide.heightAnchor) ]) return view }() private lazy var chipStack: UIStackView = { let stack = UIStackView() stack.axis = .horizontal stack.spacing = 8 stack.alignment = .fill return stack }() private func makeChip(title: String, groupKey: String) -> UIButton { let btn = UIButton(type: .custom) btn.setTitle(title, for: .normal) btn.titleLabel?.font = .systemFont(ofSize: 13, weight: .medium) btn.contentEdgeInsets = UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12) btn.layer.cornerRadius = 8 btn.layer.borderWidth = 1 btn.accessibilityIdentifier = groupKey btn.addTarget(self, action: #selector(tapChip(_:)), for: .touchUpInside) btn.setContentHuggingPriority(.required, for: .horizontal) btn.setContentCompressionResistancePriority(.required, for: .horizontal) return btn } private func applyChipStyle(_ btn: UIButton, selected: Bool) { if selected { btn.setTitleColor(UIColor(hexStr: "#16B3FF"), for: .normal) btn.backgroundColor = .white btn.layer.borderColor = UIColor(hexStr: "#16B3FF").cgColor } else { btn.setTitleColor(UIColor(hexStr: "#C0C4CC"), for: .normal) btn.backgroundColor = UIColor(hexStr: "#F2F3F5") btn.layer.borderColor = UIColor.clear.cgColor } } @objc private func tapChip(_ sender: UIButton) { let key = sender.accessibilityIdentifier ?? "" selectedGroupKey = key for btn in chipButtons { applyChipStyle(btn, selected: btn === sender) } onSelectGroup?(key) } override init(frame: CGRect) { super.init(frame: .zero) backgroundColor = .white setupUI() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }