优化举报摄影师页面

This commit is contained in:
2026-07-08 14:02:44 +08:00
parent ccd63380cf
commit 8ca8bcf948
3 changed files with 1357 additions and 168 deletions

View File

@ -14,7 +14,7 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
private let contentStack = UIStackView()
private let descriptionView = UITextView()
private let contactField = UITextField()
private let submitButton = AppButton(title: "提交举报")
private let submitButton = UIButton(type: .system)
init(
homeViewModel: WildPhotographerReportHomeViewModel,
@ -40,45 +40,50 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
override func setupUI() {
view.backgroundColor = AppColor.pageBackgroundSoft
scrollView.keyboardDismissMode = .interactive
scrollView.showsVerticalScrollIndicator = false
contentStack.axis = .vertical
contentStack.spacing = AppSpacing.sm
descriptionView.font = .app(.body)
descriptionView.font = .systemFont(ofSize: 15)
descriptionView.textColor = AppColor.textPrimary
descriptionView.backgroundColor = AppColor.inputBackground
descriptionView.layer.cornerRadius = AppRadius.md
descriptionView.textContainerInset = UIEdgeInsets(top: 12, left: 10, bottom: 12, right: 10)
descriptionView.backgroundColor = .clear
descriptionView.textContainerInset = UIEdgeInsets(top: 10, left: 8, bottom: 34, right: 8)
descriptionView.delegate = self
contactField.placeholder = "微信号或手机号(选填)"
contactField.placeholder = "请输入摄影师微信号或手机号(选填)"
contactField.font = .app(.body)
contactField.textColor = AppColor.textPrimary
contactField.backgroundColor = AppColor.inputBackground
contactField.layer.cornerRadius = AppRadius.md
contactField.backgroundColor = UIColor(hex: 0xFBFCFE)
contactField.layer.cornerRadius = 10
contactField.layer.borderWidth = 1
contactField.layer.borderColor = UIColor(hex: 0xCDD5E1).cgColor
contactField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 1))
contactField.leftViewMode = .always
contactField.addTarget(self, action: #selector(contactChanged), for: .editingChanged)
submitButton.setTitle("提交举报", for: .normal)
submitButton.titleLabel?.font = .systemFont(ofSize: 22, weight: .bold)
submitButton.setTitleColor(.white, for: .normal)
submitButton.backgroundColor = AppColor.primary
submitButton.layer.cornerRadius = 14
submitButton.layer.shadowColor = AppColor.primary.cgColor
submitButton.layer.shadowOpacity = 0.22
submitButton.layer.shadowRadius = 12
submitButton.layer.shadowOffset = CGSize(width: 0, height: 6)
submitButton.addTarget(self, action: #selector(submitTapped), for: .touchUpInside)
view.addSubview(scrollView)
scrollView.addSubview(contentStack)
view.addSubview(submitButton)
rebuildContent()
}
override func setupConstraints() {
submitButton.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(AppSpacing.sm)
}
scrollView.snp.makeConstraints { make in
make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
make.bottom.equalTo(submitButton.snp.top).offset(-AppSpacing.sm)
make.edges.equalTo(view.safeAreaLayoutGuide)
}
contentStack.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(UIEdgeInsets(top: AppSpacing.sm, left: AppSpacing.md, bottom: AppSpacing.lg, right: AppSpacing.md))
make.width.equalTo(scrollView.snp.width).offset(-AppSpacing.md * 2)
make.edges.equalTo(scrollView.contentLayoutGuide).inset(UIEdgeInsets(top: 14, left: 18, bottom: 26, right: 18))
make.width.equalTo(scrollView.frameLayoutGuide).offset(-36)
}
}
@ -114,37 +119,68 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
contentStack.removeArrangedSubview(view)
view.removeFromSuperview()
}
contentStack.addArrangedSubview(makeTipsCard())
contentStack.addArrangedSubview(makeRealNameBanner())
contentStack.addArrangedSubview(makeTypeCard())
contentStack.addArrangedSubview(makeEvidenceCard())
contentStack.addArrangedSubview(makeDescriptionCard())
contentStack.addArrangedSubview(makeLocationCard())
contentStack.addArrangedSubview(makeContactCard())
contentStack.addArrangedSubview(makePaymentCard())
let paymentCard = makePaymentCard()
contentStack.addArrangedSubview(paymentCard)
contentStack.setCustomSpacing(16, after: paymentCard)
contentStack.addArrangedSubview(submitButton)
submitButton.snp.remakeConstraints { make in
make.height.equalTo(56)
}
}
private func makeTipsCard() -> UIView {
let card = WildReportCardView(spacing: AppSpacing.xs)
card.stack.addArrangedSubview(WildReportUI.label("实名登录后提交,景区公安将接收并处理", font: .app(.bodyMedium), color: AppColor.textPrimary, lines: 0))
card.stack.addArrangedSubview(WildReportUI.label("请描述摄影师位置、外貌特征和具体行为。", font: .app(.caption), color: AppColor.textSecondary, lines: 0))
return card
private func makeRealNameBanner() -> UIView {
let banner = UIView()
banner.backgroundColor = UIColor(hex: 0xF6FAFF)
banner.layer.cornerRadius = 16
banner.layer.borderWidth = 1
banner.layer.borderColor = UIColor(hex: 0xBFD7FF).cgColor
let iconWrap = UIView()
iconWrap.backgroundColor = AppColor.primary.withAlphaComponent(0.10)
iconWrap.layer.cornerRadius = 17
let icon = UIImageView(image: UIImage(systemName: "checkmark.shield.fill"))
icon.tintColor = AppColor.primary
iconWrap.addSubview(icon)
icon.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(22)
}
let message = UILabel()
message.numberOfLines = 0
message.attributedText = realNameBannerText()
banner.addSubview(iconWrap)
banner.addSubview(message)
iconWrap.snp.makeConstraints { make in
make.top.leading.equalToSuperview().offset(16)
make.size.equalTo(34)
make.bottom.lessThanOrEqualToSuperview().inset(16)
}
message.snp.makeConstraints { make in
make.top.trailing.bottom.equalToSuperview().inset(16)
make.leading.equalTo(iconWrap.snp.trailing).offset(12)
}
return banner
}
private func makeTypeCard() -> UIView {
let card = sectionCard(index: 1, title: "选择举报类型")
let card = sectionCard(index: 1, title: "举报类型")
let row = UIStackView()
row.axis = .vertical
row.spacing = AppSpacing.xs
row.axis = .horizontal
row.spacing = 8
row.distribution = .fillEqually
WildReportType.allCases.forEach { type in
let button = UIButton(type: .system)
button.contentHorizontalAlignment = .left
button.titleLabel?.font = .app(.bodyMedium)
button.setTitle(" \(type.rawValue)", for: .normal)
button.setImage(UIImage(systemName: type == viewModel.selectedReportType ? "largecircle.fill.circle" : "circle"), for: .normal)
button.tintColor = AppColor.primary
button.setTitleColor(AppColor.textPrimary, for: .normal)
let button = WildReportTypeOptionButton()
button.apply(type: type, isSelected: type == viewModel.selectedReportType)
button.addAction(UIAction { [weak self] _ in self?.viewModel.selectReportType(type) }, for: .touchUpInside)
button.snp.makeConstraints { make in make.height.equalTo(38) }
button.snp.makeConstraints { make in make.height.equalTo(72) }
row.addArrangedSubview(button)
}
card.stack.addArrangedSubview(row)
@ -153,84 +189,306 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
private func makeEvidenceCard() -> UIView {
let card = sectionCard(index: 2, title: "上传现场证据")
let buttonRow = UIStackView()
buttonRow.axis = .horizontal
buttonRow.spacing = AppSpacing.sm
buttonRow.distribution = .fillEqually
let imageButton = WildReportUI.iconButton(title: "添加图片", imageName: "photo", style: .secondary)
imageButton.addTarget(self, action: #selector(addImageTapped), for: .touchUpInside)
let videoButton = WildReportUI.iconButton(title: "添加视频", imageName: "video", style: .secondary)
videoButton.addTarget(self, action: #selector(addVideoTapped), for: .touchUpInside)
[imageButton, videoButton].forEach { button in
button.snp.makeConstraints { make in make.height.equalTo(44) }
buttonRow.addArrangedSubview(button)
}
card.stack.addArrangedSubview(buttonRow)
addAttachments(viewModel.images + viewModel.videos, to: card)
card.stack.addArrangedSubview(makeEvidenceUploadBlock(
icon: "photo.fill",
title: "上传图片",
subtitle: "支持 JPG、PNG 格式,最多 9 张",
attachments: viewModel.images,
maxCount: 9,
kind: .image
))
card.stack.addArrangedSubview(makeDivider())
card.stack.addArrangedSubview(makeEvidenceUploadBlock(
icon: "video.fill",
title: "上传视频",
subtitle: "支持 MP4 格式,时长不超过 60 秒",
attachments: viewModel.videos,
maxCount: 3,
kind: .video
))
return card
}
private func makeDescriptionCard() -> UIView {
let card = sectionCard(index: 3, title: "举报说明")
descriptionView.text = viewModel.description
card.stack.addArrangedSubview(descriptionView)
let inputContainer = UIView()
inputContainer.backgroundColor = UIColor(hex: 0xFBFCFE)
inputContainer.layer.cornerRadius = 12
inputContainer.layer.borderWidth = 1
inputContainer.layer.borderColor = UIColor(hex: 0xCDD5E1).cgColor
let placeholder = UILabel()
placeholder.text = "请描述摄影师的位置、特征、行为..."
placeholder.font = .systemFont(ofSize: 15)
placeholder.textColor = UIColor(hex: 0x9CA3AF)
placeholder.isHidden = !viewModel.description.isEmpty
let count = WildReportUI.label("\(viewModel.description.count)/500", font: .systemFont(ofSize: 14), color: UIColor(hex: 0x6B7280))
count.textAlignment = .right
inputContainer.addSubview(descriptionView)
inputContainer.addSubview(placeholder)
inputContainer.addSubview(count)
descriptionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
make.height.equalTo(132)
}
let count = WildReportUI.label("\(viewModel.description.count)/500", font: .app(.caption), color: AppColor.textTertiary)
count.textAlignment = .right
card.stack.addArrangedSubview(count)
placeholder.snp.makeConstraints { make in
make.top.equalToSuperview().offset(18)
make.leading.equalToSuperview().offset(14)
make.trailing.lessThanOrEqualToSuperview().inset(14)
}
count.snp.makeConstraints { make in
make.trailing.bottom.equalToSuperview().inset(12)
}
card.stack.addArrangedSubview(inputContainer)
return card
}
private func makeLocationCard() -> UIView {
let card = sectionCard(index: 4, title: "举报位置")
let title = WildReportUI.label(viewModel.locationTitleText, font: .app(.bodyMedium), color: AppColor.textPrimary, lines: 0)
let subtitle = WildReportUI.label(viewModel.locationSubtitleText, font: .app(.caption), color: AppColor.textSecondary, lines: 0)
let button = WildReportUI.iconButton(title: viewModel.isUpdatingLocation ? "定位中" : "更新定位", imageName: "location.fill", style: .secondary)
let container = UIView()
container.backgroundColor = UIColor(hex: 0xF6FAFF)
container.layer.cornerRadius = 12
container.layer.borderWidth = 1
container.layer.borderColor = UIColor(hex: 0xC8DDFF).cgColor
let iconWrap = UIView()
iconWrap.backgroundColor = AppColor.primary.withAlphaComponent(0.10)
iconWrap.layer.cornerRadius = 21
let icon = UIImageView(image: UIImage(systemName: "mappin.circle.fill"))
icon.tintColor = AppColor.primary
iconWrap.addSubview(icon)
icon.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(30)
}
let textStack = UIStackView()
textStack.axis = .vertical
textStack.spacing = 5
let title = WildReportUI.label(viewModel.locationTitleText, font: .systemFont(ofSize: 15, weight: .semibold), color: AppColor.textPrimary, lines: 2)
title.adjustsFontSizeToFitWidth = true
title.minimumScaleFactor = 0.78
let subtitle = WildReportUI.label(viewModel.locationSubtitleText, font: .systemFont(ofSize: 12), color: AppColor.textSecondary, lines: 0)
textStack.addArrangedSubview(title)
textStack.addArrangedSubview(subtitle)
let button = UIButton(type: .system)
button.setTitle(viewModel.isUpdatingLocation ? "定位中" : "更新定位", for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 13, weight: .semibold)
button.setTitleColor(AppColor.primary, for: .normal)
button.backgroundColor = .white
button.layer.cornerRadius = 17
button.layer.borderWidth = 1
button.layer.borderColor = AppColor.primary.cgColor
button.isEnabled = !viewModel.isUpdatingLocation
button.alpha = viewModel.isUpdatingLocation ? 0.6 : 1
button.addTarget(self, action: #selector(refreshLocationTapped), for: .touchUpInside)
button.snp.makeConstraints { make in make.height.equalTo(42) }
card.stack.addArrangedSubview(title)
card.stack.addArrangedSubview(subtitle)
card.stack.addArrangedSubview(button)
container.addSubview(iconWrap)
container.addSubview(textStack)
container.addSubview(button)
iconWrap.snp.makeConstraints { make in
make.leading.top.bottom.equalToSuperview().inset(12)
make.size.equalTo(42)
}
button.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(12)
make.centerY.equalToSuperview()
make.width.equalTo(82)
make.height.equalTo(34)
}
textStack.snp.makeConstraints { make in
make.leading.equalTo(iconWrap.snp.trailing).offset(12)
make.trailing.equalTo(button.snp.leading).offset(-8)
make.centerY.equalToSuperview()
make.top.greaterThanOrEqualToSuperview().offset(12)
make.bottom.lessThanOrEqualToSuperview().inset(12)
}
card.stack.addArrangedSubview(container)
return card
}
private func makeContactCard() -> UIView {
let card = sectionCard(index: 5, title: "联系方式(选填)")
let card = sectionCard(index: 5, title: "摄影师微信号/手机号", optional: true)
contactField.text = viewModel.contact
card.stack.addArrangedSubview(contactField)
contactField.snp.makeConstraints { make in make.height.equalTo(46) }
contactField.snp.makeConstraints { make in make.height.equalTo(48) }
return card
}
private func makePaymentCard() -> UIView {
let card = sectionCard(index: 6, title: "支付截图(选填)")
card.stack.addArrangedSubview(WildReportUI.label("上传线下微信/支付宝支付截图,最多 3 张。", font: .app(.caption), color: AppColor.textSecondary, lines: 0))
let button = WildReportUI.iconButton(title: "添加截图", imageName: "creditcard", style: .secondary)
button.addTarget(self, action: #selector(addPaymentTapped), for: .touchUpInside)
button.snp.makeConstraints { make in make.height.equalTo(42) }
card.stack.addArrangedSubview(button)
addAttachments(viewModel.paymentImages, to: card)
return card
}
let card = sectionCard(index: 6, title: "线下微信/支付宝支付截图", optional: true)
let row = UIView()
row.backgroundColor = UIColor(hex: 0xFBFCFE)
row.layer.cornerRadius = 12
row.layer.borderWidth = 1
row.layer.borderColor = UIColor(hex: 0xCDD5E1).cgColor
private func sectionCard(index: Int, title: String) -> WildReportCardView {
let card = WildReportCardView(spacing: AppSpacing.sm)
card.stack.addArrangedSubview(WildReportUI.label("\(index). \(title)", font: .app(.title), color: AppColor.textPrimary))
return card
}
private func addAttachments(_ attachments: [WildReportAttachment], to card: WildReportCardView) {
guard !attachments.isEmpty else { return }
attachments.forEach { attachment in
let chip = WildReportAttachmentChipView(attachment: attachment)
chip.onRemove = { [weak self] in
self?.viewModel.removeAttachment(attachment)
}
card.stack.addArrangedSubview(chip)
let iconWrap = UIView()
iconWrap.backgroundColor = AppColor.primaryLight
iconWrap.layer.cornerRadius = 12
let icon = UIImageView(image: UIImage(systemName: "creditcard.fill"))
icon.tintColor = AppColor.primary
iconWrap.addSubview(icon)
icon.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(24)
}
let textStack = UIStackView()
textStack.axis = .vertical
textStack.spacing = 4
textStack.addArrangedSubview(WildReportUI.label("上传线下微信/支付宝支付截图(选填)", font: .systemFont(ofSize: 15, weight: .semibold), color: AppColor.textPrimary, lines: 0))
textStack.addArrangedSubview(WildReportUI.label("支持 JPG、PNG 格式,最多 3 张", font: .systemFont(ofSize: 12), color: AppColor.textSecondary))
let trailingView: UIView
if let first = viewModel.paymentImages.first {
trailingView = WildReportAttachmentTileView(attachment: first) { [weak self] in
self?.viewModel.removeAttachment(first)
}
} else {
trailingView = WildReportAddAttachmentTileView { [weak self] in
self?.viewModel.addPaymentImage()
}
}
row.addSubview(iconWrap)
row.addSubview(textStack)
row.addSubview(trailingView)
iconWrap.snp.makeConstraints { make in
make.leading.top.bottom.equalToSuperview().inset(12)
make.size.equalTo(44)
}
trailingView.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(12)
make.centerY.equalToSuperview()
make.size.equalTo(58)
}
textStack.snp.makeConstraints { make in
make.leading.equalTo(iconWrap.snp.trailing).offset(12)
make.trailing.lessThanOrEqualTo(trailingView.snp.leading).offset(-10)
make.centerY.equalToSuperview()
make.top.greaterThanOrEqualToSuperview().offset(12)
make.bottom.lessThanOrEqualToSuperview().inset(12)
}
card.stack.addArrangedSubview(row)
return card
}
private func sectionCard(index: Int, title: String, optional: Bool = false) -> WildReportCardView {
let card = WildReportCardView(spacing: 18, inset: 16)
card.layer.cornerRadius = 16
card.stack.addArrangedSubview(WildReportSectionTitleView(index: index, title: title, optional: optional))
return card
}
private func makeEvidenceUploadBlock(
icon: String,
title: String,
subtitle: String,
attachments: [WildReportAttachment],
maxCount: Int,
kind: WildReportAttachmentKind
) -> UIView {
let block = UIStackView()
block.axis = .vertical
block.spacing = 12
let header = UIStackView()
header.axis = .horizontal
header.alignment = .center
header.spacing = 12
let iconWrap = UIView()
iconWrap.backgroundColor = AppColor.primaryLight
iconWrap.layer.cornerRadius = 12
let image = UIImageView(image: UIImage(systemName: icon))
image.tintColor = AppColor.primary
iconWrap.addSubview(image)
image.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(22)
}
iconWrap.snp.makeConstraints { make in
make.size.equalTo(42)
}
let textStack = UIStackView()
textStack.axis = .vertical
textStack.spacing = 3
textStack.addArrangedSubview(WildReportUI.label(title, font: .systemFont(ofSize: 16, weight: .bold), color: AppColor.textPrimary))
textStack.addArrangedSubview(WildReportUI.label(subtitle, font: .systemFont(ofSize: 13), color: AppColor.textSecondary, lines: 0))
header.addArrangedSubview(iconWrap)
header.addArrangedSubview(textStack)
header.addArrangedSubview(UIView())
block.addArrangedSubview(header)
let scroll = UIScrollView()
scroll.showsHorizontalScrollIndicator = false
let tiles = UIStackView()
tiles.axis = .horizontal
tiles.spacing = 10
scroll.addSubview(tiles)
tiles.snp.makeConstraints { make in
make.edges.equalTo(scroll.contentLayoutGuide).inset(UIEdgeInsets(top: 2, left: 0, bottom: 2, right: 0))
make.height.equalTo(scroll.frameLayoutGuide).offset(-4)
}
attachments.forEach { attachment in
tiles.addArrangedSubview(WildReportAttachmentTileView(attachment: attachment) { [weak self] in
self?.viewModel.removeAttachment(attachment)
})
}
let addCount = max(0, min(3, maxCount - attachments.count))
for _ in 0..<addCount {
let addTile = WildReportAddAttachmentTileView { [weak self] in
switch kind {
case .image:
self?.viewModel.addImage()
case .video:
self?.viewModel.addVideo()
case .payment:
self?.viewModel.addPaymentImage()
}
}
tiles.addArrangedSubview(addTile)
}
scroll.snp.makeConstraints { make in
make.height.equalTo(62)
}
block.addArrangedSubview(scroll)
return block
}
private func makeDivider() -> UIView {
let divider = UIView()
divider.backgroundColor = AppColor.border
divider.snp.makeConstraints { make in
make.height.equalTo(1)
}
return divider
}
private func realNameBannerText() -> NSAttributedString {
let text = NSMutableAttributedString()
[
("实名登录", AppColor.primary, UIFont.systemFont(ofSize: 16, weight: .bold)),
("后提交,", AppColor.textPrimary, UIFont.systemFont(ofSize: 16, weight: .medium)),
("景区公安", AppColor.primary, UIFont.systemFont(ofSize: 16, weight: .bold)),
("将接收并处理", AppColor.textPrimary, UIFont.systemFont(ofSize: 16, weight: .medium))
].forEach { value, color, font in
text.append(NSAttributedString(string: value, attributes: [
.foregroundColor: color,
.font: font
]))
}
let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 4
text.addAttribute(.paragraphStyle, value: paragraph, range: NSRange(location: 0, length: text.length))
return text
}
@objc private func addImageTapped() { viewModel.addImage() }
@ -247,6 +505,209 @@ extension WildPhotographerReportSubmitViewController: UITextViewDelegate {
}
}
///
private final class WildReportSectionTitleView: UIView {
init(index: Int, title: String, optional: Bool) {
super.init(frame: .zero)
let bar = UIView()
bar.backgroundColor = AppColor.primary
bar.layer.cornerRadius = 2
let label = UILabel()
label.font = .systemFont(ofSize: 17, weight: .bold)
label.textColor = AppColor.textPrimary
label.text = "\(index). \(title)"
let optionalLabel = UILabel()
optionalLabel.font = .systemFont(ofSize: 14)
optionalLabel.textColor = AppColor.textSecondary
optionalLabel.text = "(选填)"
optionalLabel.isHidden = !optional
addSubview(bar)
addSubview(label)
addSubview(optionalLabel)
bar.snp.makeConstraints { make in
make.leading.equalToSuperview()
make.centerY.equalToSuperview()
make.width.equalTo(4)
make.height.equalTo(20)
}
label.snp.makeConstraints { make in
make.leading.equalTo(bar.snp.trailing).offset(8)
make.top.bottom.equalToSuperview()
}
optionalLabel.snp.makeConstraints { make in
make.leading.equalTo(label.snp.trailing)
make.centerY.equalTo(label)
make.trailing.lessThanOrEqualToSuperview()
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
///
private final class WildReportTypeOptionButton: UIControl {
private let iconView = UIImageView()
private let titleLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
layer.cornerRadius = 12
layer.borderWidth = 1
let stack = UIStackView()
stack.axis = .vertical
stack.alignment = .center
stack.spacing = 6
stack.isUserInteractionEnabled = false
iconView.contentMode = .scaleAspectFit
titleLabel.font = .systemFont(ofSize: 13, weight: .bold)
titleLabel.textAlignment = .center
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.8
titleLabel.lineBreakMode = .byClipping
addSubview(stack)
stack.addArrangedSubview(iconView)
stack.addArrangedSubview(titleLabel)
iconView.snp.makeConstraints { make in
make.size.equalTo(22)
}
stack.snp.makeConstraints { make in
make.center.equalToSuperview()
make.leading.trailing.equalToSuperview().inset(6)
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func apply(type: WildReportType, isSelected: Bool) {
iconView.image = UIImage(systemName: type.iconName)
titleLabel.text = type.rawValue
backgroundColor = isSelected ? AppColor.primary : UIColor(hex: 0xF6FAFF)
layer.borderColor = (isSelected ? AppColor.primary : UIColor(hex: 0xC8DDFF)).cgColor
iconView.tintColor = isSelected ? .white : AppColor.textPrimary
titleLabel.textColor = isSelected ? .white : AppColor.textPrimary
}
}
/// tile使 Mock
private final class WildReportAttachmentTileView: UIControl {
private let gradientLayer = CAGradientLayer()
private let removeAction: () -> Void
init(attachment: WildReportAttachment, onRemove: @escaping () -> Void) {
self.removeAction = onRemove
super.init(frame: .zero)
layer.cornerRadius = 10
clipsToBounds = false
gradientLayer.cornerRadius = 10
let colors: [UIColor] = attachment.kind == .video
? [UIColor(hex: 0xB7D8FF), UIColor(hex: 0x4C8FEF)]
: [UIColor(hex: 0xCFE6FF), UIColor(hex: 0x7EB4FF)]
gradientLayer.colors = colors.map(\.cgColor)
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)
layer.insertSublayer(gradientLayer, at: 0)
let icon = UIImageView(image: UIImage(systemName: attachment.kind == .video ? "play.circle.fill" : "mountain.2.fill"))
icon.tintColor = UIColor.white.withAlphaComponent(0.95)
icon.contentMode = .scaleAspectFit
addSubview(icon)
icon.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(attachment.kind == .video ? 30 : 26)
}
let removeButton = UIButton(type: .system)
removeButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal)
removeButton.tintColor = UIColor(hex: 0x8D93A1)
removeButton.backgroundColor = .white
removeButton.layer.cornerRadius = 9
removeButton.addTarget(self, action: #selector(removeTapped), for: .touchUpInside)
addSubview(removeButton)
removeButton.snp.makeConstraints { make in
make.top.trailing.equalToSuperview().inset(-6)
make.size.equalTo(18)
}
snp.makeConstraints { make in
make.size.equalTo(58)
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
}
@objc private func removeTapped() {
removeAction()
}
}
/// tile线
private final class WildReportAddAttachmentTileView: UIControl {
private let tapAction: () -> Void
private let borderLayer = CAShapeLayer()
init(action: @escaping () -> Void) {
self.tapAction = action
super.init(frame: .zero)
backgroundColor = .white
layer.cornerRadius = 10
borderLayer.strokeColor = UIColor(hex: 0xCDD5E1).cgColor
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.lineWidth = 1
borderLayer.lineDashPattern = [5, 4]
layer.addSublayer(borderLayer)
let icon = UIImageView(image: UIImage(systemName: "plus"))
icon.tintColor = UIColor(hex: 0x8D93A1)
icon.contentMode = .scaleAspectFit
addSubview(icon)
icon.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(30)
}
addTarget(self, action: #selector(tapped), for: .touchUpInside)
snp.makeConstraints { make in
make.size.equalTo(58)
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
borderLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 10).cgPath
}
@objc private func tapped() {
tapAction()
}
}
///
final class WildPhotographerReportSuccessViewController: BaseViewController {
private let viewModel: WildPhotographerReportSuccessViewModel