Visual_Novel_iOS/crush/Crush/Src/Components/UI/Buttons/CommonUploadImageButton.swift

286 lines
9.4 KiB
Swift

//
// CommonUploadImageButton.swift
// Crush
//
// Created by Leon on 2025/7/21.
//
import UIKit
import SnapKit
enum CommentUploadState: Int {
case loading
case success
case failed
case checkdFailed
}
class CommonUploadImageButton: UIButton {
private var indicatorBGView: UIView!
private var indicatorView: UIActivityIndicatorView!
private var retryButton: UIButton!
private var errorButton: UIButton!
private var contentImageView: UIImageView!
private var closeButton: EPIconTertiaryDarkButton!
@Published private(set) var uploadState: CommentUploadState = .loading {
didSet {
reloadViews()
}
}
private(set) var imageUrlNowIfHave: String?
var uploadModel: CommentImageModel?
var optionErrorMsg: String?
var closeAction: ((CommonUploadImageButton) -> Void)?
var tapRetryAction: ((CommonUploadImageButton) -> Void)?
var uploadSuceess: ((CommonUploadImageButton) -> Void)?
var uploadOrCheckFailed: ((CommonUploadImageButton) -> Void)?
override init(frame: CGRect) {
super.init(frame: frame)
initializeViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
initializeViews()
}
private func initializeViews() {
layer.cornerRadius = 8.0
layer.masksToBounds = true
contentImageView = {
let imageView = UIImageView()
addSubview(imageView)
imageView.contentMode = .scaleAspectFill
imageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return imageView
}()
indicatorBGView = {
let view = UIView()
addSubview(view)
view.isHidden = true
view.layer.borderColor = UIColor.c.civn.cgColor//EPSystemToken.color(.important_variant_normal).cgColor
view.layer.cornerRadius = layer.cornerRadius
view.backgroundColor = UIColor.c.csedn//EPSystemToken.color(.surface_element_dark_normal)
view.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return view
}()
indicatorView = {
let indicator = UIActivityIndicatorView()
addSubview(indicator)
indicator.color = .c.ctpsn//EPSystemToken.color(.txt_primary_specialmap_normal)
indicator.isHidden = true
indicator.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(CGSize(width: 24, height: 24))
}
return indicator
}()
closeButton = {
let button = EPIconTertiaryDarkButton(radius: .round, iconSize: .xxs, iconCode: .delete)
addSubview(button)
button.isHidden = true
button.touchAreaInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
button.addTarget(self, action: #selector(closeButtonAction), for: .touchUpInside)
button.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-8)
make.top.equalToSuperview().offset(8)
make.size.equalTo(CGSize(width: 16, height: 16))
}
return button
}()
retryButton = {
let button = UIButton(type: .custom)
addSubview(button)
button.isHidden = true
let image = MWIconFont.image(fromIcon: .iconReload, size: .init(width: 16, height: 16), color: .c.ctpsn)
button.setImage(image, for: .normal)
button.contentMode = .center
button.touchAreaInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
button.addTarget(self, action: #selector(retryButtonAction), for: .touchUpInside)
button.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(CGSize(width: 32, height: 32))
}
return button
}()
errorButton = {
let button = UIButton(type: .custom)
addSubview(button)
button.isHidden = true
button.setImage(UIImage(named: "album_reupload"), for: .normal)
button.touchAreaInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
button.addTarget(self, action: #selector(errorButtonAction), for: .touchUpInside)
button.snp.makeConstraints { make in
make.center.equalToSuperview()
make.size.equalTo(CGSize(width: 32, height: 32))
}
return button
}()
setupImageDefaultState()
}
private func reloadViews() {
indicatorBGView.isHidden = true
indicatorBGView.layer.borderWidth = 0
if indicatorView.isAnimating {
indicatorView.stopAnimating()
}
retryButton.isHidden = true
closeButton.isHidden = true
errorButton.isHidden = true
switch uploadState {
case .loading:
indicatorBGView.isHidden = false
indicatorView.startAnimating()
case .failed:
indicatorBGView.isHidden = false
retryButton.isHidden = false
closeButton.isHidden = false
indicatorBGView.layer.borderWidth = CLSystemToken.border(token: .bs)//EPSystemToken.border(.s)
case .success:
closeButton.isHidden = false
case .checkdFailed:
indicatorBGView.isHidden = false
closeButton.isHidden = false
errorButton.isHidden = false
indicatorBGView.layer.borderWidth = CLSystemToken.border(token: .bs)//EPSystemToken.border(.s)
}
if imageView?.image != nil {
setImage(nil, for: .normal)
}
}
// MARK: - Public Methods
func setupImageDefaultState() {
let image = MWIconFont.image(fromIcon: .iconUploadimg, size: .init(width: 24, height: 24), color: .c.cttn)
setImage(image, for: .normal)
backgroundColor = .c.csen//EPSystemToken.color(.surface_element_normal)
contentImageView.image = nil
imageUrlNowIfHave = nil
closeButton.isHidden = true
indicatorBGView.isHidden = true
errorButton.isHidden = true
}
@discardableResult
func bindViewImage(_ image: UIImage, report: Bool = false, checkImage: Bool = false) -> UploadPhotoM {
contentImageView.image = image
uploadState = .loading
DispatchQueue.main.async {[weak self] in
// UploadPhotoM is returned finally
self?.uploadState = .loading
}
let model = CommentImageModel()
model.isReport = report
uploadModel = model
let photo = model.startUpload(with: image, checkImage: checkImage)
uploadModel?.imageUploadComplete = { [weak self] result, photo in
guard let self = self else { return }
if result {
self.uploadState = .success
self.uploadSuceess?(self)
} else if photo.imageChecked && photo.imageCheckIsViolation {
self.uploadState = .checkdFailed
self.uploadOrCheckFailed?(self)
} else {
self.uploadState = .failed
self.uploadOrCheckFailed?(self)
}
self.reloadViews()
}
reloadViews()
return photo
}
func bindViewImageNoUpload(_ image: UIImage) {
contentImageView.image = image
uploadState = .loading
reloadViews()
}
func bindViewImage(_ image: UIImage?) {
guard let img = image else{
return
}
contentImageView.image = img
}
func bindSuccessImage(_ image: UIImage?) {
guard let img = image else{
return
}
contentImageView.image = img
uploadState = .success
}
func bindViewImageUrl(_ imageUrl: String) {
imageUrlNowIfHave = imageUrl
//contentImageView.sd_setImage(with: URL(string: imageUrl), placeholderImage: UIImage.imgPlaceHolder)
contentImageView.loadImage(imageUrl)
let model = CommentImageModel()
model.uploadUrl = imageUrl
uploadModel = model
uploadState = .success
reloadViews()
}
func givtStateOutsize(_ state: CommentUploadState) {
uploadState = state
}
func setupCornerRadius(_ radius: CGFloat) {
layer.cornerRadius = radius
indicatorBGView.layer.cornerRadius = radius
}
// MARK: - Actions
@objc private func retryButtonAction() {
uploadState = .loading
reloadViews()
if let tapRetryAction = tapRetryAction {
tapRetryAction(self)
} else {
if let img = uploadModel?.image{
uploadModel?.startUpload(with: img)
}else{
fatalError()
}
}
}
@objc private func errorButtonAction() {
if let optionErrorMsg = optionErrorMsg, !optionErrorMsg.isEmpty {
//Hud.showTip(optionErrorMsg)
Hud.toast(str: optionErrorMsg)
} else {
Hud.toast(str: "NSFW materials have been detected, please upload other photos")
}
}
@objc private func closeButtonAction() {
closeAction?(self)
}
}