Implement scenic apply models, API, upload, UI, and tests; wire entry from permission apply pages and include related permission/scenic selection UI fixes. Co-authored-by: Cursor <cursoragent@cursor.com>
266 lines
8.4 KiB
Swift
266 lines
8.4 KiB
Swift
//
|
||
// PermissionApplyViews.swift
|
||
// suixinkan
|
||
//
|
||
|
||
import SnapKit
|
||
import UIKit
|
||
|
||
/// 权限申请页橙色横幅(跳转景区申请)。
|
||
final class PermissionApplyBannerView: UIView {
|
||
|
||
var onApplyNewScenic: (() -> Void)?
|
||
|
||
private let titleLabel = UILabel()
|
||
private let applyButton = UIButton(type: .system)
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
backgroundColor = AppColor.warningBackground
|
||
|
||
titleLabel.text = "没有找到心仪的景区"
|
||
titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
|
||
titleLabel.textColor = AppColor.warning
|
||
|
||
applyButton.setTitle("申请平台开通新景区", for: .normal)
|
||
applyButton.titleLabel?.font = .systemFont(ofSize: 14, weight: .medium)
|
||
applyButton.setTitleColor(AppColor.warning, for: .normal)
|
||
applyButton.addTarget(self, action: #selector(applyTapped), for: .touchUpInside)
|
||
|
||
addSubview(titleLabel)
|
||
addSubview(applyButton)
|
||
titleLabel.snp.makeConstraints { make in
|
||
make.leading.equalToSuperview().offset(16)
|
||
make.centerY.equalToSuperview()
|
||
}
|
||
applyButton.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview().offset(-16)
|
||
make.centerY.equalToSuperview()
|
||
}
|
||
snp.makeConstraints { make in
|
||
make.height.equalTo(44)
|
||
}
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
@objc private func applyTapped() {
|
||
onApplyNewScenic?()
|
||
}
|
||
}
|
||
|
||
/// 表单字段选择行,对齐 Android `FormField` + Selector。
|
||
final class PermissionFormSelectorRow: UIView {
|
||
|
||
var onTap: (() -> Void)?
|
||
|
||
private let titleLabel = UILabel()
|
||
private let tagLabel = UILabel()
|
||
private let descriptionLabel = UILabel()
|
||
private let valueLabel = UILabel()
|
||
private let chevron = UIImageView(image: UIImage(systemName: "chevron.down"))
|
||
|
||
init(title: String, tag: String, description: String, placeholder: String) {
|
||
super.init(frame: .zero)
|
||
titleLabel.text = title
|
||
titleLabel.font = .systemFont(ofSize: 16, weight: .medium)
|
||
titleLabel.textColor = AppColor.textPrimary
|
||
|
||
tagLabel.text = tag
|
||
tagLabel.font = .systemFont(ofSize: 12)
|
||
tagLabel.textColor = AppColor.textTertiary
|
||
tagLabel.textAlignment = .right
|
||
|
||
descriptionLabel.text = description
|
||
descriptionLabel.font = .systemFont(ofSize: 12)
|
||
descriptionLabel.textColor = UIColor(hex: 0xB3B8C2)
|
||
descriptionLabel.numberOfLines = 0
|
||
|
||
valueLabel.text = placeholder
|
||
valueLabel.font = .systemFont(ofSize: 14)
|
||
valueLabel.textColor = UIColor(hex: 0xB3B8C2)
|
||
|
||
chevron.tintColor = UIColor(hex: 0xB3B8C2)
|
||
chevron.contentMode = .scaleAspectFit
|
||
|
||
let tap = UITapGestureRecognizer(target: self, action: #selector(rowTapped))
|
||
addGestureRecognizer(tap)
|
||
|
||
addSubview(titleLabel)
|
||
addSubview(tagLabel)
|
||
addSubview(descriptionLabel)
|
||
addSubview(valueLabel)
|
||
addSubview(chevron)
|
||
|
||
titleLabel.snp.makeConstraints { make in
|
||
make.top.leading.equalToSuperview()
|
||
}
|
||
tagLabel.snp.makeConstraints { make in
|
||
make.centerY.equalTo(titleLabel)
|
||
make.trailing.equalToSuperview()
|
||
make.leading.greaterThanOrEqualTo(titleLabel.snp.trailing).offset(8)
|
||
}
|
||
descriptionLabel.snp.makeConstraints { make in
|
||
make.top.equalTo(titleLabel.snp.bottom).offset(4)
|
||
make.leading.trailing.equalToSuperview()
|
||
}
|
||
valueLabel.snp.makeConstraints { make in
|
||
make.top.equalTo(descriptionLabel.snp.bottom).offset(8)
|
||
make.leading.bottom.equalToSuperview()
|
||
make.trailing.lessThanOrEqualTo(chevron.snp.leading).offset(-8)
|
||
}
|
||
chevron.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview()
|
||
make.centerY.equalTo(valueLabel)
|
||
make.size.equalTo(14)
|
||
}
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
func setValue(_ text: String, isPlaceholder: Bool) {
|
||
valueLabel.text = text
|
||
valueLabel.textColor = isPlaceholder ? UIColor(hex: 0xB3B8C2) : AppColor.textPrimary
|
||
}
|
||
|
||
@objc private func rowTapped() {
|
||
onTap?()
|
||
}
|
||
}
|
||
|
||
/// 已选景区标签容器。
|
||
final class PermissionSelectedTagsView: UIView {
|
||
|
||
private let titleLabel = UILabel()
|
||
private let stackView = UIStackView()
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
titleLabel.font = .systemFont(ofSize: 16, weight: .medium)
|
||
titleLabel.textColor = UIColor(hex: 0x111827)
|
||
stackView.axis = .vertical
|
||
stackView.spacing = 8
|
||
addSubview(titleLabel)
|
||
addSubview(stackView)
|
||
titleLabel.snp.makeConstraints { make in
|
||
make.top.leading.trailing.equalToSuperview()
|
||
}
|
||
stackView.snp.makeConstraints { make in
|
||
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||
make.leading.trailing.bottom.equalToSuperview()
|
||
}
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
func apply(title: String, names: [String], onRemove: ((Int) -> Void)? = nil) {
|
||
titleLabel.text = title
|
||
stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||
guard !names.isEmpty else {
|
||
isHidden = true
|
||
return
|
||
}
|
||
isHidden = false
|
||
let row = UIStackView()
|
||
row.axis = .horizontal
|
||
row.spacing = 8
|
||
row.alignment = .leading
|
||
names.enumerated().forEach { index, name in
|
||
let chip = PermissionTagChip(title: name)
|
||
if let onRemove {
|
||
chip.onRemove = { onRemove(index) }
|
||
}
|
||
row.addArrangedSubview(chip)
|
||
}
|
||
stackView.addArrangedSubview(row)
|
||
}
|
||
}
|
||
|
||
/// 标签 Chip。
|
||
final class PermissionTagChip: UIView {
|
||
|
||
var onRemove: (() -> Void)?
|
||
|
||
private let label = UILabel()
|
||
private let removeButton = UIButton(type: .system)
|
||
|
||
init(title: String, showsRemove: Bool = true) {
|
||
super.init(frame: .zero)
|
||
layer.cornerRadius = 4
|
||
layer.borderWidth = 1
|
||
layer.borderColor = AppColor.primary.cgColor
|
||
backgroundColor = .white
|
||
|
||
label.text = title
|
||
label.font = .systemFont(ofSize: 14)
|
||
label.textColor = AppColor.primary
|
||
|
||
removeButton.setImage(UIImage(systemName: "xmark"), for: .normal)
|
||
removeButton.tintColor = AppColor.primary
|
||
removeButton.addTarget(self, action: #selector(removeTapped), for: .touchUpInside)
|
||
removeButton.isHidden = !showsRemove
|
||
|
||
addSubview(label)
|
||
addSubview(removeButton)
|
||
label.snp.makeConstraints { make in
|
||
make.leading.equalToSuperview().offset(12)
|
||
make.top.bottom.equalToSuperview().inset(8)
|
||
if showsRemove {
|
||
make.trailing.equalTo(removeButton.snp.leading).offset(-4)
|
||
} else {
|
||
make.trailing.equalToSuperview().offset(-12)
|
||
}
|
||
}
|
||
removeButton.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview().offset(-8)
|
||
make.centerY.equalToSuperview()
|
||
make.size.equalTo(20)
|
||
}
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
@objc private func removeTapped() {
|
||
onRemove?()
|
||
}
|
||
}
|
||
|
||
/// 底部主按钮。
|
||
final class PermissionSubmitButton: UIButton {
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
setTitle("提交审核", for: .normal)
|
||
setTitleColor(.white, for: .normal)
|
||
titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||
backgroundColor = AppColor.primary
|
||
layer.cornerRadius = 8
|
||
snp.makeConstraints { make in
|
||
make.height.equalTo(48)
|
||
}
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
func setSubmitting(_ submitting: Bool) {
|
||
isEnabled = !submitting
|
||
alpha = submitting ? 0.6 : 1
|
||
setTitle(submitting ? "提交中..." : "提交审核", for: .normal)
|
||
}
|
||
}
|