// // LNGameMateCenterViewController.swift // Gami // // Created by OneeChan on 2026/1/22. // import Foundation import UIKit import SnapKit extension UIView { func pushToMateCenter() { let vc = LNGameMateCenterViewController() navigationController?.pushViewController(vc, animated: true) } } class LNGameMateCenterViewController: LNViewController { private let incomeLabel = UILabel() private let exposureLabel = UILabel() private let visitorLabel = UILabel() private let statusButton = UIButton() private let statusLabel = UILabel() private let statusDescLabel = UILabel() private let skillStackView = UIStackView() override func viewDidLoad() { super.viewDidLoad() setupViews() LNEventDeliver.addObserver(self) onUserInfoChanged(userInfo: myUserInfo) onGameMateManagerInfoChanged() } } extension LNGameMateCenterViewController: LNProfileManagerNotify, LNGameMateManagerNotify { func onUserInfoChanged(userInfo: LNUserProfileVO) { guard userInfo.userNo.isMyUid else { return } skillStackView.arrangedSubviews.forEach { skillStackView.removeArrangedSubview($0) $0.removeFromSuperview() } skillStackView.superview?.isHidden = userInfo.skills.isEmpty for skill in userInfo.skills { let view = buildSkillItem(skill) skillStackView.addArrangedSubview(view) } } func onGameMateManagerInfoChanged() { guard let myGameMateInfo else { return } incomeLabel.text = myGameMateInfo.weekBeanIncome.toDisplay exposureLabel.text = "\(myGameMateInfo.exposureCountDay)" visitorLabel.text = "\(myGameMateInfo.potentialUserCount)" if myGameMateInfo.playmateOpen { statusButton.setBackgroundImage(.primary_7, for: .normal) statusLabel.text = .init(key: "B00087") statusDescLabel.text = .init(key: "B00088") } else { statusButton.setBackgroundImage(.primary_8, for: .normal) statusLabel.text = .init(key: "B00089") statusDescLabel.text = .init(key: "B00090") } } } extension LNGameMateCenterViewController { private func setupViews() { navigationBarColor = .clear view.backgroundColor = .primary_1 title = .init(key: "B00071") let topCover = UIImageView() topCover.image = .icHomeTopBg topCover.backgroundColor = .primary_1 view.addSubview(topCover) topCover.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalTo(fakeNaviBgView) } let scrollView = UIScrollView() scrollView.showsVerticalScrollIndicator = false scrollView.showsHorizontalScrollIndicator = false scrollView.contentInset = .init(top: 0, left: 0, bottom: -view.commonBottomInset, right: 0) view.addSubview(scrollView) scrollView.snp.makeConstraints { make in make.verticalEdges.equalToSuperview() make.horizontalEdges.equalToSuperview().inset(16) } let stackView = UIStackView() stackView.axis = .vertical stackView.spacing = 12 scrollView.addSubview(stackView) stackView.snp.makeConstraints { make in make.edges.equalToSuperview() make.width.equalToSuperview() } stackView.addArrangedSubview(buildRecordInfos()) stackView.addArrangedSubview(buildSkillList()) stackView.addArrangedSubview(buildOrderRecord()) } private func buildRecordInfos() -> UIView { let container = UIView() container.layer.cornerRadius = 12 container.backgroundColor = .fill let stackView = UIStackView() stackView.axis = .vertical stackView.spacing = 20 container.addSubview(stackView) stackView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(10) make.verticalEdges.equalToSuperview().inset(20) } stackView.addArrangedSubview(buildIncome()) stackView.addArrangedSubview(buildDataView()) stackView.addArrangedSubview(buildOpenButton()) return container } private func buildIncome() -> UIView { let container = UIView() container.onTap { [weak self] in guard let self else { return } view.pushToBeanView() } let incomeView = UIView() incomeView.isUserInteractionEnabled = false container.addSubview(incomeView) incomeView.snp.makeConstraints { make in make.top.equalToSuperview() make.centerX.equalToSuperview() } let beanIc = UIImageView.beanImageView() incomeView.addSubview(beanIc) beanIc.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalToSuperview() make.width.height.equalTo(28) } incomeLabel.text = "0" incomeLabel.font = .systemFont(ofSize: 30, weight: .semibold) incomeLabel.textColor = .text_5 incomeView.addSubview(incomeLabel) incomeLabel.snp.makeConstraints { make in make.verticalEdges.equalToSuperview() make.leading.equalTo(beanIc.snp.trailing) make.trailing.equalToSuperview() } let descView = UIView() descView.isUserInteractionEnabled = false container.addSubview(descView) descView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.top.equalTo(incomeView.snp.bottom).offset(4) make.bottom.equalToSuperview() } let descLabel = UILabel() descLabel.text = .init(key: "B00072") descLabel.font = .body_m descLabel.textColor = .text_5 descView.addSubview(descLabel) descLabel.snp.makeConstraints { make in make.leading.equalToSuperview() make.verticalEdges.equalToSuperview() } let arrow = UIImageView.arrowImageView(size: 12) arrow.tintColor = .text_4 descView.addSubview(arrow) arrow.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview() make.leading.equalTo(descLabel.snp.trailing).offset(4) } return container } private func buildDataView() -> UIView { let container = UIView() let stackView = UIStackView() stackView.axis = .horizontal stackView.distribution = .fillEqually container.addSubview(stackView) stackView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(5) make.verticalEdges.equalToSuperview() } stackView.addArrangedSubview(buildDataItemView(.init(key: "B00073"), contentLabel: exposureLabel, showArrow: false)) let visitorView = buildDataItemView(.init(key: "B00116"), contentLabel: visitorLabel) visitorView.onTap { [weak self] in guard let self else { return } view.pushToPotentialUsers() } stackView.addArrangedSubview(visitorView) let line = buildLine() stackView.addSubview(line) line.snp.makeConstraints { make in make.center.equalToSuperview() } return container } private func buildDataItemView(_ title: String, contentLabel: UILabel, showArrow: Bool = true) -> UIView { let container = UIView() contentLabel.text = "0" contentLabel.font = .heading_h2 contentLabel.textColor = .text_5 container.addSubview(contentLabel) contentLabel.snp.makeConstraints { make in make.top.equalToSuperview() make.centerX.equalToSuperview() } let descView = UIView() container.addSubview(descView) descView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.top.equalTo(contentLabel.snp.bottom).offset(6) make.bottom.equalToSuperview() } let descLabel = UILabel() descLabel.text = title descLabel.font = .body_s descLabel.textColor = .text_4 descView.addSubview(descLabel) descLabel.snp.makeConstraints { make in make.leading.equalToSuperview() make.verticalEdges.equalToSuperview() if !showArrow { make.trailing.equalToSuperview() } } if showArrow { let arrow = UIImageView.arrowImageView(size: 10) arrow.tintColor = .text_4 descView.addSubview(arrow) arrow.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview() make.leading.equalTo(descLabel.snp.trailing).offset(4) } } return container } private func buildOpenButton() -> UIView { statusButton.layer.cornerRadius = 26 statusButton.clipsToBounds = true statusButton.setBackgroundImage(.primary_8, for: .normal) statusButton.addAction(UIAction(handler: { _ in showLoading() let isOpen = myGameMateInfo?.playmateOpen == true LNGameMateManager.shared.enableGameMate(open: !isOpen) { success in dismissLoading() } }), for: .touchUpInside) statusButton.snp.makeConstraints { make in make.height.equalTo(56) } let container = UIView() container.isUserInteractionEnabled = false statusButton.addSubview(container) container.snp.makeConstraints { make in make.center.equalToSuperview() make.leading.greaterThanOrEqualToSuperview().offset(16) } statusLabel.font = .heading_h3 statusLabel.textColor = .text_1 statusLabel.textAlignment = .center container.addSubview(statusLabel) statusLabel.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalToSuperview() } statusDescLabel.font = .body_xs statusDescLabel.textColor = .primary_1 container.addSubview(statusDescLabel) statusDescLabel.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.bottom.equalToSuperview() make.top.equalTo(statusLabel.snp.bottom) } return statusButton } private func buildLine() -> UIView { let line = UIView() line.backgroundColor = .init(hex: "#D9D9D9") line.snp.makeConstraints { make in make.width.equalTo(1) make.height.equalTo(37) } return line } private func buildSkillList() -> UIView { let container = UIView() container.layer.cornerRadius = 12 container.backgroundColor = .fill let stackView = UIStackView() stackView.axis = .vertical container.addSubview(stackView) stackView.snp.makeConstraints { make in make.edges.equalToSuperview() } let header = buildSkillHeader() stackView.addArrangedSubview(header) let skillContainer = UIView() stackView.addArrangedSubview(skillContainer) skillStackView.axis = .vertical skillStackView.spacing = 8 skillContainer.addSubview(skillStackView) skillStackView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(12) make.top.equalToSuperview().offset(4) make.bottom.equalToSuperview().offset(-12) } return container } private func buildSkillHeader() -> UIView { let container = UIView() container.onTap { [weak self] in guard let self else { return } view.pushToSkillManager() } container.snp.makeConstraints { make in make.height.equalTo(40) } let titleLabel = UILabel() titleLabel.text = .init(key: "B00075") titleLabel.font = .heading_h3 titleLabel.textColor = .text_5 container.addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalToSuperview().offset(16) } let arrow = UIImageView.arrowImageView(size: 12) arrow.tintColor = .text_4 container.addSubview(arrow) arrow.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview().offset(-16) } return container } private func buildSkillItem(_ skill: LNGameMateSkillVO) -> UIView { let container = UIView() container.layer.cornerRadius = 12 container.layer.borderColor = .fill_4 container.layer.borderWidth = 1 container.snp.makeConstraints { make in make.height.equalTo(54) } let ic = UIImageView() ic.sd_setImage(with: URL(string: skill.icon)) container.addSubview(ic) ic.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalToSuperview().offset(10) make.width.height.equalTo(50) } let priceView = UIView() container.addSubview(priceView) priceView.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview().offset(-10) } let coin = UIImageView.coinImageView() priceView.addSubview(coin) coin.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalToSuperview() make.width.height.equalTo(16) } let priceLabel = UILabel() priceLabel.text = skill.price.toDisplay priceLabel.font = .heading_h4 priceLabel.textColor = .text_5 priceView.addSubview(priceLabel) priceLabel.snp.makeConstraints { make in make.verticalEdges.equalToSuperview() make.leading.equalTo(coin.snp.trailing).offset(1) } let unitLabel = UILabel() unitLabel.text = "/\(skill.unit)" unitLabel.font = .body_s unitLabel.textColor = .text_4 priceView.addSubview(unitLabel) unitLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(priceLabel.snp.trailing).offset(1) make.trailing.equalToSuperview() } let nameLabel = UILabel() nameLabel.text = skill.name nameLabel.font = .heading_h4 nameLabel.textColor = .text_5 nameLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) nameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) container.addSubview(nameLabel) nameLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(ic.snp.trailing).offset(4) make.trailing.lessThanOrEqualTo(priceView.snp.leading).offset(-20) } return container } private func buildOrderRecord() -> UIView { let container = UIView() container.layer.cornerRadius = 12 container.backgroundColor = .fill container.onTap { [weak self] in guard let self else { return } view.pushToOrderRecord() } container.snp.makeConstraints { make in make.height.equalTo(40) } let titleLabel = UILabel() titleLabel.text = .init(key: "A00209") titleLabel.font = .heading_h3 titleLabel.textColor = .text_5 container.addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalToSuperview().offset(16) } let arrow = UIImageView.arrowImageView(size: 12) arrow.tintColor = .text_4 container.addSubview(arrow) arrow.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview().offset(-16) } return container } }