Skip to content

Commit

Permalink
[#74]Feat: 경고창 클래스 커스텀
Browse files Browse the repository at this point in the history
- ReportAction enum 커스텀
- title, message, contentView, 왼쪽, 오른쪽, dim action 추가 함수 구현
- UIViewController에서 경고창 표시하는 함수 구현
- Color -> Image로 변환 함수 구현 => button에 State에 따른 색상을 넣기 위함
- addAction Custom -> button 혹은 view에서 동작 구현을 위함
  • Loading branch information
Minny27 authored and ibcylon committed Jun 5, 2024
1 parent 2cdaf9d commit 3dd71ad
Show file tree
Hide file tree
Showing 5 changed files with 437 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
//
// TFAlertViewController.swift
// DSKit
//
// Created by SeungMin on 4/3/24.
//

import UIKit

public enum ReportAction {
case complaints, block, withdraw

var title: String {
switch self {
case .complaints:
return "차단할까요?"
case .block:
return "어떤 문제가 있나요?"
case .withdraw:
return "계정 탈퇴하기"
}
}

var message: String? {
switch self {
case .block:
return "해당 사용자와 서로 차단됩니다."
case .withdraw:
return "정말 탈퇴하시겠어요? 회원님의 모든 정보 및\n사용 내역은 복구 불가합니다. 블링 환불 관련 문의는\n[email protected] 으로 부탁드립니다."
default:
return nil
}
}

var leftActionTitle: String {
switch self {
case .complaints:
return "차단할까요?"
case .block:
return "차단하기"
case .withdraw:
return "탈퇴하기"
}
}

var rightActionTitle: String {
switch self {
default:
return "취소"
}
}
}

public final class TFAlertViewController: TFBaseViewController {
private var titleText: String?
private var messageText: String?
private var contentView: UIView?

private lazy var dimView: UIView = {
let view = UIView()
view.backgroundColor = DSKitAsset.Color.DimColor.default.color
return view
}()

private lazy var containerStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .center
stackView.backgroundColor = DSKitAsset.Color.neutral600.color
stackView.layer.cornerRadius = 8
stackView.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
stackView.layoutMargins = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0)
stackView.isLayoutMarginsRelativeArrangement = true
return stackView
}()

private lazy var labelStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 6
stackView.alignment = .center
return stackView
}()

private lazy var buttonStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 16.0
stackView.alignment = .center
return stackView
}()

private lazy var titleLabel: UILabel? = {
guard titleText != nil else { return nil }

let label = UILabel()
label.text = titleText
label.font = UIFont.thtH5Sb
label.textAlignment = .center
label.textColor = DSKitAsset.Color.neutral50.color
label.numberOfLines = 0
return label
}()

private lazy var messageLabel: UILabel? = {
guard messageText != nil else { return nil }

let label = UILabel()
label.text = messageText
label.font = UIFont.thtP1R
label.textAlignment = .center
label.textColor = DSKitAsset.Color.neutral300.color
label.numberOfLines = 0
return label
}()

let separatorView: UIView = {
let view = UIView()
view.backgroundColor = DSKitAsset.Color.neutral400.color
return view
}()

init(
titleText: String? = nil,
messageText: String? = nil
) {
super.init(nibName: nil, bundle: nil)
self.titleText = titleText
self.messageText = messageText

modalPresentationStyle = .overFullScreen
}

convenience init(contentView: UIView) {
self.init()

self.contentView = contentView
modalPresentationStyle = .overFullScreen
}

required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

// curveEaseOut: 시작은 천천히, 끝날 땐 빠르게
UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseOut) { [weak self] in
self?.containerStackView.transform = .identity
self?.containerStackView.isHidden = false
}
}

public override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

// curveEaseIn: 시작은 빠르게, 끝날 땐 천천히
UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseIn) { [weak self] in
self?.containerStackView.transform = .identity
self?.containerStackView.isHidden = true
}
}

public override func makeUI() {
view.addSubviews([dimView, containerStackView])
containerStackView.addArrangedSubviews([labelStackView, buttonStackView])

dimView.snp.makeConstraints {
$0.edges.equalToSuperview()
}

containerStackView.snp.makeConstraints {
$0.centerY.equalToSuperview()
$0.leading.trailing.equalToSuperview().inset(28)
}

labelStackView.snp.makeConstraints {
$0.width.equalToSuperview()
}

buttonStackView.snp.makeConstraints {
$0.width.equalToSuperview()
}

if let titleLabel = titleLabel {
labelStackView.addArrangedSubview(titleLabel)

}

if let messageLabel = messageLabel {
labelStackView.addArrangedSubview(messageLabel)
}

if !labelStackView.subviews.isEmpty {
containerStackView.setCustomSpacing(20, after: labelStackView)
}

separatorView.snp.makeConstraints {
$0.width.equalToSuperview()
$0.height.equalTo(1.5)
}
}

