// // LNHourRangePickerPanel.swift // Gami // // Created by OneeChan on 2026/1/23. // import Foundation import UIKit import SnapKit class LNHourRangePickerPanel: LNPopupView { private let titleLabel = UILabel() private let descLabel = UILabel() private let fromPicker = UIPickerView() private let toPicker = UIPickerView() var isRelative: Bool = true var handler: ((Int, Int) -> Void)? override init(frame: CGRect) { super.init(frame: frame) setupViews() } func setTitles(_ title: String, desc: String? = nil) { titleLabel.text = title descLabel.text = desc descLabel.isHidden = desc?.isEmpty != false } func setDefault(from: Int, to: Int) { fromPicker.selectRow(from, inComponent: 0, animated: false) let toIndex = if isRelative { to - from - 1 } else { to } toPicker.selectRow(toIndex, inComponent: 0, animated: false) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNHourRangePickerPanel: UIPickerViewDataSource, UIPickerViewDelegate { func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { if pickerView == toPicker, isRelative { 24 } else { 24 } } func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 } func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { let itemView = view as? LNHourRangeItemView ?? LNHourRangeItemView() if pickerView == fromPicker { itemView.titleLabel.text = String(format: "%02d:00", row) } else if pickerView == toPicker { if isRelative { let from = fromPicker.selectedRow(inComponent: 0) itemView.titleLabel.text = String(format: "%02d:00", (row + from + 1) % 24) } else { itemView.titleLabel.text = String(format: "%02d:00", row) } } return itemView } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { if pickerView == fromPicker, isRelative { toPicker.reloadComponent(0) } } func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { 52 } } extension LNHourRangePickerPanel { private func setupViews() { let header = UIView() container.addSubview(header) header.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalToSuperview() } let stackView = UIStackView() stackView.axis = .vertical stackView.spacing = 4 header.addSubview(stackView) stackView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(22) make.verticalEdges.equalToSuperview().inset(9) } titleLabel.font = .heading_h3 titleLabel.textColor = .text_5 titleLabel.textAlignment = .center stackView.addArrangedSubview(titleLabel) descLabel.font = .body_s descLabel.textColor = .text_4 descLabel.textAlignment = .center descLabel.numberOfLines = 0 stackView.addArrangedSubview(descLabel) let pickerView = UIView() container.addSubview(pickerView) pickerView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(20) make.top.equalTo(header.snp.bottom) make.height.equalTo(150) } let textView = UIView() pickerView.addSubview(textView) textView.snp.makeConstraints { make in make.center.equalToSuperview() } let toLabel = UILabel() toLabel.font = .body_l toLabel.textColor = .text_5 toLabel.text = .init(key: "B00081") toLabel.textAlignment = .center toLabel.setContentHuggingPriority(.required, for: .horizontal) toLabel.setContentCompressionResistancePriority(.required, for: .horizontal) textView.addSubview(toLabel) toLabel.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(12) make.verticalEdges.equalToSuperview() } fromPicker.delegate = self fromPicker.dataSource = self pickerView.addSubview(fromPicker) fromPicker.snp.makeConstraints { make in make.verticalEdges.equalToSuperview() make.leading.equalToSuperview() make.trailing.equalTo(textView.snp.leading) } toPicker.delegate = self toPicker.dataSource = self pickerView.addSubview(toPicker) toPicker.snp.makeConstraints { make in make.verticalEdges.equalToSuperview() make.trailing.equalToSuperview() make.leading.equalTo(textView.snp.trailing) make.width.equalTo(fromPicker) } let confirm = UIButton() confirm.setTitle(.init(key: "A00002"), for: .normal) confirm.setTitleColor(.text_1, for: .normal) confirm.setBackgroundImage(.primary_8, for: .normal) confirm.layer.cornerRadius = 23.5 confirm.titleLabel?.font = .heading_h3 confirm.clipsToBounds = true confirm.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } dismiss() let from = fromPicker.selectedRow(inComponent: 0) var to = toPicker.selectedRow(inComponent: 0) if isRelative { to += from + 1 } handler?(from, to) }), for: .touchUpInside) container.addSubview(confirm) confirm.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(22) make.bottom.equalToSuperview().offset(commonBottomInset) make.height.equalTo(47) make.top.equalTo(pickerView.snp.bottom).offset(4) } runOnMain { [weak self] in guard let self else { return } fromPicker.subviews.forEach { if $0.subviews.isEmpty { $0.backgroundColor = .clear } } toPicker.subviews.forEach { if $0.subviews.isEmpty { $0.backgroundColor = .clear } } } } } private class LNHourRangeItemView: UIView { let titleLabel = UILabel() override init(frame: CGRect) { super.init(frame: frame) titleLabel.font = .body_xl titleLabel.textColor = .text_5 titleLabel.textAlignment = .center addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.center.equalToSuperview() } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }