266 lines
9.1 KiB
Swift
266 lines
9.1 KiB
Swift
|
|
//
|
||
|
|
// UploadImageView.swift
|
||
|
|
// Crush
|
||
|
|
//
|
||
|
|
// Created by Leon on 2025/7/20.
|
||
|
|
//
|
||
|
|
|
||
|
|
import UIKit
|
||
|
|
import SnapKit
|
||
|
|
|
||
|
|
enum UploadImageState: UInt {
|
||
|
|
case `default`
|
||
|
|
case uploading
|
||
|
|
case success
|
||
|
|
case failed
|
||
|
|
case oversize
|
||
|
|
case yellow
|
||
|
|
}
|
||
|
|
|
||
|
|
class UploadImageView: UIView {
|
||
|
|
// MARK: - Properties
|
||
|
|
let imageView: CLImageView
|
||
|
|
let errorLabel: UILabel
|
||
|
|
let deleteButton: EPIconTertiaryDarkButton
|
||
|
|
let indicatorView: UIActivityIndicatorView
|
||
|
|
|
||
|
|
var state: UploadImageState = .default {
|
||
|
|
didSet {
|
||
|
|
dealUploadState(state)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var notShowDeleteButton: Bool = false {
|
||
|
|
didSet {
|
||
|
|
deleteButton.alpha = notShowDeleteButton ? 0 : 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var bgTapBlock: (() -> Void)?
|
||
|
|
var deleteTapBlock: (() -> Void)?
|
||
|
|
var retryTapBlock: (() -> Void)?
|
||
|
|
|
||
|
|
private var bottomBottom: UIButton
|
||
|
|
private var bgButton: EPHighlightBorderButton
|
||
|
|
private var loadingView: UIView
|
||
|
|
private var indicatorLabel: UILabel
|
||
|
|
private var errorView: UIView
|
||
|
|
private var retryButton: UIButton
|
||
|
|
private var videoMode: Bool = false
|
||
|
|
|
||
|
|
// MARK: - Initialization
|
||
|
|
override init(frame: CGRect) {
|
||
|
|
imageView = CLImageView(frame: .zero)
|
||
|
|
errorLabel = UILabel()
|
||
|
|
deleteButton = EPIconTertiaryDarkButton(radius: .round, iconSize: .small, iconCode: .delete)
|
||
|
|
indicatorView = UIActivityIndicatorView()
|
||
|
|
bottomBottom = UIButton(type: .custom)
|
||
|
|
bgButton = EPHighlightBorderButton(type: .custom)
|
||
|
|
loadingView = UIView()
|
||
|
|
indicatorLabel = UILabel()
|
||
|
|
errorView = UIView()
|
||
|
|
retryButton = UIButton()
|
||
|
|
|
||
|
|
super.init(frame: frame)
|
||
|
|
setupUI()
|
||
|
|
}
|
||
|
|
|
||
|
|
@available(*, unavailable)
|
||
|
|
required init?(coder: NSCoder) {
|
||
|
|
fatalError("init(coder:) has not been implemented")
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Setup
|
||
|
|
private func setupUI() {
|
||
|
|
backgroundColor = .c.csen//EPSystemToken.color(.surfaceElementNormal)
|
||
|
|
layer.cornerRadius = 8
|
||
|
|
clipsToBounds = true
|
||
|
|
|
||
|
|
// Bottom button
|
||
|
|
bottomBottom.backgroundColor = .clear
|
||
|
|
bottomBottom.addTarget(self, action: #selector(bgButtonTapAction), for: .touchUpInside)
|
||
|
|
addSubview(bottomBottom)
|
||
|
|
bottomBottom.snp.makeConstraints { make in
|
||
|
|
make.edges.equalTo(self)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Background button
|
||
|
|
bgButton.layer.cornerRadius = layer.cornerRadius
|
||
|
|
bgButton.clipsToBounds = true
|
||
|
|
bgButton.addTarget(self, action: #selector(bgButtonTapAction), for: .touchUpInside)
|
||
|
|
let bgButtonImageColor: UIColor = .c.cttn
|
||
|
|
let image = MWIconFont.image(fromIcon: .iconUploadimg, size: CGSize(width: 48, height: 48), color: bgButtonImageColor)
|
||
|
|
//MWIconFont.image(fromIconInt: .iconUploadimg, size: CGSize(width: 48, height: 48), color: bgButtonImageColor, edgeInsets: .zero)
|
||
|
|
bgButton.setImage(image, for: .normal)
|
||
|
|
bgButton.setTitle("Click to generate images", for: .normal)
|
||
|
|
bgButton.setTitleColor(.c.cttn, for: .normal)
|
||
|
|
bgButton.titleLabel?.font = .t.tbm
|
||
|
|
//EPSystemToken.typography(.txtBodyM).font
|
||
|
|
addSubview(bgButton)
|
||
|
|
bgButton.snp.makeConstraints { make in
|
||
|
|
make.edges.equalTo(self)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Image view
|
||
|
|
imageView.layer.cornerRadius = 8
|
||
|
|
imageView.clipsToBounds = true
|
||
|
|
imageView.layer.borderColor = UIColor.c.civn.cgColor
|
||
|
|
imageView.isHidden = true
|
||
|
|
imageView.contentMode = .scaleAspectFill
|
||
|
|
addSubview(imageView)
|
||
|
|
imageView.snp.makeConstraints { make in
|
||
|
|
make.edges.equalTo(self)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Loading view
|
||
|
|
loadingView.isHidden = true
|
||
|
|
loadingView.backgroundColor = UIColor.black.withAlphaComponent(0.7) // Replaced hex_120E1B_bg
|
||
|
|
addSubview(loadingView)
|
||
|
|
loadingView.snp.makeConstraints { make in
|
||
|
|
make.edges.equalTo(self)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Indicator view
|
||
|
|
indicatorView.color = .white // Replaced hex_FFFFFF
|
||
|
|
loadingView.addSubview(indicatorView)
|
||
|
|
indicatorView.snp.makeConstraints { make in
|
||
|
|
make.centerX.equalTo(loadingView)
|
||
|
|
make.centerY.equalTo(loadingView).offset(-10)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Indicator label
|
||
|
|
indicatorLabel.font = .t.tbm//EPSystemToken.typography(.txtBodyM).font
|
||
|
|
indicatorLabel.textColor = .c.ctpsn//EPSystemToken.color(.txtPrimarySpecialmapNormal)
|
||
|
|
indicatorLabel.text = NSLocalizedString("uploading", comment: "")
|
||
|
|
loadingView.addSubview(indicatorLabel)
|
||
|
|
indicatorLabel.snp.makeConstraints { make in
|
||
|
|
make.centerX.equalTo(loadingView)
|
||
|
|
make.top.equalTo(indicatorView.snp.bottom).offset(12)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Error view
|
||
|
|
errorView.isHidden = true
|
||
|
|
errorView.backgroundColor = .red //EPSystemToken.color(.importantOnpicNormal)
|
||
|
|
addSubview(errorView)
|
||
|
|
errorView.snp.makeConstraints { make in
|
||
|
|
make.leading.trailing.bottom.equalTo(self)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Error label
|
||
|
|
errorLabel.isHidden = false
|
||
|
|
errorLabel.font = .t.tbs//EPSystemToken.typography(.txtBodyS).font
|
||
|
|
errorLabel.textColor = .c.ctpsn//EPSystemToken.color(.txtPrimarySpecialmapNormal)
|
||
|
|
errorLabel.numberOfLines = 5
|
||
|
|
errorLabel.textAlignment = .left
|
||
|
|
errorView.addSubview(errorLabel)
|
||
|
|
errorLabel.snp.makeConstraints { make in
|
||
|
|
make.leading.equalTo(errorView).offset(16)
|
||
|
|
make.trailing.equalTo(errorView).offset(-16)
|
||
|
|
make.top.equalTo(errorView).offset(8)
|
||
|
|
make.bottom.equalTo(errorView).offset(-8)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Delete button
|
||
|
|
let deleteButtonSize = deleteButton.bgImageSize()
|
||
|
|
deleteButton.addTarget(self, action: #selector(deleteAction), for: .touchUpInside)
|
||
|
|
addSubview(deleteButton)
|
||
|
|
deleteButton.snp.makeConstraints { make in
|
||
|
|
make.trailing.equalTo(self).offset(-16)
|
||
|
|
make.top.equalTo(self).offset(16)
|
||
|
|
make.size.equalTo(deleteButtonSize)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Retry button
|
||
|
|
retryButton.isHidden = true
|
||
|
|
|
||
|
|
let retryImage = MWIconFont.image(fromIcon: .iconReload, size: CGSize(width: 48, height: 48), color: UIColor.c.ctpsn)
|
||
|
|
retryButton.setImage(retryImage, for: .normal)
|
||
|
|
retryButton.addTarget(self, action: #selector(retryAction), for: .touchUpInside)
|
||
|
|
addSubview(retryButton)
|
||
|
|
retryButton.snp.makeConstraints { make in
|
||
|
|
make.center.equalTo(self)
|
||
|
|
make.size.equalTo(CGSize(width: 48, height: 48))
|
||
|
|
}
|
||
|
|
|
||
|
|
state = .default
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Public Methods
|
||
|
|
func setupVideoMode() {
|
||
|
|
videoMode = true
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Actions
|
||
|
|
@objc private func bgButtonTapAction() {
|
||
|
|
bgTapBlock?()
|
||
|
|
}
|
||
|
|
|
||
|
|
@objc private func deleteAction() {
|
||
|
|
deleteTapBlock?()
|
||
|
|
}
|
||
|
|
|
||
|
|
@objc private func retryAction() {
|
||
|
|
retryTapBlock?()
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - State Handling
|
||
|
|
private func dealUploadState(_ state: UploadImageState) {
|
||
|
|
indicatorView.stopAnimating()
|
||
|
|
imageView.isHidden = false
|
||
|
|
imageView.layer.borderWidth = 0
|
||
|
|
errorLabel.text = ""
|
||
|
|
bgButton.isHidden = true
|
||
|
|
|
||
|
|
switch state {
|
||
|
|
case .default:
|
||
|
|
bgButton.isHidden = false
|
||
|
|
bgButton.isEnabled = true
|
||
|
|
imageView.isHidden = true
|
||
|
|
deleteButton.isHidden = true
|
||
|
|
retryButton.isHidden = true
|
||
|
|
loadingView.isHidden = true
|
||
|
|
errorView.isHidden = true
|
||
|
|
case .uploading:
|
||
|
|
bottomBottom.isEnabled = false
|
||
|
|
deleteButton.isHidden = false
|
||
|
|
retryButton.isHidden = true
|
||
|
|
loadingView.isHidden = false
|
||
|
|
errorView.isHidden = true
|
||
|
|
indicatorView.startAnimating()
|
||
|
|
case .failed:
|
||
|
|
bottomBottom.isEnabled = false
|
||
|
|
deleteButton.isHidden = false
|
||
|
|
retryButton.isHidden = false
|
||
|
|
loadingView.isHidden = true
|
||
|
|
errorView.isHidden = false
|
||
|
|
imageView.layer.borderWidth = CLSystemToken.border(token: .bs)//EPSystemToken.border(.borderS)
|
||
|
|
case .oversize:
|
||
|
|
bottomBottom.isEnabled = false
|
||
|
|
deleteButton.isHidden = false
|
||
|
|
retryButton.isHidden = true
|
||
|
|
loadingView.isHidden = true
|
||
|
|
errorView.isHidden = false
|
||
|
|
imageView.layer.borderWidth = CLSystemToken.border(token: .bs)//EPSystemToken.border(.borderS)
|
||
|
|
case .yellow:
|
||
|
|
bottomBottom.isEnabled = false
|
||
|
|
deleteButton.isHidden = false
|
||
|
|
retryButton.isHidden = true
|
||
|
|
loadingView.isHidden = true
|
||
|
|
errorView.isHidden = false
|
||
|
|
imageView.layer.borderWidth = CLSystemToken.border(token: .bs)
|
||
|
|
case .success:
|
||
|
|
bottomBottom.isEnabled = true
|
||
|
|
deleteButton.isHidden = false
|
||
|
|
retryButton.isHidden = true
|
||
|
|
loadingView.isHidden = true
|
||
|
|
errorView.isHidden = true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Overrides
|
||
|
|
override func layoutSubviews() {
|
||
|
|
super.layoutSubviews()
|
||
|
|
bgButton.setUp(.top, padding: 12)
|
||
|
|
}
|
||
|
|
}
|