Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Koin/Core/DesignSystem/Toast/ToastConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ struct ToastConfig {
let intent: ToastIntent
let variant: ToastVariant
let message: String
let bottomInset: CGFloat
}
24 changes: 13 additions & 11 deletions Koin/Core/DesignSystem/Toast/UIViewController+Toast.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ extension UIViewController {
removeExistingToast(from: window)

var toastMessageView: ToastMessageView!
toastMessageView = ToastMessageView(config: config) { [weak self] in
self?.dismissToast(toastMessageView)
toastMessageView = ToastMessageView(config: config) {
UIViewController.dismissToast(toastMessageView)
buttonAction?()
}

window.addSubview(toastMessageView)

toastMessageView.snp.makeConstraints {
$0.leading.trailing.equalToSuperview().inset(20)
$0.bottom.equalTo(window.safeAreaLayoutGuide).inset(70)
$0.bottom.equalTo(window.safeAreaLayoutGuide).inset(config.bottomInset)
}

showToastWithAnimation(toastMessageView, duration: duration)
Expand All @@ -45,19 +45,19 @@ extension UIViewController {
private func showToastWithAnimation(_ toastMessageView: ToastMessageView, duration: TimeInterval) {
toastMessageView.alpha = 0
toastMessageView.transform = CGAffineTransform(translationX: 0, y: 20)

UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut, .allowUserInteraction]) {
toastMessageView.alpha = 1
toastMessageView.transform = .identity
} completion: { [weak self] _ in
} completion: { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + duration) { [weak toastMessageView] in
guard let toastMessageView = toastMessageView else { return }
self?.dismissToast(toastMessageView)
UIViewController.dismissToast(toastMessageView)
}
}
}