public func addActionToButton(
title: String? = nil,
completion: (() -> Void)? = nil
) {
guard let title = title else { return }

let button = UIButton()
button.titleLabel?.font = UIFont.thtSubTitle2Sb

// enable
button.setTitle(title, for: .normal)
button.setTitleColor(DSKitAsset.Color.neutral50.color, for: .normal)
button.setBackgroundImage(DSKitAsset.Color.neutral600.color.image(), for: .normal)

// disable
button.setTitleColor(DSKitAsset.Color.neutral50.color, for: .disabled)
button.setBackgroundImage(DSKitAsset.Color.neutral300.color.image(), for: .disabled)

button.addAction(for: .touchUpInside) { _ in
completion?()
}

if let _ = buttonStackView.subviews.first {
buttonStackView.addArrangedSubview(separatorView)
}

buttonStackView.addArrangedSubview(button)
button.snp.makeConstraints { $0.width.equalToSuperview() }
}

public func addActionToDim(completion: (() -> Void)? = nil) {
let tapGestureRecognizer = UITapGestureRecognizer()
tapGestureRecognizer.addAction(closure: { _ in completion?() })

dimView.addGestureRecognizer(tapGestureRecognizer)
}
}
18 changes: 18 additions & 0 deletions Projects/Modules/DesignSystem/Src/Util/UIColor+Util.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// UIColor+Util.swift
// DSKit
//
// Created by SeungMin on 4/20/24.
//

import UIKit

extension UIColor {
/// Convert color to image
func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { rendererContext in
self.setFill()
rendererContext.fill(CGRect(origin: .zero, size: size))
}
}
}
45 changes: 45 additions & 0 deletions Projects/Modules/DesignSystem/Src/Util/UIControl+Util.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// UIControl+Util.swift
// DSKit
//
// Created by SeungMin on 4/20/24.
//

import UIKit

extension UIControl {
public typealias UIControlTargetClosure = (UIControl) -> ()

private class UIControlClosureWrapper: NSObject {
let closure: UIControlTargetClosure
init(_ closure: @escaping UIControlTargetClosure) {
self.closure = closure
}
}

private struct AssociatedKeys {
static var targetClosure = "targetClosure"
}

private var targetClosure: UIControlTargetClosure? {
get {
guard let closureWrapper = objc_getAssociatedObject(self, &AssociatedKeys.targetClosure) as? UIControlClosureWrapper else { return nil }
return closureWrapper.closure

} set(newValue) {
guard let newValue = newValue else { return }
objc_setAssociatedObject(self, &AssociatedKeys.targetClosure, UIControlClosureWrapper(newValue),
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}

@objc func closureAction() {
guard let targetClosure = targetClosure else { return }
targetClosure(self)
}

public func addAction(for event: UIControl.Event, closure: @escaping UIControlTargetClosure) {
targetClosure = closure
addTarget(self, action: #selector(UIControl.closureAction), for: event)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// UITapGestureRecognizer.swift
// DSKit
//
// Created by SeungMin on 4/20/24.
//

import UIKit

extension UITapGestureRecognizer {
public typealias UITapGestureTargetClosure = (UITapGestureRecognizer) -> ()

private class UITapGestureClosureWrapper: NSObject {
let closure: UITapGestureTargetClosure
init(_ closure: @escaping UITapGestureTargetClosure) {
self.closure = closure
}
}

private struct AssociatedKeys {
static var targetClosure = "targetClosure"
}

private var targetClosure: UITapGestureTargetClosure? {
get {
guard let closureWrapper = objc_getAssociatedObject(
self,
&AssociatedKeys.targetClosure
) as? UITapGestureClosureWrapper else { return nil }
return closureWrapper.closure

} set(newValue) {
guard let newValue = newValue else { return }
objc_setAssociatedObject(
self,
&AssociatedKeys.targetClosure,
UITapGestureClosureWrapper(newValue),
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}

@objc func closureAction() {
guard let targetClosure = targetClosure else { return }
targetClosure(self)
}

public func addAction(closure: @escaping UITapGestureTargetClosure) {
targetClosure = closure
addTarget(self, action: #selector(UITapGestureRecognizer.closureAction))
}
}
Loading

0 comments on commit 3dd71ad

Please sign in to comment.