feat: add travel album module

This commit is contained in:
2026-07-07 17:23:31 +08:00
parent a80c181bd7
commit 00bda390e8
16 changed files with 3115 additions and 0 deletions

View File

@ -0,0 +1,162 @@
//
// TravelAlbumCodeDialogViewController.swift
// suixinkan
//
import Kingfisher
import SnapKit
import UIKit
/// Android `TravelAlbumCodeDialog`
final class TravelAlbumCodeDialogViewController: UIViewController {
var onClose: (() -> Void)?
var onDownload: (() -> Void)?
private let state: TravelAlbumEntryViewModel.AlbumCodeState
private let dimView = UIView()
private let cardView = UIView()
private let titleLabel = UILabel()
private let closeButton = UIButton(type: .system)
private let albumNameLabel = UILabel()
private let qrImageView = UIImageView()
private let loadingIndicator = UIActivityIndicatorView(style: .medium)
private let hintLabel = UILabel()
private let downloadButton = UIButton(type: .system)
init(state: TravelAlbumEntryViewModel.AlbumCodeState) {
self.state = state
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .overFullScreen
modalTransitionStyle = .crossDissolve
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupConstraints()
applyState()
}
private func setupUI() {
dimView.backgroundColor = UIColor.black.withAlphaComponent(0.35)
cardView.backgroundColor = .white
cardView.layer.cornerRadius = 16
cardView.clipsToBounds = true
titleLabel.text = "相册码"
titleLabel.font = .systemFont(ofSize: 18, weight: .bold)
titleLabel.textColor = AppColor.textPrimary
titleLabel.textAlignment = .center
closeButton.setImage(UIImage(systemName: "xmark"), for: .normal)
closeButton.tintColor = AppColor.textSecondary
albumNameLabel.font = .systemFont(ofSize: 18, weight: .medium)
albumNameLabel.textColor = AppColor.textPrimary
albumNameLabel.textAlignment = .center
qrImageView.contentMode = .scaleAspectFit
qrImageView.layer.cornerRadius = 8
qrImageView.clipsToBounds = true
hintLabel.textAlignment = .center
hintLabel.font = .systemFont(ofSize: 13)
hintLabel.textColor = AppColor.textSecondary
hintLabel.backgroundColor = AppColor.primary.withAlphaComponent(0.06)
hintLabel.layer.cornerRadius = 8
hintLabel.layer.borderWidth = 1
hintLabel.layer.borderColor = AppColor.primary.withAlphaComponent(0.35).cgColor
hintLabel.clipsToBounds = true
let hint = NSMutableAttributedString(string: "微信", attributes: [.foregroundColor: AppColor.textSecondary])
hint.append(NSAttributedString(string: "扫一扫", attributes: [.foregroundColor: AppColor.primary, .font: UIFont.systemFont(ofSize: 13, weight: .medium)]))
hint.append(NSAttributedString(string: ",查看下载照片", attributes: [.foregroundColor: AppColor.textSecondary]))
hintLabel.attributedText = hint
downloadButton.setTitle("下载图片", for: .normal)
downloadButton.setTitleColor(.white, for: .normal)
downloadButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
downloadButton.backgroundColor = AppColor.primary
downloadButton.layer.cornerRadius = 23
view.addSubview(dimView)
view.addSubview(cardView)
[titleLabel, closeButton, albumNameLabel, qrImageView, loadingIndicator, hintLabel, downloadButton].forEach(cardView.addSubview)
closeButton.addTarget(self, action: #selector(closeTapped), for: .touchUpInside)
downloadButton.addTarget(self, action: #selector(downloadTapped), for: .touchUpInside)
}
private func setupConstraints() {
dimView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
cardView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.width.equalToSuperview().multipliedBy(0.78)
}
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(18)
make.leading.trailing.equalToSuperview().inset(48)
}
closeButton.snp.makeConstraints { make in
make.centerY.equalTo(titleLabel)
make.trailing.equalToSuperview().offset(-20)
make.size.equalTo(28)
}
albumNameLabel.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(18)
make.leading.trailing.equalToSuperview().inset(20)
}
qrImageView.snp.makeConstraints { make in
make.top.equalTo(albumNameLabel.snp.bottom).offset(18)
make.centerX.equalToSuperview()
make.size.equalTo(190)
}
loadingIndicator.snp.makeConstraints { make in
make.center.equalTo(qrImageView)
}
hintLabel.snp.makeConstraints { make in
make.top.equalTo(qrImageView.snp.bottom).offset(18)
make.centerX.equalToSuperview()
make.height.equalTo(34)
make.leading.greaterThanOrEqualToSuperview().offset(20)
}
downloadButton.snp.makeConstraints { make in
make.top.equalTo(hintLabel.snp.bottom).offset(20)
make.leading.trailing.equalToSuperview().inset(20)
make.height.equalTo(46)
make.bottom.equalToSuperview().offset(-18)
}
}
private func applyState() {
albumNameLabel.text = state.albumName.isEmpty ? "未命名相册" : state.albumName
if state.isLoading {
loadingIndicator.startAnimating()
qrImageView.image = nil
} else {
loadingIndicator.stopAnimating()
if let url = URL(string: state.qrImageUrl), !state.qrImageUrl.isEmpty {
qrImageView.kf.setImage(with: url)
} else {
qrImageView.image = UIImage(systemName: "qrcode")
qrImageView.tintColor = AppColor.textSecondary
}
}
downloadButton.isEnabled = !state.isLoading && !state.qrImageUrl.isEmpty
downloadButton.alpha = downloadButton.isEnabled ? 1 : 0.5
}
func updateDownloading(_ isDownloading: Bool) {
downloadButton.setTitle(isDownloading ? "保存中..." : "下载图片", for: .normal)
downloadButton.isEnabled = !isDownloading
}
@objc private func closeTapped() {
onClose?()
dismiss(animated: true)
}
@objc private func downloadTapped() {
onDownload?()
}
}