private func dismissToast(_ toastView: ToastMessageView) {
private static func dismissToast(_ toastView: ToastMessageView) {
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseIn, .beginFromCurrentState]) {
toastView.alpha = 0
toastView.transform = CGAffineTransform(translationX: 0, y: 20)
Expand All @@ -81,21 +81,23 @@ extension UIViewController {
extension UIViewController {

// 기본 Toast를 표시
func showToastMessage(message: String, intent: ToastIntent = .neutral, duration: TimeInterval = 3.0) {
func showToastMessage(message: String, intent: ToastIntent = .neutral, duration: TimeInterval = 3.0, bottomInset: CGFloat = 24) {
let config = ToastConfig(
intent: intent,
variant: .standard,
message: message
message: message,
bottomInset: bottomInset
)
showToastMessage(config: config, duration: duration)
}

// 버튼이 있는 Toast를 표시
func showToastMessageWithButton(message: String, intent: ToastIntent = .neutral, buttonTitle: String, duration: TimeInterval = 3.0, buttonAction: @escaping () -> Void) {
func showToastMessageWithButton(message: String, intent: ToastIntent = .neutral, buttonTitle: String, duration: TimeInterval = 3.0, bottomInset: CGFloat = 24, buttonAction: @escaping () -> Void) {
let config = ToastConfig(
intent: intent,
variant: .action(title: buttonTitle),
message: message
message: message,
bottomInset: bottomInset
)
showToastMessage(config: config, duration: duration, buttonAction: buttonAction)
}
Expand Down
19 changes: 15 additions & 4 deletions Koin/Core/Extensions/UILabel+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ extension UILabel {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineHeightMultiple = lineHeight

let attributedString = NSMutableAttributedString(string: text)
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
let attributedString = NSMutableAttributedString(
string: text,
attributes: [
.font: self.font as Any,
.foregroundColor: self.textColor as Any,
.paragraphStyle: paragraphStyle
]
)

self.attributedText = attributedString
}

Expand All @@ -23,10 +30,14 @@ extension UILabel {

let imageAttachment = NSTextAttachment()
imageAttachment.image = image
imageAttachment.bounds = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)

let fontCapHeight = font.capHeight
let imageYOffset = (fontCapHeight - imageSize.height) / 2
imageAttachment.bounds = CGRect(x: 0, y: imageYOffset, width: imageSize.width, height: imageSize.height)

attributedString.append(NSAttributedString(attachment: imageAttachment))

let textWithSpacing = NSAttributedString(string: " " + text, attributes: [.font: font, .foregroundColor: textColor, .baselineOffset: 4])
let textWithSpacing = NSAttributedString(string: " " + text, attributes: [.font: font, .foregroundColor: textColor])

attributedString.append(textWithSpacing)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ extension ReviewListViewController {
private func deleteReview() {
let (reviewId, shopId) = viewModel.deleteParameter
reviewListCollectionView.disappearReview(reviewId, shopId: shopId)
showToastMessage(message: "리뷰가 삭제되었어요")
}

private func showZoomedImage(_ image: UIImage?) {
Expand Down Expand Up @@ -473,6 +474,7 @@ extension ReviewListViewController {
private func bindShopReviewReportViewController(_ viewController: ShopReviewReportViewController) {
viewController.reviewInfoPublisher
.sink { [weak self] tuple in
self?.showToastMessage(message: "리뷰가 신고되었어요.", intent: .neutral)
self?.reviewListCollectionView.reportReview(tuple.0, shopId: tuple.1)
}
.store(in: &cancellables)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,77 +5,74 @@
// Created by 김나훈 on 8/13/24.
//


import Combine
import UIKit
import SnapKit

final class DeleteReviewModalViewController: UIViewController {

// MARK: - Properties
let deleteButtonPublisher = PassthroughSubject<Void, Never>()
let cancelButtonPublisher = PassthroughSubject<Void, Never>()

private let messageLabel = UILabel().then {
$0.font = UIFont.appFont(.pretendardMedium, size: 18)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 8
let text = "리뷰를 삭제 하시겠습니까?"
let attributedString = NSMutableAttributedString(string: text)

let loginRange = (text as NSString).range(of: "삭제")
attributedString.addAttribute(.foregroundColor, value: UIColor.appColor(.sub500), range: loginRange)
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: text.count))
$0.attributedText = attributedString
$0.textAlignment = .center
// MARK: - UI Components
private let containerView = UIView().then {
$0.backgroundColor = .white
$0.layer.cornerRadius = 8
$0.layer.masksToBounds = true
}


private let subMessageLabel = UILabel().then {
$0.font = UIFont.appFont(.pretendardRegular, size: 14)
$0.textColor = UIColor.appColor(.neutral500)
private let reviewDeleteInfoLabel = UILabel().then {
$0.font = UIFont.appFont(.pretendardRegular, size: 15)
$0.textColor = UIColor.appColor(.neutral600)
$0.numberOfLines = 0
$0.textAlignment = .center

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 6
let text = "삭제한 리뷰는 되돌릴 수 없습니다."
paragraphStyle.alignment = .center

let text = "삭제한 리뷰는 되돌릴 수 없습니다.\n삭제 하시겠습니까?"
let attributedString = NSMutableAttributedString(string: text)
attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: text.count))

$0.attributedText = attributedString
$0.textAlignment = .center
}

private let closeButton = UIButton().then {
$0.backgroundColor = UIColor.appColor(.neutral0)
$0.layer.borderColor = UIColor.appColor(.neutral500).cgColor
$0.layer.borderColor = UIColor.appColor(.neutral400).cgColor
$0.layer.borderWidth = 1.0
$0.setTitle("취소하기", for: .normal)
$0.setTitleColor(UIColor.appColor(.neutral600), for: .normal)
$0.titleLabel?.font = UIFont.appFont(.pretendardMedium, size: 15)
$0.layer.cornerRadius = 4
$0.layer.cornerRadius = 6
$0.layer.masksToBounds = true
}

private let deleteButton = UIButton().then {
$0.backgroundColor = UIColor.appColor(.sub500)
$0.backgroundColor = UIColor.appColor(.new500)
$0.setTitle("삭제하기", for: .normal)
$0.setTitleColor(UIColor.appColor(.neutral0), for: .normal)
$0.titleLabel?.font = UIFont.appFont(.pretendardMedium, size: 15)
$0.layer.cornerRadius = 4
$0.layer.cornerRadius = 6
$0.layer.masksToBounds = true
}

private let containerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 4
view.layer.masksToBounds = true
return view
}()

// MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
configureView()
setAddTarget()
}

private func setAddTarget() {
deleteButton.addTarget(self, action: #selector(deleteButtonTapped), for: .touchUpInside)
closeButton.addTarget(self, action: #selector(closeButtonTapped), for: .touchUpInside)
}

}

extension DeleteReviewModalViewController {
@objc private func closeButtonTapped() {
cancelButtonPublisher.send()
dismiss(animated: true, completion: nil)
Expand All @@ -87,43 +84,43 @@ final class DeleteReviewModalViewController: UIViewController {
}
}

// MARK: - UI Functions
extension DeleteReviewModalViewController {

private func setUpLayOuts() {
[containerView].forEach {
view.addSubview($0)
}
[messageLabel, subMessageLabel, closeButton, deleteButton].forEach {

[reviewDeleteInfoLabel, closeButton, deleteButton].forEach {
containerView.addSubview($0)
}
}

private func setUpConstraints() {
containerView.snp.makeConstraints { make in
make.centerX.equalTo(view.snp.centerX)
make.centerY.equalTo(view.snp.centerY)
make.width.equalTo(301)
make.height.equalTo(179)
containerView.snp.makeConstraints {
$0.centerX.equalTo(view.snp.centerX)
$0.centerY.equalTo(view.snp.centerY)
$0.width.equalTo(301)
$0.height.equalTo(168)
}
messageLabel.snp.makeConstraints { make in
make.top.equalTo(containerView.snp.top).offset(24)
make.centerX.equalTo(containerView.snp.centerX)
}
subMessageLabel.snp.makeConstraints { make in
make.top.equalTo(messageLabel.snp.bottom).offset(16)
make.centerX.equalTo(containerView.snp.centerX)

reviewDeleteInfoLabel.snp.makeConstraints {
$0.top.equalTo(containerView.snp.top).offset(24)
$0.centerX.equalTo(containerView.snp.centerX)
}
closeButton.snp.makeConstraints { make in
make.top.equalTo(subMessageLabel.snp.bottom).offset(24)
make.trailing.equalTo(containerView.snp.centerX).offset(-2)
make.width.equalTo(114.5)
make.height.equalTo(48)

closeButton.snp.makeConstraints {
$0.top.equalTo(reviewDeleteInfoLabel.snp.bottom).offset(24)
$0.trailing.equalTo(containerView.snp.centerX).offset(-4)
$0.width.equalTo(114.5)
$0.height.equalTo(48)
}
deleteButton.snp.makeConstraints { make in
make.top.equalTo(subMessageLabel.snp.bottom).offset(24)
make.leading.equalTo(containerView.snp.centerX).offset(2)
make.width.equalTo(114.5)
make.height.equalTo(48)

deleteButton.snp.makeConstraints {
$0.top.equalTo(reviewDeleteInfoLabel.snp.bottom).offset(24)
$0.leading.equalTo(containerView.snp.centerX).offset(4)
$0.width.equalTo(114.5)
$0.height.equalTo(48)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,17 @@ extension ReviewListCollectionView {
}

private func calculateCellHeight(for indexPath: IndexPath, width: CGFloat) -> CGFloat {
let reviewItem = reviewList[indexPath.row]

if reviewItem.isReported {
return 24
}

let estimatedHeight: CGFloat = 1000
let dummyCell = ReviewListCollectionViewCell(
frame: CGRect(x: 0, y: 0, width: width, height: estimatedHeight)
)

let reviewItem = reviewList[indexPath.row]
dummyCell.configure(review: reviewItem)
dummyCell.setNeedsLayout()
dummyCell.layoutIfNeeded()
Expand Down
Loading