// // LNCommonAlertView.swift // Lanu // // Created by OneeChan on 2025/12/12. // import Foundation import UIKit import SnapKit extension LNCommonAlertView { static func showCommonDeleteAlert(handler: (() -> Void)?) { let alert = LNCommonAlertView() alert.titleLabel.text = .init(key: "A00308") alert.showConfirm { handler?() } alert.showCancel() alert.popup() } } class LNCommonAlertView: UIView { private let background = UIView() private let container = UIView() private let miniScale = 0.01 private let animateDuration = 0.15 let textViews = UIStackView() let titleLabel = UILabel() let messageView = UIStackView() let messageLabel = UILabel() let subMessageLabel = UILabel() let buttonViews = UIStackView() var touchOutsideCancel = true override init(frame: CGRect) { super.init(frame: frame) setupViews() } func showConfirm(_ title: String = .init(key: "A00002"), handler: @escaping () -> Void) { let button = buildConfirmButton() button.setTitle(title, for: .normal) button.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } dismiss() handler() }), for: .touchUpInside) buttonViews.insertArrangedSubview(button, at: 0) } func showCancel(_ title: String = .init(key: "A00003"), handler: (() -> Void)? = nil) { let button = buildCancelButton() button.setTitle(title, for: .normal) button.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } dismiss() handler?() }), for: .touchUpInside) buttonViews.addArrangedSubview(button) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNCommonAlertView { func popup(_ holder: UIView? = nil) { let parentView: UIView? = if let window = holder as? UIWindow { window } else if let view = holder?.viewController?.view { view } else if let window = UIView.appKeyWindow { window } else { nil } guard let parentView else { return } parentView.addSubview(self) frame = parentView.bounds titleLabel.isHidden = titleLabel.text?.isEmpty != false messageLabel.isHidden = messageLabel.text?.isEmpty != false subMessageLabel.isHidden = subMessageLabel.text?.isEmpty != false messageView.isHidden = messageLabel.isHidden && subMessageLabel.isHidden layoutIfNeeded() container.transform = .init(scaleX: miniScale, y: miniScale) UIView.animate(withDuration: animateDuration, delay: 0, options: .curveEaseInOut) { [weak self] in guard let self else { return } container.transform = .identity } } func dismiss() { UIView.animate(withDuration: animateDuration, delay: 0, options: .curveEaseInOut) { [weak self] in guard let self else { return } container.transform = .init(scaleX: miniScale, y: miniScale) } completion: { [weak self] _ in guard let self else { return } removeFromSuperview() } } } extension LNCommonAlertView { private func setupViews() { background.backgroundColor = .black.withAlphaComponent(0.4) background.onTap { [weak self] in guard let self else { return } guard touchOutsideCancel else { return } dismiss() } addSubview(background) background.snp.makeConstraints { make in make.edges.equalToSuperview() } container.backgroundColor = .fill container.layer.cornerRadius = 20 addSubview(container) container.snp.makeConstraints { make in make.center.equalToSuperview() make.width.equalToSuperview().multipliedBy(0.8) } let closeButton = UIButton() closeButton.setImage(.init(systemName: "xmark"), for: .normal) closeButton.tintColor = .text_2 closeButton.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } dismiss() }), for: .touchUpInside) container.addSubview(closeButton) closeButton.snp.makeConstraints { make in make.top.equalToSuperview().offset(10) make.trailing.equalToSuperview().offset(-10) make.width.height.equalTo(24) } textViews.axis = .vertical textViews.spacing = 10 container.addSubview(textViews) textViews.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(24) make.top.equalToSuperview().offset(30) } titleLabel.font = .heading_h3 titleLabel.textColor = .text_4 titleLabel.textAlignment = .center titleLabel.numberOfLines = 0 textViews.addArrangedSubview(titleLabel) messageView.axis = .vertical messageView.spacing = 6 textViews.addArrangedSubview(messageView) messageLabel.font = .body_m messageLabel.textColor = .text_4 messageLabel.textAlignment = .center messageLabel.numberOfLines = 0 messageView.addArrangedSubview(messageLabel) subMessageLabel.font = .body_xs subMessageLabel.textColor = .text_4 subMessageLabel.textAlignment = .center subMessageLabel.numberOfLines = 0 messageView.addArrangedSubview(subMessageLabel) buttonViews.axis = .vertical buttonViews.spacing = 16 container.addSubview(buttonViews) buttonViews.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(50) make.top.equalTo(textViews.snp.bottom).offset(16) make.bottom.equalToSuperview().offset(-30) } } private func buildConfirmButton() -> UIButton { let button = UIButton() button.setBackgroundImage(.primary_8, for: .normal) button.setTitleColor(.text_1, for: .normal) button.titleLabel?.font = .heading_h4 button.layer.cornerRadius = 18 button.clipsToBounds = true button.snp.makeConstraints { make in make.height.equalTo(36) } return button } private func buildCancelButton() -> UIButton { let button = UIButton() button.setTitleColor(.text_4, for: .normal) button.titleLabel?.font = .body_m button.layer.cornerRadius = 18 button.layer.borderWidth = 1 button.layer.borderColor = UIColor.text_3.cgColor button.clipsToBounds = true button.snp.makeConstraints { make in make.height.equalTo(36) } return button } } #if DEBUG import SwiftUI struct LNCommonAlertViewPreview: UIViewRepresentable { func makeUIView(context: Context) -> some UIView { let container = UIView() container.backgroundColor = .lightGray let button = UIButton() button.backgroundColor = .red button.addAction(UIAction(handler: { [weak container] _ in guard let container else { return } let view = LNCommonAlertView() view.popup(container) }), for: .touchUpInside) container.addSubview(button) button.snp.makeConstraints { make in make.center.equalToSuperview() make.width.height.equalTo(50) } return container } func updateUIView(_ uiView: UIViewType, context: Context) { } } #Preview(body: { LNCommonAlertViewPreview() }) #endif