Add scenic application flow aligned with Android.

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>
This commit is contained in:
2026-07-07 11:09:27 +08:00
parent 2bea05b1d9
commit 77fec21563
22 changed files with 2202 additions and 216 deletions

View File

@ -6,7 +6,7 @@
import SnapKit
import UIKit
/// toast
///
final class PermissionApplyBannerView: UIView {
var onApplyNewScenic: (() -> Void)?
@ -18,11 +18,11 @@ final class PermissionApplyBannerView: UIView {
super.init(frame: frame)
backgroundColor = AppColor.warningBackground
titleLabel.text = "希望开通全新景区"
titleLabel.text = "没有找到心仪的景区"
titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
titleLabel.textColor = AppColor.warning
applyButton.setTitle("新景区申请 ", for: .normal)
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)
@ -52,50 +52,63 @@ final class PermissionApplyBannerView: UIView {
}
}
///
/// Android `FormField` + Selector
final class PermissionFormSelectorRow: UIView {
var onTap: (() -> Void)?
private let titleLabel = UILabel()
private let subtitleLabel = 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, subtitle: String, placeholder: String) {
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
subtitleLabel.text = subtitle
subtitleLabel.font = .systemFont(ofSize: 12)
subtitleLabel.textColor = AppColor.textTertiary
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 = AppColor.textTertiary
valueLabel.textColor = UIColor(hex: 0xB3B8C2)
chevron.tintColor = AppColor.textTertiary
chevron.tintColor = UIColor(hex: 0xB3B8C2)
chevron.contentMode = .scaleAspectFit
let tap = UITapGestureRecognizer(target: self, action: #selector(rowTapped))
addGestureRecognizer(tap)
addSubview(titleLabel)
addSubview(subtitleLabel)
addSubview(tagLabel)
addSubview(descriptionLabel)
addSubview(valueLabel)
addSubview(chevron)
titleLabel.snp.makeConstraints { make in
make.top.leading.equalToSuperview()
}
subtitleLabel.snp.makeConstraints { make in
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.equalToSuperview()
make.leading.trailing.equalToSuperview()
}
valueLabel.snp.makeConstraints { make in
make.top.equalTo(subtitleLabel.snp.bottom).offset(12)
make.top.equalTo(descriptionLabel.snp.bottom).offset(8)
make.leading.bottom.equalToSuperview()
make.trailing.lessThanOrEqualTo(chevron.snp.leading).offset(-8)
}
@ -113,7 +126,7 @@ final class PermissionFormSelectorRow: UIView {
func setValue(_ text: String, isPlaceholder: Bool) {
valueLabel.text = text
valueLabel.textColor = isPlaceholder ? AppColor.textTertiary : AppColor.textPrimary
valueLabel.textColor = isPlaceholder ? UIColor(hex: 0xB3B8C2) : AppColor.textPrimary
}
@objc private func rowTapped() {
@ -129,8 +142,8 @@ final class PermissionSelectedTagsView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
titleLabel.textColor = AppColor.textPrimary
titleLabel.font = .systemFont(ofSize: 16, weight: .medium)
titleLabel.textColor = UIColor(hex: 0x111827)
stackView.axis = .vertical
stackView.spacing = 8
addSubview(titleLabel)
@ -229,7 +242,7 @@ final class PermissionSubmitButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
setTitle("提交申请", for: .normal)
setTitle("提交审核", for: .normal)
setTitleColor(.white, for: .normal)
titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
backgroundColor = AppColor.primary
@ -247,6 +260,6 @@ final class PermissionSubmitButton: UIButton {
func setSubmitting(_ submitting: Bool) {
isEnabled = !submitting
alpha = submitting ? 0.6 : 1
setTitle(submitting ? "提交中..." : "提交申请", for: .normal)
setTitle(submitting ? "提交中..." : "提交审核", for: .normal)
}
}

View File

@ -41,8 +41,10 @@ final class ScenicPermissionBannerView: UIView {
make.centerY.equalToSuperview()
}
snp.makeConstraints { make in
make.height.greaterThanOrEqualTo(44)
make.height.equalTo(44)
}
setContentHuggingPriority(.required, for: .vertical)
setContentCompressionResistancePriority(.required, for: .vertical)
}
@available(*, unavailable)
@ -146,18 +148,20 @@ final class ScenicCurrentLocationBar: UIView {
iconView.snp.makeConstraints { make in
make.leading.equalToSuperview()
make.centerY.equalToSuperview()
make.centerY.equalTo(locationLabel)
make.size.equalTo(16)
}
locationLabel.snp.makeConstraints { make in
make.leading.equalTo(iconView.snp.trailing).offset(4)
make.centerY.equalToSuperview()
make.top.bottom.equalToSuperview().inset(8)
make.trailing.lessThanOrEqualTo(relocateButton.snp.leading).offset(-12)
}
relocateButton.snp.makeConstraints { make in
make.trailing.equalToSuperview()
make.centerY.equalToSuperview()
make.centerY.equalTo(locationLabel)
}
setContentHuggingPriority(.required, for: .vertical)
setContentCompressionResistancePriority(.required, for: .vertical)
}
@available(*, unavailable)
@ -165,8 +169,10 @@ final class ScenicCurrentLocationBar: UIView {
fatalError("init(coder:) has not been implemented")
}
func apply(locationText: String) {
locationLabel.text = locationText
func apply(locationText: String, isLocating: Bool = false) {
locationLabel.text = isLocating ? "定位中..." : locationText
relocateButton.isEnabled = !isLocating
relocateButton.alpha = isLocating ? 0.5 : 1
}
@objc private func relocateTapped() {