From 5cab539b874dce097dd6d49c53182d5981c24ec6 Mon Sep 17 00:00:00 2001 From: JinUng41 Date: Thu, 11 Jul 2024 08:38:48 +0900 Subject: [PATCH] =?UTF-8?q?feat/#149=20=EB=AA=A8=EC=9E=84=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 엠티뷰 분기 처리는 아직 미구현 --- KkuMulKum.xcodeproj/project.pbxproj | 24 ++---- KkuMulKum/Resource/Extension/UIFont+.swift | 6 ++ KkuMulKum/Resource/Util/Toast.swift | 79 +++++++++++++++++++ .../View/InvitationCodePopUpView.swift | 69 +++++----------- .../MeetingInfo/View/MeetingInfoView.swift | 29 +++---- .../MeetingInfo/View/MeetingPromiseCell.swift | 1 + .../InvitationCodePopUpViewController.swift | 31 +++++++- .../MeetingInfoViewController.swift | 12 ++- .../ViewModel/MeetingInfoViewModel.swift | 8 +- 9 files changed, 175 insertions(+), 84 deletions(-) create mode 100644 KkuMulKum/Resource/Util/Toast.swift diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index 71363590..0591003c 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -107,7 +107,6 @@ DE254ACC2C311DC200A4015E /* Pretendard-Thin.otf in Resources */ = {isa = PBXBuildFile; fileRef = DE254AC32C311DC200A4015E /* Pretendard-Thin.otf */; }; DE32D1D22C3BF703006848DF /* LoginUserResponseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE32D1D12C3BF703006848DF /* LoginUserResponseModel.swift */; }; DE32D1D42C3BFB56006848DF /* UpdateProfileNameModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE32D1D32C3BFB56006848DF /* UpdateProfileNameModel.swift */; }; - DE6D4CFF2C3F08090005584B /* InvitationCodePopUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6D4CFE2C3F08090005584B /* InvitationCodePopUpView.swift */; }; DE6D4D0F2C3F14D80005584B /* MeetingInfoService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6D4D012C3F14D80005584B /* MeetingInfoService.swift */; }; DE6D4D102C3F14D80005584B /* InvitationCodePopUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6D4D032C3F14D80005584B /* InvitationCodePopUpView.swift */; }; DE6D4D112C3F14D80005584B /* MeetingInfoBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6D4D042C3F14D80005584B /* MeetingInfoBannerView.swift */; }; @@ -125,6 +124,7 @@ DE9E188B2C3BC92500DB76B4 /* EmptyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9E188A2C3BC92500DB76B4 /* EmptyModel.swift */; }; DE9E18922C3BCC9D00DB76B4 /* SocialLoginRequestModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9E18912C3BCC9D00DB76B4 /* SocialLoginRequestModel.swift */; }; DE9E189A2C3BCCBE00DB76B4 /* UtilsTemp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9E18992C3BCCBE00DB76B4 /* UtilsTemp.swift */; }; + DEA932182C3F180800FDF637 /* MeetingPromisesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA932172C3F180800FDF637 /* MeetingPromisesModel.swift */; }; DEBA032F2C3C24F2002ED8F2 /* ModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEBA032E2C3C24F2002ED8F2 /* ModelType.swift */; }; DEBA03312C3C2972002ED8F2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEBA03302C3C2972002ED8F2 /* ViewController.swift */; }; DED5DBEC2C345210006ECE7E /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED5DBEB2C345210006ECE7E /* BaseViewController.swift */; }; @@ -132,7 +132,7 @@ DED5DBF02C345317006ECE7E /* BaseCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED5DBEF2C345317006ECE7E /* BaseCollectionViewCell.swift */; }; DED5DBF22C34534A006ECE7E /* BaseCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED5DBF12C34534A006ECE7E /* BaseCollectionReusableView.swift */; }; DED5DBF42C34539A006ECE7E /* BaseTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED5DBF32C34539A006ECE7E /* BaseTableViewCell.swift */; }; - DEF8D1552C3E76B600BCB6CB /* InvitationCodePopUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF8D1542C3E76B600BCB6CB /* InvitationCodePopUpViewController.swift */; }; + DEF725DB2C3F3BBF008C87C7 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF725DA2C3F3BBF008C87C7 /* Toast.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -200,7 +200,6 @@ DE254AC32C311DC200A4015E /* Pretendard-Thin.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Thin.otf"; sourceTree = ""; }; DE32D1D12C3BF703006848DF /* LoginUserResponseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginUserResponseModel.swift; sourceTree = ""; }; DE32D1D32C3BFB56006848DF /* UpdateProfileNameModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateProfileNameModel.swift; sourceTree = ""; }; - DE6D4CFE2C3F08090005584B /* InvitationCodePopUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitationCodePopUpView.swift; sourceTree = ""; }; DE6D4D012C3F14D80005584B /* MeetingInfoService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingInfoService.swift; sourceTree = ""; }; DE6D4D032C3F14D80005584B /* InvitationCodePopUpView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvitationCodePopUpView.swift; sourceTree = ""; }; DE6D4D042C3F14D80005584B /* MeetingInfoBannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingInfoBannerView.swift; sourceTree = ""; }; @@ -218,6 +217,7 @@ DE9E188A2C3BC92500DB76B4 /* EmptyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyModel.swift; sourceTree = ""; }; DE9E18912C3BCC9D00DB76B4 /* SocialLoginRequestModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialLoginRequestModel.swift; sourceTree = ""; }; DE9E18992C3BCCBE00DB76B4 /* UtilsTemp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilsTemp.swift; sourceTree = ""; }; + DEA932172C3F180800FDF637 /* MeetingPromisesModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingPromisesModel.swift; sourceTree = ""; }; DEBA032E2C3C24F2002ED8F2 /* ModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelType.swift; sourceTree = ""; }; DEBA03302C3C2972002ED8F2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; DED5DBEB2C345210006ECE7E /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; @@ -225,7 +225,7 @@ DED5DBEF2C345317006ECE7E /* BaseCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCollectionViewCell.swift; sourceTree = ""; }; DED5DBF12C34534A006ECE7E /* BaseCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCollectionReusableView.swift; sourceTree = ""; }; DED5DBF32C34539A006ECE7E /* BaseTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewCell.swift; sourceTree = ""; }; - DEF8D1542C3E76B600BCB6CB /* InvitationCodePopUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitationCodePopUpViewController.swift; sourceTree = ""; }; + DEF725DA2C3F3BBF008C87C7 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -306,7 +306,6 @@ children = ( 78B9286A2C29402C006D9942 /* KkuMulKum */, 78B928692C29402C006D9942 /* Products */, - DE6D4D002C3F14B80005584B /* Recovered References */, ); sourceTree = ""; }; @@ -499,6 +498,7 @@ children = ( DE254AB62C3119D000A4015E /* ReuseIdentifiable.swift */, DE254AB82C311AB300A4015E /* Screen.swift */, + DEF725DA2C3F3BBF008C87C7 /* Toast.swift */, ); path = Util; sourceTree = ""; @@ -519,15 +519,6 @@ path = Font; sourceTree = ""; }; - DE6D4D002C3F14B80005584B /* Recovered References */ = { - isa = PBXGroup; - children = ( - DE6D4CFE2C3F08090005584B /* InvitationCodePopUpView.swift */, - DEF8D1542C3E76B600BCB6CB /* InvitationCodePopUpViewController.swift */, - ); - name = "Recovered References"; - sourceTree = ""; - }; DE6D4D022C3F14D80005584B /* Service */ = { isa = PBXGroup; children = ( @@ -668,6 +659,7 @@ DE9E188F2C3BCC7600DB76B4 /* Promises */ = { isa = PBXGroup; children = ( + DEA932172C3F180800FDF637 /* MeetingPromisesModel.swift */, DD3072132C3BF87A00416D9F /* NearestPromiseResponseModel.swift */, DD3072152C3BFE4E00416D9F /* UpcomingPromiseListResponseModel.swift */, DD3072192C3C011600416D9F /* AddPromiseRequestModel.swift */, @@ -868,8 +860,10 @@ DD931B742C3DAB9A00526452 /* ReadyPlanInfoView.swift in Sources */, 789873342C3D1A7B00435E96 /* LoginView.swift in Sources */, A3FB18592C3BF77D001483E5 /* MeetingInfoResponseModel.swift in Sources */, + DEA932182C3F180800FDF637 /* MeetingPromisesModel.swift in Sources */, DE9E18842C3BA84500DB76B4 /* CustomTextField.swift in Sources */, A3FB184F2C3BF4BC001483E5 /* MakeMeetingsResponseModel.swift in Sources */, + DEF725DB2C3F3BBF008C87C7 /* Toast.swift in Sources */, DE254AAC2C31192400A4015E /* UILabel+.swift in Sources */, DE254AB72C3119D000A4015E /* ReuseIdentifiable.swift in Sources */, DDA2EE752C385FB1007C6059 /* HomeViewController.swift in Sources */, @@ -886,7 +880,6 @@ DE9E18922C3BCC9D00DB76B4 /* SocialLoginRequestModel.swift in Sources */, DE254AA82C3118EA00A4015E /* UIView+.swift in Sources */, DE254AAE2C31193600A4015E /* UIFont+.swift in Sources */, - DE6D4CFF2C3F08090005584B /* InvitationCodePopUpView.swift in Sources */, DE6D4D152C3F14D80005584B /* InvitationCodePopUpViewController.swift in Sources */, DE9E189A2C3BCCBE00DB76B4 /* UtilsTemp.swift in Sources */, DD3072142C3BF87A00416D9F /* NearestPromiseResponseModel.swift in Sources */, @@ -896,7 +889,6 @@ DE6D4D162C3F14D80005584B /* MeetingInfoViewController.swift in Sources */, DDA2EE772C385FC3007C6059 /* GroupListViewController.swift in Sources */, 78B9286C2C29402C006D9942 /* AppDelegate.swift in Sources */, - DEF8D1552C3E76B600BCB6CB /* InvitationCodePopUpViewController.swift in Sources */, DEBA032F2C3C24F2002ED8F2 /* ModelType.swift in Sources */, 789AD4B52C3C0147002E2688 /* ResissueResponseModel.swift in Sources */, DE6D4D0F2C3F14D80005584B /* MeetingInfoService.swift in Sources */, diff --git a/KkuMulKum/Resource/Extension/UIFont+.swift b/KkuMulKum/Resource/Extension/UIFont+.swift index 11355a14..8f736d26 100644 --- a/KkuMulKum/Resource/Extension/UIFont+.swift +++ b/KkuMulKum/Resource/Extension/UIFont+.swift @@ -13,6 +13,8 @@ extension UIFont { } enum Pretendard { + private static let scaleRatio: CGFloat = max(Screen.height(1), Screen.width(1)) + case title00, title01, title02 case head01, head02 case body01, body02, body03, body04, body05, body06 @@ -31,6 +33,10 @@ extension UIFont { } var size: CGFloat { + return defaultSize * Pretendard.scaleRatio + } + + private var defaultSize: CGFloat { switch self { case .title00, .title01, .title02: 24 case .head01, .head02: 22 diff --git a/KkuMulKum/Resource/Util/Toast.swift b/KkuMulKum/Resource/Util/Toast.swift new file mode 100644 index 00000000..7260e863 --- /dev/null +++ b/KkuMulKum/Resource/Util/Toast.swift @@ -0,0 +1,79 @@ +// +// Toast.swift +// KkuMulKum +// +// Created by 김진웅 on 7/11/24. +// + +import UIKit + +import SnapKit + +final class Toast: UIView { + enum Position { + case top, bottom + } + + func show(message: String, view: UIView, position: Position, inset: CGFloat) { + setupToastAppearance() + + let toastLabel = setupToastLabel(with: message) + + view.addSubview(self) + addSubview(toastLabel) + + setPositionConstraints(position: position, inset: inset) + + toastLabel.snp.makeConstraints { + $0.horizontalEdges.equalToSuperview().inset(24) + $0.verticalEdges.equalToSuperview().inset(12) + } + + animateToast() + } +} + +private extension Toast { + func setupToastLabel(with message: String) -> UILabel { + let toastLabel = UILabel().then { + $0.textColor = .white + $0.textAlignment = .center + $0.text = message + $0.font = .pretendard(.body02) + $0.clipsToBounds = true + $0.numberOfLines = 0 + $0.sizeToFit() + } + return toastLabel + } + + func setupToastAppearance() { + layer.cornerRadius = 25 + backgroundColor = .black.withAlphaComponent(0.4) + isUserInteractionEnabled = false + } + + func setPositionConstraints(position: Position, inset: CGFloat) { + self.snp.makeConstraints { + $0.centerX.equalToSuperview() + switch position { + case .top: + $0.top.equalToSuperview().inset(inset) + case .bottom: + $0.bottom.equalToSuperview().inset(inset) + } + } + } + + func animateToast() { + UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveEaseIn, animations: { + self.alpha = 1.0 + }, completion: { _ in + UIView.animate(withDuration: 1, delay: 1.8, options: .curveEaseOut, animations: { + self.alpha = 0.0 + }, completion: { _ in + self.removeFromSuperview() + }) + }) + } +} diff --git a/KkuMulKum/Source/MeetingInfo/View/InvitationCodePopUpView.swift b/KkuMulKum/Source/MeetingInfo/View/InvitationCodePopUpView.swift index 3249fb22..9caf2b2f 100644 --- a/KkuMulKum/Source/MeetingInfo/View/InvitationCodePopUpView.swift +++ b/KkuMulKum/Source/MeetingInfo/View/InvitationCodePopUpView.swift @@ -13,75 +13,57 @@ import SnapKit import Then final class InvitationCodePopUpView: BaseView { - private let contentView = UIView().then { - $0.backgroundColor = .white + private let contentView = UIView(backgroundColor: .white).then { $0.layer.cornerRadius = 8 } private let titleLabel = UILabel().then { - $0.text = "친구 초대하기" - $0.font = UIFont.systemFont(ofSize: 16) - $0.textColor = .gray8 + $0.setText("친구 초대하기", style: .body01, color: .gray8) } private let subtitleLabel = UILabel().then { - $0.text = "초대 코드를 공유해 함께할 꾸물이를 추가해 보세요" - $0.font = UIFont.systemFont(ofSize: 12) - $0.textColor = .gray6 + $0.setText( + "초대 코드를 공유해 함께할 꾸물이를 추가해 보세요", + style: .caption02, + color: .gray6 + ) } - // TODO: gray -> gray0 - private let innerContentView = UIView().then { - $0.backgroundColor = .gray + private let innerContentView = UIView(backgroundColor: .gray0).then { $0.layer.cornerRadius = 4 } private let descriptionLabel = UILabel().then { - $0.text = "초대코드" - $0.font = UIFont.systemFont(ofSize: 14) - $0.textColor = .gray8 + $0.setText("초대코드", style: .body06, color: .gray8) } private let invitationCodeLabel = UILabel() - private let inviteLaterButton = UIButton().then { - $0.setTitle("나중에 초대하기", for: .normal) - $0.titleLabel?.font = UIFont.systemFont(ofSize: 14) - $0.setTitleColor(.white, for: .normal) - $0.backgroundColor = .gray3 + private let inviteLaterButton = UIButton(backgroundColor: .gray3).then { + $0.setTitle("나중에 초대하기", style: .body05, color: .white) $0.layer.cornerRadius = 8 $0.layer.maskedCorners = [.layerMinXMaxYCorner] } - private let copyButton = UIButton().then { - $0.setTitle("복사하기", for: .normal) - $0.titleLabel?.font = UIFont.systemFont(ofSize: 14) - $0.setTitleColor(.white, for: .normal) + private let copyButton = UIButton(backgroundColor: .gray7).then { + $0.setTitle("복사하기", style: .body05, color: .white) $0.backgroundColor = .gray7 $0.layer.cornerRadius = 8 $0.layer.maskedCorners = [.layerMaxXMaxYCorner] } - private let buttonStackView = UIStackView().then { - $0.axis = .horizontal + private let buttonStackView = UIStackView(axis: .horizontal).then { $0.distribution = .fillEqually $0.layer.cornerRadius = 8 $0.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] } override func setupView() { - backgroundColor = .black.withAlphaComponent(0.6) + backgroundColor = .black.withAlphaComponent(0.7) - setupBlurView() - - innerContentView.addSubview(descriptionLabel) - innerContentView.addSubview(invitationCodeLabel) - buttonStackView.addArrangedSubview(inviteLaterButton) - buttonStackView.addArrangedSubview(copyButton) - contentView.addSubview(titleLabel) - contentView.addSubview(subtitleLabel) - contentView.addSubview(innerContentView) - contentView.addSubview(buttonStackView) + innerContentView.addSubviews(descriptionLabel, invitationCodeLabel) + buttonStackView.addArrangedSubviews(inviteLaterButton, copyButton) + contentView.addSubviews(titleLabel, subtitleLabel, innerContentView, buttonStackView) addSubview(contentView) } @@ -137,17 +119,8 @@ extension InvitationCodePopUpView { func isBackgroundViewDidTap(with location: CGPoint) -> Bool { return !contentView.frame.contains(location) } -} - -private extension InvitationCodePopUpView { - func setupBlurView() { - let blurEffect = UIBlurEffect(style: .dark) - let blurView = UIVisualEffectView(effect: blurEffect) - - addSubview(blurView) - - blurView.snp.makeConstraints { - $0.edges.equalToSuperview() - } + + func setInvitationCodeText(_ invitationCode: String) { + invitationCodeLabel.setText(invitationCode, style: .body01, color: .maincolor) } } diff --git a/KkuMulKum/Source/MeetingInfo/View/MeetingInfoView.swift b/KkuMulKum/Source/MeetingInfo/View/MeetingInfoView.swift index ee77d64c..b3b2a9c3 100644 --- a/KkuMulKum/Source/MeetingInfo/View/MeetingInfoView.swift +++ b/KkuMulKum/Source/MeetingInfo/View/MeetingInfoView.swift @@ -7,6 +7,8 @@ import UIKit +import RxCocoa +import RxSwift import SnapKit import Then @@ -61,15 +63,13 @@ final class MeetingInfoView: BaseView { $0.contentMode = .scaleAspectFill } - private let addPromiseButton = UIButton().then { + private let createPromiseButton = UIButton(backgroundColor: .maincolor).then { $0.setTitle("+ 약속추가", style: .body01, color: .white) - $0.backgroundColor = .maincolor $0.layer.cornerRadius = Screen.height(52) / 2 $0.clipsToBounds = true } - // TODO: gray0으로 수정 - private let grayBackgroundView = UIView(backgroundColor: .gray).then { + private let grayBackgroundView = UIView(backgroundColor: .gray0).then { $0.roundCorners( cornerRadius: 18, maskedCorners: [.layerMinXMinYCorner, .layerMaxXMinYCorner] @@ -85,10 +85,10 @@ final class MeetingInfoView: BaseView { grayBackgroundView.addSubviews(promiseDescriptionLabel, promiseListView) addSubviews( - infoBanner, memberCountLabel, arrowButton, memberListView, addPromiseButton, + infoBanner, memberCountLabel, arrowButton, memberListView, createPromiseButton, grayBackgroundView ) - bringSubviewToFront(addPromiseButton) + bringSubviewToFront(createPromiseButton) } override func setupAutoLayout() { @@ -100,12 +100,12 @@ final class MeetingInfoView: BaseView { } memberCountLabel.snp.makeConstraints { - $0.top.equalTo(infoBanner.snp.bottom).offset(24) + $0.top.equalTo(infoBanner.snp.bottom).offset(20) $0.leading.equalTo(infoBanner) } arrowButton.snp.makeConstraints { - $0.trailing.equalToSuperview().offset(-27) + $0.trailing.equalToSuperview().offset(-20) $0.centerY.equalTo(memberCountLabel) } @@ -116,9 +116,8 @@ final class MeetingInfoView: BaseView { } grayBackgroundView.snp.makeConstraints { - $0.top.equalTo(memberListView.snp.bottom).offset(40) - $0.horizontalEdges.equalToSuperview() - $0.bottom.equalTo(safeArea) + $0.top.equalTo(memberListView.snp.bottom).offset(35) + $0.horizontalEdges.bottom.equalToSuperview() } promiseDescriptionLabel.snp.makeConstraints { @@ -132,9 +131,9 @@ final class MeetingInfoView: BaseView { $0.height.equalTo(Screen.height(188)) } - addPromiseButton.snp.makeConstraints { - $0.bottom.equalTo(safeArea).offset(-20) - $0.trailing.equalTo(safeArea).offset(-14) + createPromiseButton.snp.makeConstraints { + $0.top.equalTo(promiseListView.snp.bottom).offset(45) + $0.trailing.equalTo(safeArea).offset(-16) $0.width.equalTo(Screen.width(136)) $0.height.equalTo(Screen.height(52)) } @@ -142,6 +141,8 @@ final class MeetingInfoView: BaseView { } extension MeetingInfoView { + var createPromiseButtonDidTap: Observable { createPromiseButton.rx.tap.asObservable() } + func configureInfo(createdAt: String, metCount: Int) { infoBanner.configure(createdAt: createdAt, metCount: metCount) } diff --git a/KkuMulKum/Source/MeetingInfo/View/MeetingPromiseCell.swift b/KkuMulKum/Source/MeetingInfo/View/MeetingPromiseCell.swift index bf9201ae..470ada19 100644 --- a/KkuMulKum/Source/MeetingInfo/View/MeetingPromiseCell.swift +++ b/KkuMulKum/Source/MeetingInfo/View/MeetingPromiseCell.swift @@ -63,6 +63,7 @@ final class MeetingPromiseCell: BaseCollectionViewCell { private let contentStackView = UIStackView(axis: .vertical).then { $0.spacing = 8 + $0.distribution = .equalSpacing } override func setupView() { diff --git a/KkuMulKum/Source/MeetingInfo/ViewController/InvitationCodePopUpViewController.swift b/KkuMulKum/Source/MeetingInfo/ViewController/InvitationCodePopUpViewController.swift index d1ceed8f..8784e263 100644 --- a/KkuMulKum/Source/MeetingInfo/ViewController/InvitationCodePopUpViewController.swift +++ b/KkuMulKum/Source/MeetingInfo/ViewController/InvitationCodePopUpViewController.swift @@ -13,14 +13,13 @@ import SnapKit import Then final class InvitationCodePopUpViewController: BaseViewController { - private let invitationCode: String private let disposeBag = DisposeBag() private let rootView = InvitationCodePopUpView() // MARK: - Initializer - + init(invitationCode: String) { self.invitationCode = invitationCode super.init(nibName: nil, bundle: nil) @@ -30,6 +29,19 @@ final class InvitationCodePopUpViewController: BaseViewController { fatalError("init(coder:) has not been implemented") } + + // MARK: - Life Cycle + + override func loadView() { + view = rootView + } + + override func viewDidLoad() { + super.viewDidLoad() + + rootView.setInvitationCodeText(invitationCode) + } + override func setupAction() { let tapGesture = UITapGestureRecognizer() view.addGestureRecognizer(tapGesture) @@ -53,9 +65,20 @@ final class InvitationCodePopUpViewController: BaseViewController { .subscribe(with: self) { owner, _ in UIPasteboard.general.string = owner.invitationCode - // TODO: Toast 메세지로 복사되었다고 알리기 - + let toast = Toast() + toast.show( + message: "클립보드에 복사되었슈", + view: owner.view, + position: .bottom, + inset: 100 + ) } .disposed(by: disposeBag) } } + +private extension InvitationCodePopUpViewController { + func copyInvitationCode() { + UIPasteboard.general.string = invitationCode + } +} diff --git a/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift b/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift index 21a4e76f..9cba0821 100644 --- a/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift +++ b/KkuMulKum/Source/MeetingInfo/ViewController/MeetingInfoViewController.swift @@ -62,7 +62,8 @@ final class MeetingInfoViewController: BaseViewController { private extension MeetingInfoViewController { func bindViewModel() { let input = MeetingInfoViewModel.Input( - viewWillAppear: viewWillAppearRelay + viewWillAppear: viewWillAppearRelay, + createPromiseButtonDidTap: rootView.createPromiseButtonDidTap ) let output = viewModel.transform(input: input, disposeBag: disposeBag) @@ -113,9 +114,18 @@ private extension MeetingInfoViewController { ) } .disposed(by: disposeBag) + + output.createNewPromise + .drive(with: self) { owner, _ in + // TODO: 약속 추가 화면으로 이동 + } + .disposed(by: disposeBag) } } + +// MARK: - MeetingMemberCellDelegate + extension MeetingInfoViewController: MeetingMemberCellDelegate { func profileImageButtonDidTap() { guard let code = viewModel.meetingInvitationCode else { return } diff --git a/KkuMulKum/Source/MeetingInfo/ViewModel/MeetingInfoViewModel.swift b/KkuMulKum/Source/MeetingInfo/ViewModel/MeetingInfoViewModel.swift index 382e8e40..c95c1d25 100644 --- a/KkuMulKum/Source/MeetingInfo/ViewModel/MeetingInfoViewModel.swift +++ b/KkuMulKum/Source/MeetingInfo/ViewModel/MeetingInfoViewModel.swift @@ -26,6 +26,7 @@ final class MeetingInfoViewModel { extension MeetingInfoViewModel: ViewModelType { struct Input { let viewWillAppear: PublishRelay + let createPromiseButtonDidTap: Observable } struct Output { @@ -33,6 +34,7 @@ extension MeetingInfoViewModel: ViewModelType { let memberCount: Driver let members: Driver<[Member]> let promises: Driver<[MeetingPromise]> + let createNewPromise: Driver } func transform(input: Input, disposeBag: DisposeBag) -> Output { @@ -78,11 +80,15 @@ extension MeetingInfoViewModel: ViewModelType { .map { $0.sorted { $0.dDay < $1.dDay }} .asDriver(onErrorJustReturn: []) + let createNewPromise = input.createPromiseButtonDidTap + .asDriver(onErrorJustReturn: ()) + let output = Output( info: info, memberCount: memberCount, members: members, - promises: promises + promises: promises, + createNewPromise: createNewPromise ) return output