jsdw_ios/QuickLocation/Section/Mine/Feedback/FeedbackVC.swift

143 lines
4.4 KiB
Swift

//
// FeedbackVC.swift
// QuickLocation
//
import UIKit
import RxSwift
import RxCocoa
final class FeedbackVC: BaseViewController {
private enum FeedbackCategory: String, CaseIterable {
case feature = "功能问题"
case suggestion = "优化建议"
case other = "其他"
}
private struct FeedbackDraft {
let category: FeedbackCategory
let detail: String
let images: [UIImage]
let contact: String
}
private var rootView: FeedbackView!
private var selectedCategory: FeedbackCategory = .feature
private var selectedImages: [UIImage] = []
private var pendingDraft: FeedbackDraft?
private var isSubmitting = false
override func loadView() {
rootView = FeedbackView(frame: UIScreen.main.bounds)
view = rootView
}
override func viewDidLoad() {
super.viewDidLoad()
bind()
}
private func bind() {
rootView.navView.onBackTapped = { [weak self] in
guard self?.isSubmitting == false else { return }
self?.navigationController?.popViewController(animated: true)
}
rootView.categoryButtons.forEach { button in
button.addTarget(self, action: #selector(categoryTapped(_:)), for: .touchUpInside)
}
rootView.detailTextView.rx.text.orEmpty
.subscribe(onNext: { [weak self] text in
self?.handleDetailChange(text)
})
.disposed(by: disposeBag)
rootView.contactTextField.rx.controlEvent(.editingDidEndOnExit)
.subscribe(onNext: { [weak self] in
self?.rootView.contactTextField.resignFirstResponder()
})
.disposed(by: disposeBag)
rootView.onAddImage = { [weak self] in
self?.showAlbum()
}
rootView.onDeleteImage = { [weak self] index in
guard let self, self.selectedImages.indices.contains(index) else { return }
self.selectedImages.remove(at: index)
self.rootView.updateImages(self.selectedImages)
}
rootView.saveBtn.rx.tap
.subscribe(onNext: { [weak self] in
self?.submit()
})
.disposed(by: disposeBag)
}
@objc private func categoryTapped(_ sender: UIButton) {
let categories = FeedbackCategory.allCases
guard categories.indices.contains(sender.tag) else { return }
let category = categories[sender.tag]
selectedCategory = category
rootView.updateCategory(selectedIndex: sender.tag)
}
private func handleDetailChange(_ text: String) {
let limitedText = text.count > 200 ? String(text.prefix(200)) : text
if limitedText != text {
rootView.detailTextView.text = limitedText
rootView.detailTextView.selectedRange = NSRange(location: limitedText.count, length: 0)
}
rootView.updateDetail(text: limitedText)
}
private func showAlbum() {
let remainingCount = 3 - selectedImages.count
guard remainingCount > 0, !isSubmitting else { return }
let picker = PhotoPickerVC(maxCount: remainingCount)
picker.onConfirm = { [weak self] images in
guard let self else { return }
self.selectedImages.append(contentsOf: images.prefix(remainingCount))
self.selectedImages = Array(self.selectedImages.prefix(3))
self.rootView.updateImages(self.selectedImages)
}
present(picker, animated: true)
}
private func submit() {
guard !isSubmitting else { return }
view.endEditing(true)
let detail = (rootView.detailTextView.text ?? "")
.trimmingCharacters(in: .whitespacesAndNewlines)
guard !detail.isEmpty else {
DLToast.show(text: "请补充详细问题或意见")
return
}
pendingDraft = FeedbackDraft(
category: selectedCategory,
detail: detail,
images: selectedImages,
contact: rootView.contactTextField.text ?? ""
)
isSubmitting = true
rootView.setSubmitting(true)
let successView = FeedbackSuccessView()
successView.show(in: view)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self, weak successView] in
guard let self, let successView else { return }
successView.dismiss {
AppRouter.shared.popOrDismiss()
}
}
}
}