From 665fdc650f11e955ca302ad4b3a33c50091a66bb Mon Sep 17 00:00:00 2001 From: julia0926 Date: Tue, 21 Nov 2023 10:28:48 +0900 Subject: [PATCH 01/44] =?UTF-8?q?=E2=9C=A8=20=EB=82=98=EA=B0=80=EA=B8=B0?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC,=20=EB=A7=90=ED=92=8D=EC=84=A0=20UI=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 말풍선 폴더 위치 변경 (홈 -> 디자인시스템) --- .../Contents.json | 23 +++++++++++ .../icon_bubble_tail_exit.png | Bin 0 -> 337 bytes .../icon_bubble_tail_exit@2x.png | Bin 0 -> 536 bytes .../icon_bubble_tail_exit@3x.png | Bin 0 -> 741 bytes .../Primary.colorset/Contents.json | 6 +-- .../NavigationBar/TTNavigationBar.swift | 8 +++- .../Sources}/Component/SpeechBubbleView.swift | 36 +++++++++++++----- .../DesignSystem/Sources/Font/UIFont+.swift | 13 ++++--- .../InvitationWaitViewController.swift | 28 +++++++++++++- 9 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/icon_bubble_tail_exit.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/icon_bubble_tail_exit@2x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/icon_bubble_tail_exit@3x.png rename {Scene/HomeScene/Sources/HomeScene/Views/Flower => Core/DesignSystem/Sources/DesignSystem/Sources}/Component/SpeechBubbleView.swift (64%) diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/Contents.json b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/Contents.json new file mode 100644 index 00000000..949f7748 --- /dev/null +++ b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "icon_bubble_tail_exit.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icon_bubble_tail_exit@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icon_bubble_tail_exit@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/icon_bubble_tail_exit.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/speechBubble/icon_bubble_tail_exit.imageset/icon_bubble_tail_exit.png new file mode 100644 index 0000000000000000000000000000000000000000..d0809c0c43bc050d1d13073210d6b132d2b1f9ca GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9Q!3HFy+4N(86lZ})WHAE+w=f7ZGR&GI0Tg5` z4sv&5Sa(k5C6L3C?&#~tz_78O`%fY(kpIln#WAFUap|Ouf=v!0F5iVSyu8?CGuR^< zgBmY2hBW}0eWC_o3uGghTxLz0b*HlY4iC@ae z5^A5Ob&8*K_PBG^a7(zTU5AF(s(qFGHj&;gkCXG>-I0wnXZ?JvtLX`&y1S5g!HK%? zxc=F5tBySAe5!r_kI18aHy)~V-$`%1vTHYEam$R(+TTr5g2Eq!tE}@@; zNl?jP^P!OL?7*=ACs=`YpdFBd$~9L#@O- zh78$BzWHU}+l@d2XkI7~?)kLON5;n#0@vbnP$Ch5L~NK>8)TJ=?|PORN+OkCGg-}* z%w9_(DG=Kk@=xvXX%`nO~L4|IqZ3A_NLRa&q=>E1*H2(~BQ09IFTUu!Y z>xSAcb3bcsU>V3vWWo@;C+BD9SPvAlBDc zKg@1GvYkE-1tBlBq3Ca?4ym-E2OJ6{-Xy+p$EPLsPYFr4(kyPgKjA;LsS3MCKXYpL aNaYWFm6hGTHk*b30000Fi(C$H_SaNFYUXQLulbeQc@%h!m!;kA9%JsAp2VpMQe@>`Sp+g8ymLH;Ebj z7hkxSq(ovStv1VRgt6QQ)4TP(%OTcFzU$kg?$Vb zSeBwy_6IAB6miUOhi$bznIRIM#I}-s#1~~4ap^xgu_$3w!=itV#JE*Gq9^J%B8f^& zU*$XWEr$e=`j1WQ08-539y_=&2E8|%u6Z7rfV=?cKL2_!H zn1J5hC`zrR{zDRD@5G%1=)YBARu~$4SU(w^J8N@5yTo({X}z4gRchXa>6;_2elV0& zU;g>&yR(-()~I(E-um}VY+ZVH;jMpXVx8#Sg-0LhPD~3mxiNT1tg*1N9~`59WaX7b zEzOB_sdqOAO;hCB!dgsoyP|Q5Tq%!U3Zt6ZF+yEpeO`jg)J~D#B&KikF&^wFZF8v5 z|J%eKdZ>376_Q&iO#E_Rj_maqVX+i@)DMQT(nl^Omh574i!!WCk!@ldq<0q!{XZwR zDSCIYm?A5C$sO~#Rv#h#o5Xf8G#>R%LTRNK8j1QWcb`YcB-Cr2VrXbZR(yxQ7#fM5 zCPnk8rx*%a9h#bo*Vvt+cWgC;00000NkvXXu0mjfeBDEM literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/Primary Color/Primary.colorset/Contents.json b/Core/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/Primary Color/Primary.colorset/Contents.json index e699b918..bb33345c 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/Primary Color/Primary.colorset/Contents.json +++ b/Core/DesignSystem/Sources/DesignSystem/Resources/Colors.xcassets/Primary Color/Primary.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.094", - "green" : "0.188", - "red" : "0.267" + "blue" : "0x17", + "green" : "0x2F", + "red" : "0x44" } }, "idiom" : "universal" diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/NavigationBar/TTNavigationBar.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/NavigationBar/TTNavigationBar.swift index 51d16f91..6cd4cdad 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/NavigationBar/TTNavigationBar.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/NavigationBar/TTNavigationBar.swift @@ -59,7 +59,8 @@ public final class TTNavigationBar: UIView { /// TTNavigationBar(title: "마이페이지", rightButtonImage: .asset(.icon_info)) /// ``` public convenience init(title: String?, - rightButtonImage: UIImage?) { + rightButtonImage: UIImage?, + rightButtonText: String? = nil) { self.init() if let _title = title, _title == "TwoToo" { self.logoImageView.isHidden = false @@ -67,6 +68,11 @@ public final class TTNavigationBar: UIView { self.titleLabel.text = title } self.rightButton.setImage(rightButtonImage, for: .normal) + if let text = rightButtonText { + self.rightButton.setTitle(text, for: .normal) + self.rightButton.titleLabel?.font = .h4 + self.rightButton.setTitleColor(.primary, for: .normal) + } } required init?(coder: NSCoder) { diff --git a/Scene/HomeScene/Sources/HomeScene/Views/Flower/Component/SpeechBubbleView.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift similarity index 64% rename from Scene/HomeScene/Sources/HomeScene/Views/Flower/Component/SpeechBubbleView.swift rename to Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift index a947f22c..acb6e1dc 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/Flower/Component/SpeechBubbleView.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift @@ -6,24 +6,28 @@ // import UIKit -import DesignSystem /// 말풍선 뷰 /// /// Parameter /// - title : 말풍선 텍스트 /// - tailPosition : 말풍선 꼬리 위치 (좌 / 우) -final class SpeechBubbleView: UIView { +final public class SpeechBubbleView: UIView { private var _backgroundColor: UIColor = .white private var tailCoordinate: CGFloat = 0.5 + private var tailPosition: TailPosition = .my - enum TailPosition{ + public enum TailPosition{ + /// 홈 - 파트너 말풍선 case partner + /// 홈 - 내 말풍선 case my + /// 챌린지 대기중 - 나가기 말풍선 + case exit } - let titleLabel: UILabel = { + public let titleLabel: UILabel = { let v = UILabel() v.font = .body1 v.textAlignment = .center @@ -38,8 +42,9 @@ final class SpeechBubbleView: UIView { return v }() - init(tailPosition: TailPosition) { + public init(tailPosition: TailPosition) { super.init(frame: .zero) + self.tailPosition = tailPosition switch tailPosition { case .partner: self._backgroundColor = UIColor.mainLightPink @@ -49,6 +54,10 @@ final class SpeechBubbleView: UIView { self._backgroundColor = UIColor.second01 self.tailCoordinate = 1.5 self.tailImageView.image = UIImage.asset(.icon_bubble_tail_my) + case .exit: + self._backgroundColor = UIColor.second01 + self.tailImageView.image = UIImage(resource: .iconBubbleTailExit) + self.tailCoordinate = 1.7 } self.layout() self.attribute() @@ -65,10 +74,19 @@ final class SpeechBubbleView: UIView { self.titleLabel.snp.makeConstraints { make in make.edges.equalToSuperview().inset(10) } - self.tailImageView.snp.makeConstraints { make in - make.bottom.equalToSuperview().offset(10) - make.centerX.equalToSuperview().multipliedBy(self.tailCoordinate) + switch tailPosition { + case .partner, .my: + self.tailImageView.snp.makeConstraints { make in + make.bottom.equalToSuperview().offset(10) + make.centerX.equalToSuperview().multipliedBy(self.tailCoordinate) + } + case .exit: + self.tailImageView.snp.makeConstraints { make in + make.top.equalToSuperview().offset(-10) + make.centerX.equalToSuperview().multipliedBy(self.tailCoordinate) + } } + } func attribute() { @@ -76,7 +94,7 @@ final class SpeechBubbleView: UIView { self.backgroundColor = _backgroundColor } - func configure(title: String) { + public func configure(title: String) { if title.count > 10 { let index = title.index(title.startIndex, offsetBy: 10) let firstPart = title[.. Date: Wed, 22 Nov 2023 09:47:51 +0900 Subject: [PATCH 02/44] =?UTF-8?q?=E2=9C=A8=20=EC=B1=8C=EB=A6=B0=EC=A7=80?= =?UTF-8?q?=20=EC=88=98=EB=9D=BD=20=ED=99=94=EB=A9=B4=20=EB=82=98=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20>=20=ED=99=88=20=EC=A7=84?= =?UTF-8?q?=EC=9E=85=EC=A0=90=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InvitationWaitInteractor.swift | 16 ++++++++++++++++ .../InvitationWaitSceneFactory.swift | 5 +++++ .../InvitationWaitViewController.swift | 5 ++++- TwoToo/SceneDelegate.swift | 3 ++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift index ab2f7f14..c3a35b36 100644 --- a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift +++ b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift @@ -15,11 +15,15 @@ protocol InvitationWaitBusinessLogic { func didTapRefreshButton() async /// 초대장 다시 보내기 버튼 클릭 func didTapResendButton() async + /// 나가기 버튼 클릭 + func didTapExitButton() async } protocol InvitationWaitDataStore: AnyObject { /// 홈 화면 이동 트리거 var didTriggerRouteToHomeScene: PassthroughSubject { get } + /// 로그인 화면 이동 트리거 + var didTriggerRouteToLoginScene: PassthroughSubject { get } /// 공유 링크 (optional) var invitationLink: String? { get } } @@ -36,18 +40,21 @@ final class InvitationWaitInteractor: InvitationWaitDataStore, InvitationWaitBus router: InvitationWaitRoutingLogic, worker: InvitationWaitWorkerProtocol, didTriggerRouteToHomeScene: PassthroughSubject, + didTriggerRouteToLoginScene: PassthroughSubject, invitationLink: String? ) { self.presenter = presenter self.router = router self.worker = worker self.didTriggerRouteToHomeScene = didTriggerRouteToHomeScene + self.didTriggerRouteToLoginScene = didTriggerRouteToLoginScene self.invitationLink = invitationLink } // MARK: - DataStore var didTriggerRouteToHomeScene: PassthroughSubject + var didTriggerRouteToLoginScene: PassthroughSubject var invitationLink: String? } @@ -110,6 +117,15 @@ extension InvitationWaitInteractor { } } +// MARK: Feature (나가기 > 로그인 화면 이동) + +extension InvitationWaitInteractor { + + func didTapExitButton() async { + self.didTriggerRouteToLoginScene.send(()) + } +} + // MARK: - Application Business Logic // MARK: UseCase () diff --git a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift index ef1b5876..dc009a60 100644 --- a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift +++ b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift @@ -16,14 +16,18 @@ public protocol InvitationWaitScene: AnyObject, Scene { public struct InvitationWaitConfiguration { /// 홈 화면 이동 트리거 public var didTriggerRouteToHomeScene: PassthroughSubject + /// 로그인 화면 이동 트리거 + public var didTriggerRouteToLoginScene: PassthroughSubject /// 공유 링크 (optional) public var invitationLink: String? public init( didTriggerRouteToHomeScene: PassthroughSubject, + didTriggerRouteToLoginScene: PassthroughSubject, invitationLink: String? = nil ) { self.didTriggerRouteToHomeScene = didTriggerRouteToHomeScene + self.didTriggerRouteToLoginScene = didTriggerRouteToLoginScene self.invitationLink = invitationLink } } @@ -55,6 +59,7 @@ public final class InvitationWaitSceneFactory { router: router, worker: worker, didTriggerRouteToHomeScene: configuration.didTriggerRouteToHomeScene, + didTriggerRouteToLoginScene: configuration.didTriggerRouteToLoginScene, invitationLink: configuration.invitationLink ) let viewController = InvitationWaitViewController( diff --git a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitViewController.swift b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitViewController.swift index 3c031c57..7870a975 100644 --- a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitViewController.swift +++ b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitViewController.swift @@ -201,7 +201,10 @@ extension InvitationWaitViewController: InvitationWaitDisplayLogic { } extension InvitationWaitViewController: TTNavigationBarDelegate { + /// 나가기 버튼 탭 했을 때 func didTapRightButton() { - // TODO: 나가기 구현 + Task { + await self.interactor.didTapExitButton() + } } } diff --git a/TwoToo/SceneDelegate.swift b/TwoToo/SceneDelegate.swift index 4f27ce05..441771fd 100644 --- a/TwoToo/SceneDelegate.swift +++ b/TwoToo/SceneDelegate.swift @@ -168,7 +168,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { .receive(on: DispatchQueue.main) .sink { let invitationWaitScene = InvitationWaitSceneFactory().make(with: .init( - didTriggerRouteToHomeScene: self.didTriggerRouteToHomeScene, + didTriggerRouteToHomeScene: self.didTriggerRouteToHomeScene, + didTriggerRouteToLoginScene: self.didTriggerRouteToLoginScene, invitationLink: $0 )) let vc = invitationWaitScene.viewController From b2ef8e8039856f6a81a6b1bfcf493cf0561a813e Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Wed, 22 Nov 2023 21:44:01 +0900 Subject: [PATCH 03/44] =?UTF-8?q?=E2=9C=A8=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=97=90=EC=85=8B=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets.xcassets/update/Contents.json | 6 +++++ .../update/update_icon.imageset/Contents.json | 23 ++++++++++++++++++ .../update_icon.imageset/update_icon@1x.png | Bin 0 -> 7897 bytes .../update_icon.imageset/update_icon@2x.png | Bin 0 -> 23872 bytes .../update_icon.imageset/update_icon@3x.png | Bin 0 -> 46643 bytes 5 files changed, 29 insertions(+) create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@1x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@2x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@3x.png diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/Contents.json b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/Contents.json b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/Contents.json new file mode 100644 index 00000000..17b206b0 --- /dev/null +++ b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "update_icon@1x.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "update_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "update_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@1x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..e2630fe280e837439ec53aa2fb6adb50160142b8 GIT binary patch literal 7897 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 literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@2x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..574a022aa62347394357ad3956e9bc267b6a8988 GIT binary patch literal 23872 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 D?)L{0 literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@3x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/update/update_icon.imageset/update_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f0ede8c4dc1a5794fa61566807993046c4276e0f GIT binary patch literal 46643 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 literal 0 HcmV?d00001 From ed152126816f8d98aa307ebbea98762088a895c1 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Tue, 28 Nov 2023 17:24:22 +0900 Subject: [PATCH 04/44] =?UTF-8?q?=E2=9C=A8=20=EA=B0=95=EC=A0=9C=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesignSystem/Sources/Assets/Assets.swift | 1 + .../AppVersionNetworkWorker.swift | 45 +++++++++++++++++++ .../SplashScene/SplashInteractor.swift | 26 ++++++++++- .../Sources/SplashScene/SplashModels.swift | 11 ++++- .../Sources/SplashScene/SplashPresenter.swift | 9 +++- .../SplashScene/SplashSceneFactory.swift | 4 +- .../SplashScene/SplashViewController.swift | 34 ++++++++++++-- .../Sources/SplashScene/SplashWorker.swift | 12 ++++- 8 files changed, 133 insertions(+), 9 deletions(-) create mode 100644 Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift index 3a6acb0d..1bd3d740 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift @@ -139,6 +139,7 @@ public enum Assets: String { case flowerPopup_background case icon_challenge_progress case icon_title_arrow + case update_icon public var image: UIImage { return .init(named: self.rawValue, in: Bundle.module, with: nil)! diff --git a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift new file mode 100644 index 00000000..66f3b650 --- /dev/null +++ b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift @@ -0,0 +1,45 @@ +// +// AppVersionNetworkWorker.swift +// +// +// Created by Eddy on 2023/11/28. +// + +import Foundation +import Network + +public protocol AppVersionNetworkWorkerProtocol { + func requestAppVersion() async throws -> Bool +} + +/// 강제 업데이트 앱 버전 확인 Worker +public final class AppVersionNetworkWorker: AppVersionNetworkWorkerProtocol { + + public init() {} + + public func requestAppVersion() async throws -> Bool { + guard let info = Bundle.main.infoDictionary, + // 현재 버전 가져오기 + let currentVersion = info["CFBundleShortVersionString"] as? String, + // 앱 번들아이디 가져오기 + let identifier = info["CFBundleIdentifier"] as? String, + let url = URL(string: "http://itunes.apple.com/kr/lookup?bundleId=\(identifier)") + else { + return false + } + + let data = try await URLSession.shared.data(from: url).0 + let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any] + + guard let result = (json?["results"] as? [Any])?.first as? [String: Any], + let version = result["version"] as? String + else { + return false + } + + let verFloat = NSString.init(string: version).floatValue + let currentVerFloat = NSString.init(string: currentVersion).floatValue + + return verFloat == currentVerFloat + } +} diff --git a/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift b/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift index d69a5297..557b424d 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift @@ -11,6 +11,8 @@ import CoreKit protocol SplashBusinessLogic { /// 첫 진입 func didLoad() async + /// 업데이트 버튼 클릭 + func didTapUpdateButton() async } protocol SplashDataStore: AnyObject { @@ -78,10 +80,18 @@ extension SplashInteractor { // MARK: Feature (진입) +import UIKit + extension SplashInteractor { - + func didLoad() async { + do { + let isVersionSame = try await self.worker.checkAppVersion() + + if !isVersionSame { + await self.presenter.presentUpdatePopup() + } else { let userState = try await self.worker.fetchUserState() switch userState { case .login: @@ -99,6 +109,7 @@ extension SplashInteractor { case .home: self.didTriggerRouteToHomeScene.send(()) } + } } catch { self.didTriggerRouteToLoginScene.send(()) @@ -106,6 +117,19 @@ extension SplashInteractor { } } +// MARK: Feature (강제업데이트) + +extension SplashInteractor { + func didTapUpdateButton() async { + let appleId = "6455260918" + DispatchQueue.main.async { + if let url = URL(string: "itms-apps://itunes.apple.com/app/apple-store/\(appleId)"), UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } + } + } +} + // MARK: - Application Business Logic // MARK: UseCase () diff --git a/Scene/SplashScene/Sources/SplashScene/SplashModels.swift b/Scene/SplashScene/Sources/SplashScene/SplashModels.swift index c60cc4c7..e70b5f03 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashModels.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashModels.swift @@ -29,6 +29,15 @@ enum Splash { } enum ViewModel { - + struct UpdatePopup { + /// 타이틀 + var title: String + /// 업데이트 아이콘 + var iconImage: UIImage + /// 설명 + var description: String + /// 버튼 타이틀 + var buttonTitle: [String] + } } } diff --git a/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift b/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift index 729d0cf4..baba47e6 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift @@ -9,7 +9,10 @@ import UIKit @MainActor -protocol SplashPresentationLogic {} +protocol SplashPresentationLogic { + // 강제 업데이트 팝업을 보여준다. + func presentUpdatePopup() +} final class SplashPresenter { weak var viewController: SplashDisplayLogic? @@ -19,5 +22,9 @@ final class SplashPresenter { // MARK: - Presentation Logic extension SplashPresenter: SplashPresentationLogic { + func presentUpdatePopup() { + let viewModel = Splash.ViewModel.UpdatePopup(title: "업데이트 알림", iconImage: .asset(.update_icon)!, description: "앱을 업데이트 하고\n더욱 안정된 투투를 만나보세요 :)", buttonTitle: ["업데이트"]) + self.viewController?.displayUpdatePopup(viewModel: viewModel) + } } diff --git a/Scene/SplashScene/Sources/SplashScene/SplashSceneFactory.swift b/Scene/SplashScene/Sources/SplashScene/SplashSceneFactory.swift index 1422ff35..e3991817 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashSceneFactory.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashSceneFactory.swift @@ -44,13 +44,15 @@ public final class SplashSceneFactory { let meLocalWorker = MeLocalWorker(localDataSource: localDataSource) let invitationLocalWorker = InvitationLocalWorker(localDataSource: localDataSource) let meNetworkWorker = MeNetworkWorker() + let appVersionWorker = AppVersionNetworkWorker() let presenter = SplashPresenter() let router = SplashRouter() let worker = SplashWorker( meLocalWorker: meLocalWorker, invitationLocalWorker: invitationLocalWorker, - meNetworkWorker: meNetworkWorker + meNetworkWorker: meNetworkWorker, + appVersionWorker: appVersionWorker ) let interactor = SplashInteractor( presenter: presenter, diff --git a/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift b/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift index 63068d08..3b47ccf6 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift @@ -9,7 +9,9 @@ import CoreKit import UIKit -protocol SplashDisplayLogic: AnyObject {} +protocol SplashDisplayLogic: AnyObject { + func displayUpdatePopup(viewModel: Splash.ViewModel.UpdatePopup) +} final class SplashViewController: UIViewController { var interactor: SplashBusinessLogic @@ -29,8 +31,7 @@ final class SplashViewController: UIViewController { let v = UIStackView() v.axis = .vertical v.spacing = 28 - v.addArrangedSubview(self.appIconImageView) - v.addArrangedSubview(self.appLogoImageView) + v.addArrangedSubviews(self.appIconImageView, self.appLogoImageView, self.updatePopupView) return v }() @@ -45,6 +46,17 @@ final class SplashViewController: UIViewController { v.image = .asset(.app_logo)! return v }() + + lazy var updatePopupView: TTPopup = { + let v = TTPopup() + v.isHidden = true + v.didTapLeftButton { + Task { [weak self] in + await self?.interactor.didTapUpdateButton() + } + } + return v + }() // MARK: - View Lifecycle @@ -62,7 +74,8 @@ final class SplashViewController: UIViewController { private func setUI() { self.view.setBackgroundDefault() - self.view.addSubview(self.contentView) + self.view.addSubviews(self.contentView, self.updatePopupView) + self.view.bringSubviewToFront(self.updatePopupView) self.contentView.snp.makeConstraints { make in make.center.equalToSuperview() @@ -75,6 +88,10 @@ final class SplashViewController: UIViewController { make.width.equalTo(135) make.height.equalTo(23) } + + self.updatePopupView.snp.makeConstraints { make in + make.center.equalToSuperview() + } } } @@ -89,5 +106,14 @@ extension SplashViewController: SplashScene { // MARK: - Display Logic extension SplashViewController: SplashDisplayLogic { + func displayUpdatePopup(viewModel: Splash.ViewModel.UpdatePopup) { + updatePopupView.configure( + title: viewModel.title, + resultView: UIImageView(image: viewModel.iconImage), + description: viewModel.description, + buttonTitles: viewModel.buttonTitle + ) + self.updatePopupView.isHidden = false + } } diff --git a/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift b/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift index 4901180b..7fb9cd8c 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift @@ -7,10 +7,12 @@ // import CoreKit +import Foundation protocol SplashWorkerProtocol { /// 유저 상태 조회 func fetchUserState() async throws -> Splash.Model.UserState + func checkAppVersion() async throws -> Bool } final class SplashWorker: SplashWorkerProtocol { @@ -18,15 +20,23 @@ final class SplashWorker: SplashWorkerProtocol { var meLocalWorker: MeLocalWorkerProtocol var invitationLocalWorker: InvitationLocalWorkerProtocol var meNetworkWorker: MeNetworkWorkerProtocol + var appVersionWorker: AppVersionNetworkWorkerProtocol init( meLocalWorker: MeLocalWorkerProtocol, invitationLocalWorker: InvitationLocalWorkerProtocol, - meNetworkWorker: MeNetworkWorkerProtocol + meNetworkWorker: MeNetworkWorkerProtocol, + appVersionWorker: AppVersionNetworkWorkerProtocol ) { self.meLocalWorker = meLocalWorker self.invitationLocalWorker = invitationLocalWorker self.meNetworkWorker = meNetworkWorker + self.appVersionWorker = appVersionWorker + } + + // 최신버전인지 아닌지 확인하는 함수 + func checkAppVersion() async throws -> Bool { + return try await self.appVersionWorker.requestAppVersion() } func fetchUserState() async throws -> Splash.Model.UserState { From 5e76823b2f0c88f749287737d43130c13b70cb73 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Tue, 28 Nov 2023 18:58:23 +0900 Subject: [PATCH 05/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20=EA=B0=95?= =?UTF-8?q?=EC=A0=9C=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=EC=A1=B0=EA=B1=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift index 66f3b650..33ec8726 100644 --- a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift +++ b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift @@ -40,6 +40,6 @@ public final class AppVersionNetworkWorker: AppVersionNetworkWorkerProtocol { let verFloat = NSString.init(string: version).floatValue let currentVerFloat = NSString.init(string: currentVersion).floatValue - return verFloat == currentVerFloat + return verFloat < currentVerFloat ? true : false } } From 7300d612a66b81217ae7f0ce06755ea8fc214c54 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Tue, 5 Dec 2023 09:15:33 +0900 Subject: [PATCH 06/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=90=EA=B0=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppVersionNetworkWorker.swift | 52 +++++++++---------- .../SplashScene/SplashInteractor.swift | 32 ++++++------ .../Sources/SplashScene/SplashModels.swift | 20 +++---- .../Sources/SplashScene/SplashPresenter.swift | 14 ++--- .../SplashScene/SplashViewController.swift | 40 +++++++------- .../Sources/SplashScene/SplashWorker.swift | 2 +- 6 files changed, 80 insertions(+), 80 deletions(-) diff --git a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift index 33ec8726..ce3bc7e6 100644 --- a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift +++ b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift @@ -9,37 +9,37 @@ import Foundation import Network public protocol AppVersionNetworkWorkerProtocol { - func requestAppVersion() async throws -> Bool + func requestAppVersion() async throws -> Bool } /// 강제 업데이트 앱 버전 확인 Worker public final class AppVersionNetworkWorker: AppVersionNetworkWorkerProtocol { - - public init() {} - - public func requestAppVersion() async throws -> Bool { - guard let info = Bundle.main.infoDictionary, - // 현재 버전 가져오기 - let currentVersion = info["CFBundleShortVersionString"] as? String, - // 앱 번들아이디 가져오기 - let identifier = info["CFBundleIdentifier"] as? String, - let url = URL(string: "http://itunes.apple.com/kr/lookup?bundleId=\(identifier)") - else { - return false - } - let data = try await URLSession.shared.data(from: url).0 - let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any] + public init() {} - guard let result = (json?["results"] as? [Any])?.first as? [String: Any], - let version = result["version"] as? String - else { - return false + public func requestAppVersion() async throws -> Bool { + guard let info = Bundle.main.infoDictionary, + // 현재 버전 가져오기 + let currentVersion = info["CFBundleShortVersionString"] as? String, + // 앱 번들아이디 가져오기 + let identifier = info["CFBundleIdentifier"] as? String, + let url = URL(string: "http://itunes.apple.com/kr/lookup?bundleId=\(identifier)") + else { + return false + } + + let data = try await URLSession.shared.data(from: url).0 + let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any] + + guard let result = (json?["results"] as? [Any])?.first as? [String: Any], + let version = result["version"] as? String + else { + return false + } + + let verFloat = NSString.init(string: version).floatValue + let currentVerFloat = NSString.init(string: currentVersion).floatValue + + return verFloat < currentVerFloat ? true : false } - - let verFloat = NSString.init(string: version).floatValue - let currentVerFloat = NSString.init(string: currentVersion).floatValue - - return verFloat < currentVerFloat ? true : false - } } diff --git a/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift b/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift index 557b424d..a8d05f33 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift @@ -83,17 +83,17 @@ extension SplashInteractor { import UIKit extension SplashInteractor { - + func didLoad() async { - + do { - let isVersionSame = try await self.worker.checkAppVersion() - - if !isVersionSame { - await self.presenter.presentUpdatePopup() - } else { - let userState = try await self.worker.fetchUserState() - switch userState { + let isVersionSame = try await self.worker.checkAppVersion() + + if !isVersionSame { + await self.presenter.presentUpdatePopup() + } else { + let userState = try await self.worker.fetchUserState() + switch userState { case .login: self.didTriggerRouteToLoginScene.send(()) @@ -108,8 +108,8 @@ extension SplashInteractor { case .home: self.didTriggerRouteToHomeScene.send(()) + } } - } } catch { self.didTriggerRouteToLoginScene.send(()) @@ -120,14 +120,14 @@ extension SplashInteractor { // MARK: Feature (강제업데이트) extension SplashInteractor { - func didTapUpdateButton() async { - let appleId = "6455260918" - DispatchQueue.main.async { - if let url = URL(string: "itms-apps://itunes.apple.com/app/apple-store/\(appleId)"), UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) + func didTapUpdateButton() async { + let appleId = "6455260918" + DispatchQueue.main.async { + if let url = URL(string: "itms-apps://itunes.apple.com/app/apple-store/\(appleId)"), UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } } } - } } // MARK: - Application Business Logic diff --git a/Scene/SplashScene/Sources/SplashScene/SplashModels.swift b/Scene/SplashScene/Sources/SplashScene/SplashModels.swift index e70b5f03..edac53cb 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashModels.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashModels.swift @@ -29,15 +29,15 @@ enum Splash { } enum ViewModel { - struct UpdatePopup { - /// 타이틀 - var title: String - /// 업데이트 아이콘 - var iconImage: UIImage - /// 설명 - var description: String - /// 버튼 타이틀 - var buttonTitle: [String] - } + struct UpdatePopup { + /// 타이틀 + var title: String + /// 업데이트 아이콘 + var iconImage: UIImage + /// 설명 + var description: String + /// 버튼 타이틀 + var buttonTitle: [String] + } } } diff --git a/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift b/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift index baba47e6..deff24cc 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashPresenter.swift @@ -10,8 +10,8 @@ import UIKit @MainActor protocol SplashPresentationLogic { - // 강제 업데이트 팝업을 보여준다. - func presentUpdatePopup() + // 강제 업데이트 팝업을 보여준다. + func presentUpdatePopup() } final class SplashPresenter { @@ -22,9 +22,9 @@ final class SplashPresenter { // MARK: - Presentation Logic extension SplashPresenter: SplashPresentationLogic { - func presentUpdatePopup() { - let viewModel = Splash.ViewModel.UpdatePopup(title: "업데이트 알림", iconImage: .asset(.update_icon)!, description: "앱을 업데이트 하고\n더욱 안정된 투투를 만나보세요 :)", buttonTitle: ["업데이트"]) - - self.viewController?.displayUpdatePopup(viewModel: viewModel) - } + func presentUpdatePopup() { + let viewModel = Splash.ViewModel.UpdatePopup(title: "업데이트 알림", iconImage: .asset(.update_icon)!, description: "앱을 업데이트 하고\n더욱 안정된 투투를 만나보세요 :)", buttonTitle: ["업데이트"]) + + self.viewController?.displayUpdatePopup(viewModel: viewModel) + } } diff --git a/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift b/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift index 3b47ccf6..12efde4f 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashViewController.swift @@ -10,7 +10,7 @@ import CoreKit import UIKit protocol SplashDisplayLogic: AnyObject { - func displayUpdatePopup(viewModel: Splash.ViewModel.UpdatePopup) + func displayUpdatePopup(viewModel: Splash.ViewModel.UpdatePopup) } final class SplashViewController: UIViewController { @@ -46,16 +46,16 @@ final class SplashViewController: UIViewController { v.image = .asset(.app_logo)! return v }() - + lazy var updatePopupView: TTPopup = { - let v = TTPopup() - v.isHidden = true - v.didTapLeftButton { - Task { [weak self] in - await self?.interactor.didTapUpdateButton() + let v = TTPopup() + v.isHidden = true + v.didTapLeftButton { + Task { [weak self] in + await self?.interactor.didTapUpdateButton() + } } - } - return v + return v }() // MARK: - View Lifecycle @@ -88,7 +88,7 @@ final class SplashViewController: UIViewController { make.width.equalTo(135) make.height.equalTo(23) } - + self.updatePopupView.snp.makeConstraints { make in make.center.equalToSuperview() } @@ -106,14 +106,14 @@ extension SplashViewController: SplashScene { // MARK: - Display Logic extension SplashViewController: SplashDisplayLogic { - func displayUpdatePopup(viewModel: Splash.ViewModel.UpdatePopup) { - - updatePopupView.configure( - title: viewModel.title, - resultView: UIImageView(image: viewModel.iconImage), - description: viewModel.description, - buttonTitles: viewModel.buttonTitle - ) - self.updatePopupView.isHidden = false - } + func displayUpdatePopup(viewModel: Splash.ViewModel.UpdatePopup) { + + updatePopupView.configure( + title: viewModel.title, + resultView: UIImageView(image: viewModel.iconImage), + description: viewModel.description, + buttonTitles: viewModel.buttonTitle + ) + self.updatePopupView.isHidden = false + } } diff --git a/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift b/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift index 7fb9cd8c..fa5488d3 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashWorker.swift @@ -33,7 +33,7 @@ final class SplashWorker: SplashWorkerProtocol { self.meNetworkWorker = meNetworkWorker self.appVersionWorker = appVersionWorker } - + // 최신버전인지 아닌지 확인하는 함수 func checkAppVersion() async throws -> Bool { return try await self.appVersionWorker.requestAppVersion() From 39648b3ec66ffd97afa2bc7f88d9659efc73e89a Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Tue, 5 Dec 2023 09:26:05 +0900 Subject: [PATCH 07/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A0=EC=9D=B4=EB=93=A4=20URL=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scene/MyInfoScene/Sources/MyInfoScene/MyInfoInteractor.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scene/MyInfoScene/Sources/MyInfoScene/MyInfoInteractor.swift b/Scene/MyInfoScene/Sources/MyInfoScene/MyInfoInteractor.swift index 6e17d515..ac890d48 100644 --- a/Scene/MyInfoScene/Sources/MyInfoScene/MyInfoInteractor.swift +++ b/Scene/MyInfoScene/Sources/MyInfoScene/MyInfoInteractor.swift @@ -80,7 +80,7 @@ final class MyInfoInteractor: MyInfoDataStore, MyInfoBusinessLogic { case .inquery: return URL(string: "https://docs.google.com/forms/d/e/1FAIpQLSeUGNUGzl3MnGUAIR-rtfgYYrDYRIoKh_Ozpd4prqA1qIBKRw/viewform?usp=sf_link") case .creators: - return URL(string: "https://two2too2.github.io/creater.html") + return URL(string: "https://twotoo-landing.vercel.app/makers") case .logout: return nil case .singout: From 8317ead52079880faaf440c42eab54c89ccb4cd0 Mon Sep 17 00:00:00 2001 From: julia0926 Date: Fri, 22 Dec 2023 14:43:54 +0900 Subject: [PATCH 08/44] =?UTF-8?q?=E2=9C=A8=20=EB=82=98=EA=B0=80=EA=B8=B0?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=20=ED=83=AD=ED=95=A0=20=EC=8B=9C=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Local/Sources/Local/LocalDataSource.swift | 6 +++++- .../InvitationWaitInteractor.swift | 1 + .../InvitationWaitSceneFactory.swift | 5 ++++- .../InvitationWaitWorker.swift | 15 ++++++++++++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Core/Local/Sources/Local/LocalDataSource.swift b/Core/Local/Sources/Local/LocalDataSource.swift index f2d270c4..64146228 100644 --- a/Core/Local/Sources/Local/LocalDataSource.swift +++ b/Core/Local/Sources/Local/LocalDataSource.swift @@ -21,7 +21,11 @@ public protocol LocalDataSourceProtocol { func remove(key: String) } -public final class LocalDataSource: LocalDataSourceProtocol { +public protocol ResetLocalDataSourceProtocol { + func removeAll() +} + +public final class LocalDataSource: LocalDataSourceProtocol, ResetLocalDataSourceProtocol { public init() {} diff --git a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift index c3a35b36..c3cbe891 100644 --- a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift +++ b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitInteractor.swift @@ -123,6 +123,7 @@ extension InvitationWaitInteractor { func didTapExitButton() async { self.didTriggerRouteToLoginScene.send(()) + await self.worker.resetLocalData() } } diff --git a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift index dc009a60..62a64721 100644 --- a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift +++ b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitSceneFactory.swift @@ -44,6 +44,7 @@ public final class InvitationWaitSceneFactory { let meLocalWorker = MeLocalWorker(localDataSource: localDataSource) let partnerNetworkWorker = PartnerNetworkWorker() let nicknameNetworkWorker = NicknameNetworkWorker() + let onboardLocalWorker = OnboardingLocalWorker(localDataSource: localDataSource) let presenter = InvitationWaitPresenter() let router = InvitationWaitRouter() @@ -52,7 +53,9 @@ public final class InvitationWaitSceneFactory { invitationLocalWorker: invitationLocalWorker, meLocalWorker: meLocalWorker, partnerNetworkWorker: partnerNetworkWorker, - nicknameNetworkWorker: nicknameNetworkWorker + nicknameNetworkWorker: nicknameNetworkWorker, + resetLocalDataSource: localDataSource, + onboardLocalWorker: onboardLocalWorker ) let interactor = InvitationWaitInteractor( presenter: presenter, diff --git a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitWorker.swift b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitWorker.swift index 5a626a28..2579910e 100644 --- a/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitWorker.swift +++ b/Scene/InvitationWaitScene/Sources/InvitationWaitScene/InvitationWaitWorker.swift @@ -13,6 +13,8 @@ protocol InvitationWaitWorkerProtocol { var invitationLink: String? { get } /// 파트너 조회 func inquiryPartner() async throws -> InvitationWait.Model.Partner? + /// 로컬 데이터 리셋 + func resetLocalData() async } final class InvitationWaitWorker: InvitationWaitWorkerProtocol { @@ -22,19 +24,25 @@ final class InvitationWaitWorker: InvitationWaitWorkerProtocol { var meLocalWorker: MeLocalWorkerProtocol var partnerNetworkWorker: PartnerNetworkWorkerProtocol var nicknameNetworkWorker: NicknameNetworkWorkerProtocol + var resetLocalDataSource: ResetLocalDataSourceProtocol + var onboardLocalWorker: OnboardingLocalWorkerProtocol init( invitedUserLocalWorker: InvitedUserLocalWorkerProtocol, invitationLocalWorker: InvitationLocalWorkerProtocol, meLocalWorker: MeLocalWorkerProtocol, partnerNetworkWorker: PartnerNetworkWorkerProtocol, - nicknameNetworkWorker: NicknameNetworkWorkerProtocol + nicknameNetworkWorker: NicknameNetworkWorkerProtocol, + resetLocalDataSource: ResetLocalDataSourceProtocol, + onboardLocalWorker: OnboardingLocalWorkerProtocol ) { self.invitedUserLocalWorker = invitedUserLocalWorker self.invitationLocalWorker = invitationLocalWorker self.meLocalWorker = meLocalWorker self.partnerNetworkWorker = partnerNetworkWorker self.nicknameNetworkWorker = nicknameNetworkWorker + self.resetLocalDataSource = resetLocalDataSource + self.onboardLocalWorker = onboardLocalWorker } var invitationLink: String? { @@ -77,4 +85,9 @@ final class InvitationWaitWorker: InvitationWaitWorkerProtocol { return nil } } + + func resetLocalData() async { + self.resetLocalDataSource.removeAll() + self.onboardLocalWorker.isCheckedOnboarding = true + } } From 273098066615f67551f36c4a84d2bc8fccc3eb39 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Wed, 27 Dec 2023 14:33:16 +0900 Subject: [PATCH 09/44] =?UTF-8?q?fix:=20=EA=B0=95=EC=A0=9C=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=A1=B0=EA=B1=B4=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift b/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift index a8d05f33..43e0a35f 100644 --- a/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift +++ b/Scene/SplashScene/Sources/SplashScene/SplashInteractor.swift @@ -87,9 +87,9 @@ extension SplashInteractor { func didLoad() async { do { - let isVersionSame = try await self.worker.checkAppVersion() + let isNeedUpdate = try await self.worker.checkAppVersion() - if !isVersionSame { + if isNeedUpdate { await self.presenter.presentUpdatePopup() } else { let userState = try await self.worker.fetchUserState() From 579316fb200586d5672f998f67ac9060ea30dfd7 Mon Sep 17 00:00:00 2001 From: julia0926 Date: Wed, 27 Dec 2023 14:41:22 +0900 Subject: [PATCH 10/44] =?UTF-8?q?=F0=9F=9A=9A=20progressBar=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=ED=8C=8C=EC=9D=BC=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Home->DesignSystem --- .../Sources/Component}/TTProgressBar.swift | 29 +++++++++++-------- .../Sources/HomeScene/HomeModels.swift | 4 +-- .../Views/ChallengeCompletedView.swift | 3 +- .../Views/ChallengeInProgressView.swift | 3 +- 4 files changed, 23 insertions(+), 16 deletions(-) rename {Scene/HomeScene/Sources/HomeScene/Views/Common => Core/DesignSystem/Sources/DesignSystem/Sources/Component}/TTProgressBar.swift (89%) diff --git a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTProgressBar.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/TTProgressBar.swift similarity index 89% rename from Scene/HomeScene/Sources/HomeScene/Views/Common/TTProgressBar.swift rename to Core/DesignSystem/Sources/DesignSystem/Sources/Component/TTProgressBar.swift index b509a308..10da5bf9 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTProgressBar.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/TTProgressBar.swift @@ -7,7 +7,22 @@ import UIKit -final class TTProgressBar: UIView { +public protocol TTProgressViewModelProtocol { + /// 상대방 이름 텍스트 + var partnerNameText: String { get set } + /// 내 이름 텍스트 + var myNameText: String { get set } + /// 상대방 퍼센테이지 텍스트 + var partnerPercentageText: String { get set } + /// 내 퍼센테이지 텍스트 + var myPercentageText: String { get set } + /// 상대방 퍼센테이지 넘버 + var partnerPercentageNumber: Double { get set } + /// 내 퍼센테이지 넘버 + var myPercentageNumber: Double { get set } +} + +public final class TTProgressBar: UIView { // MARK: - My UI private lazy var partnerNicknameLabel: UILabel = { @@ -137,7 +152,7 @@ final class TTProgressBar: UIView { self.layer.cornerRadius = 15 } - func configureInProgress(viewModel: Home.ViewModel.ChallengeInProgressViewModel.ProgressViewModel) { + public func configure(viewModel: TTProgressViewModelProtocol) { self.myNicknameLabel.text = viewModel.myNameText self.myPercentLabel.text = viewModel.myPercentageText self.partnerNicknameLabel.text = viewModel.partnerNameText @@ -146,16 +161,6 @@ final class TTProgressBar: UIView { partner: viewModel.partnerPercentageNumber) } - func configureCompleted(viewModel: Home.ViewModel.ChallengeCompletedViewModel.ProgressViewModel) { - self.myNicknameLabel.text = viewModel.myNameText - self.myPercentLabel.text = viewModel.myPercentageText - self.partnerNicknameLabel.text = viewModel.partnerNameText - self.partnerPercentLabel.text = viewModel.partnerPercentageText - self.configurePercent(my: viewModel.myPercentageNumber, - partner: viewModel.partnerPercentageNumber) - } - - private func configurePercent(my: Double, partner: Double) { if my == 0 { self.myPercentView.snp.remakeConstraints { make in diff --git a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift index 3844d566..4e366e8f 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift @@ -193,7 +193,7 @@ enum Home { } /// 프로그래스 - struct ProgressViewModel { + struct ProgressViewModel: TTProgressViewModelProtocol { /// 상대방 이름 텍스트 var partnerNameText: String /// 내 이름 텍스트 @@ -298,7 +298,7 @@ enum Home { } /// 프로그래스 - struct ProgressViewModel { + struct ProgressViewModel: TTProgressViewModelProtocol { /// 상대방 이름 텍스트 var partnerNameText: String /// 내 이름 텍스트 diff --git a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift index e3adcbae..0ab7e3c2 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift +++ b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift @@ -33,6 +33,7 @@ final class ChallengeCompletedView: UIView { /// 챌린지 진행도 뷰 lazy var progressBar: TTProgressBar = { let v = TTProgressBar() + v.isHidden = true return v }() /// 나와 상대의 닉네임 뷰 @@ -156,7 +157,7 @@ final class ChallengeCompletedView: UIView { func configure(viewModel: Home.ViewModel.ChallengeCompletedViewModel) { self.topChallengeInfoView.configureCompleted(viewModel: viewModel.challengeInfo) - self.progressBar.configureCompleted(viewModel: viewModel.progress) + self.progressBar.configure(viewModel: viewModel.progress) self.nicknameStackView.configure(challengeOrderText: viewModel.order.challengeOrderText, myNickname: viewModel.order.myNameText, partnerNickname: viewModel.order.partenrNameText) diff --git a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift index 08238010..c76c8fae 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift +++ b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift @@ -6,6 +6,7 @@ // import UIKit +import DesignSystem protocol ChallengeInProgressViewDelegate: AnyObject { func didTapCertificateButton() @@ -176,7 +177,7 @@ final class ChallengeInProgressView: UIView { func configure(viewModel: Home.ViewModel.ChallengeInProgressViewModel) { self.topChallengeInfoView.configureInProgress(viewModel: viewModel.challengeInfo) - self.progressBar.configureInProgress(viewModel: viewModel.progress) + self.progressBar.configure(viewModel: viewModel.progress) self.nicknameStackView.configure(challengeOrderText: viewModel.order.challengeOrderText, myNickname: viewModel.order.myNameText, partnerNickname: viewModel.order.partenrNameText) From 7ddc95441c218207af40c0796dd3020b001cd18d Mon Sep 17 00:00:00 2001 From: julia0926 Date: Wed, 27 Dec 2023 14:44:23 +0900 Subject: [PATCH 11/44] =?UTF-8?q?=E2=9C=A8=20=EC=B1=8C=EB=A6=B0=EC=A7=80?= =?UTF-8?q?=20=ED=9E=88=EC=8A=A4=ED=86=A0=EB=A6=AC=20progressBar=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryModels.swift | 21 ++++++++++ .../ChallengeHistoryPresenter.swift | 42 ++++++++++++++++++- .../ChallengeHistoryViewController.swift | 22 +++++++++- .../ChallengeHistoryWorker.swift | 7 +++- 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryModels.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryModels.swift index 98c89bde..bc7f4e18 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryModels.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryModels.swift @@ -6,6 +6,7 @@ // Copyright (c) 2023 TwoToo. All rights reserved. // +import CoreKit import UIKit enum ChallengeHistory { @@ -40,6 +41,8 @@ enum ChallengeHistory { var id: String /// 닉네임 var nickname: String + /// 인증 횟수 + var certCount: Int? /// 인증 리스트 var certificates: [Certificate] } @@ -73,6 +76,8 @@ enum ChallengeHistory { var dDayText: String /// 챌린지 추가 정보 문구 var additionalInfo: String? + /// 프로그래스 + var progress: ProgressViewModel /// 유저 닉네임 var myNickname: String /// 상대방 닉네임 @@ -81,6 +86,22 @@ enum ChallengeHistory { var cellInfo: CellInfoList } + /// 프로그래스 + struct ProgressViewModel: TTProgressViewModelProtocol { + /// 상대방 이름 텍스트 + var partnerNameText: String + /// 내 이름 텍스트 + var myNameText: String + /// 상대방 퍼센테이지 텍스트 + var partnerPercentageText: String + /// 내 퍼센테이지 텍스트 + var myPercentageText: String + /// 상대방 퍼센테이지 넘버 + var partnerPercentageNumber: Double + /// 내 퍼센테이지 넘버 + var myPercentageNumber: Double + } + /// 챌린지 테이블 셀 리스트 typealias CellInfoList = [CellInfo] /// 챌린지 테이블 뷰 셀 정보 diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryPresenter.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryPresenter.swift index d1b0f0cc..34c09b21 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryPresenter.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryPresenter.swift @@ -89,7 +89,8 @@ extension ChallengeHistoryPresenter { dDayText: self.makedDayText(start: Date(), end: model.endDate, isFinished: model.isFinished), - additionalInfo: model.additionalInfo, + additionalInfo: model.additionalInfo, + progress: self.mappingProgress(partnerInfo: model.partnerInfo, myInfo: model.myInfo), myNickname: model.myInfo.nickname, partnerNickname: model.partnerInfo.nickname, cellInfo: self.makeCellInfoList(start: model.startDate, @@ -97,6 +98,15 @@ extension ChallengeHistoryPresenter { myList: model.myInfo.certificates, partnerList: model.partnerInfo.certificates)) } + + private func mappingProgress(partnerInfo: ChallengeHistory.Model.User, myInfo: ChallengeHistory.Model.User) -> ChallengeHistory.ViewModel.ProgressViewModel { + return .init(partnerNameText: partnerInfo.nickname, + myNameText: myInfo.nickname, + partnerPercentageText: self.calculatePercentageText(certCount: partnerInfo.certCount), + myPercentageText: self.calculatePercentageText(certCount: myInfo.certCount), + partnerPercentageNumber: self.calculatePercentageNumber(certCount: partnerInfo.certCount), + myPercentageNumber: self.calculatePercentageNumber(certCount: myInfo.certCount)) + } /// cell 뷰모델 리스트 생성 private func makeCellInfoList(start: Date, end: Date, @@ -193,4 +203,34 @@ extension ChallengeHistoryPresenter { return Calendar.current.isDate(today, inSameDayAs: date) } + private func calculatePercentageText(certCount: Int?) -> String { + guard let certCount = certCount else { + return "" + } + + if certCount < 20 { + let percentage = (certCount * 5) // 5% 씩 증가 + return "\(percentage)%" + } else if certCount < 22 { + return "99%" // 20부터 99%로 유지 + } else { + return "100%" // 22가 되면 100%로 표시 + } + } + + private func calculatePercentageNumber(certCount: Int?) -> Double { + guard let certCount = certCount else { + return 0.0 + } + + if certCount < 20 { + return Double(certCount) * 0.05 // 5% 씩 증가 + } else if certCount < 22 { + return 0.99 // 20부터 99%로 유지 + } else { + return 1.0 // 22가 되면 100%로 표시 + } + } + + } diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryViewController.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryViewController.swift index f86759e7..750bf8af 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryViewController.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryViewController.swift @@ -67,6 +67,12 @@ final class ChallengeHistoryViewController: UIViewController, UITableViewDataSou return v }() + private let progressBar: TTProgressBar = { + let v = TTProgressBar() + v.isHidden = true + return v + }() + private let myNicknameTagView: TTTagView = { let v = TTTagView(textColor: .mainCoral, fontSize: .body2, @@ -166,6 +172,7 @@ final class ChallengeHistoryViewController: UIViewController, UITableViewDataSou self.dDayTagView, self.titleLabel, self.additionalInfoLabel, + self.progressBar, self.myNicknameTagView, self.partnerNicknameTagView, self.underLineView, @@ -199,14 +206,21 @@ final class ChallengeHistoryViewController: UIViewController, UITableViewDataSou make.trailing.equalToSuperview().inset(25) } + self.progressBar.snp.makeConstraints { make in + make.top.equalTo(self.additionalInfoLabel.snp.bottom).offset(12) + make.leading.equalToSuperview().offset(24) + make.width.equalToSuperview().multipliedBy(0.55) + make.height.equalTo(62) + } + self.partnerNicknameTagView.snp.makeConstraints { make in - make.top.equalTo(self.additionalInfoLabel.snp.bottom).offset(40) + make.top.equalTo(self.progressBar.snp.bottom).offset(30) make.centerX.equalToSuperview().multipliedBy(0.5) make.height.equalTo(28) } self.myNicknameTagView.snp.makeConstraints { make in - make.top.equalTo(self.additionalInfoLabel.snp.bottom).offset(40) + make.top.equalTo(self.progressBar.snp.bottom).offset(30) make.centerX.equalToSuperview().multipliedBy(1.5) make.height.equalTo(28) } @@ -231,6 +245,7 @@ final class ChallengeHistoryViewController: UIViewController, UITableViewDataSou make.height.equalTo(349) } } + // MARK: - UITableViewDataSource var certificateList: ChallengeHistory.ViewModel.CellInfoList = [] @@ -300,8 +315,11 @@ extension ChallengeHistoryViewController: ChallengeHistoryDisplayLogic { self.myNicknameTagView.titleLabel.text = viewModel.myNickname self.partnerNicknameTagView.titleLabel.text = viewModel.partnerNickname self.certificateList = viewModel.cellInfo + self.progressBar.isHidden = false + self.progressBar.configure(viewModel: viewModel.progress) self.certificateTableView.reloadData() } + func displayOptionPopup(title: String) { let alertVC = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryWorker.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryWorker.swift index 80b6835f..b8ac9e81 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryWorker.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryWorker.swift @@ -97,7 +97,11 @@ final class ChallengeHistoryWorker: ChallengeHistoryWorkerProtocol { return self.meLocalWorker.partnerNickname } - private func mapUserInfo(from user: ChallengeDetailResponse.User, commitList: [ChallengeDetailResponse.Commit]?, commitCount: Int?) -> ChallengeHistory.Model.User { + private func mapUserInfo(from user: ChallengeDetailResponse.User, + commitList: [ChallengeDetailResponse.Commit]?, + commitCount: Int?) + -> ChallengeHistory.Model.User + { var certificates: [ChallengeHistory.Model.Certificate] = [] if let commitList = commitList { certificates = commitList.map { @@ -114,6 +118,7 @@ final class ChallengeHistoryWorker: ChallengeHistoryWorkerProtocol { let userInfo: ChallengeHistory.Model.User = .init( id: String(user.userNo), nickname: user.nickname, + certCount: commitCount, certificates: certificates ) From fb6da0c94f896e56afb61266729635ac605395f4 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Wed, 27 Dec 2023 15:17:40 +0900 Subject: [PATCH 12/44] =?UTF-8?q?refactor:=20=EB=B2=84=EC=A0=84=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Worker/NetworkWorker/AppVersionNetworkWorker.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift index ce3bc7e6..21ce0826 100644 --- a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift +++ b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift @@ -19,10 +19,11 @@ public final class AppVersionNetworkWorker: AppVersionNetworkWorkerProtocol { public func requestAppVersion() async throws -> Bool { guard let info = Bundle.main.infoDictionary, - // 현재 버전 가져오기 + // 내 디바이스 현재 버전 가져오기 let currentVersion = info["CFBundleShortVersionString"] as? String, // 앱 번들아이디 가져오기 let identifier = info["CFBundleIdentifier"] as? String, + // 앱스토어 앱버전 let url = URL(string: "http://itunes.apple.com/kr/lookup?bundleId=\(identifier)") else { return false @@ -37,9 +38,9 @@ public final class AppVersionNetworkWorker: AppVersionNetworkWorkerProtocol { return false } - let verFloat = NSString.init(string: version).floatValue - let currentVerFloat = NSString.init(string: currentVersion).floatValue + let appStoreAppVersion = NSString.init(string: version).floatValue + let deviceAppVersion = NSString.init(string: currentVersion).floatValue - return verFloat < currentVerFloat ? true : false + return appStoreAppVersion > deviceAppVersion ? true : false } } From 32d61e94f9ec7e9d3eeb3664703be96ebc9d9a97 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Wed, 27 Dec 2023 17:05:46 +0900 Subject: [PATCH 13/44] =?UTF-8?q?fix:=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Worker/NetworkWorker/AppVersionNetworkWorker.swift | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift index 21ce0826..4d087d2f 100644 --- a/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift +++ b/Core/Worker/Sources/Worker/NetworkWorker/AppVersionNetworkWorker.swift @@ -20,7 +20,7 @@ public final class AppVersionNetworkWorker: AppVersionNetworkWorkerProtocol { public func requestAppVersion() async throws -> Bool { guard let info = Bundle.main.infoDictionary, // 내 디바이스 현재 버전 가져오기 - let currentVersion = info["CFBundleShortVersionString"] as? String, + let deviceAppVersion = info["CFBundleShortVersionString"] as? String, // 앱 번들아이디 가져오기 let identifier = info["CFBundleIdentifier"] as? String, // 앱스토어 앱버전 @@ -33,14 +33,10 @@ public final class AppVersionNetworkWorker: AppVersionNetworkWorkerProtocol { let json = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) as? [String: Any] guard let result = (json?["results"] as? [Any])?.first as? [String: Any], - let version = result["version"] as? String + let appStoreAppVersion = result["version"] as? String else { return false } - - let appStoreAppVersion = NSString.init(string: version).floatValue - let deviceAppVersion = NSString.init(string: currentVersion).floatValue - - return appStoreAppVersion > deviceAppVersion ? true : false + return appStoreAppVersion > deviceAppVersion } } From b26a1a33b0b717dc4dbc17c0231941e0cc845d1f Mon Sep 17 00:00:00 2001 From: julia0926 Date: Tue, 2 Jan 2024 19:40:29 +0900 Subject: [PATCH 14/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=B0=8C=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EB=B3=B4=EC=9D=B4=EC=A7=80=20=EC=95=8A=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 바텀시트 높이 SE 대응 --- .../Layout/SelfSizingScrollView.swift | 6 ++--- .../NudgeSendViewController.swift | 27 +++++++++++++++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/BottomSheet/Layout/SelfSizingScrollView.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/BottomSheet/Layout/SelfSizingScrollView.swift index a33a69a6..2c692c23 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/BottomSheet/Layout/SelfSizingScrollView.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/BottomSheet/Layout/SelfSizingScrollView.swift @@ -8,7 +8,7 @@ import UIKit public final class SelfSizingScrollView: UIScrollView { - private var maxHeight: CGFloat = UIScreen.main.bounds.height * 0.67 + private var maxHeight: CGFloat = UIScreen.main.bounds.height public override var intrinsicContentSize: CGSize { CGSize(width: contentSize.width, @@ -20,9 +20,9 @@ public final class SelfSizingScrollView: UIScrollView { invalidateIntrinsicContentSize() } - public convenience init(maxHeight: CGFloat) { + public convenience init(maxHeightRatio: CGFloat = 0.67) { self.init() - self.maxHeight = maxHeight + self.maxHeight *= maxHeightRatio } public override init(frame: CGRect) { diff --git a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendViewController.swift b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendViewController.swift index 0d0c0035..998ed38d 100644 --- a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendViewController.swift +++ b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendViewController.swift @@ -43,7 +43,8 @@ final class NudgeSendViewController: UIViewController, BottomSheetViewController }() private lazy var messageTextView: TTTextView = { - let v = TTTextView(placeHolder: "찌르기 문구를 입력해주세요.\n최대 30자까지 입력 가능", maxCount: 30) + let v = TTTextView(placeHolder: "찌르기 문구를 입력해주세요.\n최대 30자까지 입력 가능", + maxCount: 30) v.customDelegate = self return v }() @@ -71,7 +72,8 @@ final class NudgeSendViewController: UIViewController, BottomSheetViewController }() private lazy var backScrollView: UIScrollView = { - let v = SelfSizingScrollView() + let heightRatio = UIDevice.current.deviceType == .default ? 0.8 : 0.67 + let v = SelfSizingScrollView(maxHeightRatio: heightRatio) v.addSubview(self.scrollSizeFitView) return v }() @@ -82,6 +84,8 @@ final class NudgeSendViewController: UIViewController, BottomSheetViewController super.viewDidLoad() self.setUI() self.messageTextView.becomeFirstResponder() + self.registKeyboardDelegate() + Task { await self.interactor.didLoad() } @@ -177,3 +181,22 @@ extension NudgeSendViewController: NudgeSendDisplayLogic { } } } + +extension NudgeSendViewController: KeyboardDelegate { + func willShowKeyboard(keyboardFrame: CGRect, duration: Double) { + let bottomOffset = keyboardFrame.height + 14 + UIView.animate(withDuration: duration) { + self.pushButton.snp.remakeConstraints { make in + make.leading.equalToSuperview().offset(24) + make.trailing.equalToSuperview().inset(24) + make.height.equalTo(57) + make.bottom.equalTo(self.view.snp.bottom).inset(bottomOffset) + } + self.view.layoutIfNeeded() + } + } + + func willHideKeyboard(duration: Double) { + // 키보드 안내려가게 고정해둠 + } +} From 051ea0018dd08ceb215ed5c21e30700aeb10618a Mon Sep 17 00:00:00 2001 From: julia0926 Date: Tue, 2 Jan 2024 19:47:13 +0900 Subject: [PATCH 15/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EB=B3=B4=EC=9D=B4=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeCertificateViewController.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift b/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift index bcd55143..4c19531f 100644 --- a/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift +++ b/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift @@ -102,7 +102,8 @@ final class ChallengeCertificateViewController: UIViewController, BottomSheetVie }() private lazy var backScrollView: UIScrollView = { - let v = SelfSizingScrollView(maxHeight: UIScreen.main.bounds.height * 0.72) + let heightRatio = UIDevice.current.deviceType == .default ? 0.85 : 0.72 + let v = SelfSizingScrollView(maxHeightRatio: heightRatio) v.delegate = self v.addTapAction { [weak self] in self?.view.endEditing(true) @@ -198,6 +199,13 @@ extension ChallengeCertificateViewController: TTTextViewDelegate, make.bottom.equalToSuperview().inset(keyboardFrame.height) } self.backScrollView.contentOffset.y = keyboardFrame.height + let bottomOffset = keyboardFrame.height + 14 + self.commitButton.snp.remakeConstraints { make in + make.leading.equalToSuperview().offset(24) + make.trailing.equalToSuperview().inset(24) + make.height.equalTo(57) + make.bottom.equalTo(self.view.snp.bottom).inset(bottomOffset) + } self.view.layoutIfNeeded() } } From 0804ac242923ecb3981da771fc37f006273604cf Mon Sep 17 00:00:00 2001 From: julia0926 Date: Fri, 5 Jan 2024 09:31:52 +0900 Subject: [PATCH 16/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=B0=94=ED=85=80=EC=8B=9C=ED=8A=B8=20SE=20=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=20=EA=B0=80=EB=A6=AC=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeCertificateViewController.swift | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift b/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift index 4c19531f..2c6ca170 100644 --- a/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift +++ b/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift @@ -25,6 +25,10 @@ protocol ChallengeCertificateDisplayLogic: AnyObject { final class ChallengeCertificateViewController: UIViewController, BottomSheetViewController { var interactor: ChallengeCertificateBusinessLogic + private var isCheckDeviceSE: Bool { + UIDevice.current.deviceType == .default + } + init(interactor: ChallengeCertificateBusinessLogic) { self.interactor = interactor super.init(nibName: nil, bundle: nil) @@ -102,7 +106,7 @@ final class ChallengeCertificateViewController: UIViewController, BottomSheetVie }() private lazy var backScrollView: UIScrollView = { - let heightRatio = UIDevice.current.deviceType == .default ? 0.85 : 0.72 + let heightRatio = UIDevice.current.deviceType == .default ? 0.87 : 0.72 let v = SelfSizingScrollView(maxHeightRatio: heightRatio) v.delegate = self v.addTapAction { [weak self] in @@ -142,10 +146,13 @@ final class ChallengeCertificateViewController: UIViewController, BottomSheetVie make.centerX.equalToSuperview() } + let leadingTrailningInset = isCheckDeviceSE ? 5 : 0 + let height = isCheckDeviceSE ? 300 : 312 self.commitPhotoView.snp.makeConstraints { make in make.top.equalTo(self.titleLabel.snp.bottom).offset(16) - make.leading.trailing.equalToSuperview() - make.height.equalTo(self.commitPhotoView.snp.width) + make.leading.equalToSuperview().offset(leadingTrailningInset) + make.trailing.equalToSuperview().offset(-leadingTrailningInset) + make.height.equalTo(height) } self.commentTextView.snp.makeConstraints { make in @@ -154,11 +161,12 @@ final class ChallengeCertificateViewController: UIViewController, BottomSheetVie make.height.equalTo(85) } + let bottomOffset = isCheckDeviceSE ? 4 : 0 self.commitButton.snp.makeConstraints { make in make.top.equalTo(self.commentTextView.snp.bottom).offset(29) make.leading.trailing.equalToSuperview() make.height.equalTo(57) - make.bottom.equalToSuperview() + make.bottom.equalToSuperview().inset(bottomOffset) } self.scrollSizeFitView.snp.makeConstraints { make in @@ -198,14 +206,18 @@ extension ChallengeCertificateViewController: TTTextViewDelegate, self.scrollSizeFitView.snp.updateConstraints { make in make.bottom.equalToSuperview().inset(keyboardFrame.height) } - self.backScrollView.contentOffset.y = keyboardFrame.height - let bottomOffset = keyboardFrame.height + 14 - self.commitButton.snp.remakeConstraints { make in - make.leading.equalToSuperview().offset(24) - make.trailing.equalToSuperview().inset(24) - make.height.equalTo(57) - make.bottom.equalTo(self.view.snp.bottom).inset(bottomOffset) + var scrollOffset = keyboardFrame.height + if UIDevice.current.deviceType == .default { + scrollOffset += 14 } + self.backScrollView.contentOffset.y = scrollOffset +// let bottomOffset = keyboardFrame.height + 14 +// self.commitButton.snp.remakeConstraints { make in +// make.leading.equalToSuperview().offset(24) +// make.trailing.equalToSuperview().inset(24) +// make.height.equalTo(57) +// make.bottom.equalTo(self.view.snp.bottom).inset(bottomOffset) +// } self.view.layoutIfNeeded() } } From b5af39db87282792cefd593ff730ba36f5301825 Mon Sep 17 00:00:00 2001 From: ji_in Date: Mon, 8 Jan 2024 21:46:32 +0900 Subject: [PATCH 17/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=B1=8C=EB=A6=B0?= =?UTF-8?q?=EC=A7=80=20=EC=99=84=EB=A3=8C=20=EB=B2=84=ED=8A=BC=EC=9D=B4=20?= =?UTF-8?q?SE=20=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=99=80=20=EA=B2=B9=EC=B9=98=EB=8A=94=20?= =?UTF-8?q?=EC=9D=B4=EC=8A=88=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/HomeScene/Views/ChallengeCompletedView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift index e3adcbae..ccdc602b 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift +++ b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeCompletedView.swift @@ -112,7 +112,7 @@ final class ChallengeCompletedView: UIView { make.trailing.equalToSuperview().inset(24) } - let flowerBottomOffset = UIDevice.current.deviceType == .default ? -12 : 33 + let flowerBottomOffset = UIDevice.current.deviceType == .default ? 12 : 33 // --> PartnerFlower self.partnerFlowerTopView.snp.makeConstraints { make in @@ -143,10 +143,10 @@ final class ChallengeCompletedView: UIView { make.trailing.equalToSuperview() make.bottom.equalTo(self.confirmButton.snp.top).offset(-flowerBottomOffset) } - + let bottomInset = UIDevice.current.deviceType == .default ? 20 : 49 self.confirmButton.snp.makeConstraints { make in make.centerX.equalToSuperview() - make.bottom.equalToSuperview().inset(49) + make.bottom.equalToSuperview().inset(bottomInset) make.width.equalTo(177) } } From f899a66402dd646c04e51ae6d6e3a0c70d3c7cf8 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Wed, 10 Jan 2024 14:41:18 +0900 Subject: [PATCH 18/44] =?UTF-8?q?=E2=9C=A8=20=EB=AA=A8=EB=91=90=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EC=99=84=EB=A3=8C=20=ED=8C=9D=EC=97=85=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=B0=8F=20=ED=9E=88=EC=8A=A4=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EB=94=94=ED=85=8C=EC=9D=BC=20=EC=B9=AD=EC=B0=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailInteractor.swift | 18 +++++-- .../ChallengeHistoryDetailRouter.swift | 14 +++++ ...ChallengeHistoryDetailViewController.swift | 39 +++++++++++--- .../ChallengeHistoryRouter.swift | 19 ++++--- .../Sources/HomeScene/HomeInteractor.swift | 28 +--------- .../Sources/HomeScene/HomeModels.swift | 22 +++----- .../Sources/HomeScene/HomePresenter.swift | 12 ----- .../Sources/HomeScene/HomeRouter.swift | 36 ++++++++----- .../HomeScene/HomeViewController.swift | 54 ------------------- 9 files changed, 104 insertions(+), 138 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift index 7096deaf..3a678c70 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift @@ -15,6 +15,8 @@ protocol ChallengeHistoryDetailBusinessLogic { func didTapCloseButton() async /// 사진 클릭 func didTapPhoto() async + /// 칭찬하기 버튼 클릭 + func didTapPraiseButton() async } protocol ChallengeHistoryDetailDataStore: AnyObject { @@ -22,7 +24,7 @@ protocol ChallengeHistoryDetailDataStore: AnyObject { var detail: ChallengeHistoryDetail.Model.ChallengeDetail { get } } -final class ChallengeHistoryDetailInteractor: ChallengeHistoryDetailDataStore, ChallengeHistoryDetailBusinessLogic { +final class ChallengeHistoryDetailInteractor: ChallengeHistoryDetailDataStore, ChallengeHistoryDetailBusinessLogic { var cancellables: Set = [] @@ -71,7 +73,7 @@ extension ChallengeHistoryDetailInteractor { extension ChallengeHistoryDetailInteractor { func didTapPhoto() async { - await self.presenter.presentPhoto(imageUrl: self.detail.certificateImageUrl) + await self.presenter.presentPhoto(imageUrl: self.detail.certificateImageUrl) } } @@ -82,7 +84,17 @@ extension ChallengeHistoryDetailInteractor { func didTapCloseButton() async { await self.router.dismiss() } - +} + +// MARK: Feature (칭찬하기) + +extension ChallengeHistoryDetailInteractor { + + func didTapPraiseButton() async { + if self.detail.complicateComment?.isEmpty != nil { + await self.router.routeToPraiseSendScene() + } + } } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailRouter.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailRouter.swift index f87bbe7a..83a13f28 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailRouter.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailRouter.swift @@ -7,11 +7,14 @@ // import UIKit +import PraiseSendScene @MainActor protocol ChallengeHistoryDetailRoutingLogic { /// 화면을 닫는다. func dismiss() + /// 칭찬하기 화면으로 이동한다. + func routeToPraiseSendScene() } final class ChallengeHistoryDetailRouter { @@ -23,4 +26,15 @@ extension ChallengeHistoryDetailRouter: ChallengeHistoryDetailRoutingLogic { func dismiss() { self.viewController?.dismiss(animated: true) } + + func routeToPraiseSendScene() { + guard let dataStore = self.dataStore else { + return + } + + let praiseSendScene = PraiseSendSceneFactory().make( + with: .init(certificateID: dataStore.detail.id) + ) + self.viewController?.present(praiseSendScene.bottomSheetViewController, animated: true) + } } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift index c24f3254..b01c160b 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift @@ -102,6 +102,19 @@ final class ChallengeHistoryDetailViewController: UIViewController { v.isHidden = true return v }() + + /// 칭찬하기 버튼 + private lazy var prasiseButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "칭찬하기", .large) + v.addAction { [weak self] in + Task { + try await Task.sleep(nanoseconds: 100000000) + await self?.interactor.didTapPraiseButton() + } + } + v.setIsEnabled(true) + return v + }() private lazy var scrollView: UIScrollView = { let v = UIScrollView() @@ -129,13 +142,16 @@ final class ChallengeHistoryDetailViewController: UIViewController { let leadingTrailingPadding: Int = 24 let guide = self.view.safeAreaLayoutGuide - self.scrollContentView.addSubviews(self.dateLabel, - self.certificateImageView, - self.challengeNameLabel, - self.certificationCommentLabel, - self.timeLabel, - self.complimentTitleLabel, - self.complimentContentView) + self.scrollContentView.addSubviews( + self.dateLabel, + self.certificateImageView, + self.challengeNameLabel, + self.certificationCommentLabel, + self.timeLabel, + self.complimentTitleLabel, + self.complimentContentView, + self.prasiseButton + ) self.scrollView.addSubview(self.scrollContentView) self.view.addSubviews(self.navigationBar, @@ -197,6 +213,13 @@ final class ChallengeHistoryDetailViewController: UIViewController { make.trailing.equalToSuperview().inset(leadingTrailingPadding) make.bottom.equalToSuperview() } + + self.prasiseButton.snp.makeConstraints { make in + make.leading.equalToSuperview().offset(leadingTrailingPadding) + make.trailing.equalToSuperview().inset(leadingTrailingPadding) + make.top.equalTo(self.timeLabel.snp.bottom).offset(80) + make.bottom.equalToSuperview() + } // ---> 스크롤뷰 self.scrollView.snp.makeConstraints { make in @@ -244,11 +267,13 @@ extension ChallengeHistoryDetailViewController: ChallengeHistoryDetailDisplayLog if !(compliment.complimentComment?.isEmpty ?? true) { self.complimentTitleLabel.isHidden = false self.complimentContentView.isHidden = false + self.prasiseButton.isHidden = true self.complimentTitleLabel.text = compliment.complimentTitle self.complimentLabel.text = compliment.complimentComment self.complimentLabel.setLineSpacing(8) } else { + self.prasiseButton.isHidden = false self.complimentTitleLabel.isHidden = true self.complimentContentView.isHidden = true } diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift index 01220453..b324d445 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift @@ -35,13 +35,18 @@ extension ChallengeHistoryRouter: ChallengeHistoryRoutingLogic { nickname: String, partnerNickname: String) { - let fac = ChallengeHistoryDetailSceneFactory().make(with: .init(detail: .init(id: certificate.id, - challengeName: title, - certificateImageUrl: certificate.certificateImageUrl, - certificateComment: certificate.certificateComment, - certificateTime: certificate.certificateTime, - complimentComment: certificate.complimentComment), - user: .init(myNickname: nickname, partnerNickname: partnerNickname))) + let fac = ChallengeHistoryDetailSceneFactory().make( + with: .init( + detail: .init( + id: certificate.id, + challengeName: title, + certificateImageUrl: certificate.certificateImageUrl, + certificateComment: certificate.certificateComment, + certificateTime: certificate.certificateTime, + complimentComment: certificate.complimentComment), + user: .init(myNickname: nickname, partnerNickname: partnerNickname) + ) + ) let vc = fac.viewController vc.modalPresentationStyle = .fullScreen self.viewController?.present(vc, animated: true) diff --git a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift index d5a404e5..fc79c0d1 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift @@ -22,12 +22,6 @@ protocol HomeBusinessLogic { func didTapChallengeCompletedPopupConfirmButton() async /// 챌린지 완료하기 버튼 클릭 func didTapChallengeCompleteButton() async - /// 둘다 인증 팝업의 배경 클릭 - func didTapBothCertificationPopupBackground() async - /// 둘다 인증 팝업의 괜찮아요(no) 버튼 클릭 - func didTapBothCertificationPopupNoOption() async - /// 둘다 인증 팝업의 칭찬하기(yes) 버튼 클릭 - func didTapBothCertificationPopupYesOption() async /// 내 칭찬 문구 클릭 func didTapMyComplimentCommnet() async /// 내 꽃 클릭 @@ -130,11 +124,6 @@ extension HomeInteractor { case let .inProgress(inProgress): await self.presenter.presentChallengeInProgress(challenge: challenge) - if inProgress == .bothCertificated(.uncomfirmed) { - self.worker.bothCertificationConfirmed = true - await self.presenter.presentBothCertificationPopup() - } - case let .completed(completed): await self.presenter.presentChallengeCompleted(challenge: challenge) @@ -217,23 +206,8 @@ extension HomeInteractor { extension HomeInteractor { - func didTapBothCertificationPopupBackground() async { - await self.presenter.dismissBothCertificationPopup() - } - - func didTapBothCertificationPopupNoOption() async { - await self.presenter.dismissBothCertificationPopup() - } - - func didTapBothCertificationPopupYesOption() async { - await self.presenter.dismissBothCertificationPopup() - await self.router.routeToPraiseSendScene() - } - func didTapMyComplimentCommnet() async { - if self.challenge?.partnerInfo.todayCert?.complimentComment?.isEmpty ?? true { - await self.router.routeToPraiseSendScene() - } + await self.router.routeToPartnerHistoryDetailScene(title: "", certificate: .init(id: ""), nickname: "", partnerNickname: "") } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift index 4e366e8f..2bea9c0a 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift @@ -65,6 +65,12 @@ enum Home { struct Certificate: Equatable { /// 인증 ID var id: String +// /// 인증 사진 +// var certificateImageUrl: String +// /// 인증 소감 +// var certificateComment: String +// /// 입력 시간 +// var certificateTime: Date /// 칭찬 문구 var complimentComment: String? } @@ -259,22 +265,6 @@ enum Home { var complimentCommentText: String } } - - /// 둘다 인증 팝업 - struct BothCertificationPopupViewModel { - var show: (UIImage)? - var dismiss: ()? - - /// 타이틀 - static let title: String = "모두 인증 완료" - /// 메세지 - static let message: String = "서로 인증을 완료했어요!\n 짝꿍에게 응원 한마디를 남겨요" - /// 아니요 - static let noOptionText: String = "괜찮아요" - /// 네 옵션 - static let yesOptionText: String = "칭찬하기" - } - } diff --git a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift index 70605499..346d3a00 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift @@ -23,10 +23,6 @@ protocol HomePresentationLogic { func presentChallengeAfterStartDate(challenge: Home.Model.Challenge) /// 챌린지 진행중 화면을 보여준다. func presentChallengeInProgress(challenge: Home.Model.Challenge) - /// 둘다 인증 팝업을 보여준다. - func presentBothCertificationPopup() - /// 둘다 인증 팝업을 닫는다. - func dismissBothCertificationPopup() /// 챌린지 완료 화면을 보여준다. func presentChallengeCompleted(challenge: Home.Model.Challenge) /// 챌린지 완료 팝업을 보여준다. @@ -86,14 +82,6 @@ extension HomePresenter: HomePresentationLogic { ) } - func presentBothCertificationPopup() { - self.viewController?.displayBothCertificationViewModel(viewModel: .init(show: (.asset(.icon_all_verified)!))) - } - - func dismissBothCertificationPopup() { - self.viewController?.displayBothCertificationViewModel(viewModel: .init(dismiss: ())) - } - func presentChallengeCompleted(challenge: Home.Model.Challenge) { self.viewController?.displayChallengeCompletedViewModel(viewModel: challenge.toChallengeCompletedViewModel()) } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index 6977c110..bcb3442a 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -7,9 +7,9 @@ // import NudgeSendScene -import PraiseSendScene import ChallengeCertificateScene import ChallengeHistoryScene +import ChallengeHistoryDetailScene import ChallengeEssentialInfoInputScene import ChallengeConfirmScene import SafariServices @@ -21,8 +21,8 @@ protocol HomeRoutingLogic { func routeToChallengeEssentialInfoInputScene() /// 챌린지 정보 확인 화면으로 이동한다. func routeToChallengeConfirmScene(entryPoint: String) - /// 칭찬하기 화면으로 이동한다. - func routeToPraiseSendScene() + /// 상대방 챌린지 히스토리 디테일 화면으로 이동한다. + func routeToPartnerHistoryDetailScene(title: String, certificate: Home.Model.Certificate, nickname: String, partnerNickname: String) /// 인증하기 화면으로 이동한다. func routeToChallengeCertificateScene() /// 찌르기 화면으로 이동한다. @@ -39,7 +39,6 @@ final class HomeRouter { } extension HomeRouter: HomeRoutingLogic { - func routeToChallengeEssentialInfoInputScene() { let challengeEssentialInfoInputScene = ChallengeEssentialInfoInputSceneFactory().make(with: .init()) let challengeEssentialInfoInputViewController = challengeEssentialInfoInputScene.viewController @@ -64,14 +63,27 @@ extension HomeRouter: HomeRoutingLogic { self.viewController?.navigationController?.pushViewController(challengeConfirmViewController, animated: true) } - func routeToPraiseSendScene() { - guard let dataStore = self.dataStore else { - return - } - let praiseSendScene = PraiseSendSceneFactory().make( - with: .init(certificateID: dataStore.challenge?.partnerInfo.todayCert?.id ?? "") - ) - self.viewController?.present(praiseSendScene.bottomSheetViewController, animated: true) + + func routeToPartnerHistoryDetailScene(title: String, + certificate: Home.Model.Certificate, + nickname: String, + partnerNickname: String) { + guard let dataStore = self.dataStore else { + return + } + + let historyDetailScene = ChallengeHistoryDetailSceneFactory().make(with: .init( + detail: .init( + id: certificate.id, + challengeName: dataStore.challenge?.name ?? "", + certificateImageUrl: "", + certificateComment: "", + certificateTime: Date(), + complimentComment: "" + ), user: .init( + myNickname: dataStore.challenge?.myInfo.nickname ?? "", + partnerNickname: dataStore.challenge?.partnerInfo.nickname ?? "") + )) } func routeToChallengeCertificateScene() { diff --git a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift index 97b2f04e..4314278c 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift @@ -17,7 +17,6 @@ protocol HomeDisplayLogic: AnyObject { func displayChallengeAfterStartDateViewModel(viewModel: Home.ViewModel.ChallengeAfterStartDateViewModel) func displayChallengeInProgressViewModel(viewModel: Home.ViewModel.ChallengeInProgressViewModel) func displayChallengeCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel) - func displayBothCertificationViewModel(viewModel: Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel) func displayCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel.CompletedPopupViewModel) func displayToast(viewModel: Home.ViewModel.Toast) } @@ -287,59 +286,6 @@ extension HomeViewController: HomeDisplayLogic { } } - func displayBothCertificationViewModel(viewModel: Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel) { - self.displayWithAnimation { [weak self] in - viewModel.show.unwrap { - let popupContentView = UIView() - let imageView = UIImageView() - imageView.image = $0 - imageView.contentMode = .scaleAspectFit - popupContentView.addSubview(imageView) - imageView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - let popupView = TTPopup() - popupView.configure(title: Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel.title, - resultView: popupContentView, - description: Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel.message, - buttonTitles: [ - Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel.noOptionText, - Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel.yesOptionText - ]) - - popupView.didTapLeftButton { - Task { - await self?.interactor.didTapBothCertificationPopupNoOption() - } - } - - popupView.didTapRightButton { - Task { - await self?.interactor.didTapBothCertificationPopupYesOption() - } - } - - popupView.didTapBackground { - Task { - await self?.interactor.didTapBothCertificationPopupBackground() - } - } - - self?.bothCertificationPopupView = popupView - - if let bothCertificationPopupView = self?.bothCertificationPopupView { - self?.view.addSubview(bothCertificationPopupView) - } - } - - viewModel.dismiss.unwrap { - self?.bothCertificationPopupView?.removeFromSuperview() - self?.bothCertificationPopupView = nil - } - } - } - func displayCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel.CompletedPopupViewModel) { self.displayWithAnimation { [weak self] in viewModel.show.unwrap { From 860b4ddbc9af452858ec3990841f2be50d0fd8b7 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Wed, 10 Jan 2024 15:22:18 +0900 Subject: [PATCH 19/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=B9=AD=EC=B0=AC?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=EC=9D=B4=20=EC=96=91?= =?UTF-8?q?=EC=AA=BD=20=EB=82=98=EC=98=A4=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailModels.swift | 4 ++++ .../ChallengeHistoryDetailPresenter.swift | 21 ++++++++++++------- .../ChallengeHistoryDetailSceneFactory.swift | 15 +++++++++---- ...ChallengeHistoryDetailViewController.swift | 2 +- .../ChallengeHistoryInteractor.swift | 4 ++-- .../ChallengeHistoryRouter.swift | 16 +++++++------- .../Sources/HomeScene/HomeInteractor.swift | 2 +- .../Sources/HomeScene/HomeRouter.swift | 5 ++++- 8 files changed, 45 insertions(+), 24 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift index 0fb0d9e3..23d92006 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift @@ -33,6 +33,8 @@ enum ChallengeHistoryDetail { var partnerNickname: String /// 칭찬 문구 var complicateComment: String? + /// 내 챌린지 상세정보 여부 + var isMyHistoryDetail: Bool } } @@ -60,6 +62,8 @@ enum ChallengeHistoryDetail { var complimentTitle: String /// 칭찬 문구 var complimentComment: String? + /// 내 히스토리 디테일 여부 + var isMyHitstoyDetail: Bool } /// 사진 diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift index ed7941ea..02251405 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift @@ -47,16 +47,21 @@ extension ChallengeHistoryDetailPresenter: ChallengeHistoryDetailPresentationLog let dateText = model.certificateTime.dateToString(.hangleYearMonthDay) let timeText = "인증 시간 " + model.certificateTime.dateToString(.hourMinute) let title = "\(model.myNickname)의 기록" - let certification = ChallengeHistoryDetail.ViewModel.Challenge(challengeName: model.challengeName, - certificationDateText: dateText, - navigationTitle: title, - certificationImageURL: URL(string: model.certificateImageUrl), - certificationComment: model.certificateComment, - certificationTimeText: timeText) + let certification = ChallengeHistoryDetail.ViewModel.Challenge( + challengeName: model.challengeName, + certificationDateText: dateText, + navigationTitle: title, + certificationImageURL: URL(string: model.certificateImageUrl), + certificationComment: model.certificateComment, + certificationTimeText: timeText + ) let complimentTitle = "\(model.partnerNickname)이 보낸 칭찬" - let compliment = ChallengeHistoryDetail.ViewModel.Compliment(complimentTitle: complimentTitle, - complimentComment: model.complicateComment) + let compliment = ChallengeHistoryDetail.ViewModel.Compliment( + complimentTitle: complimentTitle, + complimentComment: model.complicateComment, + isMyHitstoyDetail: model.isMyHistoryDetail + ) return (certification, compliment) } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift index 6b6f4810..a8f8487b 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift @@ -61,11 +61,17 @@ public struct ChallengeHistoryDetailConfiguration { public var myNickname: String /// 상대방 닉네임 public var partnerNickname: String - - public init(myNickname: String, - partnerNickname: String) { + /// 본인여부 파악 + public var isMyHistoryDetail: Bool + + public init( + myNickname: String, + partnerNickname: String, + isMyHistoryDetail: Bool + ) { self.myNickname = myNickname self.partnerNickname = partnerNickname + self.isMyHistoryDetail = isMyHistoryDetail } } @@ -91,7 +97,8 @@ public final class ChallengeHistoryDetailSceneFactory { certificateComment: configuration.detail.certificateComment, certificateTime: configuration.detail.certificateTime, partnerNickname: configuration.user.partnerNickname, - complicateComment: configuration.detail.complimentComment) + complicateComment: configuration.detail.complimentComment, + isMyHistoryDetail: configuration.user.isMyHistoryDetail) ) let viewController = ChallengeHistoryDetailViewController( interactor: interactor diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift index b01c160b..e90edd90 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift @@ -273,7 +273,7 @@ extension ChallengeHistoryDetailViewController: ChallengeHistoryDetailDisplayLog self.complimentLabel.setLineSpacing(8) } else { - self.prasiseButton.isHidden = false + self.prasiseButton.isHidden = compliment.isMyHitstoyDetail self.complimentTitleLabel.isHidden = true self.complimentContentView.isHidden = true } diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift index 02a15f1f..739d8b38 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift @@ -131,13 +131,13 @@ extension ChallengeHistoryInteractor { await self.router.routeToChallengeHistoryDetailScene(title: challenge.name, certificate: myCertificate, nickname: self.worker.myNickname ?? "", - partnerNickname: self.worker.partnerNickname ?? "") + partnerNickname: self.worker.partnerNickname ?? "", isMyHistoryDetail: true) } else if let partnerCertificate = partnerCertificate { await self.router.routeToChallengeHistoryDetailScene(title: challenge.name, certificate: partnerCertificate, nickname: self.worker.partnerNickname ?? "", - partnerNickname: self.worker.myNickname ?? "") + partnerNickname: self.worker.myNickname ?? "", isMyHistoryDetail: false) } } } diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift index b324d445..58711499 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift @@ -19,7 +19,7 @@ protocol ChallengeHistoryRoutingLogic { func routeToChallengeHistoryDetailScene(title: String, certificate: ChallengeHistory.Model.Certificate, nickname: String, - partnerNickname: String) + partnerNickname: String, isMyHistoryDetail: Bool) /// 화면을 닫는다. func dismiss() } @@ -30,11 +30,13 @@ final class ChallengeHistoryRouter { } extension ChallengeHistoryRouter: ChallengeHistoryRoutingLogic { - func routeToChallengeHistoryDetailScene(title: String, - certificate: ChallengeHistory.Model.Certificate, - nickname: String, - partnerNickname: String) { - + func routeToChallengeHistoryDetailScene( + title: String, + certificate: ChallengeHistory.Model.Certificate, + nickname: String, + partnerNickname: String, + isMyHistoryDetail: Bool + ) { let fac = ChallengeHistoryDetailSceneFactory().make( with: .init( detail: .init( @@ -44,7 +46,7 @@ extension ChallengeHistoryRouter: ChallengeHistoryRoutingLogic { certificateComment: certificate.certificateComment, certificateTime: certificate.certificateTime, complimentComment: certificate.complimentComment), - user: .init(myNickname: nickname, partnerNickname: partnerNickname) + user: .init(myNickname: nickname, partnerNickname: partnerNickname, isMyHistoryDetail: isMyHistoryDetail) ) ) let vc = fac.viewController diff --git a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift index fc79c0d1..67f9c239 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift @@ -205,7 +205,7 @@ extension HomeInteractor { // MARK: Feature (칭찬) extension HomeInteractor { - + // TODO: - 값 넣어줘야함 func didTapMyComplimentCommnet() async { await self.router.routeToPartnerHistoryDetailScene(title: "", certificate: .init(id: ""), nickname: "", partnerNickname: "") } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index bcb3442a..a7b95e75 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -64,6 +64,7 @@ extension HomeRouter: HomeRoutingLogic { } + // TODO: - 값 넣어줘야함 func routeToPartnerHistoryDetailScene(title: String, certificate: Home.Model.Certificate, nickname: String, @@ -82,7 +83,9 @@ extension HomeRouter: HomeRoutingLogic { complimentComment: "" ), user: .init( myNickname: dataStore.challenge?.myInfo.nickname ?? "", - partnerNickname: dataStore.challenge?.partnerInfo.nickname ?? "") + partnerNickname: dataStore.challenge?.partnerInfo.nickname ?? "", + isMyHistoryDetail: false + ) )) } From 1e6fd682d8926ad8db57f33acc75619dc6329994 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Wed, 10 Jan 2024 16:29:54 +0900 Subject: [PATCH 20/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=ED=99=88=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=B9=AD=EC=B0=AC=EB=AC=B8=EA=B5=AC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=98=EA=B8=B0=20=ED=83=AD=ED=95=98=EB=A9=B4=20?= =?UTF-8?q?=EC=83=81=EB=8C=80=EB=B0=A9=20=ED=9E=88=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EB=94=94=ED=85=8C=EC=9D=BC=EB=A1=9C=20=EA=B0=80?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailPresenter.swift | 2 +- .../Sources/HomeScene/HomeInteractor.swift | 22 +++++++++++++++---- .../Sources/HomeScene/HomeModels.swift | 12 +++++----- .../Sources/HomeScene/HomeRouter.swift | 14 +++++++----- .../HomeScene/HomeViewController.swift | 2 +- .../Sources/HomeScene/HomeWorker.swift | 2 +- 6 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift index 02251405..6f4376ae 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift @@ -46,7 +46,7 @@ extension ChallengeHistoryDetailPresenter: ChallengeHistoryDetailPresentationLog { let dateText = model.certificateTime.dateToString(.hangleYearMonthDay) let timeText = "인증 시간 " + model.certificateTime.dateToString(.hourMinute) - let title = "\(model.myNickname)의 기록" + let title = "\(model.isMyHistoryDetail ? model.myNickname : model.partnerNickname)의 기록" let certification = ChallengeHistoryDetail.ViewModel.Challenge( challengeName: model.challengeName, certificationDateText: dateText, diff --git a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift index 67f9c239..beeb9964 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift @@ -23,7 +23,7 @@ protocol HomeBusinessLogic { /// 챌린지 완료하기 버튼 클릭 func didTapChallengeCompleteButton() async /// 내 칭찬 문구 클릭 - func didTapMyComplimentCommnet() async + func didTapMyComplimentComment() async /// 내 꽃 클릭 func didTapMyFlower() async /// 찌르기 버튼 클릭 @@ -205,9 +205,23 @@ extension HomeInteractor { // MARK: Feature (칭찬) extension HomeInteractor { - // TODO: - 값 넣어줘야함 - func didTapMyComplimentCommnet() async { - await self.router.routeToPartnerHistoryDetailScene(title: "", certificate: .init(id: ""), nickname: "", partnerNickname: "") + func didTapMyComplimentComment() async { + guard let challenge = self.challenge else { + return + } + + await self.router.routeToPartnerHistoryDetailScene( + title: challenge.name ?? "", + certificate: .init( + id: challenge.partnerInfo.todayCert?.id ?? "", + complimentComment: challenge.partnerInfo.todayCert?.complimentComment, + imageURL: challenge.partnerInfo.todayCert?.imageURL ?? "", + time: challenge.partnerInfo.todayCert?.time ?? "", + contents: challenge.partnerInfo.todayCert?.contents ?? "" + ), + nickname: challenge.myInfo.nickname, + partnerNickname: challenge.partnerInfo.nickname + ) } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift index 2bea9c0a..e8b6e4e5 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift @@ -65,14 +65,14 @@ enum Home { struct Certificate: Equatable { /// 인증 ID var id: String -// /// 인증 사진 -// var certificateImageUrl: String -// /// 인증 소감 -// var certificateComment: String -// /// 입력 시간 -// var certificateTime: Date /// 칭찬 문구 var complimentComment: String? + /// 인증 Image URL + var imageURL: String + /// 인증 시간 + var time: String + /// 인증 내용 + var contents: String } /// 성장도 diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index a7b95e75..ff983b8f 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -63,8 +63,6 @@ extension HomeRouter: HomeRoutingLogic { self.viewController?.navigationController?.pushViewController(challengeConfirmViewController, animated: true) } - - // TODO: - 값 넣어줘야함 func routeToPartnerHistoryDetailScene(title: String, certificate: Home.Model.Certificate, nickname: String, @@ -77,16 +75,20 @@ extension HomeRouter: HomeRoutingLogic { detail: .init( id: certificate.id, challengeName: dataStore.challenge?.name ?? "", - certificateImageUrl: "", - certificateComment: "", - certificateTime: Date(), - complimentComment: "" + certificateImageUrl: certificate.imageURL, + certificateComment: certificate.contents, + certificateTime: dataStore.challenge?.partnerInfo.todayCert?.time.fullStringDate(.iso) ?? Date(), + complimentComment: certificate.complimentComment ), user: .init( myNickname: dataStore.challenge?.myInfo.nickname ?? "", partnerNickname: dataStore.challenge?.partnerInfo.nickname ?? "", isMyHistoryDetail: false ) )) + + let vc = historyDetailScene.viewController + vc.modalPresentationStyle = .fullScreen + self.viewController?.present(vc, animated: true) } func routeToChallengeCertificateScene() { diff --git a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift index 4314278c..83184d01 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift @@ -415,7 +415,7 @@ extension HomeViewController: ChallengeInProgressViewDelegate{ func didTapMyFlowerEmptySpeechBubbleView() { Task { - await self.interactor.didTapMyComplimentCommnet() + await self.interactor.didTapMyComplimentComment() } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift index b517a050..0779ac7c 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift @@ -184,7 +184,7 @@ final class HomeWorker: HomeWorkerProtocol { ) if let commit = commit { - userInfo.todayCert = .init(id: String(commit.commitNo), complimentComment: commit.partnerComment) + userInfo.todayCert = .init(id: String(commit.commitNo), complimentComment: commit.partnerComment, imageURL: commit.photoUrl, time: commit.createdAt, contents: commit.text) } userInfo.certCount = commitCount ?? 0 From d4cbc44519cb768272f1e64701d6ce955a3e18fb Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Wed, 10 Jan 2024 16:40:35 +0900 Subject: [PATCH 21/44] =?UTF-8?q?=F0=9F=90=9B=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EB=94=94=ED=85=8C=EC=9D=BC=20=EB=84=A4?= =?UTF-8?q?=EB=B9=84=20=ED=83=80=EC=9D=B4=ED=8B=80=20=EC=A0=9C=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=95=88=EB=82=98=EC=98=A4=EB=8A=94=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailPresenter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift index 6f4376ae..02251405 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift @@ -46,7 +46,7 @@ extension ChallengeHistoryDetailPresenter: ChallengeHistoryDetailPresentationLog { let dateText = model.certificateTime.dateToString(.hangleYearMonthDay) let timeText = "인증 시간 " + model.certificateTime.dateToString(.hourMinute) - let title = "\(model.isMyHistoryDetail ? model.myNickname : model.partnerNickname)의 기록" + let title = "\(model.myNickname)의 기록" let certification = ChallengeHistoryDetail.ViewModel.Challenge( challengeName: model.challengeName, certificationDateText: dateText, From b1a784a98d1963b81a22a7e475bd9a25fae96f13 Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Wed, 10 Jan 2024 21:06:35 +0900 Subject: [PATCH 22/44] =?UTF-8?q?=F0=9F=90=9B=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EB=94=94=ED=85=8C=EC=9D=BC=20=EB=84=A4?= =?UTF-8?q?=EB=B9=84=20=ED=83=80=EC=9D=B4=ED=8B=80=20=EB=B0=98=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EB=82=98=EC=98=A4=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailPresenter.swift | 2 +- .../ChallengeHistoryScene/ChallengeHistoryInteractor.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift index 02251405..6f4376ae 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift @@ -46,7 +46,7 @@ extension ChallengeHistoryDetailPresenter: ChallengeHistoryDetailPresentationLog { let dateText = model.certificateTime.dateToString(.hangleYearMonthDay) let timeText = "인증 시간 " + model.certificateTime.dateToString(.hourMinute) - let title = "\(model.myNickname)의 기록" + let title = "\(model.isMyHistoryDetail ? model.myNickname : model.partnerNickname)의 기록" let certification = ChallengeHistoryDetail.ViewModel.Challenge( challengeName: model.challengeName, certificationDateText: dateText, diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift index 739d8b38..fc756881 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift @@ -136,8 +136,8 @@ extension ChallengeHistoryInteractor { else if let partnerCertificate = partnerCertificate { await self.router.routeToChallengeHistoryDetailScene(title: challenge.name, certificate: partnerCertificate, - nickname: self.worker.partnerNickname ?? "", - partnerNickname: self.worker.myNickname ?? "", isMyHistoryDetail: false) + nickname: self.worker.myNickname ?? "", + partnerNickname: self.worker.partnerNickname ?? "", isMyHistoryDetail: false) } } } From 33ea47d047f8fe9aae1eb25f84cadb86fc733937 Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Wed, 10 Jan 2024 22:57:57 +0900 Subject: [PATCH 23/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EB=94=94=ED=85=8C=EC=9D=BC=20reload=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailInteractor.swift | 36 ++++++----- .../ChallengeHistoryDetailModels.swift | 2 + .../ChallengeHistoryDetailSceneFactory.swift | 15 +++-- ...ChallengeHistoryDetailViewController.swift | 24 +++++++- .../ChallengeHistoryDetailWorker.swift | 29 ++++++++- .../ChallengeHistoryInteractor.swift | 48 +++++++-------- .../ChallengeHistoryRouter.swift | 40 +++++++------ .../Sources/HomeScene/HomeRouter.swift | 59 ++++++++++--------- 8 files changed, 159 insertions(+), 94 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift index 3a678c70..3007a507 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift @@ -24,14 +24,14 @@ protocol ChallengeHistoryDetailDataStore: AnyObject { var detail: ChallengeHistoryDetail.Model.ChallengeDetail { get } } -final class ChallengeHistoryDetailInteractor: ChallengeHistoryDetailDataStore, ChallengeHistoryDetailBusinessLogic { - +final class ChallengeHistoryDetailInteractor: ChallengeHistoryDetailDataStore, ChallengeHistoryDetailBusinessLogic { + var cancellables: Set = [] - + var presenter: ChallengeHistoryDetailPresentationLogic var router: ChallengeHistoryDetailRoutingLogic var worker: ChallengeHistoryDetailWorkerProtocol - + init( presenter: ChallengeHistoryDetailPresentationLogic, router: ChallengeHistoryDetailRoutingLogic, @@ -43,7 +43,7 @@ final class ChallengeHistoryDetailInteractor: ChallengeHistoryDetailDataStore, C self.worker = worker self.detail = detail } - + // MARK: - DataStore var detail: ChallengeHistoryDetail.Model.ChallengeDetail } @@ -51,10 +51,10 @@ final class ChallengeHistoryDetailInteractor: ChallengeHistoryDetailDataStore, C // MARK: - Interactive Business Logic extension ChallengeHistoryDetailInteractor { - + /// 외부 액션 옵저빙 func observe() { - + } } @@ -63,17 +63,21 @@ extension ChallengeHistoryDetailInteractor { extension ChallengeHistoryDetailInteractor { func didLoad() async { - await self.presenter.presentChallengeDetail(detail: self.detail) + do { + try await self.worker.requestChallengeDetailInquiry(challengeID: self.detail.challengeID) + await self.presenter.presentChallengeDetail(detail: self.detail) + } catch { + print("실패") + } } - } // MARK: - Feature (사진 상세) extension ChallengeHistoryDetailInteractor { - + func didTapPhoto() async { - await self.presenter.presentPhoto(imageUrl: self.detail.certificateImageUrl) + await self.presenter.presentPhoto(imageUrl: self.detail.certificateImageUrl) } } @@ -90,11 +94,11 @@ extension ChallengeHistoryDetailInteractor { extension ChallengeHistoryDetailInteractor { - func didTapPraiseButton() async { - if self.detail.complicateComment?.isEmpty != nil { - await self.router.routeToPraiseSendScene() + func didTapPraiseButton() async { + if self.detail.complicateComment?.isEmpty != nil { + await self.router.routeToPraiseSendScene() + } } - } } @@ -103,5 +107,5 @@ extension ChallengeHistoryDetailInteractor { // MARK: UseCase () extension ChallengeHistoryDetailInteractor { - + } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift index 23d92006..dcf82dac 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift @@ -17,6 +17,8 @@ enum ChallengeHistoryDetail { /// 챌린지 상세 정보 struct ChallengeDetail: Equatable { + /// 챌린지 ID + var challengeID: String /// 인증 ID var id: String /// 챌린지 이름 diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift index a8f8487b..81124f86 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift @@ -27,6 +27,8 @@ public struct ChallengeHistoryDetailConfiguration { /// 챌린지 인증 상세 정보 public struct ChallengeDetail { + /// 챌린지 ID + public var challengeID: String /// 인증 ID public var id: String /// 챌린지 이름 @@ -40,12 +42,14 @@ public struct ChallengeHistoryDetailConfiguration { /// 칭찬 문구 public var complimentComment: String? - public init(id: String, + public init(challengeID: String, + id: String, challengeName: String, certificateImageUrl: String, certificateComment: String, certificateTime: Date, complimentComment: String?) { + self.challengeID = challengeID self.id = id self.challengeName = challengeName self.certificateImageUrl = certificateImageUrl @@ -82,15 +86,18 @@ public final class ChallengeHistoryDetailSceneFactory { public init() {} public func make(with configuration: ChallengeHistoryDetailConfiguration) -> ChallengeHistoryDetailScene { - + let meLocalWorker = MeLocalWorker(localDataSource: LocalDataSource()) + let challengeDetailNetworkWorker = ChallengeDetailNetworkWorker() + let presenter = ChallengeHistoryDetailPresenter() let router = ChallengeHistoryDetailRouter() - let worker = ChallengeHistoryDetailWorker() + let worker = ChallengeHistoryDetailWorker(meLocalWorker: meLocalWorker, challengeDetailNetworkWorker: challengeDetailNetworkWorker) let interactor = ChallengeHistoryDetailInteractor( presenter: presenter, router: router, worker: worker, - detail: .init(id: configuration.detail.id, + detail: .init(challengeID: configuration.detail.challengeID, + id: configuration.detail.id, challengeName: configuration.detail.challengeName, myNickname: configuration.user.myNickname, certificateImageUrl: configuration.detail.certificateImageUrl, diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift index e90edd90..ea0c5712 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift @@ -130,12 +130,34 @@ final class ChallengeHistoryDetailViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.setUI() + self.registNotification() self.view.setBackgroundDefault() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + Task { + await self.interactor.didLoad() + } + } + + @objc private func viewDidAppearWithModalDismissed() { Task { + Loading.shared.showLoadingView() await self.interactor.didLoad() + Loading.shared.stopLoadingView() } } - + + private func registNotification() { + NotificationCenter.default.addObserver( + self, + selector: #selector(self.viewDidAppearWithModalDismissed), + name: NSNotification.Name("modal_dismissed"), + object: nil + ) + } + // MARK: - Layout private func setUI() { diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift index bf9edaae..6b96a7f9 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift @@ -7,7 +7,32 @@ // import CoreKit +import CoreKit + +protocol ChallengeHistoryDetailWorkerProtocol { + /// 챌린지 상세 조회를 요청한다. + func requestChallengeDetailInquiry(challengeID: String) async throws -> ChallengeHistoryDetail.Model.ChallengeDetail +} + +final class ChallengeHistoryDetailWorker: ChallengeHistoryDetailWorkerProtocol { + var meLocalWorker: MeLocalWorkerProtocol + var challengeDetailNetworkWorker: ChallengeDetailNetworkWorkerProtocol + + init( + meLocalWorker: MeLocalWorkerProtocol, + challengeDetailNetworkWorker: ChallengeDetailNetworkWorkerProtocol + ) { + self.meLocalWorker = meLocalWorker + self.challengeDetailNetworkWorker = challengeDetailNetworkWorker + } -protocol ChallengeHistoryDetailWorkerProtocol {} + func requestChallengeDetailInquiry(challengeID: String) async throws -> ChallengeHistoryDetail.Model.ChallengeDetail { + let challengeDetailResponse = try await self.challengeDetailNetworkWorker.requestChallengeDetailInquiry( + challengeNo: Int(challengeID) ?? 0 + ) -final class ChallengeHistoryDetailWorker: ChallengeHistoryDetailWorkerProtocol {} + if let list = challengeDetailResponse.user2CommitList { + + } + } +} diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift index fc756881..f69f9596 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift @@ -42,11 +42,11 @@ protocol ChallengeHistoryDataStore: AnyObject { final class ChallengeHistoryInteractor: ChallengeHistoryDataStore, ChallengeHistoryBusinessLogic { var cancellables: Set = [] - + var presenter: ChallengeHistoryPresentationLogic var router: ChallengeHistoryRoutingLogic var worker: ChallengeHistoryWorkerProtocol - + init( presenter: ChallengeHistoryPresentationLogic, router: ChallengeHistoryRoutingLogic, @@ -58,17 +58,17 @@ final class ChallengeHistoryInteractor: ChallengeHistoryDataStore, ChallengeHist self.worker = worker self.challengeID = challengeID } - + // MARK: - DataStore - + var challengeID: String - + var challenge: ChallengeHistory.Model.Challenge? - + var myNickname: String? { self.worker.myNickname } - + var partnerNickname: String? { self.worker.partnerNickname } @@ -77,17 +77,17 @@ final class ChallengeHistoryInteractor: ChallengeHistoryDataStore, ChallengeHist // MARK: - Interactive Business Logic extension ChallengeHistoryInteractor { - + /// 외부 액션 옵저빙 func observe() { - + } } // MARK: Feature (진입) extension ChallengeHistoryInteractor { - + func didAppear() async { do { let challenge = try await self.worker.requestChallengeDetailInquiry(challengeID: self.challengeID) @@ -103,7 +103,7 @@ extension ChallengeHistoryInteractor { // MARK: Feature (인증) extension ChallengeHistoryInteractor { - + func didTapCertificate() async { await self.router.routeToChallengeCertificateScene() } @@ -112,12 +112,12 @@ extension ChallengeHistoryInteractor { // MARK: Feature (인증 상세) extension ChallengeHistoryInteractor { - + func didSelectCertificate(certificateID: String) async { guard let challenge = self.challenge else { return } - + let myCertificate = challenge.myInfo.certificates .filter { $0.id == certificateID @@ -126,15 +126,17 @@ extension ChallengeHistoryInteractor { .filter { $0.id == certificateID }.first - + if let myCertificate = myCertificate { - await self.router.routeToChallengeHistoryDetailScene(title: challenge.name, + await self.router.routeToChallengeHistoryDetailScene(challenge: challenge, + title: challenge.name, certificate: myCertificate, nickname: self.worker.myNickname ?? "", partnerNickname: self.worker.partnerNickname ?? "", isMyHistoryDetail: true) } else if let partnerCertificate = partnerCertificate { - await self.router.routeToChallengeHistoryDetailScene(title: challenge.name, + await self.router.routeToChallengeHistoryDetailScene(challenge: challenge, + title: challenge.name, certificate: partnerCertificate, nickname: self.worker.myNickname ?? "", partnerNickname: self.worker.partnerNickname ?? "", isMyHistoryDetail: false) @@ -145,23 +147,23 @@ extension ChallengeHistoryInteractor { // MARK: Feature (챌린지 그만두기) extension ChallengeHistoryInteractor { - + func didTapOptionButton() async { await self.presenter.presentOptionPopup() } - + func didTapOptionPopupQuitButton() async { await self.presenter.presentQuitPopup() } - + func didTapQuitPopupCancelButton() async { await self.presenter.dismissQuitPopup() } - + func didTapQuitPopupBackground() async { await self.presenter.dismissQuitPopup() } - + func didTapQuitPopupQuitButton() async { do { try await self.worker.requestChallengeQuit(challengeID: self.challengeID) @@ -177,7 +179,7 @@ extension ChallengeHistoryInteractor { // MARK: Feature (뒤로가기) extension ChallengeHistoryInteractor { - + func didTapBackButton() async { await self.router.dismiss() } @@ -188,5 +190,5 @@ extension ChallengeHistoryInteractor { // MARK: UseCase () extension ChallengeHistoryInteractor { - + } diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift index 58711499..8cdc53ec 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift @@ -16,7 +16,7 @@ protocol ChallengeHistoryRoutingLogic { /// 인증하기 화면으로 이동한다. func routeToChallengeCertificateScene() /// 인증 상세 화면으로 이동한다. - func routeToChallengeHistoryDetailScene(title: String, + func routeToChallengeHistoryDetailScene(challenge: ChallengeHistory.Model.Challenge, title: String, certificate: ChallengeHistory.Model.Certificate, nickname: String, partnerNickname: String, isMyHistoryDetail: Bool) @@ -31,30 +31,32 @@ final class ChallengeHistoryRouter { extension ChallengeHistoryRouter: ChallengeHistoryRoutingLogic { func routeToChallengeHistoryDetailScene( - title: String, - certificate: ChallengeHistory.Model.Certificate, - nickname: String, - partnerNickname: String, - isMyHistoryDetail: Bool + challenge: ChallengeHistory.Model.Challenge, + title: String, + certificate: ChallengeHistory.Model.Certificate, + nickname: String, + partnerNickname: String, + isMyHistoryDetail: Bool ) { let fac = ChallengeHistoryDetailSceneFactory().make( - with: .init( - detail: .init( - id: certificate.id, - challengeName: title, - certificateImageUrl: certificate.certificateImageUrl, - certificateComment: certificate.certificateComment, - certificateTime: certificate.certificateTime, - complimentComment: certificate.complimentComment), - user: .init(myNickname: nickname, partnerNickname: partnerNickname, isMyHistoryDetail: isMyHistoryDetail) - ) + with: .init( + detail: .init( + challengeID: challenge.id, + id: certificate.id, + challengeName: title, + certificateImageUrl: certificate.certificateImageUrl, + certificateComment: certificate.certificateComment, + certificateTime: certificate.certificateTime, + complimentComment: certificate.complimentComment), + user: .init(myNickname: nickname, partnerNickname: partnerNickname, isMyHistoryDetail: isMyHistoryDetail) + ) ) let vc = fac.viewController vc.modalPresentationStyle = .fullScreen self.viewController?.present(vc, animated: true) } - - + + func routeToChallengeCertificateScene() { guard let dataStore = self.dataStore else { return @@ -64,7 +66,7 @@ extension ChallengeHistoryRouter: ChallengeHistoryRoutingLogic { ) self.viewController?.present(challengeCertificateScene.bottomSheetViewController, animated: true) } - + func dismiss() { self.viewController?.navigationController?.popViewController(animated: true) } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index ff983b8f..6d95f7f6 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -45,7 +45,7 @@ extension HomeRouter: HomeRoutingLogic { challengeEssentialInfoInputViewController.hidesBottomBarWhenPushed = true self.viewController?.navigationController?.pushViewController(challengeEssentialInfoInputViewController, animated: true) } - + func routeToChallengeConfirmScene(entryPoint: String) { guard let dataStore = self.dataStore else { return @@ -62,35 +62,36 @@ extension HomeRouter: HomeRoutingLogic { challengeConfirmViewController.hidesBottomBarWhenPushed = true self.viewController?.navigationController?.pushViewController(challengeConfirmViewController, animated: true) } - + func routeToPartnerHistoryDetailScene(title: String, certificate: Home.Model.Certificate, nickname: String, partnerNickname: String) { - guard let dataStore = self.dataStore else { - return - } - - let historyDetailScene = ChallengeHistoryDetailSceneFactory().make(with: .init( - detail: .init( - id: certificate.id, - challengeName: dataStore.challenge?.name ?? "", - certificateImageUrl: certificate.imageURL, - certificateComment: certificate.contents, - certificateTime: dataStore.challenge?.partnerInfo.todayCert?.time.fullStringDate(.iso) ?? Date(), - complimentComment: certificate.complimentComment - ), user: .init( - myNickname: dataStore.challenge?.myInfo.nickname ?? "", - partnerNickname: dataStore.challenge?.partnerInfo.nickname ?? "", - isMyHistoryDetail: false - ) - )) - - let vc = historyDetailScene.viewController - vc.modalPresentationStyle = .fullScreen - self.viewController?.present(vc, animated: true) + guard let dataStore = self.dataStore else { + return + } + + let historyDetailScene = ChallengeHistoryDetailSceneFactory().make(with: .init( + detail: .init( + challengeID: dataStore.challenge?.id ?? "", + id: certificate.id, + challengeName: dataStore.challenge?.name ?? "", + certificateImageUrl: certificate.imageURL, + certificateComment: certificate.contents, + certificateTime: dataStore.challenge?.partnerInfo.todayCert?.time.fullStringDate(.iso) ?? Date(), + complimentComment: certificate.complimentComment + ), user: .init( + myNickname: dataStore.challenge?.myInfo.nickname ?? "", + partnerNickname: dataStore.challenge?.partnerInfo.nickname ?? "", + isMyHistoryDetail: false + ) + )) + + let vc = historyDetailScene.viewController + vc.modalPresentationStyle = .fullScreen + self.viewController?.present(vc, animated: true) } - + func routeToChallengeCertificateScene() { guard let dataStore = self.dataStore else { return @@ -100,7 +101,7 @@ extension HomeRouter: HomeRoutingLogic { ) self.viewController?.present(challengeCertificateScene.bottomSheetViewController, animated: true) } - + func routeToNudgeSendScene() { guard let dataStore = self.dataStore else { return @@ -110,7 +111,7 @@ extension HomeRouter: HomeRoutingLogic { ) self.viewController?.present(nudgeSendScene.bottomSheetViewController, animated: true) } - + func routeToChallengeHistoryScene() { guard let dataStore = self.dataStore else { return @@ -122,13 +123,13 @@ extension HomeRouter: HomeRoutingLogic { challengeHistoryViewController.hidesBottomBarWhenPushed = true self.viewController?.navigationController?.pushViewController(challengeHistoryViewController, animated: true) } - + func routeToGuideScene() { guard let url = URL(string: "https://two2too2.github.io/") else { return } let safariViewController = SFSafariViewController(url: url) - + self.viewController?.present(safariViewController, animated: true, completion: nil) } } From 2a203e08ca443e917fb418f8f0df824e658ef4a1 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Fri, 12 Jan 2024 10:38:43 +0900 Subject: [PATCH 24/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EB=94=94=ED=85=8C=EC=9D=BC=20reload=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailInteractor.swift | 6 +- .../ChallengeHistoryDetailModels.swift | 3 +- .../ChallengeHistoryDetailPresenter.swift | 4 +- .../ChallengeHistoryDetailSceneFactory.swift | 8 +- ...ChallengeHistoryDetailViewController.swift | 87 ++++++++++--------- .../ChallengeHistoryDetailWorker.swift | 43 +++++++-- .../ChallengeHistoryInteractor.swift | 4 +- .../ChallengeHistoryRouter.swift | 6 +- .../Sources/HomeScene/HomeRouter.swift | 2 +- 9 files changed, 96 insertions(+), 67 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift index 3007a507..d374e75a 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift @@ -64,10 +64,12 @@ extension ChallengeHistoryDetailInteractor { func didLoad() async { do { - try await self.worker.requestChallengeDetailInquiry(challengeID: self.detail.challengeID) + let challenge = try await self.worker + .requestChallengeDetailInquiry(challengeID: self.detail.challengeID, commitID: Int(self.detail.id) ?? 0) + self.detail = challenge await self.presenter.presentChallengeDetail(detail: self.detail) } catch { - print("실패") + print("히스토리 디테일 가져오기 실패했습니다.") } } } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift index dcf82dac..e7e18b64 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift @@ -36,9 +36,8 @@ enum ChallengeHistoryDetail { /// 칭찬 문구 var complicateComment: String? /// 내 챌린지 상세정보 여부 - var isMyHistoryDetail: Bool + var isMine: Bool } - } enum ViewModel { diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift index 6f4376ae..d9e69d01 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift @@ -46,7 +46,7 @@ extension ChallengeHistoryDetailPresenter: ChallengeHistoryDetailPresentationLog { let dateText = model.certificateTime.dateToString(.hangleYearMonthDay) let timeText = "인증 시간 " + model.certificateTime.dateToString(.hourMinute) - let title = "\(model.isMyHistoryDetail ? model.myNickname : model.partnerNickname)의 기록" + let title = "\(model.myNickname)의 기록" let certification = ChallengeHistoryDetail.ViewModel.Challenge( challengeName: model.challengeName, certificationDateText: dateText, @@ -60,7 +60,7 @@ extension ChallengeHistoryDetailPresenter: ChallengeHistoryDetailPresentationLog let compliment = ChallengeHistoryDetail.ViewModel.Compliment( complimentTitle: complimentTitle, complimentComment: model.complicateComment, - isMyHitstoyDetail: model.isMyHistoryDetail + isMyHitstoyDetail: model.isMine ) return (certification, compliment) } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift index 81124f86..2e857b1f 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailSceneFactory.swift @@ -66,16 +66,16 @@ public struct ChallengeHistoryDetailConfiguration { /// 상대방 닉네임 public var partnerNickname: String /// 본인여부 파악 - public var isMyHistoryDetail: Bool + public var isMine: Bool public init( myNickname: String, partnerNickname: String, - isMyHistoryDetail: Bool + isMine: Bool ) { self.myNickname = myNickname self.partnerNickname = partnerNickname - self.isMyHistoryDetail = isMyHistoryDetail + self.isMine = isMine } } @@ -105,7 +105,7 @@ public final class ChallengeHistoryDetailSceneFactory { certificateTime: configuration.detail.certificateTime, partnerNickname: configuration.user.partnerNickname, complicateComment: configuration.detail.complimentComment, - isMyHistoryDetail: configuration.user.isMyHistoryDetail) + isMine: configuration.user.isMine) ) let viewController = ChallengeHistoryDetailViewController( interactor: interactor diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift index ea0c5712..cd0c65aa 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift @@ -102,18 +102,19 @@ final class ChallengeHistoryDetailViewController: UIViewController { v.isHidden = true return v }() - + /// 칭찬하기 버튼 private lazy var prasiseButton: TTPrimaryButtonType = { - let v = TTPrimaryButton.create(title: "칭찬하기", .large) - v.addAction { [weak self] in - Task { - try await Task.sleep(nanoseconds: 100000000) - await self?.interactor.didTapPraiseButton() + let v = TTPrimaryButton.create(title: "칭찬하기", .large) + v.addAction { [weak self] in + Task { + try await Task.sleep(nanoseconds: 100000000) + await self?.interactor.didTapPraiseButton() + } } - } - v.setIsEnabled(true) - return v + v.setIsEnabled(true) + v.isHidden = true + return v }() private lazy var scrollView: UIScrollView = { @@ -129,18 +130,20 @@ final class ChallengeHistoryDetailViewController: UIViewController { // MARK: - View Lifecycle override func viewDidLoad() { super.viewDidLoad() - self.setUI() self.registNotification() self.view.setBackgroundDefault() + self.setUI() } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - Task { - await self.interactor.didLoad() + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + Task { + Loading.shared.showLoadingView() + await self.interactor.didLoad() + Loading.shared.stopLoadingView() + } } - } - + @objc private func viewDidAppearWithModalDismissed() { Task { Loading.shared.showLoadingView() @@ -148,7 +151,7 @@ final class ChallengeHistoryDetailViewController: UIViewController { Loading.shared.stopLoadingView() } } - + private func registNotification() { NotificationCenter.default.addObserver( self, @@ -157,22 +160,22 @@ final class ChallengeHistoryDetailViewController: UIViewController { object: nil ) } - + // MARK: - Layout private func setUI() { let leadingTrailingPadding: Int = 24 let guide = self.view.safeAreaLayoutGuide - + self.scrollContentView.addSubviews( - self.dateLabel, - self.certificateImageView, - self.challengeNameLabel, - self.certificationCommentLabel, - self.timeLabel, - self.complimentTitleLabel, - self.complimentContentView, - self.prasiseButton + self.dateLabel, + self.certificateImageView, + self.challengeNameLabel, + self.certificationCommentLabel, + self.timeLabel, + self.complimentTitleLabel, + self.complimentContentView, + self.prasiseButton ) self.scrollView.addSubview(self.scrollContentView) @@ -185,50 +188,50 @@ final class ChallengeHistoryDetailViewController: UIViewController { make.leading.trailing.equalToSuperview() make.height.equalTo(44) } - + // ---> 컴포넌트 self.dateLabel.snp.makeConstraints { make in make.top.equalToSuperview().offset(18) make.leading.equalToSuperview().offset(leadingTrailingPadding) make.trailing.equalToSuperview().inset(leadingTrailingPadding) } - + let widthHeight = UIScreen.main.bounds.width - CGFloat(leadingTrailingPadding * 2) self.certificateImageView.snp.makeConstraints { make in make.top.equalTo(self.dateLabel.snp.bottom).offset(21) make.width.height.equalTo(widthHeight) make.centerX.equalToSuperview() } - + self.challengeNameLabel.snp.makeConstraints { make in make.top.equalTo(self.certificateImageView.snp.bottom).offset(24) make.leading.equalTo(leadingTrailingPadding) } - + self.certificationCommentLabel.snp.makeConstraints { make in make.top.equalTo(self.challengeNameLabel.snp.bottom).offset(24) make.leading.equalToSuperview().offset(leadingTrailingPadding) make.trailing.equalToSuperview().inset(leadingTrailingPadding) } - + self.timeLabel.snp.makeConstraints { make in make.top.equalTo(self.certificationCommentLabel.snp.bottom).offset(20) make.leading.equalToSuperview().offset(leadingTrailingPadding) } - + // ---> 칭찬 self.complimentTitleLabel.snp.makeConstraints { make in make.top.equalTo(self.timeLabel.snp.bottom).offset(33) make.leading.equalToSuperview().offset(leadingTrailingPadding) } - + self.complimentLabel.snp.makeConstraints { make in make.top.equalToSuperview().offset(15) make.leading.equalToSuperview().offset(10) make.trailing.equalToSuperview().inset(10) make.bottom.equalToSuperview().inset(15) } - + self.complimentContentView.snp.makeConstraints { make in make.top.equalTo(self.complimentTitleLabel.snp.bottom).offset(8) make.leading.equalToSuperview().offset(leadingTrailingPadding) @@ -237,18 +240,18 @@ final class ChallengeHistoryDetailViewController: UIViewController { } self.prasiseButton.snp.makeConstraints { make in - make.leading.equalToSuperview().offset(leadingTrailingPadding) - make.trailing.equalToSuperview().inset(leadingTrailingPadding) - make.top.equalTo(self.timeLabel.snp.bottom).offset(80) - make.bottom.equalToSuperview() + make.leading.equalToSuperview().offset(leadingTrailingPadding) + make.trailing.equalToSuperview().inset(leadingTrailingPadding) + make.top.equalTo(self.timeLabel.snp.bottom).offset(80) + make.bottom.equalToSuperview() } - + // ---> 스크롤뷰 self.scrollView.snp.makeConstraints { make in make.top.equalTo(self.navigationBar.snp.bottom) make.leading.trailing.bottom.equalToSuperview() } - + self.scrollContentView.snp.makeConstraints { make in make.edges.equalToSuperview() make.width.equalToSuperview() diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift index 6b96a7f9..253ffce7 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift @@ -7,17 +7,17 @@ // import CoreKit -import CoreKit +import Foundation protocol ChallengeHistoryDetailWorkerProtocol { /// 챌린지 상세 조회를 요청한다. - func requestChallengeDetailInquiry(challengeID: String) async throws -> ChallengeHistoryDetail.Model.ChallengeDetail + func requestChallengeDetailInquiry(challengeID: String, commitID: Int) async throws -> ChallengeHistoryDetail.Model.ChallengeDetail } final class ChallengeHistoryDetailWorker: ChallengeHistoryDetailWorkerProtocol { var meLocalWorker: MeLocalWorkerProtocol var challengeDetailNetworkWorker: ChallengeDetailNetworkWorkerProtocol - + init( meLocalWorker: MeLocalWorkerProtocol, challengeDetailNetworkWorker: ChallengeDetailNetworkWorkerProtocol @@ -25,14 +25,39 @@ final class ChallengeHistoryDetailWorker: ChallengeHistoryDetailWorkerProtocol { self.meLocalWorker = meLocalWorker self.challengeDetailNetworkWorker = challengeDetailNetworkWorker } - - func requestChallengeDetailInquiry(challengeID: String) async throws -> ChallengeHistoryDetail.Model.ChallengeDetail { - let challengeDetailResponse = try await self.challengeDetailNetworkWorker.requestChallengeDetailInquiry( + + func requestChallengeDetailInquiry(challengeID: String, commitID: Int) async throws -> ChallengeHistoryDetail.Model.ChallengeDetail { + let challengeDetailListResponse = try await self.challengeDetailNetworkWorker.requestChallengeDetailInquiry( challengeNo: Int(challengeID) ?? 0 ) - - if let list = challengeDetailResponse.user2CommitList { - + + guard let data = (challengeDetailListResponse.user2CommitList + challengeDetailListResponse.user1CommitList).filter({ $0.commitNo == commitID }).first else { + throw NSError(domain: "not exist detail history", code: -1) + } + + let myNickname: String + let partnerNickname: String + let isMine = challengeDetailListResponse.user1CommitList.map(\.commitNo).contains(commitID) + + if isMine { + myNickname = challengeDetailListResponse.user1.nickname + partnerNickname = challengeDetailListResponse.user2.nickname + } else { + myNickname = challengeDetailListResponse.user2.nickname + partnerNickname = challengeDetailListResponse.user1.nickname } + + return .init( + challengeID: String(challengeDetailListResponse.challengeNo), + id: String(data.commitNo), + challengeName: challengeDetailListResponse.name, + myNickname: myNickname, + certificateImageUrl: data.photoUrl, + certificateComment: data.text, + certificateTime: data.createdAt.fullStringDate(.iso), + partnerNickname: partnerNickname, + complicateComment: data.partnerComment, + isMine: isMine + ) } } diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift index f69f9596..1ae0f5ff 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryInteractor.swift @@ -132,14 +132,14 @@ extension ChallengeHistoryInteractor { title: challenge.name, certificate: myCertificate, nickname: self.worker.myNickname ?? "", - partnerNickname: self.worker.partnerNickname ?? "", isMyHistoryDetail: true) + partnerNickname: self.worker.partnerNickname ?? "", isMine: true) } else if let partnerCertificate = partnerCertificate { await self.router.routeToChallengeHistoryDetailScene(challenge: challenge, title: challenge.name, certificate: partnerCertificate, nickname: self.worker.myNickname ?? "", - partnerNickname: self.worker.partnerNickname ?? "", isMyHistoryDetail: false) + partnerNickname: self.worker.partnerNickname ?? "", isMine: false) } } } diff --git a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift index 8cdc53ec..07514f50 100644 --- a/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift +++ b/Scene/ChallengeHistoryScene/Sources/ChallengeHistoryScene/ChallengeHistoryRouter.swift @@ -19,7 +19,7 @@ protocol ChallengeHistoryRoutingLogic { func routeToChallengeHistoryDetailScene(challenge: ChallengeHistory.Model.Challenge, title: String, certificate: ChallengeHistory.Model.Certificate, nickname: String, - partnerNickname: String, isMyHistoryDetail: Bool) + partnerNickname: String, isMine: Bool) /// 화면을 닫는다. func dismiss() } @@ -36,7 +36,7 @@ extension ChallengeHistoryRouter: ChallengeHistoryRoutingLogic { certificate: ChallengeHistory.Model.Certificate, nickname: String, partnerNickname: String, - isMyHistoryDetail: Bool + isMine: Bool ) { let fac = ChallengeHistoryDetailSceneFactory().make( with: .init( @@ -48,7 +48,7 @@ extension ChallengeHistoryRouter: ChallengeHistoryRoutingLogic { certificateComment: certificate.certificateComment, certificateTime: certificate.certificateTime, complimentComment: certificate.complimentComment), - user: .init(myNickname: nickname, partnerNickname: partnerNickname, isMyHistoryDetail: isMyHistoryDetail) + user: .init(myNickname: nickname, partnerNickname: partnerNickname, isMine: isMine) ) ) let vc = fac.viewController diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index 6d95f7f6..51993a95 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -83,7 +83,7 @@ extension HomeRouter: HomeRoutingLogic { ), user: .init( myNickname: dataStore.challenge?.myInfo.nickname ?? "", partnerNickname: dataStore.challenge?.partnerInfo.nickname ?? "", - isMyHistoryDetail: false + isMine: false ) )) From db05811c01d265403bfa5f6238f993701371be53 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Sun, 14 Jan 2024 13:45:09 +0900 Subject: [PATCH 25/44] =?UTF-8?q?=E2=9C=A8=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EB=85=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=A1=B0=EA=B1=B4=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../icon_send_card.imageset/Contents.json | 23 ++++++++++++ .../icon_send_card.png | Bin 0 -> 2429 bytes .../icon_send_card@2x.png | Bin 0 -> 6084 bytes .../icon_send_card@3x.png | Bin 0 -> 10953 bytes .../Contents.json | 23 ++++++++++++ .../img_send_card_tooltip.png | Bin 0 -> 3330 bytes .../img_send_card_tooltip@2x.png | Bin 0 -> 6927 bytes .../img_send_card_tooltip@3x.png | Bin 0 -> 10653 bytes .../DesignSystem/Sources/Assets/Assets.swift | 2 + .../Sources/Component/SpeechBubbleView.swift | 2 +- .../Sources/HomeScene/HomeInteractor.swift | 11 ++++++ .../Sources/HomeScene/HomeModels.swift | 4 ++ .../Sources/HomeScene/HomePresenter.swift | 19 ++++++++-- .../HomeScene/HomeViewController.swift | 5 +++ .../Views/ChallengeInProgressView.swift | 35 +++++++++++++++++- .../HomeSceneTests/HomeInteractorSpec.swift | 18 +++++++++ 16 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@2x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@3x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@2x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@3x.png diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json new file mode 100644 index 00000000..bcecb460 --- /dev/null +++ b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "icon_send_card.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icon_send_card@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icon_send_card@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card.png new file mode 100644 index 0000000000000000000000000000000000000000..df4b8d91ba34a7aa1018c4ec213e6b0540bdfae2 GIT binary patch literal 2429 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 KMNUMnLSTaM<&_8k literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@3x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..13e1a160275ab103d0b2de453425cfb8ef4f10d3 GIT binary patch literal 10953 zcmV;)DmK-LP)o00009a7bBm001F4 z001F40Y#QEU;qFB0drDELIAGL9O(c600d`2O+f$vv5yPfgKsf(|qE{1KmAsRD>SuhZVo>q_4>S2kJNHy2uQcEroZ~pDQc#(T%WoBh&#Rn!U zGcq#PFaG_1&p?5mu-7iF!4j;2g|ql^9bad_nl&(%maT)q?*wc5>V%ElUu*EM{Stq> ziLa{=!=`!q{8cE>69x)+Ffpre4&VL=gqV(?Q#t@7u0cXu_=HJ}FLUzz1{7c%XtLUy zm)4OOuc4%S871X8m?kj?#|FNxLJA+E1io^R$$Oy4sw({~67*I4_!`V6Is1Vm?-hvP z10?PhI6zoGKz1fv^x{RaO5c-k`VOU`WwH;q2QBi{O~e zHCff0e-jRlsvjK|F3vk?=aQ^UQh;~x2D}ahhQl0_cCN@;sQa@blVnwC`g54ibm+W;r0g5Bn97|gvKG>Grtlu7aNmX*!px9WW2PTLAx&oq zGiA$0Fauyu-@?aG5Ovl-0_0{z;wQ^r)uYHxn{Q)n_#iJt(k<_!;^j@4yr=aR-ZuYPnjf zz#_xIyXbUXfC*xvWYx01LZTiVyp6HgiQVssk(G__!bUxKFwyJg_E6^EljVsHwX9ufrs0s{#u{d0N zm#l?DRiHn_;i4Y9Jz!5{ReNL|3KZy%b!`S686%qk+AjSO6eutZq;UHRjDV5Isx8w+ z0d;{B~B#Q8cDC@?%mHV1~5tm^$=g8~Kif)UJt;U#Nfrxq9o?C{cc zD6-nGFTDh8dTDOrRzYF zwQ#BmOb`R7Vh5G1Q|VqTa3HY;>0tcoD_IMvT3{+LXuI~2u7gO{LaG*+JQCa2cI_!y z3#nRQis%~|=qFhVsajxK=o=a6O;%e>=Tl&cFwvX6YF@jNwa8W#*ax^-%{!vIWQ{lp zP@urH@oKj(IyzV=RnH<>7jr}v6QOlOFN6O#`8{0*V^g4B@&Yq}E)`j&jw{DJneRft zni8Z@6>L<7M)^r-mX1Oiuh7_{P_5nM<@7#EYj}+kh??6FCy()$i4wTL)REZN@c%2V zi#to!8Od>`|7#u~kG38aQDg<)dT z%}L``CUkZ88-O`dGjzP#aU)NxX2TZvVE^Idg z3>vu8xHs0y%S2-t9xg$0?X13t7w;I~FfT!Eb}~d(gExaNHt*8N>04fg-;zCx5|(c^ zzMAn7Ubl?q0^O`xC9TEdrt_~aokoH_LHYqo$u>W*Nwf-b+?LH9!)G2L0au`2S>@lF z2+tkOAd6%LBzbDfe7;STx~8&1k1$dczbhs9?;)E~eA9S)O=wh}f^zvDtUmfBKLlez zYG}TKE8(IxnxJI850f4T0Iyr~+6E-w+=Te#35ZXh0<*LPqkt~9#V7yakw0WGktwo)Jsvl3D?Qy;qc&@2CPo}OFEkh5t)oaI2XR6Mp2wk$0jL8HHk()?wNn_cF z_gQY-ft9Uas|4ON+Dw6*WYzZS$q!h8YNz@67ts9jIy67~9HQgLq55xr4AG%OLv4nx zVvVFp=}CM~(os|t-5hq1*z4C-E%>W$^=27;Z$;*^6sDWWHk>}k7A0)0`V8B9%iEtp z+!Xb<-yrR=v-0~W9p%_;BxVeg&qjQ%Y^Pf#A=#l!Mt94NoU7A3Cf4iV5Q}BtzK(dO z_%CI%iIy9KHZSUHA~F4vomV`r2zFr%*Qm`DXpOT@WvZC;{wAc~-Vy>e(O$fL2b!OL zj_;d8Y{lS>ItjJq-$T`RjBQSGj`%_v$Zm=e2ZJ37vduuGL+0sQk+|Y&F=0c~f!9DX z)GJTJ?(*}vpBVNV&GH)TF8vdHh)%LINe?EgUn|m6&et*lCCZV?XNr8V6gB=~gzz0d zsP5&z&LFmv*z|Z!Qd3p=9c$EOiJi2uJWXpJw%Iwioh{`!iyjdVMPAZXZAQ82}%Q?PEs^3Ie-9IO3C<%DVz0%?be9+#4hLvM8^6)!iDE>D$8PNjn` zALIaR_B$_!o%ogakW&s0h*4oz;g28K?EtVz;$ zlRHS5TIH06Uz~)Dd_+#EgJs1Fl`EqgVrOeyQq}Jd$Q0liV6rVo-E*>|BDwJ`BsYJ@=a)86x}t>L z{rUz(Ye(9z6kW^RIwa_HbtNm3lOzk-Z1PmAdQ(DqM(O|7I+E$%K=X-ROJ+a`5>}HE z(&=adSdkwTm!h!?_33KqC)Mi38pWeOC zj#d7kXdOJ+-FB(#u(kSq4NsvlZ!k;~SN%`j|G)g}KZpPNpZ^TL_|+$w!{DGFc}<)B z%CPAWXA(6$ESssnP~|mC$Iv8r7A6XccC0*)M16{#N6;9lc=C~tTx9F}pXDB0|0Nwh zWvF}vAox0`&E=`Kw%y^hsr4)8Zj*IBf`qij24l~;x4hL!*{h|KCo!m84j6)ndpIXV zN zcLF}O>DQRvY-A_I^I07 z=hBRqRzg}vzsqce4ltQiBI0ag)-2_a&=^6{4pjXtxk=&!NHLDaLZQ{MfsCZ4mmzA@ zcDJE0=wJ#2VJo*i;b@fYN4MvkswmxsrQNTfT)zurM^&O!6D2F1OzHVEP#Mr`m}Xj z@%W?Qo>&cZOK}I&p{s<_U#WDZK=}5`_s8d0;IVPE14C4j<0s8jQi-T`A>>IZQm(7@ zq$`C-KY*d?oF@KV3hohi_CG%?RNO-K14*5Uy0raU=qmE}f>cZaP36GLFd-O>0#twW z$58p>KLT^~u#mCay7;mrRb$L`rv^UWJOsCEW#(=ZCG-8qkD=k>vmLHC-N2vx$3KIm zl~w+{yR)Ma>);NI3Y+{{s{1J1_kZ;!?@0OxvbDO%O4pJhzL%O3{jKvE{NORXBu6xKBKk!rk|UNNi8W*2iP4R)h<$Xd0MEXI2=wVH0D zM7@T@onTZ%g{eezZd{sx?Ct{69*-YE^Ov7;eE@m?Ts(oK;tPM|5Y+$lC-A=?oPx*A zylq-SQ{ua)PQr_)PU*Iq;5_6|H8vY{`1`AW4bQHB2aY{;LROU!fco@Kx@c;W-zH)T zP(ZAS5*))*re7eEj@PAlsn#jk=5Q9-Z^MEzQjal~$`6YP9UL3F_t{0%C&{0;Q`fFg z#}()}N5~A|pAQe)r zLj24LG!ZaWim_Po{!OG#SfdHQUHLt@yLt*$e_jrzYMVXx)RS@#*=CY$MqHCAu|J9h zo;Y;|mem}9AfrV^#=wE~M8Z|x6_y)q{9l_7ws$-i$rypg7Hz!5)kksiFy|@vL!*2g ziTW~U+k~f)i>YabE>pu^<*Q>9CNMflOsSQKa^Fcppp)7N<5#+UXQ$$y7#~7c!M2Px z>gwZP;kj3iRW=$U6A-FyHRW3tKZJFxZ59r$YP1(A7p zg_h$I)RB~l+MbVgFe`?Hu9RXa%wYSHR5%3oTo8W>C5nmIVetf&x;K$1zVIdD5E`W` zeHB(0c&*DetmRyM9m84W`mKR)BAF1|hkn4@h|&H{p{zwG;`#duG067i-+M_Y)n-0l zXG|cKOLD5YbLl`-ZvpVd@F{B`8=kht1=$fx)e4>;Ia6e>PYoCZh$a>Z7zB7hqP3$? zT7M48FTVtpfBA>7R4Ks==_4p>SY)@^$eCgdB+@Rbd4J(!RhzDeLpB`zwK;*2h4zgS z+10X|%+m&`(#p{JX*R)jEY}M}oVO>!rUOI=sEU7k^?MvYW?pd7c;w6doFNcqshl|@ z|Jy9~>(0T2llasVA-uJ@ZTRv>+que2YFiU;YD5}0B`Hr{|KW!pPnW2Ibt3D`Ot==U zu0VWv1?fGydy^S znchSIX!8dB4+Aw!@{I_KzoQz{X60$<1qw@18a1IbD)&OUI4bXuUq&4)&$Bemb`06R z`B+^HG---S;%geRxU46pf%ec`D6S!Jceya8!J1+PrRnP9PXYEr6{mKcB>Xze3Mdrx z4Bq6e2eA6tU&0?%zJ`DMTpeCHQH2%Egt;P=+YcVLMFAXgS*UDbwhN~sZTl)t^I1b( z3wd+G4sd^rni)jI-KEoBg|{7}q3W&EoU$b%7$v4e7~meV`sNJG3do2* z`3y8D%SEMy*RR3R6UX3(EBE2d%9HSazCtpfk)2YX6tz#gB9=BO*}h%lIBabYe1d#Q zr{{=s$Rg!}Bd!_fB)IzkZBgnRZM9vgf{JQ!lNe*pY&NV&e;4KKP2?qMtGyhil=HhY zKAgm5f}NZ!{y&tIE{JE?8D&XK@45OcmS)1neLVJEjG=y`=de#C^{~grT+g+4@J*uF zXbnSJ+oJBthB|I@B^O}joYuFS&B z*7EijY?JP;JkK4o6q`+5L5h|p$`2)8%i|dIkmjxo&=-#T62{CVfIvgoaBJ*1qV!B8 z43%)pdCdDI2}&8MrJZZz>rx#b)@Dw!Itjt|u%#!jP0HHc|5C{^ReLnP@J-1|SPBhk#9 zWNm)+4cN!qazhTUc3qEDB_#z&#qw}Kgn`6sMiXt>%oCOVMq*l+RC~8nN|_e>xc6SN zAlaiM|AJL3;4xFgAhNsM+fU)HF!m`DFf3H*9)+->ITOGaUb~1v5QFvR4M^Q74_r}u zz;V-fhDoYe8*?Me9)VXny?a-@&_k;{ra<>~o2asGa*9)YAOi!r?BOOLsOxNVXw*^C z-mb8HV}K32t#Is=+mxwjoYIs?Q(jhTc@R~b*dEf=embsog*miIcpw0 z%Md9!{h%1bd&3+qiehhSSRJOw6;PY5apIN*nT_LD2n(oN&w~wo&NjJ1oj_}7(t!wC zsr^pt8s-BtWwV-U1*-r0U-94a!e=@x=9Y zucohC)p8;&A9r+oc<%#3st;hZQ^U2YoVSSqAEohp<;Ct!&-Q-ABV$uktr}LSm8jEUSvx=q> zNh3$e{bEMbqQfwM(CBVgpcG9&>TZds(!xzuUQfdI%8Rgyp|xR(ZuS$iWwSaEkxGL< zM+O}h!xcffrJYyK*?XdGJKOUud zSVEDvuF@5po8@d+SIOjG!-vO)fpw*MD(8(W)6)*pk)IW#ht9(cl_f^ap{*@$OEJ?g z_ZtZdAz3AbNHI}Y)@KJKRj`f$&H5yq!IGel>*}<*=)u_e>Le;amUwVAx;m(uH&X`P zdCO|ysDYG0<41!AwL^!?Oz;65BUrL-zyg3;E~IEV)x7^8jtm6VP0p5;B!CS@J`vBz zdh=p*^R-(r--5J(TQ2dlUb<_ll;gEhkj=TbzT|TCtHCZ^Y?gbgno*lh^AT&M zD=?kW#U>0=XA*di!1qw~GxAJOCdd^>vY0B7sIHR-L9#-lpRpLWi=q#P4|8K+CkeA@fw>cV6F8jR@W z3y*E~)nG=ZuTpYjwxp0t4A@RT*@GG2Yf?4D;O$X40<~lzn-wtv-wvba)Qok)39hoz z^X7@?q{m-s0vc?`FK>O$4%Ix)QEQ$)e>Kv1hBja!5b4Z$_hsS>>YI1csTZg6;Z`4S z^+n4*?y0Mf$+-#%3R#30z&|9qjGO$LKGVcA|B(qmjuj2Yp)cSmhAO_v(an9eyz>um z=;7ZYQU787B&vY5e<}E|4s(uj{db)Ira>ckmW+E52rNkhEiJAU9HJ)XT)SJbUC?Hi=61nfQ zz`6{~)>0^)I2Wr0oz#BId+UPo!@#!h z$M=BoSOPL;71`l3a-wsx3~Lb@5RT?jC0m_ltCn#J7KEq-C9A*u_Qs`aumE-|wQub3 zH10GNPs%D$<~EHvu%Atd)6MYAz?mP=xm`Qy_P}~@LuIzkn>8}j;g>qyx@6Sw_$foj z_BfH220vEi$YCw+{om#$Kx$>78LPRie7><^PMv?A-h}1&{~s2BtP+b%xFJq@o+R`W zH!*WlI;>gMVEBhl-ja30o=3fK}--rIA)}S*3mxDz#fMm(te4C+=-XRuZ*8g*gWiwSrLr8eD=iIgv~+ zE@J_Z`i#Nlfuw*#bMPAcw>BHZOqKx16py{yY#jB0!$nj~lkYf%5l$rdQKSQLa7k;- zgBF9%d%(l}&`jNIHpq}eJjx2JinEEYM&)U!SMTz9keL+m7zT+ax^ZHB7RhYkvU{7| z0fP%I{0tTVd^3os<-ztlEw+K;xp1nY!x!AT%(NWNq66 zhODZ%t*Q`>%>vp*1H*NPxkOUxR6$DsDUuNDv_~;dLr=CWO()9blpqr>$Bj)HUkh#f zxcQJJa&7{U{YKnj3U_nz{01yaodBsokP-X1pvBi~x-=$uRnJRZ6CH#@TiQU)50kca zy`s*bg*;LBno*E^EV!a-xLBM>NKO4do>xuiH}i5YJ~JLRgjBO`cSOCL$I`g^D|>n(vnxPF#Tq z|4|Z~exa#eV7{9?xqXztjYD8y??N{6+jZNdQ2?erGevtc^`*N3^tOY4-0iEt# z>_^s~G+?i$QJpDib#&(}_dcTRGth;DR-G8&QTxW{!*r~w$t5;ALR-!AbKiys9-O_l z!jRq1Q3ebNlC~OXnxeg96HS0C;ey;=wW#GoSOl;s@H+{lvudnEiHFKeIX!6-3G0M6 z)y*T&wL^9UqRDXS6*XVY7;Ql_z}L3hLG}J!r`Q{X&`=`Rk*rgR8CY|2whEpZuhv0)0Au2qaV|ltponH^9BL3SyTqWcpeO6 zT=iGX5B*dI@-eneXtwWlflL9Bswu1gl(Sf6Pf)QOQyE&vw>!tfk%u>AJHH1PwMu(S zWbFp%+b^cQTE@?W2oO&8(ew9X5QWA~P6uWhHY;VV`b$UH(vYtB??`Dx1sKP{4r|LXRm=0iP?)@|#QMMma0Xx*>X_UvBAmhYOyGGVafgf|(u=U@RqHJ((=u^YbtT#3b!F@oIK`#vq&DI^4wg>u!8Smb z@b*KtJTPfwkEs-JqiI1SW0x9tr#Z@?F9+;|t}zI9v}|{l&l@OhSlzkK>WpTe7S&(! zSu7KFjrM?e?p?nOY&^FN28MNWu7=$WLu|m=w63&J7y8gs>(=tqzw29+rqozS)3Z~` zdaA==c5$p6dI!wv@E$BsMvGFgBq=15BsQHjPDN%jWcNZi4N(rtPorJ65R|hF4ilt+ zA&C4A25*bnE?W)*7cI60{g!&z%8dv7+Lzv~$X@9Ab+0cMD~u(m?tYD=-9)MJEmze? zE_B7I*ukjLG1TO;oKdV&E!CVm3=CiB;_b*p?MHytY+EaAZVUowk207Zztgd>O0`?C zf)X`CEi~+7wr5y#F|4rag#M|Bn5FB&fb7)j?scvr5>h38cy|NY^pYcOo7Hfnj!isJ zjMc+tZ^YShbIGa(@c;MNcb5mKZC5TLV8z>~7WTuB{uW;!vs1M%=p$7L16@sfDM(6(curODvrf-wir3KDdlioFi*EbfrYjFZSRW8h480jjo9L^%h7+E!_SD!+{VxS$RZHfW+kqfeeeGrW1L^<_qq9Dkw zs-B0a)Ru0Yf0e(pE_UzV0JPH8y11-vQ9B}N8BNPhb}0=d#2v4*gAItyz&_DXS08Ox zdIA=rsjwGls`Vz?veZFZTRtrV{8Bb4(%z;Ki0h;sJq$6XeVb-Q)i%9i4WZ?SEb?S_ zZ7e>?mMxdX^f{YjR;&h@jirnpKE+L=*&?YRg*VLU^A`tQeP~gEg#8E>Bn{gg#?QJ( zeMxoh<*Gn}=0ajB;3p{_XlSAgQYn=R>0SO^O^i%&)4M?G63M8=I+zfnb>KJYcCZ@2 zPf*>{e73iwh)2f`m_hW+R&~PgbGI6}fYBtGAhB+RGe@FWAw-0@f2h5=I zLK%+$R2&9L&93?UNN1CYg4qKl%_#$A(04Kk2HC3-4;owspJZ?kh?OBZS%OmQHG21z z`VEdB%iLD2fz}y=fgi(=7|95;UtfA}A-Z5kf)K1xIR=gLaoAm2SBJ{Qk!!HEw5Ws*{!AE87J2)I^q8HPR8i83B?xg%9Ui4@)R@#2}s5KdKy z(a0)AE+6CDbvV$7&`dbWQ3Pq3iFtfj%h3c3Qek*3<$-?5)|DDs%QI9b5`4$2&t?Va za2q@T8zll7+$v4$(}Wd7>=KeQi4U{Q%k>TTnbM-se#c0M#|G5k747#M3M0p3?9EH( z@EUyt1r$2!pElLW90z3c9_Q(T8l~fWwcSvh^fy70i>lv&B%hU$qQM+ z6fvzwA*XWv9?at~>mI27Tf0^V|LGoZu+4!%Ax;qyRP0b028afcU^|#dPJR4H&O~Re zCZdz%lp!t~+N8Gt7*YK@?2W92IZ$A54DJ25VoynMwmZbDTbMG!0u#aJDBgc7_FS={ zWnCAbK!NVK(69V&5R9d~2*vw*y?SQ~9AJ>0O8giD##vTG*)6hP&q9F$1PfQqv*%xd zF=4!gn+DFq!b|{HV2{{9cAbYYVyu#tfbrLLe4pz@`_*6{6~fiP)^ISls@t0t_PRv;Y2Gm@uY7R>DDPi8+9Hd(sls zVQOS0U|8#QGz)$X1r`HC_E7B=Qza`w!&+1aTf|}K7n>NK`thW^{%)Ac95Ep@tVJof z4Ja^=*x-Qwl!;21I#~&v*^rX4sh@CxJpgn4TIs(5`+%vN0j(&y4dw)UtnwcR_C>OW zKm(mF03{EK0`A!a-Iurbo2Z0+m#hw207H(~Iuw`{Z0x7nZ^gb#RtLHu+@n(zanA-& z?Q_fYj1ZMDGmGbvd^ z6t?VCaD~P&n^lrJ%sg2gG*wH*FzZlYTp&;X!nAVxd&S(4mB3Oqfwzjd?4BWWoYmpI zQO2CwFU%EL9n>^<7Zz+%j;X+!i!_G+EP45ZVlK(*P>^eD*<+wocVwp7jva zs90FChOjp-y@r42wNMk!0jqg)86Bn%U>B|~k`(QP13}ghn#z40=2zlwpalJpB*guxDB9Ojq2WI z5UYVVP$*9*kLdvZ{727pLa^1X*}0!9^{Mjks1BAj+)%1pd3aO_G7YY2D5{K~_B^VH z;?ojS`B=)MdLRwepgcUPjC)j#Vcvposix+cs&IW=jh_FgVv-yC!Xut))cmrm-9jP{yA#VciMD&HuyX5ymvRFrbvYo+Ba^|&o~iM@p{kU z_tg3)zNdP2{8sgLzoaIvUsG#;vO#~=7&`w$Iey^eTl)2}Kb}`>f4Cs=dMlrLM)bNE zo!4^zgKEW-Kep_drLVDAh`{y7Dmb2Nu6S&A$$Quc4(#2opXV)DsOHUoR4w}U52ChP zglHrSX&*p5+lE204Z=My{jy)$!DjCN?3q)lR#7vgqJuYeZj;e|P5+G}QH=w8`$~=h zD8j{0&P9Y;EKXYY+|MF%nB#EJdU1ve$bq9S8Mx1O%SP^h?8?7YQ`0QDzh+_-jkR)rkcxXvQq3`*NAf;Sdh?w>>t}m(X1t6CpqkRk`oRN;xJA|-jrTx+K=Smc((VFHs7bo{0 zd@Ul^n7lu5;;o9duL~7vr6|m>TqC#R4ShasUvQ>yeVnC`^X4y%rcJJg8r#60ffGkc zh-=$ii>RsTj}eIT=`=>Sx zMZ=;Jl}0(!Ef3nafejEcE}nx(s0hYbGx+jcK2>on}uBb4Y9OhIPuJcbokk!clB#j zAyc8%8^RBjuN2d%ZfQmgLDxN=aMAb5Cid2I#Vn@X3bpCbe z+~Vb;b|!I1dl;zV;9y#m(VN>Dor@ED#JO?6q5X&U1=EhY6*${~OdtO3{Sp-cL3|Xf z?1*!0plYa+S*0>fjsD}KNL`1APRsd0dkhY2fKWl8J~N694UxGw?&+vZzu3qzEC7sh zGPO3>xJrSVB9#eZ>1?L7u`9t;fzue(M-T3cK4)o!nS3POW=O4L{XQ>KI(@asY2lR19(MX2c$6y~*YGahj7%y4T-VFq+Nm3CIGo6^g z)?ojh?a@jJ^dEYClByV_$>j{_bVF&JgtM23qPQU5D%U0hfN9dC7J#jox9pXeYUV77 z@p931QLgToSa2eSXr_%?M`n3zwx~QjstCWK>``@iQh8Jzo>X5Dh!4N0O!$|bai12c zSjF^(TPHSHt;9Vl!DPK%*r|oM&N3U%z}+`12bTJ2I-ZAKQP)6L zJ0`D^bvhjbxY4*;D7GQWm5;DRf&<+Z77pS)oeGeS>+OEIq-~b&X3x$zk~|mta5hLh za(%#cf~4lGNrQrv1gkcagyjC>Y=)RF$ePnPw4a}}t#oZtw%+uMNfWSQvMUq<8)oV} z8A(+7mQ^SqTMy`Ku4`(t@E1u{yN|dB2uNFOsMD6Q51ZV913B3?Vs%`Ujc?8!a1yzd zkVqpDRP6Il_9W_DHGsq~rWhudXlNIL!>G-^ri&`Z%x5cCh z=-BmE9;=-4#=$<1oYI@`{3RksoVxKD`-D7P8_1=hK&X!m>~V8-2KdAbXj4R}iwx&K zDmw_J*XN#23qgj%?Jh`C$v+UvPTxQ-H<4QjiKLay}Ibs4NLl6vYtA&VL!T3(92P zP#5Jq)T%?W`FsXBn=PB^7ZmV7n7~EVAc(23g_y+{d+mH6Hu5lgnn_3`m99<>GK+5pnY{9aqUHoZ?C>*Gxi3*DuR{2BGLQ+vYf!QeSrj<2YyALk-l2GMnD5FKUAH%HKUQy+h2+ zj^fz^%)IW({U)kaa|Z+JNepOaBSXweg^D&(On*VOqV7D2Q#Q$nuz_K_`?{lIG>D@m z-I>NX4#E^-iq`baN-RP9?mn9vo8TN%S*ha`dA+;$7kbKb;~eAgUT0gzB{s+5B-G3; z;DZ#Evh$|+&yBlY?cEwV#bm>A4s}uhB_cku?~lDq%6=dc1nb+^uhj~BIkwdrr~@bd zAldcTg1)=_&uB29QlsZT*8LgW>$MUxnk^!`=F25IZP6dAo(f`VOfueB$e%)0|^_e=G!PqNV6|jh>==K zSNac@E)eW^!v;h_y^?HZ`K{HqcdMETm{v^%#6*e_jGab>3_6%r<$cp1r~!S=Di)RO zjUnqKJDz+-A4|VOKAs_;-N)F7y#(=GBTfJ7V!%*9P_tuG*mF!I6?3V(ky{R|uok7L z_i=BEn1jwRGR^4NE2GaQR=LigBPR;i^=n(6x1@CT{=Iz_k1O}pDMl`_&qT^80XtDE zHp>g)7c3ypQOj9l;YzS2R4LkCY*jJX_X=o_k{g0=1`$)=X=1S1bF?zq(|#JIL3!;| zj2%u4{{4!6W?&?3YENrJ8D(l)`gkhBRf79HyEv4~Z@CUgGYV0SG`sz2k8=T8E;wJX zXbIyx76ZZ578D95mer^rrXdt)u~G=2Bg`e4x_YKgqvUCAH><#;eltEAOY!|gU!~wt zb@;tMkE+9y%A@LN$S8G5d3aO_{7hrRO_h0Dd3aO}#Su}e;&J8SQ6=yb*fTEX3zr_s zHh*2F!S5>%k7+=rzFh+&`NKL;zoG8!QToT$Jv?p?;ZI)o@OlRST*_bl?}OQI9LcB~ z_j$$gm?}^xA=C>cKhAH1pTNE$TW3X;S?qrg)T11NtU>1OqQvCyjpT=%&*~E^TC<-{ z_y68O@&`w*Jf=KKP|wNFoSHU@yOhTy)U8qh+4npnPfOKp0Qnyr$v>n#CZXQ9X>MDs zWQDU#dBmcwNkxDuit~FlMaVh7bN`P!k6Wnw4P{ZB9-+zA^k-zQ&ZtT}_Wz3+s?KpC zU%2{kw&^~VKDPRmWR3mSRt5Od7s2Q1D?8IvYjBKAnLWy*B0Q-CLy`%;sTy8Raj2j6 zQlPF=3N8{-3`3$)e#MspUa3k^R*CLWYU*ERtW(r|pl+jF84xK13C^dSdZ<@;rE(CK z0YxbWf^(ljm>RrNIiL(^UbbmW$kYm@ZYuTjL1!10iZ2$lO literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@2x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..de0d6d9d0b87895139b9f8be867a855381d19141 GIT binary patch literal 6927 zcmZu$bx<2lu!dj(N(o-HxJ!ZJ6baBmaR?CH-L1Goad#&a+5ka{XAj2 z$m_bJppY{CH&7Kc7*C!TQQb8@fKjSOsdk?YbZcp4X%rM>BJRB@1_}yAiGr*fW6 z-!aax-)C@pj#=%HV&~g;Q0TpO64;Wov@*s};627XD}96XN06zlLaN!dnvvZZQ@Qa3 zkK=*bIYzDqlS#^uEy+PBt5tlsx@D7Hiq&BT9C^@3U-dn9&dTvvn>qULNYJQH)%Iw< zi1p~t#qX<+K@)af$3K1YZwj}4wz91$*i$@vW2*|Z$)>+oPY!OE4V=Vj#HQu6=n;VB ziQ|8K)?jIHirWoZqEOR0m>2rw#5!=7T*@9QyMLw=@v(j2Q_nnlx(;9w?r0E&CM%0{h0rmYYs| zp{Ve1unTED(Ub$yz58J9re@gTy=1x9Bl@5HBQCoYYvy?UKX+pOPVe^upGoM#|FN=$ zqQu%g10~U5l;NC12|_><^CJfDRG$-+CI zx#IMXP4Lf}Ny`uZ0V?y5o=toz1|fcki~p#6H!OAqk6S8@4TKY*+J7xOtb*Bl`Hq{d08gsL9Smo*-b*Ate&FYKNE z_+3poPoy+ruc2`aR=2`3h7%kCkft2k6(4h$pES)jxkD3>JUo6>qKEM81}J+cJdiKi z8sBa$XLr^i*r9n|L0hW7tX&c;BXE|-2u~9pto%ufUm|<0X{qR;ZZvL^r;>fI2ERk} zZ6r=aW#<={>z4*`+Zvk|pK}nPyolhkB^WCeTC$*leyDGF4`auVU`L@~qNw&5Ei0?r z!a^uj#<4j*6rJMvin{#y6Mb^CUZCVbN+7PhlyiLktPsr_s_!8ay^q1 z=*z3jk6n)$OEry52s+c62$Ny=IAmXQW~g60cqNYoaw#G+Nz1G|VTZ}aib z2OCn5$pm)9Fj_%T+a*=hEvEr>w^N)%CK|Qb`u4FpUBN=DjDV-o2-9Q;fn=|jnXBQn zxc2ge?Zru|am=H*C?98J?U2B^u9r+%u;QSxuS}j=KkbzxJuRdLRCh$VD?!YTPxNh> z_Y`NHe&;omYeyDD@mA00tfOL4>Yhg%PxQ~_c88+`r5i)-tKr=@+@OfXxr>_4Saa#Y zUSuox-qK`ztQ;pBG~~?C%LG-aP|_Kp>=h)Z+hXTfiyv?=j8E|HK7L;>T}?@)YB4e4 zq3F<)Tqz3m>IHI$UYjmD61<6;zwolWI8}b|N1eQb&PZuCPBuQU7#KEh3NCVQzdq2J zGfJg>-1+Ipj`cYr;&wJ8=wN!~&MX-*4h~yqBl@D}I_>&L_*8Nh{CPzwg%fzU-&^@ zcI(WPgIh!G1q|m@2+@3Ih!8wP%W(57!!;h^EdiR$Ni4+ge2fSjTTJ8G+xi>IY07YU zS!!;ws#uOz7{Oo8+R$VAC_(wAuE%r0ebi?BZe$j9b&r=BmwC$b6oAW!f z(=z=10%%uC(57ZWSdR7Uw^1*LCL08NmX`&YD=HdIjwgPen!&X0e&^uNQ0ya>)M%p~ zc@erFy^jOy5y-eY(aXP4UK_w|CW9Tu-bEiHW~vy_{aC60h9`B0QhlTKq{h)g@hSd- zCSB5K%YlOj;VjMfTY5vyy0J9`%y%Y63=ctR%=)vJLu7}<4&X z@k|Y9Gep`yJVbYbuUu$c&=yTT$wwi7-8J0VKk;lcnzZ@!VBxA9RRX^{(ycq+uXHov zbIqUWF*7s^5hrS;sIWp%1^0fx^%<5-9eB$;FJKl7YAa|bxtx9W}wWzs=kHRiC(ZD_$A53g!W*n8e*;2-f zM$MsJX?uu&MZVnqj-cuF47Q_eU>g|6mFYqnh7;UnLkL-(B=zgE2eAOBpmW%!uHB*F zn9gPr`Lw>Ljs#!#J@Drwi+=i|UhyP7!daF^o{$xKGlBF0eX#VZTKh=+`U=%q-^;;h z+M6AYrL~@UW!9MZP9$mn3`4$&-6QXRY?BuUm4kKF7bO~|@UgLLQX2}~_ zE=pXE!V|DAa?W4^!8v93^Wes{$XwsGcZUu-f7^t2nS%2&6sG+9qw&^CV_~2pv@Eh5LYnebvrrl=slYaq%^tI?PpEC8yOKjE? z)}9YdSrG_aal6@)om-)al9vuQag0%9iEeKeROXjI6L3~K9J)%0!4c;1pAH;HsH93W zHPHRce_ed1gN>ubXfr|?x1aeiX+WBt+#!w!!Z-B$o)ZHklw2=!2@Y=Yu8q5uGGBqlfAt7C7-cNp zvN;d_5nY-wi+HKY%mtwK@U*D4*6IUypITwFBgBDP8jf_F|IAk7tV(PdHRCUv`m05+ zuJUdc7Ow)h1DXveHY1|q?U0O%5nz(&w<;djhI78B@A?nb;eUrdenNZH?eb;qorpr8 zD69WG-ORFL5Dq;Zu(0)8UR@WRaZ|1Xg$&mQx;&gPeDVHq)A2|B9jX$#6<5-k8XSku zv2Q2O%VuHVSKy~)m_3veIi29_WZaaj5;zo>@V%-PdqK$+$;i|l$6O#{x%7I1;p->6 z5AcMH8nTScrRiSErkr+GXv?3nA^`AZ=po@cWq^pJ^e1|mxWRl~Y$?K^Z*5r{^Y}GA z){I$yJ2#zUm`>@)*cr8fUlWP5PAKYr71J)RX)h}9-U!tzmlcyMPVGvA*!p755bO%Q zLxA}t@F(3UTr&H7s}MjaG#~bmbolEr&0&~%8Wtyj0%p3Jf zN1Vw)nPD!o;R|J_lWP?ksUM{bMk;5MMoRCU9m&6I5A}zu(LHW58?SjM?uCRp+yAuB zsnS*b-{Q-FI~Fu?t_FXu;P4}2{(sfK2%5~@bt=uN&7ugqU^vfwi`4`d0iw5o%{2k;F8TWCU@!I)9DvKbW4Y!sT04KigQ@e}e8pF(6LY zYsQCsgF=+&6r~-vmakjE4>Ljcekbk~)Az9F3u`fo7@NW)4B?qMl;XS3wbjkiWKpfR zd{{RMvN&~y@00P^r$a9vif->!pRN`gk73ocwj@_IDsSRP#KM;fjcsj%2d%|tGaR4lvH+`~->XJxEKsReOsEC}Eqv zKhH8bxDpHSEtEgni#@xGa+J6~NNib+`OOT{ z?6i4FyLQy%E)6FAhkNuBRc?UMMD(J2zo$XUl1zKkZR%Cd^3DcJ;5Ay^TD?eOigr0M z8hW!alodTgL)$WH*50z3f^ksTghaVr#1Qd?l4zR)mqgSK5tT-QPay4ajZooP3&r)l zHbK_bO5_ksvCA;Y%65&j?q}U$PCr-ZT-sh+fiDNC%zt#R#a1FC+~K$NN_*AI#E#@- zTzCr|)d!=QO#edDKK)qMfqEMf1W$PmiSm@`#q>)p_~dz0PvZ`czjz-N?OZH&#AER2 zm`j7V)R~19$)y2u=5(N&abz`wqGQVat)20Kkh1G4lg{pUV~2(5?BX^wTm+JDFvIFb ztg=(v2Uf+FMS;5b#!L5EdS59$Y@Td5CH6VPs~P4LysOq-msFAj%|j&P8g;Y?=17kZZ9x_{ADt?)8D*>{)HfMifI zp*>`ng@q~mX+o)sTi=yF8 zXL??lEy{W2LXntGelNV$ju$!<(oxswx5duJiEfu@?DiK}anD-=liqq7xR#QRB5I}F zs?`oJ0Ac8*mzY>E!t@pw*!0uUQwA zbCE=$P%53ksyRGtH?+(%Z6IAvLt0z;M3fvEj&#r`c9j!AF#{z}Wdd4vXwfWglt~+_XP96!ogNg2TaC(Vg~Y69O{=ZE>_gBU+sLh5hJ@vp8kOSKam zwZ2qJ+?0O%B@%nV?_%keh&92~ywUbwYo-u7L3o_Jx!+&g^AvSQt76kw!BsI%Pf4HT zA`>us^<~5iPV^OW*^;qJQ2WWzt1ThxtFk4mHg;*=B>bcQUi&}-u1PHQXWKzlFTv@o zZ?PpZCeX(6*=#Le{ysQ4uN$QA1$W(x=I?2KhSS6}6gzo7#jBw>ah9?lGkySI-ic5y z!5Oct0a#qPFqb74G`R_SWdRd(fa#_)G!LWd~mC~-ap8Gqf9>F zQ`E=&X<}K`Dp#eXSAY=MMXiry<2XHtYA(URd7Y5F;@i7{w1&6sY5oO#rExrXWo@(b z1_iD1N33L`vW zS7m!2o~BX%13s5#A(_`5OX27y>Sh+sN`+YBw7`vH+ZpK5?=2jGa~Th&tOVReJu`87 z@5tQTsqquyt~V}7IZPu>%kERg>{i$Ae+UCgKWbqQQt{->r4#i4M->crWfOt{+G4)+ z)|Xn{pn7PxZn0@tq`Yo2Aub~^@RHXtTA7qktU)XZMUmh%520R``^We2I*)@Dn&c_# z8I%7|lWgisY3%#nKIm2=M(&V1BPQAUfT;RzK@9ydwcqAgpl4UFq1LFF=d%{$7P=7S zHY*#x)6fUfgu{Wf^0^2cdZwTF-Nj}5Mb_?pF6Tsrcw1K{z-h;o4)-+7h;Ldu(Gdoz z2sTz-r?mWq$Zr-?`*E{B$QmUaAK$-JiL-%VIQ6NuzBi%Nci#z4R2ve!dGy zGU;3=-#@uoU~`q(^wauA5N*r zHQ4ecfNJVUFeN(@QDXCocu|k>i#9A&UcrRKskd5BG&DYc8O@&otlNdB?_||xY>n~M_8{u8MZCUAB}p|E4yG#B#(bA@=`93;eJK5qU>EO!c{5^&{h+I{H9aWq=^O{QNv z4^z4TRiJDKbPf&^aA0Wns&jBGZ&bX?E+L_+EDKO{_%%c0&yXjP#FpSrKrpa<2$DlY z1BM}pB#P^Y|$x|q*|ZqFQ|BkU%}WlKQl6;{qB)@Z=kSHy*M__?~Pi4y#kwV zZw#;s@n!)PqTPCf!SOB_W?p8}f01LY8E@*4+uc?2b=PgYiZXCH_#4z2CvVRdJbBVe zhE+cM6sPJpB;*{>)B#G1NjSR(hO}%sv z=8qOb7b>ax97)N@{7K7#X12u$Wh z?6{j^e-BmUJf)H48^fr&?NV4X6r1=+pZ{f{ln@2jDib-sTUPm4$ga?+KiYbvo(Lqlnt0x=>G7WKeIZ6j= zkP`qy?Bia64auKUvPAXyfg5@oTH*po7V5kY`IQ!6|5^4AcXQgkUEOs2JSU>5s?4+` zD^a9*YAtk1OAY3>fE2d=TJU_*o0tvg;llana!Omu#__eeh1c?>C`WMbsMdus5#tGJ z7IA&<51pD<4F!jOIu=2Mj2~W%R)wT1F{+qlcrp%U^p_|gS~b5v4i_Z2r0^&3Yz`p6ImFnj&6Y}%&)b}v{S$42C7K<@DYsY%Ms&38}<49 zd<3-9VoVwk)oGWWhU|5I($|zd{8D)2Ag)_u8 z!Y6?d&m4X$_>1gcv(asa#bB^psLf9sMP!$+dCD%Zgz`<6N@$wA&b9qlh9oDc*cgjY z4-E9dbBV|?8!y*b`Vw3DDLhQcPXK`I|R236?IThP&<+5b=a85BSrxO z0QrUE4mS2eL7^9Y`k*R(=7%7Ss9rkC@+g&KR69=>I>@QZp`g?x;N4jv?_d{DQIym3 zMLozd|7g~q_N(j{c+YV_*e`QHHL-@9tDh(rJ1mUbF5cQk89PEw1)FbKz3(zEbnbR= zq*~LM5Tg@9Y!Eny@deC}orrkQT)f4n7$5$`~6_->DJ$^*>pXpCBxShY$dy3{j@Q|QvVKy z2%x-)1G55m)`_NL7QqG6tL+dHa-d0eXsYZ z|3ONB2I}8R#N$#@m*)$2506Lch-()mIHS~}C- z|G7o%ewGB1sh5AcKM3t(M<_@C6L?x}{i0K1O;1)N8UAtqvpvckGa_euuXXo?n3_c9 z=@zX2E?@D;Wiao@7g?#Cv8;c2a+qRsSvt&0%WhfOf%xTo6^1wcCmouyd+tPG@qqtQ zcXg{C4fZhkd$#Q41aEpG*)D!%{dhIGNaK+IJwnj?s(rLnRhX0C;qF?-P2^Np21y=A~}fp+o>;YGQV9FSA1C@Id5K8Dk6K^JEc{P9E!= z+!4g`Ib`2U*z&djQj2SIa=e0hSaTantxh~r`qE{(GDbPF9Qj451?Y+ToE?o9?Ksu;D!_gI_OqW7)bcFV>0#?*J`SplS9;-PMx! z6wBuC5AmjyD`Y_orJ58C+fWBQ+OErZ6Y>bD;5dtjP#;`6#Q9Ab6j--Za`})Cc9TEe zW8eewtE4Ni;D@N}Uj1F0=#*RKqd+sl@bpYFcvhat_mPy(D454WFcoq@^#`P}$b`98 z7W7X<@6T86hL!rC$A|4HHZ|jfu#0IKj9JO;qoouhzaf}e|M;TI;-ygeS>RGZ%l(8% zRJ!F~N6NcSd(zwb^d*^sxvv$YtL;%B-2IU+3FxWYY^jG0^OXEU6prudVF)?Ftvm}-ql(Vh`v(CUj z+6?w?PUEk({2|cBOJp-}Qq^ow`f=#>$`8e)KhW*=cE$a-Yy3q?;E4zPc4VyO{Gd31 zq;WOrl6_nW*NGPy7bpR`b9l!%fMUwf`9!3xxiK7*Z#Eol+8w2O&w$pSGmJz z#EPhs(ae?jmApnw9z3rMiNZNY_Tw9dODpIu$yhl2`n3 zL=axgZvKN(0!EF$A7EEYDjr&Q;#6u)3)G7eRuJnZomMW_#sb&wX6(2cVe?#8r~aN$ zmoid3qAF^G73{DOc>lPoT#eN_C=D=&H!7IO;KV=WYavyQuHDh#o*~tnpO`1Lw|XJ; zHMnTUhC~z@Meck~>%ZO$g#9Ka=E}!)rNb@owlZ$FcV#?c!uuePM%d%-@r|L!{j^@D z5=)~HFE?a5i=<@x^(n@^aj`zpMY~!T!0Zn;cvx@(FsMgvCWxrwZn&b(ca7^(oPJfL zmT~J6ZA!k{V(OvvZ|R~i;OmvQ=zuqSsH4+4yrpvb3z@F5r;+p(f8S0Q{}SKcB!h|xOD-`N#RE%8DOQ;FT{j0 zf82v9Phe9&leFvSe&gXmljEvPIxKxD?bdvt?=I21UkYK>D{f`>aImyL#YT-`htUqL z-;P)sS%sRo(uRr^oI~fTs|l1^jWac^-Wt48I6TbovTIi;pzz|Q)i*i-FfR7^Huy!M z88RWmeWL7%_W!iaQawP^V*$Em!5-dQ1KJN;h-Y;S^9sj%@`wf&(G7|2=XHjc+N)x> zEVPd0)oxAK4Uj|DSfR2N6YH}=4zxU}e1mF*Bh&eWh?l8FS801_tmygndqmwRvn{&3 zkU}#0v05JXXZ(hx92?pkwOzk|4bMzK`n{u9v816fDno6hQC{5pf0FEVsT-HT!8 zy&-OUM0GVs_`7SaKVXuEo%OIEPC6&cMb)A1t1_+-T=Kt3FnP{AH^7|`2}8!NQ%O1H z4k2>Qh@81N90JZWSCJJ9RnSa$Fno=b^7h5^W;8eEN&L0VXoEK*WqrHBm2|&(i;W6` zdpz&V(0oU1vp3P`HLg%z&!aMi04V~YGdzZ5`ID@Wc=N~hm)$liKB3#)%(V8Ay^-S3 z$8k_Jr14)y@|$m0-Z%|M-7SK|RIi1s(1eJOq*`g-D9%#A4OXS)$c=H-%ZMjhes5jI z#1fbis@^&(Pl_WLFKFyc^SLs1$S|?#xER*?Lw>)Edr|2t!zI7JsQX2jpP`LpPFa!m zyk>A>CEvM=NwlEci9g+ULOjz#ot zx#(5?qTt>K6_ge2SJ>8WyM;bpcIL0}^M0xyMp-i?)b0<{AZCsCBG8Q^vDkqf-Esx* z5pSHMQf|%%CV$Gg%uH&MOq68EKg#)%Z?TRpz(Jxmi*_;2{fYY0if( zSUqzyRF&)rjL8Vx7{@+a0{)>BAry@0s|~}37bxqdipC~Kj_b!6u!8R^U{tCOx*Pu# zgs}twt%o!6&~~Yv{TD`9mygE2Q{A5>307-Of^VF4kI39bo$JEN=<-Q8h^`xRwi^`2 z`V6G`tuLiRKT`6{ol%93oTc{AHtak!W{ULy)o%W6`#;4R|I4}d7=u{X1e1jS~FRCAYFwu#RW zd1`njogOX|y!%q{_SRp2Yf4~OJu4G=Y>DlJ{Z*>il&cw97u118c4QjDh#O z)z7utWw`4ZLvtPPC{rqN_Ny-?ev-&iEQTF2kWor!V2@LrYcF_?eh6=$tgrt`zUQ#2 zloR0aY5XboX`C+CA|Bf5ift{GNZ6n%+-TzhI9MBc-KY(X;)ke|c5XxS&Xq z&gCfhY(HdD{6}ytu(Rp8=GUB|?u=+#(cmJ)KfwsV-4*uNG9|Ll28ozvZl5bxMcv(I z-4^qg#zmMfh|S2jmJBYOT!@M_#hc?iq};96u>x`{m0o1Z@Gg(S-i;XcK!taBkB2ef?=QlTKb_(NkFq%B_C(CgbSa{Q)#AfGIC(e7UThyeY~9F)`m# zHr)p5q0zUQ_LY`pTp6RkLQ4;%d z{iP@)uxOgV7*+In;HPJ%gcsKgXfNdfTAeg`DN1rqZNE0=K7DO7&~g8j=zSAG4b2k~ zt?A|=58CJtmmBQd=LJ%8MF2$^$NO7xWWxWu1K)9!T&t(dHcx!V}VG?64 zv;~`9b_l=R!8|c>pLj#!X^r8T$BU3ELLtCv_HT4B_`_65V^1abCv@drlRiMD`l|5g z8w(3pb8#0?w}y4@b~+C5h1376Xe+x9Wkq$F)7XwB_EloV&Obj?5MfidNR zNdFDj2wnQb?#k_g)}IgWgpqGC4qJV^jNG_+ws4B5sh{|h@Z%ctpc>-aO=(N21{4DB zQJ%XFGo>FuY?w5aMnJ8A_>#C>dnSHKuLl$e9o)XD9N|mwTB>A}aYg$+;X&q*EGRNf0lTT`e zYJ0u(iV-)C64q{LYnkOnJp=IOqt-k#YPRo~;ebh~zdNdSZ)KtPGFcNRq{K?=`U$k$ z&dHza)VlM>R(nT&Oa^p6 z#|Ec6X9j`;f+tCJ-%wrJooCkLS4Eg_gaRpJEeS)rk{AdQ(jb#Vrx7O_7GG>EhaJL3 z#V`4v-98lbkyQ$oSZ1_09DFXDub274p@Y12f5~FQxK?L=mAe;GrEutPg-`+ZFhMW<@OKzx(`hb*v6s6D{!}n z1SKK5>Sk(*J`4T5C>P$e=FcLQX^81cmm^xsBEgPyf$h1o)s7e4H$qTL0UQPatL)bOM9h$S3q|}k2+vN}z4klYhrwWb`ymfaxxVo3oSE})Xr-xo; zY8Yf?dbL%$*S{61M;&5fZH~=o#72up0q=pV z>Z{vKt$Ckh?i7#i3vSpzI9L0~`g`w(FPEwNl^coURLyNL2u4_m2#G|$DHX#b@p?wU z{Pz6bJu?awOKQDi1X)xm$4BOhjR=pH;t<2#+XWkYjtw6Ze>cCW)eRdWfdjM!qGD)b z#a>}C#1UlLqw@Q2jX|CRSeFBXx-p!kX<0vz#k5tG@m$+mp=(0lN*JE@B(TQ7AU!`iU=(G*e;|V&cV?^O^lAp+08W<+#Nagre}34A#>7_&vbL&h#n&IB{DF!ez3(dyk*KIZ*kG(C@;OvrO;Vndv#iwd3>k&+GjM zN7>H4>-XB|q6s*oz9>wd`LV4A+0;fVexen4;oLkl=CWBWx$PhyVTc)R>OGJ1$x79) z#+u2E?$O>EDcRtFQY}czk4t}mndzG{_jz;K}gF~z0>lXC=wrY9lZV+Y;WK40ARGWr$S-xr7b0s?pKSQ8XUlv;$=1XNoG z1%iZCkAISh^4vx?XrZ3Dn5CDg`j4$QD-qlKsTOK|2ZV|Nvzq!D5P&{_>z=jfV1E_w z+)3j7bI=Lu!AvS7G*;}n*LAUQ#E97kmp4&G&TNWz)$?)pxodblxEQ?yG$clUHrf;D zRv!DZevv&}{6e*)s06Qtk9uw9GJVguLbN#Py2})1DB^=93B$o1(%ezdd*35Q9Acq$ z+(#2Ifzgb!Se7J%@#BsyG9a zYIgvvNNA>4EgFEIC*gB{7hGLt;8Vt>jp+5IopGv)r=s)?)M?#1xF0X?ItTL;5=-N7 zIhgVGnO;ogf;zvn$iPU227T68DmJ(jRX7_oAaj{#3VAm8(h`5gc^eJOuFeS6wriTzeieB+9w<{i>zZECI0VAr`rkx2Tr_K$>jB6Dv)UvLoOPHkm`5{ z0`K3S0$!=~-*dF2x0@LS>k;E256!0+l;LMDLXJP?`CvnoUj@9j6h_1I@5gl^75i57 zjhZ2^9>5D=!{+mya-FcH2iIC!=f~`(D`AB6)yN$>{8l+})VNK~a4e$aVo_yVwc%Sys)dDi$jQ$+(?00Jj+41 zq|c@fKP!u|G4T0ahM&-I>03a`oSW$RgT!!DEU?o@yXmSwXss(M(Cf5IN;+-4>)=)O zA41v=JbMO?d~1bledei`CIExHyYhR$t5{bu9vZc)oEPt`7QvW#q<$tJqbV-kXAXn5 z=PkLf+Esi-?(tH15h|$x<1dSQ`xPL{Rg^U%`97Lb0*1I>OKwtpdeUhU)(PS$-e6@w z`ScPv;+?aEKDV}mw?9-cW-a!QvtspOKAbXKl+cm*JzL}o{oP044@Pr+yrW&w^ohi?L-O#fk--w>T{{cgrV@=+jRxcO52s#%TcgL0T8< z_O{AneW|#DA|QbXM8nmN&R#~}j6zf!Nf=-RK{gX!1cU%(&B|(;Fu7HS$k?@h{UBhK zUg;14AM}VSX%m_@-P8-aAmC9SG^U!myMq1%t-hTo>-sW)q08xg)*yUujw#2gXAEW- z9WJFt<#E4#qxofu;t|tLihlvjERG%Kt907`SCz%vzrXReRy^ zf6ARfyfotTJv6w?HkZ3)K=T#uGpBHnl7pyG$|mLybhz#``Lp(LNe6z~AvDTn2wgC8 z5=h67n>DR!&L4_2^})8r>$TI6aB8OaFgFf6Hk zOZrbU!E?OZd|hy8Rcc?Q@iTc=_Tqvw+8f?KF|OKpB^?FFZrGOE26-Q=dka${w|l~1 z5?@@G%`?D_yP1(0t0weNB_80P<*cfEkNkxRJw5&%;J+79dn&5~40r*LWOd4YTx{lC zwM=V*`%p+!=I#E}Kt~x#7atkVzjh7YP_q67H!7F??!(f?#yGwN6a6%e1}D64iBg?R zcm&k9vQlTHS1m62?&^s4fUO9hqD9d4Wg+EFpxWq2IhgVFMVK{DkALb4?1u5nrpcyjX; z2DItT)Z99`1I~7eIUAVNO&%&gKb_XhJ?-BMDuhZP9PHtYpTL023O5QPdIKsdklk` zf}ReP+(!a`dg)92-be8Ffpdjy_2BO1)wU};n`RcAyf#qCgXO~P$jq>&$(wXu$6Rzc z1JtnM+MeTBfpULZ-feO1`&-rliQzJOSi>;|?6h&SB`Xs|W$dRjIq7rUyJ7!+UnnKZ zEnc~azP9?ctc5{d`}pjzGwdZw*KAK6E9tG*21>^1Vq;%>66agR>dh~NEd0ug8{oqeQ+AQH#HOq>7b8#s`#*mR-!p0#)Kf$5PTdc3!tN9kP6{8kGGh z>9zfF6Z7z++8P*kshrjG!qtJ`y=gx$m*=qeD(ng~;;X_}EuJIeG}wmUDWAvi;80!P zCN-)UUsT1mqHbi5nj@R82xT_DuO%Pd>FaIb07* zW^RU!)8qC9^R_})c+@8b#>B#aV#oZ~O5SMSliRt+u0$?4Mt4C5+Nq*U%?q|+r6rRz zzp8IuRV#~sSzl}NaaYhTQi5I9B`IkAWW#E;LV zCS|3CE%f-}h22+W)Px>NvxVK6Nh%-tc4_g61vq+r#JQFD!2Kfb=yU4XxR}&9guv2! zsIgAV&1wHJbFXXsPc|X@(Kl|m14oJ~%oXjufED~BzT3P-bjIriD0!eX$lge{=dQlN zekTHF<$+F5@-e!)I=Z7xqth+Y1hG$y2P@uo25S>#C|gL9H;KmEJn2H(d2o86502>VEhUMmngE=`vkcSgRU7OsCTMsna@ zE)7ch;j|^wLLxS3ofLAfzc_9peexZkT~QB7&%?U@5X1?!Quc(L&z6u1-k`4Yw91)! zk?Rdii%~`+euQpD4-3$?UA}dHHCu;h(=IzU5WeUg!wgq4jo93LF}(a1HvdZ42ZII8 zwR)U%Mx>gx^Sx*J=Wy1GsN`KMG_~SdGcq);o_t&nLc3NHKNHc2UqBJeOfp<3o|2bP zA`VcfA5q{52*1e#93)Ya34#QzewkXW*-WMp*pa+k;)sl;y|_ZmpVO-M%zh%}GzN2f zx~SC?2UOvso#px0X8}BjpXW0l^nR9@Cbq((<$5TG4Ms)Yz8)`WZ%r}Junz|3N>(d% zYU&)QoQ(!yC156~>(O(?!-jV90EhIEMbABoxvRN<)j)cz3m$xTtyDrP4ZO9{;y{eJ=7rvjd3ka@CGm2G!j{GL2qT6R@Ro=gy3C!`HVORD8%UU_u)a!{uHg%qF9jR-XH+* ztJJ6Zp_bEb=|pm(^`OlQAqQuGpLl{gXm?j}eW5JCGO!Pza*Tbe!3dRe4}n%tFH!ht zRgBp5Y*`5|=IZ4mTX~o3)I#oIUq4^2;21<({hHWNVvJI4w4}+)DoV40VcV3XAeJEQ z!*S#9&AAsN()@G4WcG@{Wb+s0gHZJS5ZaV+#{p)ppVKZDIRC_>zm@BpiBEFA&20>v z!i8ve`F6E29h&~l#!i1{#;r|UXOk#TPLjgr_?AQM&fVr`F2u}mS}r#W5yIIYk6y7c z&K$E=!~U2RHJvm+3-*$dMvEVR5wtGhEW9;@=1qXFg5GLgX0-lc5A);=BQ57kQG*{A z^S#-N48*_IyOt{@)A?N?uTAil5T{P%r$_IyGiOmODqHuaLq8}i?nZYh(haYX1rsYC zWTFVR(T?%%E2amO4Jc5l^Gw~W=RWV0WFeoANfEDh3wtMF#G35a3NT)h;=*b2{4Quv z>-BR>Ph$J~8THCU02iCOjv%O^c--arpq(8pdK;M!8?@rhVwK+V;O)`-J=n&jk88L& zaR8_=lbruUQPd@l1VG^xM1BK8B70Vd(n7L6o?IPZ7v5~@pNUzKS!oOp;CpK#j$nFE zYl~G9m>h^Mkwb@J6xTnjI#XKyMdH22=-3!9u(qy?KP2gl=JTzHZbA!Q`9p~{w}jXl zso&i9a;|lOnmW9BmLJQfdG6I;smxl+cfL+nGiK)xiWjpJM1P7Ie8!1ye^adL+=cuj zJqwQ211F;cm7R-zCe`fG(Xrokg1Rv+*T&LM7of_% zgPKkl6Oj0h;O`KqJ&K+$w?=MC42?(DH+S|Hd?ET09o=of;kGITmp|;?PJM2eTzyx^ zN0-dv%gp1h`OlUG-~kW|@Fz-YcyQv($SfCK>;B>6)HpSbY(MQ#@eMI198CVM`YZ2i zr5i!Za{pB;%*V-UrFJ3C_e2n)$5eJC<8vy&!&!fBo`fF19n0M0 zB`ZBzJTFeuHosNvL{a_+%2bW&OQldPR)nx3#<2FFl#~2=#4$g4L3N`tm5Hcgo?x_7SQ*mm*U< zqOo@`)1)Z!A1xAJM8$*bE$3)KO6~G^t0VvXc!u=59}X1}zmShaUy8(g)>qJrap3KweZT^}BuX;+pcsfT8oH!s)| z_8#NepPqmX8$f>;zL+f>mx?uq)mA8ZR@Z>iS@}3*CW{<)Wdi@c?N2nhOIgtjzN?+( z)PKEOIT5d~59==UMUDdmih?bs@-GMR>TRyuRJftf86$2EUX_-%Xmsx2A_$+$V>`u9 z&L@}VPQRL|n@Q_j!?=*Ezly92n>`zgO_Y{BH0&((=XG^>edu9UgiXJU451s8c2CJ~ z{?Gn$>O~~#Y2AS>znZi17SkxWaZ6TU)0cd`O6rhp#rmOlkFjNe66HD5NlecKAd#6A z$^P+IGhnmtxgQ%VeIIR=q>OwEMYho-BbKlT^{@)|anxtp9nKD|INBZiJwiDiSXj_& zB6*XrC##0x7__6dZG-k^&0spx@woL6`|<|ciQ?aNQb!@>=>z1PI;YaC9Gjk7p^HkPTx z4=uruuzkiYGdW9l{w>AD77hy}*k+1oLiTWjM*p7e{Io0yz17>2f6q!U)}@CfujlYx zI#tic+@-^2-H;j3T9Msa#+$eA`U&@Hh41ZsVe3i9w9nyu&DXe~vTb?!~t z!A;;|U}AN=CeqnbJ=a{%NxTW6Bl|84Oy)(Zmv-r{luCAKrtOjXsja7EK_bS-Yy(=? z_!ZvGmg;coQ9|xDabd*a8wF27fJ|=#-z2w5_2Pw z)1mnlN&nq_5A9KK#&JSN`a@M*ByCH1*MnRShJ|FrWA!Q9hEFDD^?V#2)R9R$vCCMf zj^wT{>1iLRt$qM*2#~aq(HELO8Hoy|%Q*-~x1(muKuGouf5<$fFhtbhBLTsOz9*fO zaTMLAAmO~jd>8N>uDL5qdf?oQj2svNQUj)$c=MIJ=|>uC`HBj73&{}^02W4hi3erR zv2#YJ&p}55Qjv@O8)f-K!Ppb0>~g#4XhzAoQCp6NJ53A`@17x@&=EjxW0fOiaExlG z8Bw?y_6}dht}Gby4GsIFseYPI^c3y)vvC)&eXv|y;nNm^O#A=e1AOoi-J9w5gT)_@ SW2BlAMMX(Nu~Hrq_WuE7@@N47 literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift index 1bd3d740..bb79640f 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift @@ -94,6 +94,7 @@ public enum Assets: String { case home_background case icon_airplane case icon_push_bee + case icon_send_card case icon_certificated case icon_failed case icon_flower_seed @@ -140,6 +141,7 @@ public enum Assets: String { case icon_challenge_progress case icon_title_arrow case update_icon + case img_send_card_tooltip public var image: UIImage { return .init(named: self.rawValue, in: Bundle.module, with: nil)! diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift index acb6e1dc..8135d8fa 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift @@ -56,7 +56,7 @@ final public class SpeechBubbleView: UIView { self.tailImageView.image = UIImage.asset(.icon_bubble_tail_my) case .exit: self._backgroundColor = UIColor.second01 - self.tailImageView.image = UIImage(resource: .iconBubbleTailExit) +// self.tailImageView.image = UIImage(resource: .iconBubbleTailExit) self.tailCoordinate = 1.7 } self.layout() diff --git a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift index d5a404e5..73162c6a 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift @@ -34,6 +34,8 @@ protocol HomeBusinessLogic { func didTapMyFlower() async /// 찌르기 버튼 클릭 func didTapStickButton() async + /// 카드 보내기 버튼 클릭 + func didTapCardSendButton() async /// 챌린지 정보 클릭 func didTapChallengeInfo() async /// 설명서 버튼 클릭 @@ -237,6 +239,15 @@ extension HomeInteractor { } } +// MARK: - Feature (공유하기) + +extension HomeInteractor { + + func didTapCardSendButton() async { + + } +} + // MARK: Feature (인증) extension HomeInteractor { diff --git a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift index 4e366e8f..7e2f5925 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift @@ -183,6 +183,10 @@ enum Home { var isHeartHidden: Bool /// 찌르기 텍스트 var stickText: String + /// 카드 보내기 유도 툴팁 히든 여부 + var isCardSendTooltipHidden: Bool + /// 카드 보내기 히든 여부 + var isCardSendHidden: Bool /// 챌린지 정보 struct ChallengeInfoViewModel { diff --git a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift index 70605499..9192f346 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift @@ -39,6 +39,8 @@ protocol HomePresentationLogic { func presentCompleteRequestError(error: Error) /// 찌르기 횟수 초과 오류를 보여준다. func presentExceededStickCountError() + /// 인증 성공 공유하기 모달을 보여준다. + func presentCertificationSharePopup() } final class HomePresenter { @@ -117,6 +119,10 @@ extension HomePresenter: HomePresentationLogic { func presentExceededStickCountError() { self.viewController?.displayToast(viewModel: .init(message: "오늘의 콕 찌르기가 다 소진되었어요 ㅠㅜ")) } + + func presentCertificationSharePopup() { + // TODO + } } // MARK: - Mapping Logic @@ -171,7 +177,9 @@ extension Home.Model.Challenge { topViewModel: .init(isHiddenCetificationGuideText: false, isCertificationButtonHidden: false, cetificationGuideText: "", isComplimentCommentHidden: false, complimentCommentText: ""), myNameText: ""), isHeartHidden: false, - stickText: "" + stickText: "", + isCardSendTooltipHidden: true, + isCardSendHidden: true ) // 챌린지 정보 매핑 @@ -211,6 +219,9 @@ extension Home.Model.Challenge { viewModel.myFlower.topViewModel.complimentCommentText = self.partnerInfo.todayCert?.complimentComment ?? "" viewModel.myFlower.myNameText = self.myInfo.nickname + // 찌르기 텍스트 + viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/5)" + // 챌린지 진행 상태 매핑 switch self.status { case .inProgress(let inProgressStatus): @@ -242,14 +253,14 @@ extension Home.Model.Challenge { viewModel.myFlower.topViewModel.isComplimentCommentHidden = false viewModel.partnerFlower.topViewModel.isComplimentCommentHidden = false viewModel.isHeartHidden = false + viewModel.stickText = "카드 보내기" + viewModel.isCardSendTooltipHidden = false + viewModel.isCardSendHidden = false } default: break } - // 찌르기 텍스트 - viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/5)" - return viewModel } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift index 97b2f04e..5c82365f 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift @@ -485,6 +485,11 @@ extension HomeViewController: ChallengeInProgressViewDelegate{ } } + func didTapCardSendButton() { + Task { + await self.interactor.didTapCardSendButton() + } + } } extension HomeViewController: ChallengeCompletedViewDelegate, TTFlowerPopupDelegate { diff --git a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift index c76c8fae..d40de720 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift +++ b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift @@ -12,6 +12,7 @@ protocol ChallengeInProgressViewDelegate: AnyObject { func didTapCertificateButton() func didTapMyFlowerEmptySpeechBubbleView() func didTapStickButton() + func didTapCardSendButton() func didTapChallengeInfo() } @@ -84,6 +85,21 @@ final class ChallengeInProgressView: UIView { v.textAlignment = .center return v }() + /// 카드 보내기 버튼 + lazy var cardSendButton: UIButton = { + let v = UIButton() + v.setImage(.asset(.icon_send_card), for: .normal) + v.addAction { [weak self] in + self?.delegate?.didTapCardSendButton() + } + return v + }() + /// 카드 보내기 버튼 유도 툴팁 + lazy var cardSendButtonTooltip: UIImageView = { + let v = UIImageView() + v.image = .asset(.img_send_card_tooltip) + return v + }() // MARK: - Method override init(frame: CGRect) { @@ -105,7 +121,10 @@ final class ChallengeInProgressView: UIView { self.myFlowerView, self.heartImage, self.nudgeBeeButton, - self.nudgeTitleLabel) + self.nudgeTitleLabel, + self.cardSendButton, + self.cardSendButtonTooltip + ) self.topChallengeInfoView.snp.makeConstraints { make in make.top.equalToSuperview() @@ -173,6 +192,18 @@ final class ChallengeInProgressView: UIView { make.bottom.equalToSuperview().offset(-beeButtonBottomOffset) } + self.cardSendButton.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.width.height.equalTo(beeButtonWidthHeight) + make.bottom.equalTo(self.nudgeTitleLabel.snp.top).offset(-8) + } + + self.cardSendButtonTooltip.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalTo(self.cardSendButton.snp.top).offset(-14) + make.width.equalTo(149) + make.height.equalTo(60) + } } func configure(viewModel: Home.ViewModel.ChallengeInProgressViewModel) { @@ -187,6 +218,8 @@ final class ChallengeInProgressView: UIView { self.myFlowerTopView.configureInProgress(viewModel: viewModel.myFlower.topViewModel) self.heartImage.isHidden = viewModel.isHeartHidden self.nudgeTitleLabel.text = viewModel.stickText + self.cardSendButton.isHidden = viewModel.isCardSendHidden + self.cardSendButtonTooltip.isHidden = viewModel.isCardSendTooltipHidden } } diff --git a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift index 6c777d3f..450a8abf 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift @@ -682,6 +682,19 @@ final class HomeInteractorSpec: QuickSpec { } } } + + describe("공유하기") { + context("카드 보내기 버튼을 클릭하였을 때") { + beforeEach { + await interactor.didTapCardSendButton() + } + + it("인증 성공 공유하기 팝업이 표출된다.") { + let isPresentCertificationSharePopupCalled = await presenter.isPresentCertificationSharePopupCalled + expect(isPresentCertificationSharePopupCalled).to(beTrue()) + } + } + } } } @@ -701,6 +714,7 @@ class HomePresenterMock: HomePresentationLogic { var isPresentHomeErrorCalled = false var isPresentCompleteRequestErrorCalled = false var isPresentExceededStickCountErrorCalled = false + var isPresentCertificationSharePopupCalled = false var lastChallenge: Home.Model.Challenge? var lastHomeError: Error? @@ -771,6 +785,10 @@ class HomePresenterMock: HomePresentationLogic { func presentExceededStickCountError() { self.isPresentExceededStickCountErrorCalled = true } + + func presentCertificationSharePopup() { + self.isPresentCertificationSharePopupCalled = true + } } class HomeWorkerMock: HomeWorkerProtocol { From 2e0bdebc1e410e8156983ca41fb5eac57a2a4876 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Sun, 14 Jan 2024 13:58:36 +0900 Subject: [PATCH 26/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EB=85=B8=EC=B6=9C=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scene/HomeScene/Sources/HomeScene/HomePresenter.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift index 9192f346..35e4c0e6 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift @@ -253,14 +253,19 @@ extension Home.Model.Challenge { viewModel.myFlower.topViewModel.isComplimentCommentHidden = false viewModel.partnerFlower.topViewModel.isComplimentCommentHidden = false viewModel.isHeartHidden = false - viewModel.stickText = "카드 보내기" - viewModel.isCardSendTooltipHidden = false - viewModel.isCardSendHidden = false } default: break } + // 카드 보내기 활성화 여부 + if !(self.partnerInfo.todayCert?.complimentComment ?? "").isEmpty, + !(self.myInfo.todayCert?.complimentComment ?? "").isEmpty { + viewModel.stickText = "카드 보내기" + viewModel.isCardSendTooltipHidden = false + viewModel.isCardSendHidden = false + } + return viewModel } From e88e4154fd23202772e38e55c800ec678da6bf17 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Sun, 14 Jan 2024 14:02:17 +0900 Subject: [PATCH 27/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20=EC=B0=8C?= =?UTF-8?q?=EB=A5=B4=EA=B8=B0=20=EC=B5=9C=EB=8C=80=20=ED=9A=9F=EC=88=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(5=20->=203)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scene/HomeScene/Sources/HomeScene/HomePresenter.swift | 2 +- Scene/HomeScene/Sources/HomeScene/HomeRouter.swift | 2 +- Scene/HomeScene/Sources/HomeScene/HomeWorker.swift | 2 +- .../Mapping/ChallengeInProgressMappingSpec.swift | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift index 35e4c0e6..dabcf3b4 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift @@ -220,7 +220,7 @@ extension Home.Model.Challenge { viewModel.myFlower.myNameText = self.myInfo.nickname // 찌르기 텍스트 - viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/5)" + viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/3)" // 챌린지 진행 상태 매핑 switch self.status { diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index 6977c110..02f58b7a 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -89,7 +89,7 @@ extension HomeRouter: HomeRoutingLogic { return } let nudgeSendScene = NudgeSendSceneFactory().make( - with: .init(remainingNudgeCount: dataStore.challenge?.stickRemaining ?? 5) + with: .init(remainingNudgeCount: dataStore.challenge?.stickRemaining ?? 3) ) self.viewController?.present(nudgeSendScene.bottomSheetViewController, animated: true) } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift index b517a050..d7b8a76f 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift @@ -116,7 +116,7 @@ final class HomeWorker: HomeWorkerProtocol { status: challengeStatus, myInfo: myInfo, partnerInfo: partnerInfo, - stickRemaining: 5 - (homeResponse.myStingCnt ?? 0), + stickRemaining: 3 - (homeResponse.myStingCnt ?? 0), description: homeResponse.onGoingChallenge?.description ) diff --git a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift index 122d1cea..27334e78 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift @@ -34,7 +34,7 @@ final class ChallengeInProgressMappingSpec: QuickSpec { certCount: 1, todayCert: .init(id: "certId", complimentComment: "Test") ), - stickRemaining: 5 + stickRemaining: 3 ) viewModel = model.toChallengeInProgressViewModel() @@ -283,8 +283,8 @@ final class ChallengeInProgressMappingSpec: QuickSpec { } context("찌르기 남은 횟수") { - it("찌르기 텍스트가 '콕 찌르기 (5/5)'로 표현된다.") { - expect(viewModel.stickText).to(equal("콕 찌르기 (5/5)")) + it("찌르기 텍스트가 '콕 찌르기 (3/3)'로 표현된다.") { + expect(viewModel.stickText).to(equal("콕 찌르기 (3/3)")) } } } From 54eabeeef7b0228a77d45dc0015a99d4e50f3b77 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Sun, 14 Jan 2024 14:03:19 +0900 Subject: [PATCH 28/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20=EC=B0=8C?= =?UTF-8?q?=EB=A5=B4=EA=B8=B0=20=ED=99=94=EB=A9=B4=20=EC=B0=8C=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=B5=9C=EB=8C=80=20=ED=9A=9F=EC=88=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/HomeScene/Views/ChallengeInProgressView.swift | 2 +- .../Sources/NudgeSendScene/NudgeSendPresenter.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift index d40de720..fe460699 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift +++ b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift @@ -79,7 +79,7 @@ final class ChallengeInProgressView: UIView { /// 찌르기 버튼 타이틀 lazy var nudgeTitleLabel: UILabel = { let v = UILabel() - v.text = "콕 찌르기 (5/5)" + v.text = "콕 찌르기 (3/3)" v.textColor = .primary v.font = .body2 v.textAlignment = .center diff --git a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift index 498efdf4..0940a946 100644 --- a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift +++ b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift @@ -33,7 +33,7 @@ extension NudgeSendPresenter: NudgeSendPresentationLogic { func presentRemainingNudgeCount(remainingNudgeCount: Int) { self.viewController?.displayTitle(viewModel: .init( - text: "찌르기 문구 보내기 (\(remainingNudgeCount)/5)" + text: "찌르기 문구 보내기 (\(remainingNudgeCount)/3)" )) } From 2d66f4f4be940a9ed49306f738c4d2b7cc6339ab Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Sun, 14 Jan 2024 14:17:05 +0900 Subject: [PATCH 29/44] =?UTF-8?q?=E2=9C=A8=20=ED=9E=88=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EB=94=94=ED=85=8C=EC=9D=BC=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20=EC=8B=A4=ED=8C=A8=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailInteractor.swift | 2 +- .../ChallengeHistoryDetailModels.swift | 4 ++++ .../ChallengeHistoryDetailPresenter.swift | 10 ++++++++-- .../ChallengeHistoryDetailViewController.swift | 8 +++++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift index d374e75a..05c72b20 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift @@ -69,7 +69,7 @@ extension ChallengeHistoryDetailInteractor { self.detail = challenge await self.presenter.presentChallengeDetail(detail: self.detail) } catch { - print("히스토리 디테일 가져오기 실패했습니다.") + await self.presenter.presentHistoryDetailError(error: error) } } } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift index e7e18b64..6a874eed 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailModels.swift @@ -71,5 +71,9 @@ enum ChallengeHistoryDetail { struct Photo { var images: [SKPhoto] } + + struct Toast { + var message: String? + } } } diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift index d9e69d01..e0f78e0d 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailPresenter.swift @@ -13,7 +13,9 @@ import SKPhotoBrowser protocol ChallengeHistoryDetailPresentationLogic { func presentChallengeDetail(detail: ChallengeHistoryDetail.Model.ChallengeDetail) func presentPhoto(imageUrl: String) - + /// 챌린지 디테일 정보 오류를 보여준다. + func presentHistoryDetailError(error: Error) + } final class ChallengeHistoryDetailPresenter { @@ -38,7 +40,11 @@ extension ChallengeHistoryDetailPresenter: ChallengeHistoryDetailPresentationLog images.append(photo) self.viewController?.displayPhoto(photo: .init(images: images)) } - + + func presentHistoryDetailError(error: Error) { + self.viewController?.displayToast(viewModel: .init(message: "히스토리 디테일 정보를 가져오는데 실패했습니다.")) + } + // model -> viewModel private func map(_ model: ChallengeHistoryDetail.Model.ChallengeDetail) -> (ChallengeHistoryDetail.ViewModel.Challenge, diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift index cd0c65aa..58e5d2f7 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailViewController.swift @@ -14,6 +14,7 @@ protocol ChallengeHistoryDetailDisplayLogic: AnyObject { func displayCertification(certification: ChallengeHistoryDetail.ViewModel.Challenge) func displayCompliment(compliment: ChallengeHistoryDetail.ViewModel.Compliment) func displayPhoto(photo: ChallengeHistoryDetail.ViewModel.Photo) + func displayToast(viewModel: ChallengeHistoryDetail.ViewModel.Toast) } final class ChallengeHistoryDetailViewController: UIViewController { @@ -108,7 +109,6 @@ final class ChallengeHistoryDetailViewController: UIViewController { let v = TTPrimaryButton.create(title: "칭찬하기", .large) v.addAction { [weak self] in Task { - try await Task.sleep(nanoseconds: 100000000) await self?.interactor.didTapPraiseButton() } } @@ -309,4 +309,10 @@ extension ChallengeHistoryDetailViewController: ChallengeHistoryDetailDisplayLog browser.initializePageIndex(0) self.present(browser, animated: true, completion: {}) } + + func displayToast(viewModel: ChallengeHistoryDetail.ViewModel.Toast) { + viewModel.message.unwrap { + Toast.shared.makeToast($0) + } + } } From 04c4e76df08869a99ba2ff0425d215f49683bef2 Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Sun, 14 Jan 2024 14:50:50 +0900 Subject: [PATCH 30/44] =?UTF-8?q?=F0=9F=90=9B=20SE=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=8B=89=EB=84=A4=EC=9E=84=20=EB=B3=80=EA=B2=BD=20=EC=8B=9C=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=A7=A4=EB=A6=AC=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChangeNicknameScene/ChangeNicknameViewController.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift b/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift index 5175ecea..83564644 100644 --- a/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift +++ b/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift @@ -176,6 +176,12 @@ extension ChangeNicknameViewController: KeyboardDelegate { func willShowKeyboard(keyboardFrame: CGRect, duration: Double) { UIView.animate(withDuration: duration) { + if UIDevice.current.deviceType == .default { + self.descriptionLabel.snp.updateConstraints { make in + make.bottom.equalTo(self.nicknameTextField.snp.top).offset(-10) + } + } + self.changeButton.snp.updateConstraints { make in make.bottom.equalTo(self.view.safeAreaLayoutGuide).inset(keyboardFrame.height + 20) } From 9496a9bd8f6043424a137cc7649eb224f6e1664e Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Sun, 14 Jan 2024 15:18:03 +0900 Subject: [PATCH 31/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=9D=B4=EC=83=81=ED=95=9C=20=EC=A1=B0=EA=B1=B4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailInteractor.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift index 05c72b20..b7c22e37 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailInteractor.swift @@ -97,7 +97,7 @@ extension ChallengeHistoryDetailInteractor { extension ChallengeHistoryDetailInteractor { func didTapPraiseButton() async { - if self.detail.complicateComment?.isEmpty != nil { + if (self.detail.complicateComment ?? "").isEmpty { await self.router.routeToPraiseSendScene() } } From e50166b5a8bb6c6ad49ff2a03377e95836052c20 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Sun, 14 Jan 2024 16:51:01 +0900 Subject: [PATCH 32/44] =?UTF-8?q?=F0=9F=90=9B=20=EA=BD=83=20=EB=85=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=A1=B0=EA=B1=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scene/HomeScene/Sources/HomeScene/HomeWorker.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift index d7b8a76f..00c3fdb6 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift @@ -211,9 +211,9 @@ final class HomeWorker: HomeWorkerProtocol { case 10...15: return .peak case 16...21: - return .bloom - case 22: return .flower + case 22: + return .bloom default: return nil } From f0aa84bd8473a09acc58e5377a1878b830e98de4 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Sun, 14 Jan 2024 16:51:33 +0900 Subject: [PATCH 33/44] =?UTF-8?q?=E2=9C=A8=20=EC=B1=8C=EB=A6=B0=EC=A7=80?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EB=B0=8F=20=EC=B9=AD=EC=B0=AC=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=ED=9B=84=20=EC=B9=B4=EB=93=9C=20=EB=B3=B4?= =?UTF-8?q?=EB=82=B4=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Util/Constants/DateFormatType.swift | 1 + .../Sources/Util/Extensions/String+.swift | 2 + .../Sources/HomeScene/HomeInteractor.swift | 5 +- .../Sources/HomeScene/HomeModels.swift | 10 +- .../Sources/HomeScene/HomePresenter.swift | 12 +- .../HomeScene/HomeViewController.swift | 59 +++++ .../Common/TTCertificationSharePopup.swift | 212 ++++++++++++++++++ .../HomeSceneTests/HomeInteractorSpec.swift | 2 +- 8 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift diff --git a/Core/Util/Sources/Util/Constants/DateFormatType.swift b/Core/Util/Sources/Util/Constants/DateFormatType.swift index 5d5da976..87fd34ee 100644 --- a/Core/Util/Sources/Util/Constants/DateFormatType.swift +++ b/Core/Util/Sources/Util/Constants/DateFormatType.swift @@ -14,6 +14,7 @@ public enum DateFormatType: String { case hourMinute = "HH:mm" case iso = "yyyy-MM-dd'T'HH:mm:ss.SSZ" case hangleYearMonthDay = "yyyy년 MM월 dd일" + case monthDayE = "M월 d일 (E)" var displayName: String { diff --git a/Core/Util/Sources/Util/Extensions/String+.swift b/Core/Util/Sources/Util/Extensions/String+.swift index fb01c480..3fd41643 100644 --- a/Core/Util/Sources/Util/Extensions/String+.swift +++ b/Core/Util/Sources/Util/Extensions/String+.swift @@ -31,6 +31,8 @@ public extension String { return "yyyy-MM-dd'T'HH:mm:ss.SSZ" case .hangleYearMonthDay: return "yyyy년 MM월 dd일" + case .monthDayE: + return "M월 d일 (E)" } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift index 73162c6a..fb0e1b6b 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift @@ -244,7 +244,10 @@ extension HomeInteractor { extension HomeInteractor { func didTapCardSendButton() async { - + guard let challenge = self.challenge else { + return + } + await self.presenter.presentCertificationSharePopup(challenge: challenge) } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift index 7e2f5925..d11a7c16 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift @@ -379,9 +379,17 @@ enum Home { } } + struct CertificationSharePopupViewModel { + /// 냘짜 텍스트 + var dateText: String + /// 챌린지 명 타이틀 텍스트 + var titleNameText: String + /// 진행도 텍스트 + var progressText: String + } + struct Toast { var message: String? } - } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift index dabcf3b4..34dd440d 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift @@ -40,7 +40,7 @@ protocol HomePresentationLogic { /// 찌르기 횟수 초과 오류를 보여준다. func presentExceededStickCountError() /// 인증 성공 공유하기 모달을 보여준다. - func presentCertificationSharePopup() + func presentCertificationSharePopup(challenge: Home.Model.Challenge) } final class HomePresenter { @@ -120,8 +120,14 @@ extension HomePresenter: HomePresentationLogic { self.viewController?.displayToast(viewModel: .init(message: "오늘의 콕 찌르기가 다 소진되었어요 ㅠㅜ")) } - func presentCertificationSharePopup() { - // TODO + func presentCertificationSharePopup(challenge: Home.Model.Challenge) { + let percentageText = challenge.calculatePercentageText(certCount: challenge.myInfo.certCount ?? 0) + let viewModel = Home.ViewModel.CertificationSharePopupViewModel( + dateText: Date().dateToString(.monthDayE), + titleNameText: challenge.name ?? "", + progressText: "\(percentageText) 달성중 인증완료" + ) + self.viewController?.displayCertificationSharePopupViewModel(viewModel: viewModel) } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift index 5c82365f..884499e1 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift @@ -19,6 +19,7 @@ protocol HomeDisplayLogic: AnyObject { func displayChallengeCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel) func displayBothCertificationViewModel(viewModel: Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel) func displayCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel.CompletedPopupViewModel) + func displayCertificationSharePopupViewModel(viewModel: Home.ViewModel.CertificationSharePopupViewModel) func displayToast(viewModel: Home.ViewModel.Toast) } @@ -38,6 +39,7 @@ final class HomeViewController: UIViewController { var bothCertificationPopupView: TTPopup? var completedPopupView: TTPopup? var flowerLanguagePopupView: TTFlowerPopup? + var certificationSharePopupView: TTCertificationSharePopup? // MARK: - UI Component /// 네비게이션 바 @@ -384,6 +386,45 @@ extension HomeViewController: HomeDisplayLogic { } } + func displayCertificationSharePopupViewModel(viewModel: Home.ViewModel.CertificationSharePopupViewModel) { + // Pre Condition + let y = 217 + self.view.safeAreaInsets.top + let height = 354.0 + + let isNudgeBeeButtonHidden = self.inProgressView.nudgeBeeButton.isHidden + let isNudgeTitleLabelHidden = self.inProgressView.nudgeTitleLabel.isHidden + let isCardSendButtonHidden = self.inProgressView.cardSendButton.isHidden + let isCardSendButtonTooltipHidden = self.inProgressView.cardSendButtonTooltip.isHidden + self.inProgressView.nudgeBeeButton.isHidden = true + self.inProgressView.nudgeTitleLabel.isHidden = true + self.inProgressView.cardSendButton.isHidden = true + self.inProgressView.cardSendButtonTooltip.isHidden = true + + + // Crop Imge + let renderer = UIGraphicsImageRenderer(bounds: .init(x: 0, y: y, width: self.view.bounds.width, height: height)) + + let image = renderer.image { ctx in + self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: true) + } + + self.inProgressView.nudgeBeeButton.isHidden = isNudgeBeeButtonHidden + self.inProgressView.nudgeTitleLabel.isHidden = isNudgeTitleLabelHidden + self.inProgressView.cardSendButton.isHidden = isCardSendButtonHidden + self.inProgressView.cardSendButtonTooltip.isHidden = isCardSendButtonTooltipHidden + + // Show Popup + let popupView = TTCertificationSharePopup(frame: .zero) + popupView.configure(image: image, viewModel: viewModel) + + self.certificationSharePopupView = popupView + self.certificationSharePopupView?.delegate = self + + if let certificationSharePopupView = self.certificationSharePopupView { + self.view.addSubview(certificationSharePopupView) + } + } + func displayToast(viewModel: Home.ViewModel.Toast) { viewModel.message.unwrap { Toast.shared.makeToast($0) @@ -538,6 +579,24 @@ extension HomeViewController: TTNavigationBarDelegate { } } +extension HomeViewController: TTCertificationSharePopupDelegate { + + func didTapCertificationSharePopupDimView() { + self.certificationSharePopupView?.removeFromSuperview() + self.certificationSharePopupView = nil + } + + func didTapCertificationSharePopupCloseButton() { + self.certificationSharePopupView?.removeFromSuperview() + self.certificationSharePopupView = nil + } + + func didTapCertificationSharePopupShareButton(image: UIImage) { + let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil) + self.present(activityViewController, animated: true) + } +} + extension HomeViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { diff --git a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift new file mode 100644 index 00000000..7d554800 --- /dev/null +++ b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift @@ -0,0 +1,212 @@ +// +// TTCertificationSharePopup.swift +// +// +// Created by 박건우 on 2024/01/14. +// + +import CoreKit +import UIKit + +protocol TTCertificationSharePopupDelegate: AnyObject { + func didTapCertificationSharePopupDimView() + func didTapCertificationSharePopupCloseButton() + func didTapCertificationSharePopupShareButton(image: UIImage) +} + +final class TTCertificationSharePopup: UIView { + + weak var delegate: TTCertificationSharePopupDelegate? + + private lazy var dimView: UIView = { + let v = UIView() + v.backgroundColor = .black.withAlphaComponent(0.5) + v.addTapAction { [weak self] in + self?.delegate?.didTapCertificationSharePopupDimView() + } + return v + }() + + private lazy var headlineLabel: UILabel = { + let v = UILabel() + v.font = .h3 + v.textColor = .white + v.text = "카드를 공유해보세요" + return v + }() + + private lazy var contentView: UIView = { + let v = UIView() + v.backgroundColor = .white + v.layer.cornerRadius = 20 + v.clipsToBounds = true + return v + }() + + private lazy var captureBgView: UIView = { + let v = UIView() + v.layer.cornerRadius = 10 + v.clipsToBounds = true + return v + }() + + private lazy var captureView: UIView = { + let v = UIView() + v.backgroundColor = .second01 + return v + }() + + private lazy var dateLabel: UILabel = { + let v = UILabel() + v.font = .body2 + v.textColor = .black + return v + }() + + private lazy var titleLabel: UILabel = { + let v = UILabel() + v.font = .h3 + v.textColor = .primary + v.lineBreakMode = .byTruncatingTail + return v + }() + + private lazy var captionLabel: UILabel = { + let v = UILabel() + v.font = .body3 + v.textColor = .mainCoral + return v + }() + + private lazy var imageView: UIImageView = { + let v = UIImageView() + v.layer.cornerRadius = 13 + v.clipsToBounds = true + return v + }() + + private lazy var logoLabel: UILabel = { + let v = UILabel() + v.font = .h4 + v.textColor = .mainCoral + v.text = "Twotoo" + return v + }() + + private lazy var shareButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "공유하기", .large) + v.setIsEnabled(true) + v.addAction { [weak self] in + guard let self = self else { + return + } + let image = self.makeImage() + self.delegate?.didTapCertificationSharePopupShareButton(image: image) + } + return v + }() + + private lazy var closeButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "닫기", .large) + v.setTitleColor(.white, for: .normal) + v.backgroundColor = .clear + v.addAction { [weak self] in + self?.delegate?.didTapCertificationSharePopupCloseButton() + } + return v + }() + + override init(frame: CGRect) { + super.init(frame: .zero) + self.layout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func didMoveToSuperview() { + super.didMoveToSuperview() + + if self.superview != nil { + self.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } + } + + func layout() { + self.addSubviews(self.dimView, self.headlineLabel, self.contentView, self.closeButton) + self.contentView.addSubviews(self.captureBgView, self.shareButton) + self.captureBgView.addSubviews(self.captureView) + self.captureView.addSubviews(self.dateLabel, self.titleLabel, self.captionLabel, self.imageView, self.logoLabel) + + self.dimView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + self.headlineLabel.snp.makeConstraints { make in + make.bottom.equalTo(self.contentView.snp.top).offset(-16) + make.centerX.equalToSuperview() + } + self.contentView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(51) + make.centerY.equalToSuperview() + } + self.closeButton.snp.makeConstraints { make in + make.top.equalTo(self.contentView.snp.bottom).offset(10) + make.centerX.equalToSuperview() + } + self.captureBgView.snp.makeConstraints { make in + make.leading.top.trailing.equalToSuperview().inset(13) + } + self.captureView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + self.shareButton.snp.makeConstraints { make in + make.top.equalTo(self.captureView.snp.bottom).offset(7) + make.leading.trailing.bottom.equalToSuperview().inset(11) + } + self.dateLabel.snp.makeConstraints { make in + make.top.equalToSuperview().inset(32) + make.leading.equalToSuperview().inset(17) + } + self.titleLabel.snp.makeConstraints { make in + make.top.equalTo(self.dateLabel.snp.bottom).offset(6) + make.leading.trailing.equalToSuperview().inset(17) + } + self.captionLabel.snp.makeConstraints { make in + make.top.equalTo(self.titleLabel.snp.bottom).offset(7) + make.leading.trailing.equalToSuperview().inset(17) + } + self.logoLabel.snp.makeConstraints { make in + make.top.equalTo(self.imageView.snp.bottom).offset(14) + make.bottom.equalToSuperview().inset(13) + make.leading.trailing.equalToSuperview().inset(17) + } + } + + func configure(image: UIImage, viewModel: Home.ViewModel.CertificationSharePopupViewModel) { + self.imageView.image = image + self.dateLabel.text = viewModel.dateText + self.titleLabel.text = viewModel.titleNameText + self.captionLabel.text = viewModel.progressText + + self.imageView.snp.remakeConstraints { make in + make.top.equalTo(self.captionLabel.snp.bottom).offset(13) + make.leading.trailing.equalToSuperview().inset(17) + make.height.equalTo(self.imageView.snp.width).dividedBy(image.size.width / image.size.height) + } + } + + // MARK: - Business Logic + + private func makeImage() -> UIImage { + let renderer = UIGraphicsImageRenderer(bounds: self.captureView.bounds) + + let image = renderer.image { ctx in + self.captureView.drawHierarchy(in: self.captureView.bounds, afterScreenUpdates: true) + } + + return image + } +} diff --git a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift index 450a8abf..739ed5b7 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift @@ -786,7 +786,7 @@ class HomePresenterMock: HomePresentationLogic { self.isPresentExceededStickCountErrorCalled = true } - func presentCertificationSharePopup() { + func presentCertificationSharePopup(challenge: Home.Model.Challenge) { self.isPresentCertificationSharePopupCalled = true } } From 449b150b43061ecc6cce0c27ea12daf2bcc85ebc Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Sun, 14 Jan 2024 17:32:46 +0900 Subject: [PATCH 34/44] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=ED=82=A4=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20hide=20=EC=8B=9C=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=9E=AC=EC=A1=B0=EC=A0=95=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChangeNicknameScene/ChangeNicknameViewController.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift b/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift index 83564644..a278c757 100644 --- a/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift +++ b/Scene/MyInfoScene/Sources/ChangeNicknameScene/ChangeNicknameViewController.swift @@ -191,6 +191,12 @@ extension ChangeNicknameViewController: KeyboardDelegate { func willHideKeyboard(duration: Double) { UIView.animate(withDuration: duration) { + if UIDevice.current.deviceType == .default { + self.descriptionLabel.snp.updateConstraints { make in + make.bottom.equalTo(self.nicknameTextField.snp.top).offset(-40) + } + } + self.changeButton.snp.updateConstraints { make in make.bottom.equalTo(self.view.safeAreaLayoutGuide).offset(-20) } From 83cacf761cc400ab73f315d1dae706e7129f80a7 Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Mon, 15 Jan 2024 12:14:03 +0900 Subject: [PATCH 35/44] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f0aa84bd8473a09acc58e5377a1878b830e98de4 Author: gunoooo Date: Sun Jan 14 16:51:33 2024 +0900 ✨ 챌린지 인증 및 칭찬 완료 후 카드 보내기 기능 추가 commit e50166b5a8bb6c6ad49ff2a03377e95836052c20 Author: gunoooo Date: Sun Jan 14 16:51:01 2024 +0900 🐛 꽃 노출 조건 수정 commit 54eabeeef7b0228a77d45dc0015a99d4e50f3b77 Author: gunoooo Date: Sun Jan 14 14:03:19 2024 +0900 ♻️ 찌르기 화면 찌르기 최대 횟수 수정 commit e88e4154fd23202772e38e55c800ec678da6bf17 Author: gunoooo Date: Sun Jan 14 14:02:17 2024 +0900 ♻️ 찌르기 최대 횟수 수정 (5 -> 3) commit 2e0bdebc1e410e8156983ca41fb5eac57a2a4876 Author: gunoooo Date: Sun Jan 14 13:58:36 2024 +0900 ♻️ 카드 보내기 노출 여부 로직 수정 commit db05811c01d265403bfa5f6238f993701371be53 Author: gunoooo Date: Sun Jan 14 13:45:09 2024 +0900 ✨ 카드 보내기 버튼 노출 조건 로직 작업 --- .../icon_send_card.imageset/Contents.json | 23 ++ .../icon_send_card.png | Bin 0 -> 2429 bytes .../icon_send_card@2x.png | Bin 0 -> 6084 bytes .../icon_send_card@3x.png | Bin 0 -> 10953 bytes .../Contents.json | 23 ++ .../img_send_card_tooltip.png | Bin 0 -> 3330 bytes .../img_send_card_tooltip@2x.png | Bin 0 -> 6927 bytes .../img_send_card_tooltip@3x.png | Bin 0 -> 10653 bytes .../DesignSystem/Sources/Assets/Assets.swift | 2 + .../Sources/Component/SpeechBubbleView.swift | 2 +- .../Util/Constants/DateFormatType.swift | 1 + .../Sources/Util/Extensions/String+.swift | 2 + .../Sources/HomeScene/HomeInteractor.swift | 14 ++ .../Sources/HomeScene/HomeModels.swift | 14 +- .../Sources/HomeScene/HomePresenter.swift | 28 ++- .../Sources/HomeScene/HomeRouter.swift | 2 +- .../HomeScene/HomeViewController.swift | 64 ++++++ .../Sources/HomeScene/HomeWorker.swift | 6 +- .../Views/ChallengeInProgressView.swift | 37 ++- .../Common/TTCertificationSharePopup.swift | 212 ++++++++++++++++++ .../HomeSceneTests/HomeInteractorSpec.swift | 18 ++ .../ChallengeInProgressMappingSpec.swift | 6 +- .../NudgeSendScene/NudgeSendPresenter.swift | 2 +- 23 files changed, 441 insertions(+), 15 deletions(-) create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@2x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@3x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@2x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@3x.png create mode 100644 Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json new file mode 100644 index 00000000..bcecb460 --- /dev/null +++ b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "icon_send_card.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icon_send_card@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icon_send_card@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card.png new file mode 100644 index 0000000000000000000000000000000000000000..df4b8d91ba34a7aa1018c4ec213e6b0540bdfae2 GIT binary patch literal 2429 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 KMNUMnLSTaM<&_8k literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@3x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/icon_send_card.imageset/icon_send_card@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..13e1a160275ab103d0b2de453425cfb8ef4f10d3 GIT binary patch literal 10953 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 literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@2x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/main_icon/img_send_card_tooltip.imageset/img_send_card_tooltip@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..de0d6d9d0b87895139b9f8be867a855381d19141 GIT binary patch literal 6927 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 SW2BlAMMX(Nu~Hrq_WuE7@@N47 literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift index 1bd3d740..bb79640f 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift @@ -94,6 +94,7 @@ public enum Assets: String { case home_background case icon_airplane case icon_push_bee + case icon_send_card case icon_certificated case icon_failed case icon_flower_seed @@ -140,6 +141,7 @@ public enum Assets: String { case icon_challenge_progress case icon_title_arrow case update_icon + case img_send_card_tooltip public var image: UIImage { return .init(named: self.rawValue, in: Bundle.module, with: nil)! diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift index acb6e1dc..8135d8fa 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Component/SpeechBubbleView.swift @@ -56,7 +56,7 @@ final public class SpeechBubbleView: UIView { self.tailImageView.image = UIImage.asset(.icon_bubble_tail_my) case .exit: self._backgroundColor = UIColor.second01 - self.tailImageView.image = UIImage(resource: .iconBubbleTailExit) +// self.tailImageView.image = UIImage(resource: .iconBubbleTailExit) self.tailCoordinate = 1.7 } self.layout() diff --git a/Core/Util/Sources/Util/Constants/DateFormatType.swift b/Core/Util/Sources/Util/Constants/DateFormatType.swift index 5d5da976..87fd34ee 100644 --- a/Core/Util/Sources/Util/Constants/DateFormatType.swift +++ b/Core/Util/Sources/Util/Constants/DateFormatType.swift @@ -14,6 +14,7 @@ public enum DateFormatType: String { case hourMinute = "HH:mm" case iso = "yyyy-MM-dd'T'HH:mm:ss.SSZ" case hangleYearMonthDay = "yyyy년 MM월 dd일" + case monthDayE = "M월 d일 (E)" var displayName: String { diff --git a/Core/Util/Sources/Util/Extensions/String+.swift b/Core/Util/Sources/Util/Extensions/String+.swift index fb01c480..3fd41643 100644 --- a/Core/Util/Sources/Util/Extensions/String+.swift +++ b/Core/Util/Sources/Util/Extensions/String+.swift @@ -31,6 +31,8 @@ public extension String { return "yyyy-MM-dd'T'HH:mm:ss.SSZ" case .hangleYearMonthDay: return "yyyy년 MM월 dd일" + case .monthDayE: + return "M월 d일 (E)" } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift index beeb9964..58784b68 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift @@ -28,6 +28,8 @@ protocol HomeBusinessLogic { func didTapMyFlower() async /// 찌르기 버튼 클릭 func didTapStickButton() async + /// 카드 보내기 버튼 클릭 + func didTapCardSendButton() async /// 챌린지 정보 클릭 func didTapChallengeInfo() async /// 설명서 버튼 클릭 @@ -225,6 +227,18 @@ extension HomeInteractor { } } +// MARK: - Feature (공유하기) + +extension HomeInteractor { + + func didTapCardSendButton() async { + guard let challenge = self.challenge else { + return + } + await self.presenter.presentCertificationSharePopup(challenge: challenge) + } +} + // MARK: Feature (인증) extension HomeInteractor { diff --git a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift index e8b6e4e5..e0a7528d 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift @@ -189,6 +189,10 @@ enum Home { var isHeartHidden: Bool /// 찌르기 텍스트 var stickText: String + /// 카드 보내기 유도 툴팁 히든 여부 + var isCardSendTooltipHidden: Bool + /// 카드 보내기 히든 여부 + var isCardSendHidden: Bool /// 챌린지 정보 struct ChallengeInfoViewModel { @@ -365,9 +369,17 @@ enum Home { } } + struct CertificationSharePopupViewModel { + /// 냘짜 텍스트 + var dateText: String + /// 챌린지 명 타이틀 텍스트 + var titleNameText: String + /// 진행도 텍스트 + var progressText: String + } + struct Toast { var message: String? } - } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift index 346d3a00..213d1c95 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift @@ -35,6 +35,8 @@ protocol HomePresentationLogic { func presentCompleteRequestError(error: Error) /// 찌르기 횟수 초과 오류를 보여준다. func presentExceededStickCountError() + /// 인증 성공 공유하기 모달을 보여준다. + func presentCertificationSharePopup(challenge: Home.Model.Challenge) } final class HomePresenter { @@ -105,6 +107,16 @@ extension HomePresenter: HomePresentationLogic { func presentExceededStickCountError() { self.viewController?.displayToast(viewModel: .init(message: "오늘의 콕 찌르기가 다 소진되었어요 ㅠㅜ")) } + + func presentCertificationSharePopup(challenge: Home.Model.Challenge) { + let percentageText = challenge.calculatePercentageText(certCount: challenge.myInfo.certCount ?? 0) + let viewModel = Home.ViewModel.CertificationSharePopupViewModel( + dateText: Date().dateToString(.monthDayE), + titleNameText: challenge.name ?? "", + progressText: "\(percentageText) 달성중 인증완료" + ) + self.viewController?.displayCertificationSharePopupViewModel(viewModel: viewModel) + } } // MARK: - Mapping Logic @@ -159,7 +171,9 @@ extension Home.Model.Challenge { topViewModel: .init(isHiddenCetificationGuideText: false, isCertificationButtonHidden: false, cetificationGuideText: "", isComplimentCommentHidden: false, complimentCommentText: ""), myNameText: ""), isHeartHidden: false, - stickText: "" + stickText: "", + isCardSendTooltipHidden: true, + isCardSendHidden: true ) // 챌린지 정보 매핑 @@ -199,6 +213,9 @@ extension Home.Model.Challenge { viewModel.myFlower.topViewModel.complimentCommentText = self.partnerInfo.todayCert?.complimentComment ?? "" viewModel.myFlower.myNameText = self.myInfo.nickname + // 찌르기 텍스트 + viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/3)" + // 챌린지 진행 상태 매핑 switch self.status { case .inProgress(let inProgressStatus): @@ -235,8 +252,13 @@ extension Home.Model.Challenge { break } - // 찌르기 텍스트 - viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/5)" + // 카드 보내기 활성화 여부 + if !(self.partnerInfo.todayCert?.complimentComment ?? "").isEmpty, + !(self.myInfo.todayCert?.complimentComment ?? "").isEmpty { + viewModel.stickText = "카드 보내기" + viewModel.isCardSendTooltipHidden = false + viewModel.isCardSendHidden = false + } return viewModel } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index 51993a95..3d98f64d 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -107,7 +107,7 @@ extension HomeRouter: HomeRoutingLogic { return } let nudgeSendScene = NudgeSendSceneFactory().make( - with: .init(remainingNudgeCount: dataStore.challenge?.stickRemaining ?? 5) + with: .init(remainingNudgeCount: dataStore.challenge?.stickRemaining ?? 3) ) self.viewController?.present(nudgeSendScene.bottomSheetViewController, animated: true) } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift index 83184d01..1eeb3e1a 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift @@ -18,6 +18,7 @@ protocol HomeDisplayLogic: AnyObject { func displayChallengeInProgressViewModel(viewModel: Home.ViewModel.ChallengeInProgressViewModel) func displayChallengeCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel) func displayCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel.CompletedPopupViewModel) + func displayCertificationSharePopupViewModel(viewModel: Home.ViewModel.CertificationSharePopupViewModel) func displayToast(viewModel: Home.ViewModel.Toast) } @@ -37,6 +38,7 @@ final class HomeViewController: UIViewController { var bothCertificationPopupView: TTPopup? var completedPopupView: TTPopup? var flowerLanguagePopupView: TTFlowerPopup? + var certificationSharePopupView: TTCertificationSharePopup? // MARK: - UI Component /// 네비게이션 바 @@ -330,6 +332,45 @@ extension HomeViewController: HomeDisplayLogic { } } + func displayCertificationSharePopupViewModel(viewModel: Home.ViewModel.CertificationSharePopupViewModel) { + // Pre Condition + let y = 217 + self.view.safeAreaInsets.top + let height = 354.0 + + let isNudgeBeeButtonHidden = self.inProgressView.nudgeBeeButton.isHidden + let isNudgeTitleLabelHidden = self.inProgressView.nudgeTitleLabel.isHidden + let isCardSendButtonHidden = self.inProgressView.cardSendButton.isHidden + let isCardSendButtonTooltipHidden = self.inProgressView.cardSendButtonTooltip.isHidden + self.inProgressView.nudgeBeeButton.isHidden = true + self.inProgressView.nudgeTitleLabel.isHidden = true + self.inProgressView.cardSendButton.isHidden = true + self.inProgressView.cardSendButtonTooltip.isHidden = true + + + // Crop Imge + let renderer = UIGraphicsImageRenderer(bounds: .init(x: 0, y: y, width: self.view.bounds.width, height: height)) + + let image = renderer.image { ctx in + self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: true) + } + + self.inProgressView.nudgeBeeButton.isHidden = isNudgeBeeButtonHidden + self.inProgressView.nudgeTitleLabel.isHidden = isNudgeTitleLabelHidden + self.inProgressView.cardSendButton.isHidden = isCardSendButtonHidden + self.inProgressView.cardSendButtonTooltip.isHidden = isCardSendButtonTooltipHidden + + // Show Popup + let popupView = TTCertificationSharePopup(frame: .zero) + popupView.configure(image: image, viewModel: viewModel) + + self.certificationSharePopupView = popupView + self.certificationSharePopupView?.delegate = self + + if let certificationSharePopupView = self.certificationSharePopupView { + self.view.addSubview(certificationSharePopupView) + } + } + func displayToast(viewModel: Home.ViewModel.Toast) { viewModel.message.unwrap { Toast.shared.makeToast($0) @@ -431,6 +472,11 @@ extension HomeViewController: ChallengeInProgressViewDelegate{ } } + func didTapCardSendButton() { + Task { + await self.interactor.didTapCardSendButton() + } + } } extension HomeViewController: ChallengeCompletedViewDelegate, TTFlowerPopupDelegate { @@ -479,6 +525,24 @@ extension HomeViewController: TTNavigationBarDelegate { } } +extension HomeViewController: TTCertificationSharePopupDelegate { + + func didTapCertificationSharePopupDimView() { + self.certificationSharePopupView?.removeFromSuperview() + self.certificationSharePopupView = nil + } + + func didTapCertificationSharePopupCloseButton() { + self.certificationSharePopupView?.removeFromSuperview() + self.certificationSharePopupView = nil + } + + func didTapCertificationSharePopupShareButton(image: UIImage) { + let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil) + self.present(activityViewController, animated: true) + } +} + extension HomeViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { diff --git a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift index 0779ac7c..f01ae58d 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift @@ -116,7 +116,7 @@ final class HomeWorker: HomeWorkerProtocol { status: challengeStatus, myInfo: myInfo, partnerInfo: partnerInfo, - stickRemaining: 5 - (homeResponse.myStingCnt ?? 0), + stickRemaining: 3 - (homeResponse.myStingCnt ?? 0), description: homeResponse.onGoingChallenge?.description ) @@ -211,9 +211,9 @@ final class HomeWorker: HomeWorkerProtocol { case 10...15: return .peak case 16...21: - return .bloom - case 22: return .flower + case 22: + return .bloom default: return nil } diff --git a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift index c76c8fae..fe460699 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift +++ b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift @@ -12,6 +12,7 @@ protocol ChallengeInProgressViewDelegate: AnyObject { func didTapCertificateButton() func didTapMyFlowerEmptySpeechBubbleView() func didTapStickButton() + func didTapCardSendButton() func didTapChallengeInfo() } @@ -78,12 +79,27 @@ final class ChallengeInProgressView: UIView { /// 찌르기 버튼 타이틀 lazy var nudgeTitleLabel: UILabel = { let v = UILabel() - v.text = "콕 찌르기 (5/5)" + v.text = "콕 찌르기 (3/3)" v.textColor = .primary v.font = .body2 v.textAlignment = .center return v }() + /// 카드 보내기 버튼 + lazy var cardSendButton: UIButton = { + let v = UIButton() + v.setImage(.asset(.icon_send_card), for: .normal) + v.addAction { [weak self] in + self?.delegate?.didTapCardSendButton() + } + return v + }() + /// 카드 보내기 버튼 유도 툴팁 + lazy var cardSendButtonTooltip: UIImageView = { + let v = UIImageView() + v.image = .asset(.img_send_card_tooltip) + return v + }() // MARK: - Method override init(frame: CGRect) { @@ -105,7 +121,10 @@ final class ChallengeInProgressView: UIView { self.myFlowerView, self.heartImage, self.nudgeBeeButton, - self.nudgeTitleLabel) + self.nudgeTitleLabel, + self.cardSendButton, + self.cardSendButtonTooltip + ) self.topChallengeInfoView.snp.makeConstraints { make in make.top.equalToSuperview() @@ -173,6 +192,18 @@ final class ChallengeInProgressView: UIView { make.bottom.equalToSuperview().offset(-beeButtonBottomOffset) } + self.cardSendButton.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.width.height.equalTo(beeButtonWidthHeight) + make.bottom.equalTo(self.nudgeTitleLabel.snp.top).offset(-8) + } + + self.cardSendButtonTooltip.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalTo(self.cardSendButton.snp.top).offset(-14) + make.width.equalTo(149) + make.height.equalTo(60) + } } func configure(viewModel: Home.ViewModel.ChallengeInProgressViewModel) { @@ -187,6 +218,8 @@ final class ChallengeInProgressView: UIView { self.myFlowerTopView.configureInProgress(viewModel: viewModel.myFlower.topViewModel) self.heartImage.isHidden = viewModel.isHeartHidden self.nudgeTitleLabel.text = viewModel.stickText + self.cardSendButton.isHidden = viewModel.isCardSendHidden + self.cardSendButtonTooltip.isHidden = viewModel.isCardSendTooltipHidden } } diff --git a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift new file mode 100644 index 00000000..7d554800 --- /dev/null +++ b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTCertificationSharePopup.swift @@ -0,0 +1,212 @@ +// +// TTCertificationSharePopup.swift +// +// +// Created by 박건우 on 2024/01/14. +// + +import CoreKit +import UIKit + +protocol TTCertificationSharePopupDelegate: AnyObject { + func didTapCertificationSharePopupDimView() + func didTapCertificationSharePopupCloseButton() + func didTapCertificationSharePopupShareButton(image: UIImage) +} + +final class TTCertificationSharePopup: UIView { + + weak var delegate: TTCertificationSharePopupDelegate? + + private lazy var dimView: UIView = { + let v = UIView() + v.backgroundColor = .black.withAlphaComponent(0.5) + v.addTapAction { [weak self] in + self?.delegate?.didTapCertificationSharePopupDimView() + } + return v + }() + + private lazy var headlineLabel: UILabel = { + let v = UILabel() + v.font = .h3 + v.textColor = .white + v.text = "카드를 공유해보세요" + return v + }() + + private lazy var contentView: UIView = { + let v = UIView() + v.backgroundColor = .white + v.layer.cornerRadius = 20 + v.clipsToBounds = true + return v + }() + + private lazy var captureBgView: UIView = { + let v = UIView() + v.layer.cornerRadius = 10 + v.clipsToBounds = true + return v + }() + + private lazy var captureView: UIView = { + let v = UIView() + v.backgroundColor = .second01 + return v + }() + + private lazy var dateLabel: UILabel = { + let v = UILabel() + v.font = .body2 + v.textColor = .black + return v + }() + + private lazy var titleLabel: UILabel = { + let v = UILabel() + v.font = .h3 + v.textColor = .primary + v.lineBreakMode = .byTruncatingTail + return v + }() + + private lazy var captionLabel: UILabel = { + let v = UILabel() + v.font = .body3 + v.textColor = .mainCoral + return v + }() + + private lazy var imageView: UIImageView = { + let v = UIImageView() + v.layer.cornerRadius = 13 + v.clipsToBounds = true + return v + }() + + private lazy var logoLabel: UILabel = { + let v = UILabel() + v.font = .h4 + v.textColor = .mainCoral + v.text = "Twotoo" + return v + }() + + private lazy var shareButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "공유하기", .large) + v.setIsEnabled(true) + v.addAction { [weak self] in + guard let self = self else { + return + } + let image = self.makeImage() + self.delegate?.didTapCertificationSharePopupShareButton(image: image) + } + return v + }() + + private lazy var closeButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "닫기", .large) + v.setTitleColor(.white, for: .normal) + v.backgroundColor = .clear + v.addAction { [weak self] in + self?.delegate?.didTapCertificationSharePopupCloseButton() + } + return v + }() + + override init(frame: CGRect) { + super.init(frame: .zero) + self.layout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func didMoveToSuperview() { + super.didMoveToSuperview() + + if self.superview != nil { + self.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } + } + + func layout() { + self.addSubviews(self.dimView, self.headlineLabel, self.contentView, self.closeButton) + self.contentView.addSubviews(self.captureBgView, self.shareButton) + self.captureBgView.addSubviews(self.captureView) + self.captureView.addSubviews(self.dateLabel, self.titleLabel, self.captionLabel, self.imageView, self.logoLabel) + + self.dimView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + self.headlineLabel.snp.makeConstraints { make in + make.bottom.equalTo(self.contentView.snp.top).offset(-16) + make.centerX.equalToSuperview() + } + self.contentView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(51) + make.centerY.equalToSuperview() + } + self.closeButton.snp.makeConstraints { make in + make.top.equalTo(self.contentView.snp.bottom).offset(10) + make.centerX.equalToSuperview() + } + self.captureBgView.snp.makeConstraints { make in + make.leading.top.trailing.equalToSuperview().inset(13) + } + self.captureView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + self.shareButton.snp.makeConstraints { make in + make.top.equalTo(self.captureView.snp.bottom).offset(7) + make.leading.trailing.bottom.equalToSuperview().inset(11) + } + self.dateLabel.snp.makeConstraints { make in + make.top.equalToSuperview().inset(32) + make.leading.equalToSuperview().inset(17) + } + self.titleLabel.snp.makeConstraints { make in + make.top.equalTo(self.dateLabel.snp.bottom).offset(6) + make.leading.trailing.equalToSuperview().inset(17) + } + self.captionLabel.snp.makeConstraints { make in + make.top.equalTo(self.titleLabel.snp.bottom).offset(7) + make.leading.trailing.equalToSuperview().inset(17) + } + self.logoLabel.snp.makeConstraints { make in + make.top.equalTo(self.imageView.snp.bottom).offset(14) + make.bottom.equalToSuperview().inset(13) + make.leading.trailing.equalToSuperview().inset(17) + } + } + + func configure(image: UIImage, viewModel: Home.ViewModel.CertificationSharePopupViewModel) { + self.imageView.image = image + self.dateLabel.text = viewModel.dateText + self.titleLabel.text = viewModel.titleNameText + self.captionLabel.text = viewModel.progressText + + self.imageView.snp.remakeConstraints { make in + make.top.equalTo(self.captionLabel.snp.bottom).offset(13) + make.leading.trailing.equalToSuperview().inset(17) + make.height.equalTo(self.imageView.snp.width).dividedBy(image.size.width / image.size.height) + } + } + + // MARK: - Business Logic + + private func makeImage() -> UIImage { + let renderer = UIGraphicsImageRenderer(bounds: self.captureView.bounds) + + let image = renderer.image { ctx in + self.captureView.drawHierarchy(in: self.captureView.bounds, afterScreenUpdates: true) + } + + return image + } +} diff --git a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift index 6c777d3f..739ed5b7 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift @@ -682,6 +682,19 @@ final class HomeInteractorSpec: QuickSpec { } } } + + describe("공유하기") { + context("카드 보내기 버튼을 클릭하였을 때") { + beforeEach { + await interactor.didTapCardSendButton() + } + + it("인증 성공 공유하기 팝업이 표출된다.") { + let isPresentCertificationSharePopupCalled = await presenter.isPresentCertificationSharePopupCalled + expect(isPresentCertificationSharePopupCalled).to(beTrue()) + } + } + } } } @@ -701,6 +714,7 @@ class HomePresenterMock: HomePresentationLogic { var isPresentHomeErrorCalled = false var isPresentCompleteRequestErrorCalled = false var isPresentExceededStickCountErrorCalled = false + var isPresentCertificationSharePopupCalled = false var lastChallenge: Home.Model.Challenge? var lastHomeError: Error? @@ -771,6 +785,10 @@ class HomePresenterMock: HomePresentationLogic { func presentExceededStickCountError() { self.isPresentExceededStickCountErrorCalled = true } + + func presentCertificationSharePopup(challenge: Home.Model.Challenge) { + self.isPresentCertificationSharePopupCalled = true + } } class HomeWorkerMock: HomeWorkerProtocol { diff --git a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift index 122d1cea..27334e78 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift @@ -34,7 +34,7 @@ final class ChallengeInProgressMappingSpec: QuickSpec { certCount: 1, todayCert: .init(id: "certId", complimentComment: "Test") ), - stickRemaining: 5 + stickRemaining: 3 ) viewModel = model.toChallengeInProgressViewModel() @@ -283,8 +283,8 @@ final class ChallengeInProgressMappingSpec: QuickSpec { } context("찌르기 남은 횟수") { - it("찌르기 텍스트가 '콕 찌르기 (5/5)'로 표현된다.") { - expect(viewModel.stickText).to(equal("콕 찌르기 (5/5)")) + it("찌르기 텍스트가 '콕 찌르기 (3/3)'로 표현된다.") { + expect(viewModel.stickText).to(equal("콕 찌르기 (3/3)")) } } } diff --git a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift index 498efdf4..0940a946 100644 --- a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift +++ b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift @@ -33,7 +33,7 @@ extension NudgeSendPresenter: NudgeSendPresentationLogic { func presentRemainingNudgeCount(remainingNudgeCount: Int) { self.viewController?.displayTitle(viewModel: .init( - text: "찌르기 문구 보내기 (\(remainingNudgeCount)/5)" + text: "찌르기 문구 보내기 (\(remainingNudgeCount)/3)" )) } From e131d90e1bb55e2e32f089224cee1d9e80069c2a Mon Sep 17 00:00:00 2001 From: kyunghoonKim Date: Mon, 15 Jan 2024 14:08:50 +0900 Subject: [PATCH 36/44] =?UTF-8?q?=E2=9C=A8=20=EC=B1=8C=EB=A6=B0=EC=A7=80?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C=20=EA=BD=83=EB=A7=90=20=EB=B3=B4=EA=B8=B0?= =?UTF-8?q?=20-=20=EA=B3=B5=EC=9C=A0=20=EB=B2=84=ED=8A=BC=20View=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomeScene/HomeViewController.swift | 57 ++-- .../Views/Common/TTFlowerPopup.swift | 187 ------------- .../Common/TTLanguageFlowerSharePopup.swift | 245 ++++++++++++++++++ 3 files changed, 278 insertions(+), 211 deletions(-) delete mode 100644 Scene/HomeScene/Sources/HomeScene/Views/Common/TTFlowerPopup.swift create mode 100644 Scene/HomeScene/Sources/HomeScene/Views/Common/TTLanguageFlowerSharePopup.swift diff --git a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift index 1eeb3e1a..0dadcfe7 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift @@ -37,8 +37,8 @@ final class HomeViewController: UIViewController { // MARK: - Popup var bothCertificationPopupView: TTPopup? var completedPopupView: TTPopup? - var flowerLanguagePopupView: TTFlowerPopup? var certificationSharePopupView: TTCertificationSharePopup? + var flowerLanguageSharePopupView: TTLanguageFlowerSharePopup? // MARK: - UI Component /// 네비게이션 바 @@ -102,7 +102,7 @@ final class HomeViewController: UIViewController { let v = UIImageView(.home_ground) return v }() - + // MARK: - View Lifecycle override func viewDidLoad() { @@ -157,7 +157,7 @@ final class HomeViewController: UIViewController { object: nil ) } - + // MARK: - Layout private func setUI() { self.view.setBackgroundDefault() @@ -362,7 +362,7 @@ extension HomeViewController: HomeDisplayLogic { // Show Popup let popupView = TTCertificationSharePopup(frame: .zero) popupView.configure(image: image, viewModel: viewModel) - + self.certificationSharePopupView = popupView self.certificationSharePopupView?.delegate = self @@ -478,38 +478,32 @@ extension HomeViewController: ChallengeInProgressViewDelegate{ } } } -extension HomeViewController: ChallengeCompletedViewDelegate, TTFlowerPopupDelegate { +extension HomeViewController: ChallengeCompletedViewDelegate { func didTapShowFlowerLaunage(viewModel: Home.ViewModel.ChallengeCompletedViewModel.FlowerLanguagePopupViewModel) { self.displayWithAnimation { [weak self] in viewModel.show.unwrap { - let popupView = TTFlowerPopup() - popupView.configure(name: $0.flowerNameText, - description: $0.flowerDescText, - image: $0.flowerImage, - order: $0.flowerOrderText) - - self?.flowerLanguagePopupView = popupView - self?.flowerLanguagePopupView?.delegate = self + guard let self = self else { return } - if let flowerLanguagePopupView = self?.flowerLanguagePopupView { - self?.view.addSubview(flowerLanguagePopupView) + // Show Popup + let popupView = TTLanguageFlowerSharePopup(frame: .zero) + popupView.configure(image: $0.flowerImage, title: $0.flowerNameText, description: $0.flowerDescText, order: $0.flowerOrderText) + + self.flowerLanguageSharePopupView = popupView + self.flowerLanguageSharePopupView?.delegate = self + + if let certificationSharePopupView = self.flowerLanguageSharePopupView { + self.view.addSubview(certificationSharePopupView) } } viewModel.dismiss.unwrap { - self?.flowerLanguagePopupView?.removeFromSuperview() - self?.flowerLanguagePopupView = nil + self?.flowerLanguageSharePopupView?.removeFromSuperview() + self?.flowerLanguageSharePopupView = nil } } } - // TTFlowerPopupDelegate - func didTapCloseView() { - self.flowerLanguagePopupView?.removeFromSuperview() - self.flowerLanguagePopupView = nil - } - func didTapChallengeCompletedFinishButton() { Task { await self.interactor.didTapChallengeCompleteButton() @@ -525,7 +519,7 @@ extension HomeViewController: TTNavigationBarDelegate { } } -extension HomeViewController: TTCertificationSharePopupDelegate { +extension HomeViewController: TTCertificationSharePopupDelegate, TTLanguageFlowerSharePopupDelegate { func didTapCertificationSharePopupDimView() { self.certificationSharePopupView?.removeFromSuperview() @@ -541,6 +535,21 @@ extension HomeViewController: TTCertificationSharePopupDelegate { let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil) self.present(activityViewController, animated: true) } + + func didTapLanguageFlowerSharePopupDimView() { + self.flowerLanguageSharePopupView?.removeFromSuperview() + self.flowerLanguageSharePopupView = nil + } + + func didTapLanguageFlowerSharePopupCloseButton() { + self.flowerLanguageSharePopupView?.removeFromSuperview() + self.flowerLanguageSharePopupView = nil + } + + func didTapLanguageFlowerSharePopupShareButton(image: UIImage) { + let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil) + self.present(activityViewController, animated: true) + } } extension HomeViewController: UIGestureRecognizerDelegate { diff --git a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTFlowerPopup.swift b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTFlowerPopup.swift deleted file mode 100644 index 32695f22..00000000 --- a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTFlowerPopup.swift +++ /dev/null @@ -1,187 +0,0 @@ -// -// TTFlowerPopup.swift -// -// -// Created by Julia on 10/10/23. -// - -import UIKit -import Util - -protocol TTFlowerPopupDelegate: AnyObject { - func didTapCloseView() -} - -final class TTFlowerPopup: UIView { - - weak var delegate: TTFlowerPopupDelegate? - - lazy var dimView: UIView = { - let v = UIView() - v.backgroundColor = .black.withAlphaComponent(0.5) - v.addTapAction { [weak self] in - self?.delegate?.didTapCloseView() - } - return v - }() - - let flowerNameLabel: UILabel = { - let v = UILabel() - v.textColor = .primary - v.font = .h2 - v.textAlignment = .center - return v - }() - - let flowerDescLabel: UILabel = { - let v = UILabel() - v.textColor = .primary - v.font = .body2 - v.textAlignment = .center - return v - }() - - lazy var flowerImageView: UIImageView = { - let v = UIImageView() - v.contentMode = .scaleAspectFit - return v - }() - - let flowerOrderLabel: PaddingLabel = { - let v = PaddingLabel(padding: .init(top: 4, left: 10, bottom: 4, right: 10)) - v.font = .body1 - v.textColor = .mainCoral - v.backgroundColor = .white - v.layer.cornerRadius = 10 - v.clipsToBounds = true - return v - }() - - lazy var closeButton: UIButton = { - let v = UIButton() - v.setImage(.asset(.icon_cancel), for: .normal) - v.addAction { [weak self] in - self?.delegate?.didTapCloseView() - } - return v - }() - - let backgroundImageView: UIImageView = { - let v = UIImageView(image: .asset(.flowerPopup_background)) - return v - }() - - /// 컴포넌트들을 담는 뷰 - lazy var contentView: UIView = { - let v = UIView() - v.backgroundColor = .second02 - v.addSubviews(self.flowerNameLabel, - self.flowerDescLabel, - self.flowerImageView, - self.flowerOrderLabel, - self.backgroundImageView, - self.closeButton) - v.sendSubviewToBack(self.backgroundImageView) - v.layer.cornerRadius = 20 - return v - }() - - override init(frame: CGRect) { - super.init(frame: .zero) - self.layout() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func didMoveToSuperview() { - super.didMoveToSuperview() - - if self.superview != nil { - self.snp.remakeConstraints { make in - make.edges.equalToSuperview() - } - } - } - - func configure(name flowerName: String, - description flowerDescription: String, - image: UIImage, - order flowerOrder: String) { - self.flowerNameLabel.text = flowerName - self.flowerDescLabel.text = flowerDescription - self.flowerImageView.image = image - self.flowerOrderLabel.text = flowerOrder - } - - func layout() { - self.addSubviews(self.dimView, - self.contentView) - - self.dimView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - self.contentView.snp.makeConstraints { make in - make.width.equalTo(273) - make.height.equalTo(349) - make.center.equalToSuperview() - } - - self.flowerNameLabel.snp.makeConstraints { make in - make.top.equalToSuperview().offset(34) - make.centerX.equalToSuperview() - } - - self.flowerDescLabel.snp.makeConstraints { make in - make.top.equalTo(self.flowerNameLabel.snp.bottom).offset(8) - make.centerX.equalToSuperview() - } - - self.flowerImageView.snp.makeConstraints { make in - make.top.equalTo(self.flowerDescLabel.snp.bottom).offset(32) - make.centerX.equalToSuperview() - make.width.equalTo(100) - make.height.lessThanOrEqualTo(165) - } - - self.flowerOrderLabel.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.bottom.equalToSuperview().offset(-30) - } - - self.backgroundImageView.snp.makeConstraints { make in - make.leading.trailing.bottom.equalToSuperview() - } - - self.closeButton.snp.makeConstraints { make in - make.top.equalToSuperview().offset(14) - make.trailing.equalToSuperview().inset(14) - } - } - -} - -extension TTFlowerPopup { - /// UILabel의 padding을 설정할 수 있는 클래스 - final class PaddingLabel: UILabel { - private var padding = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0) - - convenience init(padding: UIEdgeInsets) { - self.init() - self.padding = padding - } - - override func drawText(in rect: CGRect) { - super.drawText(in: rect.inset(by: padding)) - } - - override var intrinsicContentSize: CGSize { - var contentSize = super.intrinsicContentSize - contentSize.height += padding.top + padding.bottom - contentSize.width += padding.left + padding.right - return contentSize - } - } -} diff --git a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTLanguageFlowerSharePopup.swift b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTLanguageFlowerSharePopup.swift new file mode 100644 index 00000000..b2a99a26 --- /dev/null +++ b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTLanguageFlowerSharePopup.swift @@ -0,0 +1,245 @@ +// +// TTLanguageFlowerSharePopup.swift +// +// +// Created by Eddy on 2024/01/15. +// + +import CoreKit +import UIKit + +protocol TTLanguageFlowerSharePopupDelegate: AnyObject { + func didTapLanguageFlowerSharePopupDimView() + func didTapLanguageFlowerSharePopupCloseButton() + func didTapLanguageFlowerSharePopupShareButton(image: UIImage) +} + +final class TTLanguageFlowerSharePopup: UIView { + + weak var delegate: TTLanguageFlowerSharePopupDelegate? + + private lazy var dimView: UIView = { + let v = UIView() + v.backgroundColor = .black.withAlphaComponent(0.5) + v.addTapAction { [weak self] in + self?.delegate?.didTapLanguageFlowerSharePopupDimView() + } + return v + }() + + private lazy var headlineLabel: UILabel = { + let v = UILabel() + v.font = .h3 + v.textColor = .white + return v + }() + + private lazy var contentView: UIView = { + let v = UIView() + v.backgroundColor = .white + v.layer.cornerRadius = 20 + v.clipsToBounds = true + return v + }() + + private lazy var captureBgView: UIView = { + let v = UIView() + v.layer.cornerRadius = 10 + v.clipsToBounds = true + return v + }() + + private lazy var captureView: UIView = { + let v = UIView() + v.backgroundColor = .second02 + return v + }() + + private lazy var titleLabel: UILabel = { + let v = UILabel() + v.font = .h2 + v.textColor = .primary + v.textAlignment = .center + return v + }() + + private lazy var flowerLanguageLabel: UILabel = { + let v = UILabel() + v.font = .body2 + v.textColor = .primary + v.textAlignment = .center + return v + }() + + private lazy var imageView: UIImageView = { + let v = UIImageView() + v.contentMode = .scaleAspectFit + return v + }() + + let backgroundImageView: UIImageView = { + let v = UIImageView(image: .asset(.flowerPopup_background)) + return v + }() + + let flowerOrderLabel: PaddingLabel = { + let v = PaddingLabel(padding: .init(top: 4, left: 10, bottom: 4, right: 10)) + v.font = .body1 + v.textColor = .mainCoral + v.backgroundColor = .white + v.layer.cornerRadius = 10 + v.clipsToBounds = true + return v + }() + + private lazy var shareButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "공유하기", .large) + v.setIsEnabled(true) + v.addAction { [weak self] in + guard let self = self else { + return + } + let image = self.makeImage() + self.delegate?.didTapLanguageFlowerSharePopupShareButton(image: image) + } + return v + }() + + private lazy var closeButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "닫기", .large) + v.setTitleColor(.white, for: .normal) + v.backgroundColor = .clear + v.addAction { [weak self] in + self?.delegate?.didTapLanguageFlowerSharePopupCloseButton() + } + return v + }() + + override init(frame: CGRect) { + super.init(frame: .zero) + self.layout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func didMoveToSuperview() { + super.didMoveToSuperview() + + if self.superview != nil { + self.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } + } + + func layout() { + self.addSubviews(self.dimView, self.headlineLabel, self.contentView, self.closeButton) + self.contentView.addSubviews(self.captureBgView, self.shareButton) + self.captureBgView.addSubviews(self.captureView) + self.captureView.addSubviews(self.titleLabel, self.flowerLanguageLabel, self.imageView, self.flowerOrderLabel, self.backgroundImageView) + self.captureView.sendSubviewToBack(self.backgroundImageView) + + self.dimView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + self.headlineLabel.snp.makeConstraints { make in + make.bottom.equalTo(self.contentView.snp.top).offset(-16) + make.centerX.equalToSuperview() + } + self.contentView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(51) + make.centerY.equalToSuperview() + } + + self.closeButton.snp.makeConstraints { make in + make.top.equalTo(self.contentView.snp.bottom).offset(10) + make.centerX.equalToSuperview() + } + + self.captureBgView.snp.makeConstraints { make in + make.leading.top.trailing.equalToSuperview().inset(13) + } + + self.backgroundImageView.snp.makeConstraints { make in + make.leading.trailing.bottom.equalToSuperview() + } + + self.captureView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + self.shareButton.snp.makeConstraints { make in + make.top.equalTo(self.captureView.snp.bottom).offset(7) + make.leading.trailing.bottom.equalToSuperview().inset(11) + } + + self.titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().inset(32) + make.centerX.equalToSuperview() + } + + self.flowerLanguageLabel.snp.makeConstraints { make in + make.top.equalTo(self.titleLabel.snp.bottom).offset(6) + make.centerX.equalToSuperview() + } + + self.flowerOrderLabel.snp.makeConstraints { make in + make.top.equalTo(self.imageView.snp.bottom).offset(14) + make.bottom.equalToSuperview().inset(13) + make.centerX.equalToSuperview() + } + } + + func configure(image: UIImage, title: String, description: String, order: String) { + self.headlineLabel.text = "\(title) 카드를 획득했어요!" + self.imageView.image = image + self.titleLabel.text = title + self.flowerLanguageLabel.text = description + self.flowerOrderLabel.text = order + + self.imageView.snp.remakeConstraints { make in + make.top.equalTo(self.flowerLanguageLabel.snp.bottom).offset(18) + make.centerX.equalToSuperview() + make.width.equalTo(100) + make.height.lessThanOrEqualTo(165) + } + } + + // MARK: - Business Logic + + private func makeImage() -> UIImage { + let renderer = UIGraphicsImageRenderer(bounds: self.captureView.bounds) + + let image = renderer.image { ctx in + self.captureView.drawHierarchy(in: self.captureView.bounds, afterScreenUpdates: true) + } + + return image + } +} + +extension TTLanguageFlowerSharePopup { + /// UILabel의 padding을 설정할 수 있는 클래스 + final class PaddingLabel: UILabel { + private var padding = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0) + + convenience init(padding: UIEdgeInsets) { + self.init() + self.padding = padding + } + + override func drawText(in rect: CGRect) { + super.drawText(in: rect.inset(by: padding)) + } + + override var intrinsicContentSize: CGSize { + var contentSize = super.intrinsicContentSize + contentSize.height += padding.top + padding.bottom + contentSize.width += padding.left + padding.right + return contentSize + } + } +} From b3bb3549a89743e003a3e06f0b9900db78fd25fc Mon Sep 17 00:00:00 2001 From: julia0926 Date: Fri, 26 Jan 2024 17:21:44 +0900 Subject: [PATCH 37/44] =?UTF-8?q?=F0=9F=94=A5=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeCertificateViewController.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift b/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift index 2c6ca170..554eabea 100644 --- a/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift +++ b/Scene/ChallengeCertificateScene/Sources/ChallengeCertificateScene/ChallengeCertificateViewController.swift @@ -211,13 +211,6 @@ extension ChallengeCertificateViewController: TTTextViewDelegate, scrollOffset += 14 } self.backScrollView.contentOffset.y = scrollOffset -// let bottomOffset = keyboardFrame.height + 14 -// self.commitButton.snp.remakeConstraints { make in -// make.leading.equalToSuperview().offset(24) -// make.trailing.equalToSuperview().inset(24) -// make.height.equalTo(57) -// make.bottom.equalTo(self.view.snp.bottom).inset(bottomOffset) -// } self.view.layoutIfNeeded() } } From 90d8f4f9f0b843f0c4149c6bbf50a185b52b1bfd Mon Sep 17 00:00:00 2001 From: gunoooo Date: Mon, 29 Jan 2024 22:49:59 +0900 Subject: [PATCH 38/44] =?UTF-8?q?=E2=9C=A8=20=ED=99=88=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20=EC=84=B1=EA=B3=B5=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0=20=EB=AA=A8=EB=8B=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../popup_ground.imageset/Contents.json | 23 ++ .../popup_ground.imageset/popup_ground.png | Bin 0 -> 2476 bytes .../popup_ground.imageset/popup_ground@2x.png | Bin 0 -> 5788 bytes .../popup_ground.imageset/popup_ground@3x.png | Bin 0 -> 5768 bytes .../DesignSystem/Sources/Assets/Assets.swift | 1 + .../celebrate_lottie.dataset/Contents.json | 12 + .../lottie_celebrate.json | 1 + .../Sources/HomeScene/HomeInteractor.swift | 2 +- .../Sources/HomeScene/HomeModels.swift | 13 + .../Sources/HomeScene/HomePresenter.swift | 30 +- .../HomeScene/HomeViewController.swift | 32 +++ .../TTChallengeCompleteSharePopup.swift | 258 ++++++++++++++++++ .../ChallengeCompletedMappingSpec.swift | 20 +- .../ChallengeInProgressMappingSpec.swift | 4 +- .../Mapping/CompletedMappingSpec.swift | 2 +- 15 files changed, 376 insertions(+), 22 deletions(-) create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/Contents.json create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/popup_ground.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/popup_ground@2x.png create mode 100644 Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/popup_ground@3x.png create mode 100644 Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/Contents.json create mode 100644 Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/lottie_celebrate.json create mode 100644 Scene/HomeScene/Sources/HomeScene/Views/Common/TTChallengeCompleteSharePopup.swift diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/Contents.json b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/Contents.json new file mode 100644 index 00000000..43963997 --- /dev/null +++ b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "popup_ground.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "popup_ground@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "popup_ground@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/popup_ground.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/popup_ground.png new file mode 100644 index 0000000000000000000000000000000000000000..ad7ac8c39ef5abf47e9908e73ebe7a3249ce9545 GIT binary patch literal 2476 zcmeHJ`9Bl>AAc(%B_f6x<%+P1CS;=s5xET`$+dME(ae>UO3vI8`4mx(l`%ByldD3A zIdUwPtDG~2nSFi#fbW0s{o(a`9*^him*-Ef$Cqu)MTBLA0RSSF7N+(9@P+MgoY0<~ z{U$thV+Z!$wm<~~uutN@!v}JoOYfL`!S?3oK*e{t*&V^}Z*s{50AljKEpLIH0~1SA z6UV!J^P}je9=x*a@+KRb z5XT%PRG3FBl+_^?sNEp?F8qK}P zny!HU^lRb%8Sbc-b-e0W8W@zf;bV=FI;Z8j{MH%%^p~0RxSlC% zb0^<`a}beBx-i*4^~}~X5O2pP8)HNbTy7rAlw{Pc#T^?xiXsT%a!mu1F=*)EO^I1& zqVIdLQpe6~wO-O4eWB}lU4@uI87v8Xq`jv4Vwdy$-@HSb(#`V0-{CieX~DL$Pia-( z%xjI(EK8DWvasEuI)7IiSmDivh!aJv=8R=XuRk}8GtCU735LuU=PCv^%j;A;VlSy> zRRkO$W%Rsj^9n(W&xO#dKYPUz%uJe;7S5;^EZ&rbdi*RO zx_j%y?AQ0jI#;2?T-t}v$Ug)!LnB%}gFmqgl48WV#o0e-*qHM1yjgsNcUUDIkzP7? z2n((5e*fVPx1j+qkxhR@*j=Tzh=RjWhF!XAPcZSYW7?-ORCD<3NM9i;?c(K~Uh<;| zHs!OaVPx;qElzjU6MfDoG{q!3e~vZKSqOX7M;F>UtuuF6(EXh+q4agl`O3OGwO9HN zvhl@(8Mi`sU+@S$iYmWhueo)>YG5KwQ?6!tg2>+0F-5m2YB--K8Za8i0 zf^U-+fxkD2-1U-cJ2vK!Cxnd%!e*33eYWmevFj>%V0TI?WplfgRx z7s`nFrF3LL?M=3z!q*j>&euwA<;T}O$Z@yJvSGSX4VyHGY z2JtSEE-fkNfD3}H%}EbAdFJ>M_4XuVE9MdN#6HN;<44@gVlyMes}S?!!S|jaL{4eP z%O8!Jc^u($VP>&_wGDQXhUkzhc(JYPo*L2A3i1or85RgGGF+> z@u|txUCcb~vPH99SH_vC5#3ezv(19G9A;Rk(1F~6AcX}g#RWSqEV3q(7+%M_(ZCOq z9D56s-JsDfo{d}T#n-1$BMBQ!VwhFd1|3swS~v2l(OnV9Av3%SYG=E&wkfamw;HRB z%~`=v_C#Smkw|et6&I|$b=incKfo6g=(Ag6T&0tB z_05jjx{tAa*PITiuSKmW7#wO=fYo$XQcKHV>6}K2*%VR#G3Q>PRf<*TwfrioUJPn# znb5}jD6TShC~-8ZR|P>nyMWG0Fhh%s2NKt>Zm^Q*-)lLLa+7>#60f)BrXxzw6P1E3DUTaco0dQ^j-~N{G-rp& zPBxzo2En8*&^cj~bH&+}r%!sxkrG_x1Y+u5mQ~)pUyxuomY#AWPq=e<*d{d+cQN$0 zo)dcO=ISRsSNW%$8J{puKiOMXZ6P4QwIzZZIoZfXzH5tQ5e;v`KQuft0J;c~akxDG z_gaEV9C9yRlOI?v*>S%AdO)=kG6c#^ruDHr296IXzs~lVeq#?T_V0TGQWPf+fW1c- z{!ji#35ANPb^y#SRR}uBivweW*txwLYncH2@MhN7w$EU90gLz{?7ya-lEC!BfPOPerHTLbHdyQn4DDjTUEn`lODuI{_Rc(D0h_iDKlx*ajXB*~Ku%+l< z_rr?=z!lG4t;|V?)adq7=07ha-{U%4?{VEI-4N8GA50cx`+scL2sa-xM5AhhhIUw1*yC8Q6fTCX(CMp3`IZ^lui_+S81Umud5gp5C}vF5S4@& zX^TLpA&N)|0!v4F3oRs+2mwOE8~%*%y51koIdf*7Yv!4G?)#o+26@K@a{4#v-v9tO zZDDQ-1%P8retF@G>PU+|ouz>#G2ES4u916J!l=sN4@PCf` z+_1g@0F~*d4j%l%x4LX$dc!_ifH9d6STK?>x;Y&qpZWenz>5bGx#1EJtHJNADzCyPd!p6tj0^bB z4|+C;r1jd)yH~qt3+cy7GgCfz3{h3YR~7_b0zBCvBf=Gpwc0>O9FN80k`xX%Aja@NNKa% zdEUlpobNp=a)D3drhUJ&A9c0LO|rgpgdMl$G+i;}{=%mjZn0v@jUU18kn}2s)Cv!p zbfC@wnCPu|STFj@n1OMIN=m(-j`7Hq%d$4YDHuY^_*i#(He@`-!EMNGXXCHQhTYOb zTVP4?7r>J^k-+{*-1B6uY>sMw{IhWE=hhYK6V(_8$>|u))~>hDw%(fNmZQ6KG8=ab zS8f{Mubhq1oWRWd$ljk(G^7cb5g+hStnE{^IrGTZ74Y5%?E4oAuWFXUS=|FGokC!* zQNt5Nk(^b*?7>Oqq97)d?q%)FkUx&oaxNR;-Io%lD-k@qAG!yrKvcYQ5E=yibqUUA zr;~`sFH0|J=sbem#!ii1Grq)l`#U5&$lpIOeUXle)2U(Hg!K>UZD~*1H@TA4@8~EB37cO16rADVem3EE1DPI-&+qhXw!5c#TAWE8fIpji5{YN{Bb5SBb zQ9*qKbhs%NQ*XmcH>Dod78;`l1_j62%^`Y^yK+K>uD+C>A0VJ>nNmSo;cn5oepAR0rdw&#N&!I z*K?MZanRa8vsdBgKZ;ye2!ydJyxpU=SW%71iQ>%9Uhgn(D%$Sb8rHmqHhnT}Cb_t{ zuhaZr>uUEmPC8P1#4zHlmB(rpFN!kylRg+r!V41G!G{$pKmzV8tK#S85{gNB=${b~)WV7x0<2VL#ha?BH_ z|8_7em1EMUWko~^b$u|%v@+^9b(X^~wm!r--1>?X4?17o6R1xX3qjVP&V>V#PeX+? zo_|`0JsG;1z{u5J)LRPH>ndsBc3D~K&m;Zz;*nQI{`&1uAu!Tg{3$#dtubzOfPlk%e+j0zRp%_ z1Z?Z)2X!(=nQ*1=Ri44*!WCE^6i&FN4Q7GH&pD&(N5S z1czFM>8x9u4Z*runT;w|IXAc`$1}q6G(g1x8#~|$nBV)sUSkhs!^&6Rpyy^hh=Lr) zl1K{F76CyT+F3di*(Tecs-f)%?O_EAA%62;G_wwrgPaOuIL7+Yp-;~+Hw*?X_GenZ zR-Iym)~VEZA-GCg;u!rrRQwY~?_*7>4KzI~VylU*%S-Im?1uqPXTL^Bpmn>CLOLzF z9eFljV?}dT*r!iDMvvSS`RDtXNncb&h2*4TlISIz6a&;3WaZ1b@%VC$yBfh}y(_G{ zV1C=H-lZ6JcrmtaD(TQ~oHYGocyK0Z94vQg`Q&WR*@~B}ERo*96Vr}T*%8*O?s+?r zAZks0t4!(SuXUwzCE5`ml=}ohv~^m3v;JjKtC-l08B%Uax{FKiRZ*sE#_-N$jgJ(g z(3}>6k{!XLqO!$KZ69c7ctW_HzQ-P`*%Y)@;Otd4?c__v_fx2?3tYXq@v5TsW-kX> z_rR8dF6v_QYz0=qAlARm^J2)FR8F1pg^<=WPAO-6sstVIrBAfiO|UroCv zvr@7>k$mL`Q=#c$`@0BwL4W}Ic_?9o+MKSDza~7B#fl_aR4k`eJ5fp`R}BLZ5#4gz zX*=I_o({hk480K;9FW`prMNZOe2-#dTAviVE+q1c>%*3UN~jTg-P^W?AXL;D73Fa? zuPdlfU9Wp6Waw$^c6>oZQ-glLH!41eeN9PdOW^+RxQGzYUV!yDk4ZY9@;T?;OV9&;v$^{KCI8BeqZukRRE47@DR>;JxzS{;=}zVFZD#0K!U zLQc;T`?Us?&^~J~pwr%O@;*5qPU*_l_!-h7=3I@V#wVHHcM!S~;*l4OmWBVar{t1` zPVPpmwCGdgO$%T6Mhy-;fqL{XF9EJMhF8Iz91j#z`gdvSN zMp9%{;!O5FYM=ebcnA zWXzh%eynh#4oe75*dOc9agzxOH$g?XacASgQDF&We;)wIFX|T5&)&UVR>djL%WKd@ zMkhWGO-jyTb60D!DtGqnsTeDN_+88TcZG$Tc0xeU0Q7Wq97ef0*J{6M()X%K9rj7^ z$L4)*(1J%q;UnmCf7Q*MU{@{g z*c$)HPqgYRqGW|N;I+JLx#GjF0O0EU73D!hMf`J)nrxSq7!rrsQL*(WzdykyL@(4D z>*-cjM!`UgZV=VQG9qhx!50gBcKlct_6L6FI&yc~ZfiDk?j2FpY5?q_e~+-WRO4`v zdsYaq-l(`Fljl7*6#1r};I0k7pngD;$=Tk2>rr3mXk#6&8n(w%%@!JSO-s*HPw|28 zWESm|QT{654P9>r*@8pdI`k6DQFZma<4w)YYoG4P0n1s^3^gJy1!`%fJ(o@s6Tx>R zLG!%*!opVd2h_r?R(h6%mxmG*+&V-3ONoQJuAuddQ_?Rh`Tmn>eT2Z(Ve<2I@de0{*&2Pq?mOKK-WO22)g}& z`9)fKm_>?}I0QBo`1YwetwDOccI4VxRC}YUo4qm91aHAc=O=>ENbdN!y3oKByY$zk zg%>B;Dk}7^yL-UuH#; z+^%}#l0j|PwFxZA+mNPjJuCpU^)E8@w!z0JL)G22P)+hQQ?EC|=~-N@PRT+TqyT^T zw>BLB$YD*&t2}8U2ZjWH&rkf39PWfkQmVVuLU#F;wcI}}1G_k)3*w45e&NSlzCn>% zjA|CcAEX!KI6mGah1($sY+~K9ZKDZ=Np_!Zja@KUiEGa#FmhUM3jqKcEf&z%il9sI z?&G%f#qF5bDb5#@N58DN)nRw}Qif~q3c$D~Y7oL)xRCg}01!&EcmxM+8e=jK$3s23 z-qq_*A+Bn8l25X;D6EWtXLLqc(0Q^ZIy#8kir^1mYG4l+)&}w3F8qW%K{OwV%w5qU z%}z0DdCLK{Yr$chHsyW>{uT2BmT3@*hLWhCgZ-O5<{>{mCdyt2W_k`sk&|W>Pn89qk)pt3>$|0A{`os1xhK_+3*&a+0eeFY{?!t?c5U2x-dk z){3N6tMzs!y(Ns_WgA3tjZG87zA+?+AJ)lLZohvPcciKQF>A$Q-RdA}9Np}c007Jf zm6?uVp?j^NVXJiTUM{=5RjN*P*8NDE0)Gtw7xe`xeG3A$Gxsy{0N^pt(b9T<|HJM0 zXwDRyybSRp-=Ce5>#KI^(j|z6AWUKW$tc>ECZ`|#@K&7EXO)Y{rb>Q^N#Rf>4;dvM zSDS*~gAU)CPPjgqJn~WlqNa_dI9*uBSkekt$O=t3*zS@Xlg8HvgnxB2VPUIH*1A^h zdr+G1Z@}lXDrN;Oy6h2)gQV$>mE|4pxi9>zB%7ZTx*qR6&pb+?=JCc-rR6~rXYgFQ z^+jVR%QfOaWMc~eTyG7-4XR^f{<74QWwgHQ_`05cD@#NtE2gGEw&0BgV_$E2Y-|-- zjo3UNa#%XcGcWj9DWh-lgIxNUDqj=Ad$+6i(=VWH^ZpS8KG&IJTq)p3@)iEt!|5NW4&8A>{^7sPWuW-yBL8gP<}7Y^ z?ic__1x!Z0W*ynpDDwkZsWKq|ycPOe9{_$n4iy3(%b($29Q-TTA_oAm*Xsm<>mnx* z0I)1D%XiK2kN+9}Z#Dj(VdKNB`>-G%_nuy4P)5#C$pwV>w0?1ckLCNXvSquhL7U_w zf;hYo!jLQu!AGnZ!d>luWw}4^yz%v@>5h|v8PC{Syhzc`1H^B?jLLxyBIBst$>uB9 z`39b<35W#pUa%%hg@Cq1a*ya$Fxbl5Lt~l6Owp3VO;25vP7)74k^?-d{~F*@+#Kp4;ie6 zpXMu)nf<+Sb9nr!Qa7ykdlOv{5{?rwdjaFS>l%i?#Zmo6k>_X513Kw`iMyvE#Q1vD z?$P`;>Lpg_MLG%0T(t2^2z#=I0O~f}UMN3m$}ZBQxzw(6XEb$E{R$an*yykE2*dhw zd}T62zb`ejr0@d!ru-5I^@VK=d1~83LVOXbTeifpg>4EO=nyw-&wdZ*oKT4u-GSbz zdz>$@l@q$=gz5Yp4PJ+wJf@0_V5c!m4+23n%_B#D$1?Lc{4VwAt=v~IET^Nq?_vC( zx2FVvnVSt2lh3gXl2=l>t^px*9hHEUE={{Peb?tFw$z8fkA3vJ;jlCjgDK&}grzBV z{(!)pUcCu@TH&{qAx{^cmua}q=tVL9B0evg6i$0mkbY>{5V@I;cogqGo7g7KX{uFF z%SgInCVk{)6vzfImUJ~^3v6@vTwS4;#{~Z?V#LmHb5W)?TD}l@8qJr}D%BD_f{1ku zt;>bY+scR*a1X7+RyM2`ohou=`a+u;r^X`fJTCBKV~O@~JPiMU+U-Unw`4R!l9(!Q z3%QFLue0F09o9rvOB{$ejwk@XN{%qo{`nX5? z8D--;gT{gf^O^H)v3&s-wr+Co9EBK->F$iZgf|yjUEyZ*FV&KNE+n54rQ06(+;urRYREx&pHKmP?ULK1WU literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/popup_ground@3x.png b/Core/DesignSystem/Sources/DesignSystem/Resources/Assets.xcassets/background/popup_ground.imageset/popup_ground@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..5351c8c6a422831d7eb16141e1aa090453bbb70f GIT binary patch literal 5768 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 QDo6&{+agcCw!z;1UsT@G2><{9 literal 0 HcmV?d00001 diff --git a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift index bb79640f..ce982672 100644 --- a/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift +++ b/Core/DesignSystem/Sources/DesignSystem/Sources/Assets/Assets.swift @@ -90,6 +90,7 @@ public enum Assets: String { case icon_bubble_not_mate case icon_mypage_brown case icon_info + case popup_ground case home_ground case home_background case icon_airplane diff --git a/Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/Contents.json b/Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/Contents.json new file mode 100644 index 00000000..d781a0c1 --- /dev/null +++ b/Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/Contents.json @@ -0,0 +1,12 @@ +{ + "data" : [ + { + "filename" : "lottie_celebrate.json", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/lottie_celebrate.json b/Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/lottie_celebrate.json new file mode 100644 index 00000000..f84de5d6 --- /dev/null +++ b/Scene/HomeScene/Sources/HomeScene/Assets/Assets.xcassets/celebrate_lottie.dataset/lottie_celebrate.json @@ -0,0 +1 @@ +{"v":"5.5.6","fr":60,"ip":0,"op":300,"w":609,"h":812,"nm":"lottie (mobile)","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_small-side","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[218,320,0],"ix":2},"a":{"a":0,"k":[400,400,0],"ix":1},"s":{"a":0,"k":[-100,100,100],"ix":6}},"ao":0,"w":800,"h":800,"ip":15,"op":234,"st":15,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"streamer b","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":166,"ix":10},"p":{"a":0,"k":[554,664,0],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.929411768913,0.745098054409,0.196078434587,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[4]},{"t":57,"s":[0.5]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[0]},{"t":57,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[35]},{"t":57,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":9,"op":58,"st":9,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"streamer a","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":167,"ix":10},"p":{"a":0,"k":[532,582,0],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[-100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.196078434587,0.380392163992,0.929411768913,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[4]},{"t":48,"s":[0.5]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":48,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[35]},{"t":48,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":5,"op":49,"st":5,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"circle a","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":29,"s":[321.019]},{"t":158,"s":[1800]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":1,"s":[599.5,838,0],"to":[-30,-106.667,0],"ti":[46.667,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":29,"s":[419.5,198,0],"to":[-46.667,0,0],"ti":[0,0,0]},{"t":158,"s":[319.5,838,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":1,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":29,"s":[100,100,100]},{"t":128,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.960784316063,0.572549045086,0.180392161012,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":159,"st":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle b","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":128,"s":[1440]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[599.5,838,0],"to":[-26.667,-93.333,0],"ti":[66.667,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":21,"s":[439.5,278,0],"to":[-66.667,0,0],"ti":[0,0,0]},{"t":128,"s":[199.5,838,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":3,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":21,"s":[100,100,100]},{"t":98,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.196078434587,0.588235318661,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":129,"st":3,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"star a","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":31,"s":[343.949]},{"t":158,"s":[1800]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":1,"s":[596.087,836.292,0],"to":[-36.098,-100,0],"ti":[52.765,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":31,"s":[379.5,236.292,0],"to":[-52.765,0,0],"ti":[0,0,0]},{"t":158,"s":[279.5,836.292,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":1,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":31,"s":[100,100,100]},{"t":128,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.745098054409,0.196078434587,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":159,"st":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"star b","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":23,"s":[288]},{"t":128,"s":[1800]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[596.087,836.292,0],"to":[-39.431,-113.333,0],"ti":[66.098,1.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":23,"s":[359.5,156.292,0],"to":[-66.098,-1.667,0],"ti":[0,0,0]},{"t":128,"s":[199.5,826.292,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":3,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":23,"s":[100,100,100]},{"t":98,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.537254929543,0.196078434587,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":129,"st":3,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"rec a","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[381.468]},{"t":218,"s":[2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":0,"s":[599.5,842,0],"to":[-23.333,-100,0],"ti":[41.333,1.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":33,"s":[459.5,242,0],"to":[-41.333,-1.333,0],"ti":[0,0,0]},{"t":218,"s":[351.5,834,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":0,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":33,"s":[100,100,100]},{"t":188,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.305882364511,0.831372559071,0.411764711142,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":219,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"rec b","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[262.857]},{"t":191,"s":[2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":2,"s":[599.5,842,0],"to":[-23.333,-113.333,0],"ti":[74,5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":25,"s":[459.5,162,0],"to":[-74,-5,0],"ti":[0,0,0]},{"t":191,"s":[155.5,812,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":2,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":25,"s":[100,100,100]},{"t":161,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.196078434587,0.784313738346,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":192,"st":2,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"square a","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":35,"s":[462.385]},{"t":218,"s":[2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":0,"s":[599.5,838,0],"to":[-43.333,-123.333,0],"ti":[60,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":35,"s":[339.5,98,0],"to":[-60,0,0],"ti":[0,0,0]},{"t":218,"s":[239.5,838,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":0,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":35,"s":[100,100,100]},{"t":188,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.588235318661,0.831372559071,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":219,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"square b","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":27,"s":[285.714]},{"t":191,"s":[2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":2,"s":[599.5,838,0],"to":[-30,-120,0],"ti":[75,3.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":27,"s":[419.5,118,0],"to":[-75,-3.333,0],"ti":[0,0,0]},{"t":191,"s":[149.5,818,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0,0]},"t":2,"s":[50,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":27,"s":[100,100,100]},{"t":161,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.196078434587,0.380392163992,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":192,"st":2,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"streamer b 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":171,"ix":10},"p":{"a":0,"k":[543,427,0],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.929411768913,0.196078434587,0.317647069693,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[4]},{"t":61,"s":[0.5]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[0]},{"t":61,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[35]},{"t":61,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":13,"op":62,"st":13,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"streamer a 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":151,"ix":10},"p":{"a":0,"k":[454,444,0],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[-100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882364511,0.831372559071,0.803921580315,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[4]},{"t":53,"s":[0.5]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"t":53,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[35]},{"t":53,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":10,"op":54,"st":10,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle a 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":29,"s":[-371.368]},{"t":191,"s":[-2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":1,"s":[599.5,838,0],"to":[-53.333,-113.333,0],"ti":[56.667,-3.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":29,"s":[279.5,158,0],"to":[-56.667,3.333,0],"ti":[0,0,0]},{"t":191,"s":[259.5,858,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":1,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":29,"s":[100,100,100]},{"t":161,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.305882364511,0.831372559071,0.411764711142,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":192,"st":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle b 2","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":21,"s":[-250.839]},{"t":158,"s":[-2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[599.5,838,0],"to":[-53.333,-100,0],"ti":[63,-7,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":21,"s":[279.5,238,0],"to":[-63,7,0],"ti":[0,0,0]},{"t":158,"s":[221.5,880,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":3,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":21,"s":[100,100,100]},{"t":128,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.537254929543,0.196078434587,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":159,"st":3,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"star a 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":31,"s":[-397.895]},{"t":191,"s":[-2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":1,"s":[596.087,836.292,0],"to":[-9.431,-113.333,0],"ti":[42.765,-3.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":31,"s":[539.5,156.292,0],"to":[-42.765,3.333,0],"ti":[0,0,0]},{"t":191,"s":[339.5,856.292,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":1,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":31,"s":[100,100,100]},{"t":161,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.305882364511,0.831372559071,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":192,"st":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"star b 2","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":23,"s":[-278.71]},{"t":158,"s":[-2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":3,"s":[596.087,836.292,0],"to":[-12.765,-96.667,0],"ti":[52.765,-3.333,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":23,"s":[519.5,256.292,0],"to":[-52.765,3.333,0],"ti":[0,0,0]},{"t":158,"s":[279.5,856.292,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":3,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":23,"s":[100,100,100]},{"t":128,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.196078434587,0.784313738346,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":159,"st":3,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"rec a 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-556.875]},{"t":128,"s":[-2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":0,"s":[599.5,842,0],"to":[-16.667,-120,0],"ti":[66.667,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":33,"s":[499.5,122,0],"to":[-66.667,0,0],"ti":[0,0,0]},{"t":128,"s":[199.5,842,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":0,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":33,"s":[100,100,100]},{"t":98,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.588235318661,0.831372559071,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":129,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"rec b 2","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[-306.667]},{"t":218,"s":[-2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":2,"s":[599.5,842,0],"to":[-22.62,-109.87,0],"ti":[2.877,-2.055,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":25,"s":[339.5,262,0],"to":[-51.333,36.667,0],"ti":[0,0,0]},{"t":218,"s":[219.5,862,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":2,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":25,"s":[100,100,100]},{"t":188,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.196078434587,0.317647069693,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":219,"st":2,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"square a 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":35,"s":[-590.625]},{"t":128,"s":[-2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":0,"s":[599.5,838,0],"to":[-20,-90,0],"ti":[36.667,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":35,"s":[479.5,298,0],"to":[-36.667,0,0],"ti":[0,0,0]},{"t":128,"s":[379.5,838,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":0,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":35,"s":[100,100,100]},{"t":98,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.960784316063,0.572549045086,0.180392161012,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":129,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"square b 2","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.333],"y":[0]},"t":27,"s":[-333.333]},{"t":218,"s":[-2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":2,"s":[599.5,838,0],"to":[-10,-103.333,0],"ti":[50,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":27,"s":[539.5,218,0],"to":[-50,0,0],"ti":[0,0,0]},{"t":218,"s":[299.5,838,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0.167,0]},"t":2,"s":[100,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":27,"s":[100,100,100]},{"t":188,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.196078434587,0.588235318661,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":219,"st":2,"bm":0}]},{"id":"comp_2","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"_small-side","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[260,320,0],"ix":2},"a":{"a":0,"k":[400,400,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":800,"h":800,"ip":0,"op":219,"st":0,"bm":0}]},{"id":"comp_3","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"left","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[400,400,0],"ix":2},"a":{"a":0,"k":[400,400,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":800,"h":800,"ip":13,"op":313,"st":13,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"right","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[400,400,0],"ix":2},"a":{"a":0,"k":[400,400,0],"ix":1},"s":{"a":0,"k":[-100,100,100],"ix":6}},"ao":0,"w":800,"h":800,"ip":30,"op":330,"st":30,"bm":0}]},{"id":"comp_4","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"streamer a 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":14,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":13,"s":[219.178,-190.096,0],"to":[-95.333,426.667,0],"ti":[167.333,-560.667,0]},{"t":173,"s":[179.178,989.904,0]}],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[-100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.196078434587,0.380392163992,0.929411768913,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[4]},{"t":176,"s":[0.5]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[0]},{"t":176,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[40]},{"t":176,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":13,"op":174,"st":13,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"streamer b 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-1.458,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":5,"s":[269.863,-175.455,0],"to":[-110,415.333,0],"ti":[216,-599.333,0]},{"t":173,"s":[69.863,984.545,0]}],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.929411768913,0.745098054409,0.196078434587,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[4]},{"t":173,"s":[0.5]}],"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[0]},{"t":173,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[40]},{"t":173,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":5,"op":174,"st":5,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"circle a 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0]},{"t":155,"s":[1800]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[325.643,-26.292,0],"to":[-101.333,75.667,0],"ti":[15.333,-507.667,0]},{"t":155,"s":[125.643,835.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[50,100,100]},{"t":155,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.960784316063,0.572549045086,0.180392161012,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":8,"op":156,"st":-7,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle b 4","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"t":215,"s":[2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[619.5,-26.292,0],"to":[-138,77.667,0],"ti":[-2,-497.667,0]},{"t":215,"s":[259.5,835.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":2,"s":[50,100,100]},{"t":215,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.196078434587,0.588235318661,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":216,"st":-13,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"star a 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":245,"s":[2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[376.929,-28,0],"to":[-213.333,157.667,0],"ti":[173.333,-127.667,0]},{"t":245,"s":[116.929,834,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[50,100,100]},{"t":245,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.745098054409,0.196078434587,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":246,"st":-9,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"star b 4","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"t":125,"s":[1800]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[171.786,-28,0],"to":[0,0,0],"ti":[-161.333,-275.667,0]},{"t":125,"s":[251.786,834,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":2,"s":[50,100,100]},{"t":125,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.537254929543,0.196078434587,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":126,"st":-13,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"rec a 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":185,"s":[2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[428.214,-22.292,0],"to":[-167.333,119.667,0],"ti":[-130.667,-315.667,0]},{"t":185,"s":[228.214,839.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[50,100,100]},{"t":185,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.305882364511,0.831372559071,0.411764711142,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":186,"st":-11,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"rec b 4","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":245,"s":[2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[223.071,-22.292,0],"to":[0,0,0],"ti":[-92.571,-383.708,0]},{"t":245,"s":[223.071,839.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[50,100,100]},{"t":245,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.196078434587,0.784313738346,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":246,"st":-9,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"square a 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":217,"s":[2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[120.5,-26.292,0],"to":[13,430.305,0],"ti":[52.221,-418.892,0]},{"t":217,"s":[198.5,833.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[50,100,100]},{"t":217,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.588235318661,0.831372559071,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":218,"st":-11,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"square b 4","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0]},{"t":215,"s":[2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[274.357,-26.292,0],"to":[157.333,415.667,0],"ti":[22.667,-253.667,0]},{"t":215,"s":[114.357,835.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[50,100,100]},{"t":215,"s":[100,50,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.588235318661,0.831372559071,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":8,"op":216,"st":-7,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"streamer a 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":3,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[275.178,-173.096,0],"to":[-87.333,413.333,0],"ti":[177.333,-643.333,0]},{"t":185,"s":[219.178,974.904,0]}],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[-100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882364511,0.831372559071,0.803921580315,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[4]},{"t":177,"s":[0.5]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[0]},{"t":177,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[40]},{"t":177,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":186,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"streamer b 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":9,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":11,"s":[199.863,74.545,0],"to":[-13.363,405.455,0],"ti":[179.333,-430.667,0]},{"t":217,"s":[139.863,834.545,0]}],"ix":2},"a":{"a":0,"k":[-157,-245,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.685,-13.314],[0,-14.907],[0,-15.206],[0,-14.907],[0,-14.907],[0,-15.206],[1.754,-14.206],[-3.934,-9.465]],"o":[[-3.895,8.562],[1.872,14.789],[0,15.206],[0,14.907],[0,14.907],[0,15.206],[0,14.314],[-1.803,14.605],[0,0]],"v":[[-156.5,-406],[-166.5,-367],[-146.5,-327],[-166.5,-286],[-146.5,-246],[-166.5,-206],[-146.5,-165],[-166.5,-127],[-156.5,-84]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.929411768913,0.196078434587,0.317647069693,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[4]},{"t":199,"s":[0.5]}],"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[0]},{"t":199,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[40]},{"t":199,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":11,"op":218,"st":11,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle a 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"t":125,"s":[-1800]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[365.643,-26.292,0],"to":[-101.333,75.667,0],"ti":[15.333,-507.667,0]},{"t":125,"s":[165.643,835.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":2,"s":[100,50,100]},{"t":125,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.305882364511,0.831372559071,0.411764711142,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":126,"st":-13,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle b 3","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0]},{"t":245,"s":[-2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[519.5,-26.292,0],"to":[-138,77.667,0],"ti":[-2,-497.667,0]},{"t":245,"s":[159.5,835.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[100,50,100]},{"t":245,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.537254929543,0.196078434587,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":8,"op":246,"st":-7,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"star a 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":245,"s":[-2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[416.929,-28,0],"to":[-213.333,157.667,0],"ti":[173.333,-127.667,0]},{"t":245,"s":[156.929,834,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[100,50,100]},{"t":245,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.305882364511,0.831372559071,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":246,"st":-9,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"star b 3","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[0]},{"t":155,"s":[-2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":8,"s":[211.786,-28,0],"to":[0,0,0],"ti":[-161.333,-275.667,0]},{"t":155,"s":[291.786,834,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[100,50,100]},{"t":155,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.196078434587,0.784313738346,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":8,"op":156,"st":-7,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"rec a 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":185,"s":[-2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[468.214,-22.292,0],"to":[-167.333,119.667,0],"ti":[-130.667,-315.667,0]},{"t":185,"s":[268.214,839.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[100,50,100]},{"t":185,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.588235318661,0.831372559071,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":186,"st":-11,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"rec b 3","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[0]},{"t":245,"s":[-2880]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[263.071,-22.292,0],"to":[0,143.667,0],"ti":[-114.571,-267.708,0]},{"t":245,"s":[263.071,839.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[100,50,100]},{"t":245,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411768913,0.196078434587,0.317647069693,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":246,"st":-9,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"square a 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":2,"s":[0]},{"t":217,"s":[-2520]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":2,"s":[160.5,-26.292,0],"to":[13,430.305,0],"ti":[52.221,-418.892,0]},{"t":217,"s":[238.5,833.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":2,"s":[100,50,100]},{"t":217,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.960784316063,0.572549045086,0.180392161012,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":2,"op":218,"st":-13,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"square b 3","sr":1,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":185,"s":[-2160]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[314.357,-26.292,0],"to":[157.333,415.667,0],"ti":[22.667,-253.667,0]},{"t":185,"s":[154.357,835.708,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[100,50,100]},{"t":185,"s":[50,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.196078434587,0.588235318661,0.929411768913,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":186,"st":-11,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"cannon (small - left)","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[76,452,0],"ix":2},"a":{"a":0,"k":[0,360,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":480,"h":720,"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"cannon (small - right)","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[533,452,0],"ix":2},"a":{"a":0,"k":[479.994,360,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":480,"h":720,"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"cannon (small - top)","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[304,408,0],"ix":2},"a":{"a":0,"k":[400,400,0],"ix":1},"s":{"a":0,"k":[102,102,100],"ix":6}},"ao":0,"w":800,"h":800,"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift index fb0e1b6b..121f362d 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeInteractor.swift @@ -142,7 +142,7 @@ extension HomeInteractor { if completed == .uncomfirmed { self.worker.challengeCompletedConfirmed = true - await self.presenter.presentCompletedPopup(challenge: challenge) + await self.presenter.presentChallengeCompleteSharePopup(challenge: challenge) } } } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift index d11a7c16..2e54cef1 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeModels.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeModels.swift @@ -388,6 +388,19 @@ enum Home { var progressText: String } + struct ChallengeCompleteSharePopupViewModel { + /// 냘짜 텍스트 + var dateText: String + /// 챌린지 명 타이틀 텍스트 + var titleNameText: String + /// 챌린지 순서 텍스트 + var orderText: String + /// 상대방 꽃 이미지 + var partnerFlowerImage: UIImage + /// 내 꽃 이미지 + var myFlowerImage: UIImage + } + struct Toast { var message: String? } diff --git a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift index 34dd440d..2c19d291 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomePresenter.swift @@ -41,6 +41,8 @@ protocol HomePresentationLogic { func presentExceededStickCountError() /// 인증 성공 공유하기 모달을 보여준다. func presentCertificationSharePopup(challenge: Home.Model.Challenge) + /// 챌린지 성공 공유하기 모달을 보여준다. + func presentChallengeCompleteSharePopup(challenge: Home.Model.Challenge) } final class HomePresenter { @@ -129,6 +131,18 @@ extension HomePresenter: HomePresentationLogic { ) self.viewController?.displayCertificationSharePopupViewModel(viewModel: viewModel) } + + func presentChallengeCompleteSharePopup(challenge: Home.Model.Challenge) { + let challengeCompletedViewModel = challenge.toChallengeCompletedViewModel() + let viewModel = Home.ViewModel.ChallengeCompleteSharePopupViewModel( + dateText: Date().dateToString(.monthDayE), + titleNameText: challenge.name ?? "", + orderText: "\(challenge.order ?? 0)번째 챌린지 완료", + partnerFlowerImage: challengeCompletedViewModel.partnerFlower.image, + myFlowerImage: challengeCompletedViewModel.myFlower.image + ) + self.viewController?.displayChallengeCompleteSharePopupViewModel(viewModel: viewModel) + } } // MARK: - Mapping Logic @@ -226,7 +240,7 @@ extension Home.Model.Challenge { viewModel.myFlower.myNameText = self.myInfo.nickname // 찌르기 텍스트 - viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/3)" + viewModel.stickText = "콕 찌르기 (\(self.stickRemaining ?? 0)/5)" // 챌린지 진행 상태 매핑 switch self.status { @@ -264,13 +278,13 @@ extension Home.Model.Challenge { break } - // 카드 보내기 활성화 여부 - if !(self.partnerInfo.todayCert?.complimentComment ?? "").isEmpty, - !(self.myInfo.todayCert?.complimentComment ?? "").isEmpty { - viewModel.stickText = "카드 보내기" - viewModel.isCardSendTooltipHidden = false - viewModel.isCardSendHidden = false - } +// // 카드 보내기 활성화 여부 +// if !(self.partnerInfo.todayCert?.complimentComment ?? "").isEmpty, +// !(self.myInfo.todayCert?.complimentComment ?? "").isEmpty { +// viewModel.stickText = "카드 보내기" +// viewModel.isCardSendTooltipHidden = false +// viewModel.isCardSendHidden = false +// } return viewModel } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift index 884499e1..6f264505 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeViewController.swift @@ -20,6 +20,7 @@ protocol HomeDisplayLogic: AnyObject { func displayBothCertificationViewModel(viewModel: Home.ViewModel.ChallengeInProgressViewModel.BothCertificationPopupViewModel) func displayCompletedViewModel(viewModel: Home.ViewModel.ChallengeCompletedViewModel.CompletedPopupViewModel) func displayCertificationSharePopupViewModel(viewModel: Home.ViewModel.CertificationSharePopupViewModel) + func displayChallengeCompleteSharePopupViewModel(viewModel: Home.ViewModel.ChallengeCompleteSharePopupViewModel) func displayToast(viewModel: Home.ViewModel.Toast) } @@ -40,6 +41,7 @@ final class HomeViewController: UIViewController { var completedPopupView: TTPopup? var flowerLanguagePopupView: TTFlowerPopup? var certificationSharePopupView: TTCertificationSharePopup? + var challengeCompletePopupView: TTChallengeCompleteSharePopup? // MARK: - UI Component /// 네비게이션 바 @@ -425,6 +427,18 @@ extension HomeViewController: HomeDisplayLogic { } } + func displayChallengeCompleteSharePopupViewModel(viewModel: Home.ViewModel.ChallengeCompleteSharePopupViewModel) { + let popupView = TTChallengeCompleteSharePopup(frame: .zero) + popupView.configure(viewModel: viewModel) + + self.challengeCompletePopupView = popupView + self.challengeCompletePopupView?.delegate = self + + if let challengeCompletePopupView = self.challengeCompletePopupView { + self.view.addSubview(challengeCompletePopupView) + } + } + func displayToast(viewModel: Home.ViewModel.Toast) { viewModel.message.unwrap { Toast.shared.makeToast($0) @@ -597,6 +611,24 @@ extension HomeViewController: TTCertificationSharePopupDelegate { } } +extension HomeViewController: TTChallengeCompleteSharePopupDelegate { + + func didTapChallengeCompleteSharePopupDimView() { + self.challengeCompletePopupView?.removeFromSuperview() + self.challengeCompletePopupView = nil + } + + func didTapChallengeCompleteSharePopupCloseButton() { + self.challengeCompletePopupView?.removeFromSuperview() + self.challengeCompletePopupView = nil + } + + func didTapChallengeCompleteSharePopupShareButton(image: UIImage) { + let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil) + self.present(activityViewController, animated: true) + } +} + extension HomeViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { diff --git a/Scene/HomeScene/Sources/HomeScene/Views/Common/TTChallengeCompleteSharePopup.swift b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTChallengeCompleteSharePopup.swift new file mode 100644 index 00000000..3022bc9e --- /dev/null +++ b/Scene/HomeScene/Sources/HomeScene/Views/Common/TTChallengeCompleteSharePopup.swift @@ -0,0 +1,258 @@ +// +// TTChallengeCompleteSharePopup.swift +// +// +// Created by 박건우 on 1/29/24. +// + +import CoreKit +import Lottie +import UIKit + +protocol TTChallengeCompleteSharePopupDelegate: AnyObject { + func didTapChallengeCompleteSharePopupDimView() + func didTapChallengeCompleteSharePopupCloseButton() + func didTapChallengeCompleteSharePopupShareButton(image: UIImage) +} + +final class TTChallengeCompleteSharePopup: UIView { + + weak var delegate: TTChallengeCompleteSharePopupDelegate? + + private lazy var dimView: UIView = { + let v = UIView() + v.backgroundColor = .black.withAlphaComponent(0.5) + v.addTapAction { [weak self] in + self?.delegate?.didTapChallengeCompleteSharePopupDimView() + } + return v + }() + + private lazy var celebrateLottieView: LottieAnimationView = { + let v = LottieAnimationView(name: "celebrate_lottie", bundle: .module) + v.loopMode = .playOnce + v.animationSpeed = 1 + v.play() + return v + }() + + private lazy var headlineLabel: UILabel = { + let v = UILabel() + v.font = .h3 + v.textColor = .white + v.text = "챌린지 완료 카드를 획득했어요!" + return v + }() + + private lazy var contentView: UIView = { + let v = UIView() + v.backgroundColor = .white + v.layer.cornerRadius = 20 + v.clipsToBounds = true + return v + }() + + private lazy var captureBgView: UIView = { + let v = UIView() + v.layer.cornerRadius = 10 + v.clipsToBounds = true + return v + }() + + private lazy var captureView: UIView = { + let v = UIView() + v.backgroundColor = .second02 + return v + }() + + private lazy var dateLabel: UILabel = { + let v = UILabel() + v.font = .body2 + v.textColor = .black + return v + }() + + private lazy var titleLabel: UILabel = { + let v = UILabel() + v.font = .h3 + v.textColor = .primary + v.numberOfLines = 2 + v.lineBreakMode = .byTruncatingTail + return v + }() + + private lazy var captionBgView: UIView = { + let v = UIView() + v.backgroundColor = .white + v.layer.cornerRadius = 8 + v.clipsToBounds = true + return v + }() + + private lazy var captionLabel: UILabel = { + let v = UILabel() + v.font = .body3 + v.textColor = .mainCoral + return v + }() + + private lazy var partnerFlowerImageView: UIImageView = { + let v = UIImageView() + return v + }() + + private lazy var myFlowerImageView: UIImageView = { + let v = UIImageView() + return v + }() + + private lazy var captureBottomBgImageView: UIImageView = { + let v = UIImageView() + v.image = .asset(.popup_ground) + return v + }() + + private lazy var logoLabel: UILabel = { + let v = UILabel() + v.font = .h4 + v.textColor = .mainWhite + v.text = "Twotoo" + return v + }() + + private lazy var shareButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "공유하기", .large) + v.setIsEnabled(true) + v.addAction { [weak self] in + guard let self = self else { + return + } + let image = self.makeImage() + self.delegate?.didTapChallengeCompleteSharePopupShareButton(image: image) + } + return v + }() + + private lazy var closeButton: TTPrimaryButtonType = { + let v = TTPrimaryButton.create(title: "닫기", .large) + v.setTitleColor(.white, for: .normal) + v.backgroundColor = .clear + v.addAction { [weak self] in + self?.delegate?.didTapChallengeCompleteSharePopupCloseButton() + } + return v + }() + + override init(frame: CGRect) { + super.init(frame: .zero) + self.layout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func didMoveToSuperview() { + super.didMoveToSuperview() + + if self.superview != nil { + self.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } + } + + func layout() { + self.addSubviews(self.dimView, self.celebrateLottieView, self.headlineLabel, self.contentView, self.closeButton) + self.contentView.addSubviews(self.captureBgView, self.shareButton) + self.captureBgView.addSubviews(self.captureView) + self.captureView.addSubviews(self.captureBottomBgImageView, self.dateLabel, self.titleLabel, self.captionBgView, self.partnerFlowerImageView, self.myFlowerImageView, self.logoLabel) + self.captionBgView.addSubview(self.captionLabel) + + self.dimView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + self.celebrateLottieView.snp.makeConstraints { make in + make.top.centerX.equalToSuperview() + } + self.headlineLabel.snp.makeConstraints { make in + make.bottom.equalTo(self.contentView.snp.top).offset(-16) + make.centerX.equalToSuperview() + } + self.contentView.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(51) + make.centerY.equalToSuperview() + } + self.closeButton.snp.makeConstraints { make in + make.top.equalTo(self.contentView.snp.bottom).offset(10) + make.centerX.equalToSuperview() + } + self.captureBgView.snp.makeConstraints { make in + make.leading.top.trailing.equalToSuperview().inset(11) + } + self.captureView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + self.shareButton.snp.makeConstraints { make in + make.top.equalTo(self.captureView.snp.bottom).offset(7) + make.leading.trailing.bottom.equalToSuperview().inset(11) + } + self.dateLabel.snp.makeConstraints { make in + make.top.equalToSuperview().inset(32) + make.leading.equalToSuperview().inset(24) + } + self.titleLabel.snp.makeConstraints { make in + make.top.equalTo(self.dateLabel.snp.bottom).offset(10) + make.leading.trailing.equalToSuperview().inset(24) + } + self.captionBgView.snp.makeConstraints { make in + make.top.equalTo(self.titleLabel.snp.bottom).offset(10) + make.leading.equalToSuperview().inset(24) + } + self.captionLabel.snp.makeConstraints { make in + make.edges.equalToSuperview().inset(5) + } + self.captureBottomBgImageView.snp.makeConstraints { make in + make.leading.trailing.bottom.equalToSuperview() + make.height.equalTo(self.captureBottomBgImageView.snp.width).multipliedBy(114 / 375.0) + } + self.partnerFlowerImageView.snp.makeConstraints { make in + make.top.equalTo(self.captionBgView.snp.bottom).offset(16) + make.bottom.equalToSuperview().inset(42) + make.leading.equalTo(self.captureView.snp.centerX).offset(10) + make.width.equalToSuperview().multipliedBy(130 / 375.0) + make.height.equalTo(self.partnerFlowerImageView.snp.width).multipliedBy(217 / 130.0) + } + self.myFlowerImageView.snp.makeConstraints { make in + make.top.equalTo(self.captionBgView.snp.bottom).offset(16) + make.bottom.equalToSuperview().inset(42) + make.trailing.equalTo(self.captureView.snp.centerX).offset(-10) + make.width.equalToSuperview().multipliedBy(130 / 375.0) + make.height.equalTo(self.partnerFlowerImageView.snp.width).multipliedBy(217 / 130.0) + } + self.logoLabel.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(10) + make.leading.equalToSuperview().inset(21) + } + } + + func configure(viewModel: Home.ViewModel.ChallengeCompleteSharePopupViewModel) { + self.dateLabel.text = viewModel.dateText + self.titleLabel.text = viewModel.titleNameText + self.captionLabel.text = viewModel.orderText + self.partnerFlowerImageView.image = viewModel.partnerFlowerImage + self.myFlowerImageView.image = viewModel.myFlowerImage + } + + // MARK: - Business Logic + + private func makeImage() -> UIImage { + let renderer = UIGraphicsImageRenderer(bounds: self.captureView.bounds) + + let image = renderer.image { ctx in + self.captureView.drawHierarchy(in: self.captureView.bounds, afterScreenUpdates: true) + } + + return image + } +} diff --git a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeCompletedMappingSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeCompletedMappingSpec.swift index fe662f5d..bfed3577 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeCompletedMappingSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeCompletedMappingSpec.swift @@ -101,31 +101,31 @@ final class ChallengeCompletedMappingSpec: QuickSpec { it("내 꽃의 꽃 이름 히든 여부가 true 로 표현된다.") { model.myInfo.growStatus = .seed viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.myFlower.isFlowerTextHidden).to(beTrue()) + expect(viewModel.myFlower.isFlowerLanguageBubbleHidden).to(beTrue()) } it("내 꽃의 꽃 이름 히든 여부가 true 로 표현된다.") { model.myInfo.growStatus = .sprout viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.myFlower.isFlowerTextHidden).to(beTrue()) + expect(viewModel.myFlower.isFlowerLanguageBubbleHidden).to(beTrue()) } it("내 꽃의 꽃 이름 히든 여부가 true 로 표현된다.") { model.myInfo.growStatus = .peak viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.myFlower.isFlowerTextHidden).to(beTrue()) + expect(viewModel.myFlower.isFlowerLanguageBubbleHidden).to(beTrue()) } it("내 꽃의 꽃 이름 히든 여부가 false 로 표현된다.") { model.myInfo.growStatus = .flower viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.myFlower.isFlowerTextHidden).to(beFalse()) + expect(viewModel.myFlower.isFlowerLanguageBubbleHidden).to(beFalse()) } it("내 꽃의 꽃 이름 히든 여부가 false 로 표현된다.") { model.myInfo.growStatus = .bloom viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.myFlower.isFlowerTextHidden).to(beFalse()) + expect(viewModel.myFlower.isFlowerLanguageBubbleHidden).to(beFalse()) } } @@ -181,31 +181,31 @@ final class ChallengeCompletedMappingSpec: QuickSpec { it("상대방 꽃의 꽃 이름 히든 여부가 true 로 표현된다.") { model.partnerInfo.growStatus = .seed viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.partnerFlower.isFlowerTextHidden).to(beTrue()) + expect(viewModel.partnerFlower.isFlowerLanguageBubbleHidden).to(beTrue()) } it("상대방 꽃의 꽃 이름 히든 여부가 true 로 표현된다.") { model.partnerInfo.growStatus = .sprout viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.partnerFlower.isFlowerTextHidden).to(beTrue()) + expect(viewModel.partnerFlower.isFlowerLanguageBubbleHidden).to(beTrue()) } it("상대방 꽃의 꽃 이름 히든 여부가 true 로 표현된다.") { model.partnerInfo.growStatus = .peak viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.partnerFlower.isFlowerTextHidden).to(beTrue()) + expect(viewModel.partnerFlower.isFlowerLanguageBubbleHidden).to(beTrue()) } it("상대방 꽃의 꽃 이름 히든 여부가 false 로 표현된다.") { model.partnerInfo.growStatus = .flower viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.partnerFlower.isFlowerTextHidden).to(beFalse()) + expect(viewModel.partnerFlower.isFlowerLanguageBubbleHidden).to(beFalse()) } it("상대방 꽃의 꽃 이름 히든 여부가 false 로 표현된다.") { model.partnerInfo.growStatus = .bloom viewModel = model.toChallengeCompletedViewModel() - expect(viewModel.partnerFlower.isFlowerTextHidden).to(beFalse()) + expect(viewModel.partnerFlower.isFlowerLanguageBubbleHidden).to(beFalse()) } } } diff --git a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift index 27334e78..490875e6 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift @@ -283,8 +283,8 @@ final class ChallengeInProgressMappingSpec: QuickSpec { } context("찌르기 남은 횟수") { - it("찌르기 텍스트가 '콕 찌르기 (3/3)'로 표현된다.") { - expect(viewModel.stickText).to(equal("콕 찌르기 (3/3)")) + it("찌르기 텍스트가 '콕 찌르기 (3/5)'로 표현된다.") { + expect(viewModel.stickText).to(equal("콕 찌르기 (3/5)")) } } } diff --git a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/CompletedMappingSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/CompletedMappingSpec.swift index e281f2f2..ed45b08c 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/CompletedMappingSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/CompletedMappingSpec.swift @@ -9,7 +9,7 @@ final class CompletedMappingSpec: QuickSpec { override func spec() { describe("CompletedViewModel") { var model: Home.Model.Challenge! - var viewModel: Home.ViewModel.CompletedViewModel! + var viewModel: Home.ViewModel.ChallengeCompletedViewModel.CompletedPopupViewModel! beforeEach { var tomorrowComponents = DateComponents() From e0b4d44bd9f417c4f6bf825288db9fb9b027df01 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Wed, 31 Jan 2024 20:37:36 +0900 Subject: [PATCH 39/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=B0=8C=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=B5=9C=EB=8C=80=20=ED=9A=9F=EC=88=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(3=20->=205)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scene/HomeScene/Sources/HomeScene/HomeRouter.swift | 2 +- Scene/HomeScene/Sources/HomeScene/HomeWorker.swift | 2 +- .../Sources/HomeScene/Views/ChallengeInProgressView.swift | 2 +- .../HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift | 5 +++++ .../Mapping/ChallengeInProgressMappingSpec.swift | 2 +- .../Sources/NudgeSendScene/NudgeSendPresenter.swift | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift index 02f58b7a..6977c110 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeRouter.swift @@ -89,7 +89,7 @@ extension HomeRouter: HomeRoutingLogic { return } let nudgeSendScene = NudgeSendSceneFactory().make( - with: .init(remainingNudgeCount: dataStore.challenge?.stickRemaining ?? 3) + with: .init(remainingNudgeCount: dataStore.challenge?.stickRemaining ?? 5) ) self.viewController?.present(nudgeSendScene.bottomSheetViewController, animated: true) } diff --git a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift index 00c3fdb6..f7253a74 100644 --- a/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift +++ b/Scene/HomeScene/Sources/HomeScene/HomeWorker.swift @@ -116,7 +116,7 @@ final class HomeWorker: HomeWorkerProtocol { status: challengeStatus, myInfo: myInfo, partnerInfo: partnerInfo, - stickRemaining: 3 - (homeResponse.myStingCnt ?? 0), + stickRemaining: 5 - (homeResponse.myStingCnt ?? 0), description: homeResponse.onGoingChallenge?.description ) diff --git a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift index fe460699..d40de720 100644 --- a/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift +++ b/Scene/HomeScene/Sources/HomeScene/Views/ChallengeInProgressView.swift @@ -79,7 +79,7 @@ final class ChallengeInProgressView: UIView { /// 찌르기 버튼 타이틀 lazy var nudgeTitleLabel: UILabel = { let v = UILabel() - v.text = "콕 찌르기 (3/3)" + v.text = "콕 찌르기 (5/5)" v.textColor = .primary v.font = .body2 v.textAlignment = .center diff --git a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift index 739ed5b7..a6c5b68b 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/HomeInteractorSpec.swift @@ -715,6 +715,7 @@ class HomePresenterMock: HomePresentationLogic { var isPresentCompleteRequestErrorCalled = false var isPresentExceededStickCountErrorCalled = false var isPresentCertificationSharePopupCalled = false + var isPresentChallengeCompleteSharePopupCalled = false var lastChallenge: Home.Model.Challenge? var lastHomeError: Error? @@ -789,6 +790,10 @@ class HomePresenterMock: HomePresentationLogic { func presentCertificationSharePopup(challenge: Home.Model.Challenge) { self.isPresentCertificationSharePopupCalled = true } + + func presentChallengeCompleteSharePopup(challenge: Home.Model.Challenge) { + self.isPresentChallengeCompleteSharePopupCalled = true + } } class HomeWorkerMock: HomeWorkerProtocol { diff --git a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift index 490875e6..2df2641a 100644 --- a/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift +++ b/Scene/HomeScene/Tests/HomeSceneTests/Mapping/ChallengeInProgressMappingSpec.swift @@ -34,7 +34,7 @@ final class ChallengeInProgressMappingSpec: QuickSpec { certCount: 1, todayCert: .init(id: "certId", complimentComment: "Test") ), - stickRemaining: 3 + stickRemaining: 5 ) viewModel = model.toChallengeInProgressViewModel() diff --git a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift index 0940a946..498efdf4 100644 --- a/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift +++ b/Scene/NudgeSendScene/Sources/NudgeSendScene/NudgeSendPresenter.swift @@ -33,7 +33,7 @@ extension NudgeSendPresenter: NudgeSendPresentationLogic { func presentRemainingNudgeCount(remainingNudgeCount: Int) { self.viewController?.displayTitle(viewModel: .init( - text: "찌르기 문구 보내기 (\(remainingNudgeCount)/3)" + text: "찌르기 문구 보내기 (\(remainingNudgeCount)/5)" )) } From 57cf423fcfd5ce808651efa4f0191b4e9e36be5e Mon Sep 17 00:00:00 2001 From: gunoooo Date: Wed, 31 Jan 2024 20:58:29 +0900 Subject: [PATCH 40/44] =?UTF-8?q?=E2=9C=A8=20=EB=B2=84=EC=A0=84=EC=97=85?= =?UTF-8?q?=20(1.0.1=20->=201.1.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TwoToo.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TwoToo.xcodeproj/project.pbxproj b/TwoToo.xcodeproj/project.pbxproj index 362162e4..add747de 100644 --- a/TwoToo.xcodeproj/project.pbxproj +++ b/TwoToo.xcodeproj/project.pbxproj @@ -423,7 +423,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "kr.mash-up.TwoToo"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -464,7 +464,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "kr.mash-up.TwoToo"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; From cd5fd07c6a5eb8de2d4f770d33100fbae8e9181f Mon Sep 17 00:00:00 2001 From: ji_in Date: Wed, 31 Jan 2024 21:37:02 +0900 Subject: [PATCH 41/44] =?UTF-8?q?=F0=9F=90=9B=20=EB=B0=94=ED=85=80?= =?UTF-8?q?=EC=8B=9C=ED=8A=B8=20=EB=86=92=EC=9D=B4=EA=B0=80=20=EA=B3=A0?= =?UTF-8?q?=EC=A0=95=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeRecommendViewController.swift | 3 ++- .../Sources/PraiseSendScene/PraiseSendViewController.swift | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Scene/ChallengeCreateScene/Sources/ChallengeRecommendScene/ChallengeRecommendViewController.swift b/Scene/ChallengeCreateScene/Sources/ChallengeRecommendScene/ChallengeRecommendViewController.swift index fb20ed85..e64109fd 100644 --- a/Scene/ChallengeCreateScene/Sources/ChallengeRecommendScene/ChallengeRecommendViewController.swift +++ b/Scene/ChallengeCreateScene/Sources/ChallengeRecommendScene/ChallengeRecommendViewController.swift @@ -55,7 +55,8 @@ final class ChallengeRecommendViewController: UIViewController, BottomSheetViewC }() private lazy var backScrollView: UIScrollView = { - let v = SelfSizingScrollView() + let heightRatio = UIDevice.current.deviceType == .default ? 0.8 : 0.67 + let v = SelfSizingScrollView(maxHeightRatio: heightRatio) v.addSubview(self.scrollSizeFitView) v.delegate = self v.addTapAction { [weak self] in diff --git a/Scene/PraiseSendScene/Sources/PraiseSendScene/PraiseSendViewController.swift b/Scene/PraiseSendScene/Sources/PraiseSendScene/PraiseSendViewController.swift index 6c1564c5..073734fd 100644 --- a/Scene/PraiseSendScene/Sources/PraiseSendScene/PraiseSendViewController.swift +++ b/Scene/PraiseSendScene/Sources/PraiseSendScene/PraiseSendViewController.swift @@ -76,7 +76,8 @@ final class PraiseSendViewController: UIViewController, BottomSheetViewControlle }() private lazy var backScrollView: UIScrollView = { - let v = SelfSizingScrollView() + let heightRatio = UIDevice.current.deviceType == .default ? 0.8 : 0.67 + let v = SelfSizingScrollView(maxHeightRatio: heightRatio) v.addSubview(self.scrollSizeFitView) return v }() From 508af2643b0cb7718bf79bbf1dac608516196a16 Mon Sep 17 00:00:00 2001 From: kimkyunghun3 Date: Wed, 31 Jan 2024 21:48:06 +0900 Subject: [PATCH 42/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=B9=AD=EC=B0=AC?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=ED=94=8C=EB=A1=9C=EC=9A=B0=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChallengeHistoryDetailWorker.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift index 253ffce7..c8c4a366 100644 --- a/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift +++ b/Scene/ChallengeHistoryDetailScene/Sources/ChallengeHistoryDetailScene/ChallengeHistoryDetailWorker.swift @@ -37,14 +37,17 @@ final class ChallengeHistoryDetailWorker: ChallengeHistoryDetailWorkerProtocol { let myNickname: String let partnerNickname: String - let isMine = challengeDetailListResponse.user1CommitList.map(\.commitNo).contains(commitID) - - if isMine { + let isMine: Bool + + if challengeDetailListResponse.user1.userNo == self.meLocalWorker.userNo { myNickname = challengeDetailListResponse.user1.nickname partnerNickname = challengeDetailListResponse.user2.nickname - } else { + isMine = challengeDetailListResponse.user1CommitList.map(\.commitNo).contains(commitID) + } + else { myNickname = challengeDetailListResponse.user2.nickname partnerNickname = challengeDetailListResponse.user1.nickname + isMine = challengeDetailListResponse.user2CommitList.map(\.commitNo).contains(commitID) } return .init( From 1020af91b44690a798f21308ea784104ccd7c968 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Wed, 31 Jan 2024 21:54:39 +0900 Subject: [PATCH 43/44] =?UTF-8?q?=F0=9F=90=9B=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=A3=BC=EC=9E=85=20=EB=B0=9B=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=95=84=20=EC=83=9D=EA=B8=B4=20=EC=BB=B4=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scene/ChallengeHistoryDetailScene/Package.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Scene/ChallengeHistoryDetailScene/Package.swift b/Scene/ChallengeHistoryDetailScene/Package.swift index 343f69ff..a5177bc8 100644 --- a/Scene/ChallengeHistoryDetailScene/Package.swift +++ b/Scene/ChallengeHistoryDetailScene/Package.swift @@ -25,14 +25,16 @@ let package = Package( .package( url: "https://github.com/Quick/Quick", .upToNextMajor(from: "6.0.0") - ) + ), + .package(path: "./PraiseSendScene") ], targets: [ .target( name: "ChallengeHistoryDetailScene", dependencies: [ .product(name: "CoreKit", package: "CoreKit"), - .product(name: "SKPhotoBrowser", package: "SKPhotoBrowser") + .product(name: "SKPhotoBrowser", package: "SKPhotoBrowser"), + .product(name: "PraiseSendScene", package: "PraiseSendScene") ], resources: [.process("Assets")] ), From 5042503bc237568cacc3f800097722fcfd42c0b5 Mon Sep 17 00:00:00 2001 From: gunoooo Date: Fri, 2 Feb 2024 18:51:05 +0900 Subject: [PATCH 44/44] =?UTF-8?q?=E2=9C=A8=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EB=84=98=EB=B2=84=20=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TwoToo.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TwoToo.xcodeproj/project.pbxproj b/TwoToo.xcodeproj/project.pbxproj index add747de..79d323cc 100644 --- a/TwoToo.xcodeproj/project.pbxproj +++ b/TwoToo.xcodeproj/project.pbxproj @@ -404,7 +404,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 8; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = MRMBCYN83C; @@ -446,7 +446,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = MRMBCYN83C; GENERATE_INFOPLIST_FILE = YES;