// // LNSkillFieldPriceEditView.swift // Gami // // Created by OneeChan on 2026/1/25. // import Foundation import UIKit import SnapKit class LNSkillFieldPriceEditView: LNSkillFieldBaseEditView { private let curValueLabel = UILabel() override init(frame: CGRect) { super.init(frame: frame) setupViews() } override func update(_ field: LNSkillEditField) { super.update(field) if let text = field.value as? Double { curValueLabel.text = text.toDisplay } else { curValueLabel.text = "0" } } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNSkillFieldPriceEditView { private func setupViews() { container.backgroundColor = .fill_2 container.layer.cornerRadius = 19 container.onTap { [weak self] in guard let self else { return } guard let field else { return } let panel = LNSkillPriceEditPanel() panel.titleLabel.text = field.fieldName panel.inputField.text = (field.value as? Double)?.toDisplay panel.handleTextFieldDidChanged() panel.limit = field.validate.numLimit panel.handler = { [weak self] price in guard let self else { return } curValueLabel.text = price.toDisplay field.value = price delegate?.onSkillFieldBaseEditViewInputChanged(view: self) } panel.popup() } container.snp.makeConstraints { make in make.height.equalTo(38) } let arrow = UIImageView.arrowImageView(size: 15) arrow.tintColor = .text_3 container.addSubview(arrow) arrow.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview().offset(-16) } let coin = UIImageView.coinImageView() container.addSubview(coin) coin.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalToSuperview().offset(16) make.width.height.equalTo(18) } curValueLabel.font = .heading_h4 curValueLabel.textColor = .text_5 container.addSubview(curValueLabel) curValueLabel.snp.makeConstraints { make in make.leading.equalTo(coin.snp.trailing).offset(1) make.centerY.equalToSuperview() } } } private class LNSkillPriceEditPanel: LNPopupView, UITextFieldDelegate { let titleLabel = UILabel() let inputField = LNTextField() var limit: LNSkillFieldValidateNumLimit? private let confirmButton = UIButton() var handler: ((Double) -> Void)? override init(frame: CGRect) { super.init(frame: frame) let headerView = UIView() headerView.isUserInteractionEnabled = false container.addSubview(headerView) headerView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalToSuperview() make.height.equalTo(50) } titleLabel.font = .heading_h3 titleLabel.textColor = .text_5 titleLabel.textAlignment = .center headerView.addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.horizontalEdges.equalToSuperview().inset(16) } let inputView = buildInputView() container.addSubview(inputView) inputView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.top.equalTo(headerView.snp.bottom).offset(12) make.leading.greaterThanOrEqualToSuperview().offset(32) } confirmButton.setTitle(.init(key: "A00002"), for: .normal) confirmButton.setTitleColor(.text_1, for: .normal) confirmButton.titleLabel?.font = .heading_h3 confirmButton.layer.cornerRadius = 23.5 confirmButton.clipsToBounds = true confirmButton.isEnabled = false confirmButton.backgroundColor = .fill_4 confirmButton.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } let text = inputField.text ?? "0" let value = Double(text) ?? 0 if let limit, value < limit.min || value > limit.max { showToast(.init(key: "B00102", limit.min.toDisplay, limit.max.toDisplay)) return } dismiss() handler?(Double(inputField.text ?? "0") ?? 0) }), for: .touchUpInside) container.addSubview(confirmButton) confirmButton.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(16) make.top.equalTo(inputView.snp.bottom).offset(40) make.bottom.equalToSuperview().offset(commonBottomInset) make.height.equalTo(47) } } private func buildInputView() -> UIView { let container = UIView() container.onTap { [weak self] in guard let self else { return } inputField.becomeFirstResponder() } container.snp.makeConstraints { make in make.width.greaterThanOrEqualTo(180) } let inputView = UIView() container.addSubview(inputView) inputView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.verticalEdges.equalToSuperview() make.leading.greaterThanOrEqualToSuperview() } inputField.font = .heading_h1 inputField.textColor = .text_5 inputField.placeholder = .init(key: "B00097") inputField.keyboardType = .decimalPad inputField.delegate = self inputField.returnKeyType = .done inputField.visibleView = container inputField.cursorHeight = 18 inputField.cursorWidth = 2 inputField.tintColor = .primary_5 inputField.addTarget(self, action: #selector(handleTextFieldDidChanged), for: .editingChanged) inputView.addSubview(inputField) inputField.snp.makeConstraints { make in make.top.equalToSuperview() make.bottom.equalToSuperview().offset(-20) make.trailing.equalToSuperview() } let coin = UIImageView.coinImageView() inputView.addSubview(coin) coin.snp.makeConstraints { make in make.leading.equalToSuperview() make.centerY.equalTo(inputField) make.width.height.equalTo(24) make.trailing.equalTo(inputField.snp.leading).offset(-2) } let line = UIView() line.backgroundColor = .fill_2 container.addSubview(line) line.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.bottom.equalToSuperview().offset(-18) make.height.equalTo(1) } return container } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { guard let limit else { return true } let currentText = textField.text ?? "" guard let range = Range(range, in: currentText) else { return false } let newText = currentText.replacingCharacters(in: range, with: string) if newText.isEmpty { return true } if newText.starts(with: "00") { return false } if newText.filter({ $0 == "." }).count > 2 { return false } guard let value = Double(newText) else { return false } if value > limit.max { showToast(.init(key: "B00102", limit.min.toDisplay, limit.max.toDisplay)) return false } return true } func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } @objc func handleTextFieldDidChanged() { inputField.placeholder = inputField.text?.isEmpty == false ? "" : .init(key: "B00097") let inputAvailable = if let text = inputField.text, Double(text) != nil { true } else { false } if inputAvailable != confirmButton.isEnabled { confirmButton.isEnabled = inputAvailable confirmButton.setBackgroundImage(inputAvailable ? .primary_8 : nil, for: .normal) } } }