From a61ff00dd8bb9af71d67506c2c31f64bd8bc87bb Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Wed, 27 Dec 2023 22:26:06 +0900 Subject: [PATCH 01/13] =?UTF-8?q?[Fix]=20#344=20-=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EB=B3=80=ED=99=98=20=ED=95=A8=EC=88=98=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Data/Sources/Repository/PokeOnboardingRepository.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SOPT-iOS/Projects/Data/Sources/Repository/PokeOnboardingRepository.swift b/SOPT-iOS/Projects/Data/Sources/Repository/PokeOnboardingRepository.swift index d5990833..150578cb 100644 --- a/SOPT-iOS/Projects/Data/Sources/Repository/PokeOnboardingRepository.swift +++ b/SOPT-iOS/Projects/Data/Sources/Repository/PokeOnboardingRepository.swift @@ -31,7 +31,7 @@ extension PokeOnboardingRepository: PokeOnboardingRepositoryInterface { public func getMesseageTemplates(type: PokeMessageType) -> AnyPublisher { self.pokeService .getPokeMessages(messageType: type.rawValue) - .map { $0.messages.map { $0.toDomain() } } + .map { $0.toDomain() } .eraseToAnyPublisher() } From 420039256ca5be12ec470988332a0ff1d280a8f7 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Thu, 28 Dec 2023 00:02:55 +0900 Subject: [PATCH 02/13] =?UTF-8?q?[Delete]=20#344=20-=20NotificationListCon?= =?UTF-8?q?tentModel=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/NotificationListContentModel.swift | 33 ------------------- 1 file changed, 33 deletions(-) delete mode 100644 SOPT-iOS/Projects/Features/PokeFeature/Sources/Models/NotificationListContentModel.swift diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Models/NotificationListContentModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Models/NotificationListContentModel.swift deleted file mode 100644 index c81ea2d4..00000000 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Models/NotificationListContentModel.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// NotificationListContentModel.swift -// PokeFeature -// -// Created by Ian on 12/3/23. -// Copyright © 2023 SOPT-iOS. All rights reserved. -// - -public struct NotificationListContentModel { - let userId: Int - let avatarUrl: String - let pokeRelation: PokeRelation - let name: String - let partInfomation: String - let description: String - let chipInfo: String - let isPoked: Bool - let isFirstMeet: Bool -} - -extension NotificationListContentModel { - public init() { - self.userId = 0 - self.avatarUrl = "" - self.name = "다혜다해" - self.pokeRelation = .newFriend - self.partInfomation = "29기 안드로이드" - self.description = "Text(아는 사람이 없나요?\n화면을 밑으로 당기면 다른 친구를 볼 수 있어요)" - self.chipInfo = "친한친구" - self.isPoked = Int.random(in: 0...1) == 0 ? false : true - self.isFirstMeet = false - } -} From 4ba2779ff3b2ea3c194d7004a00650d321839691 Mon Sep 17 00:00:00 2001 From: Lee SeJin Date: Thu, 28 Dec 2023 21:12:28 +0900 Subject: [PATCH 03/13] =?UTF-8?q?[Fix]=20#344=20-=20=EB=A6=AC=ED=94=84?= =?UTF-8?q?=EB=A0=88=EC=8B=9C=20=EA=B0=80=EC=9D=B4=EB=93=9C=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift | 2 +- .../PokeOnboardingScene/PokeOnboardingViewController.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift b/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift index 613a90a9..d35cb832 100644 --- a/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift +++ b/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift @@ -327,7 +327,7 @@ public struct I18N { public static let pokeMyFriends = "내 친구를 찔러보세요" public static let pokeNearbyFriends = "내 친구의 친구를 찔러보세요" public static let emptyFriendDescription = "아직 없어요 T.T\n내 친구가 더 많은 친구가 생길 때까지 기다려주세요" - public static let refreshGuide = "화면을 밑으로 당기면\n다른 친구를 볼 수 있어요" + public static let refreshGuide = "화면을 당기면\n다른 친구를 볼 수 있어요" public static func makingFriendCompleted(name: String) -> String { return "찌르기 답장으로\n\(name)님과 친구가 되었어요!" } diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/PokeOnboardingViewController.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/PokeOnboardingViewController.swift index 3f5a8675..60d6fdca 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/PokeOnboardingViewController.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/PokeOnboardingViewController.swift @@ -84,7 +84,7 @@ public final class PokeOnboardingViewController: UIViewController, PokeOnboardin // MARK: Description private let contentFooterDescriptionLabel = UILabel().then { - $0.text = "아는 사람이 없나요?\n화면을 밑으로 당기면 다른 친구들을 볼 수 있어요" + $0.text = "아는 사람이 없나요?\n화면을 당기면 다른 친구들을 볼 수 있어요" $0.textAlignment = .center $0.numberOfLines = Constant.numberOfFooterDesciprionLines $0.textColor = DSKitAsset.Colors.gray200.color From d8f6998f2b88b18482bf8ba16b87508799e36aee Mon Sep 17 00:00:00 2001 From: Lee SeJin Date: Thu, 28 Dec 2023 21:20:36 +0900 Subject: [PATCH 04/13] =?UTF-8?q?[Fix]=20#344=20-=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A7=80=EC=86=8D=20=EC=8B=9C=EA=B0=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=B0=8F=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=83=9D=EC=84=B1=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Projects/Modules/DSKit/Sources/Components/Toast.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift index 115c54c4..7b259d3f 100644 --- a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift +++ b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift @@ -64,6 +64,8 @@ public class Toast { guard let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene else { return } guard let window = scene.windows.first(where: { $0.isKeyWindow }) else { return } + guard !window.subviews.contains(where: { $0 is MDSToast }) else { return } // 토스트가 중복으로 나오지 않도록 방지 + window.addSubview(toast) let toastHeight = 64.f @@ -81,7 +83,7 @@ public class Toast { toast.superview?.layoutIfNeeded() } completion: { _ in // 2. 토스트를 천천히 아래로 내린다. (화면에 등장) - UIView.animate(withDuration: 0.5) { + UIView.animate(withDuration: 0.4) { toast.snp.updateConstraints { make in make.top.equalTo(window.safeAreaLayoutGuide).inset(16) } @@ -94,8 +96,8 @@ public class Toast { -> 토스트에 있는 버튼이 터치가 안 되는 문제 발생 -> asyncAfter를 사용하여 4초 뒤에 Constraints를 업데이트하도록 하여 문제 해결 */ - DispatchQueue.main.asyncAfter(deadline: .now() + 4) { - UIView.animate(withDuration: 0.5, animations: { + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + UIView.animate(withDuration: 0.4, animations: { toast.snp.updateConstraints { make in make.top.equalTo(window.safeAreaLayoutGuide).inset(-toastStartingInset) } From 0afcd63c013389d416632705ac1ed140c50cd318 Mon Sep 17 00:00:00 2001 From: Lee SeJin Date: Thu, 28 Dec 2023 21:27:28 +0900 Subject: [PATCH 05/13] =?UTF-8?q?[Feat]=20#344=20-=20=EC=B0=8C=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=84=B1=EA=B3=B5=20=EC=8B=9C=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Projects/Core/Sources/Literals/StringLiterals.swift | 1 + .../Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift | 5 +++++ .../ViewModel/PokeMyFriendsListViewModel.swift | 5 +++++ .../ViewModel/PokeMyFriendsViewModel.swift | 5 +++++ .../ViewModel/PokeNotificationViewModel.swift | 6 ++++++ .../ViewModel/PokeOnboardingViewModel.swift | 6 ++++++ 6 files changed, 28 insertions(+) diff --git a/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift b/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift index d35cb832..3f4466b6 100644 --- a/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift +++ b/SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift @@ -328,6 +328,7 @@ public struct I18N { public static let pokeNearbyFriends = "내 친구의 친구를 찔러보세요" public static let emptyFriendDescription = "아직 없어요 T.T\n내 친구가 더 많은 친구가 생길 때까지 기다려주세요" public static let refreshGuide = "화면을 당기면\n다른 친구를 볼 수 있어요" + public static let pokeSuccess = "콕 찌르기를 완료했어요" public static func makingFriendCompleted(name: String) -> String { return "찌르기 답장으로\n\(name)님과 친구가 되었어요!" } diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift index b65835ba..95bda59d 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift @@ -166,6 +166,11 @@ extension PokeMainViewModel { .subscribe(output.pokeResponse) .store(in: cancelBag) + useCase.pokedResponse + .sink { _ in + ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + }.store(in: cancelBag) + useCase.madeNewFriend .sink { [weak self] userModel in self?.onNewFriendMade?(userModel.name) diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift index fffce6ab..32d58a1d 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift @@ -121,6 +121,11 @@ extension PokeMyFriendsListViewModel { output.needToReloadFriendList.send() }.store(in: cancelBag) + useCase.pokedResponse + .sink { _ in + ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + }.store(in: cancelBag) + useCase.errorMessage .compactMap { $0 } .sink { message in diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift index f38b2bfd..aff989f2 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift @@ -105,6 +105,11 @@ extension PokeMyFriendsViewModel { } }.store(in: cancelBag) + useCase.pokedResponse + .sink { _ in + ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + }.store(in: cancelBag) + useCase.errorMessage .compactMap { $0 } .sink { message in diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift index 078e07a7..a0051e93 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift @@ -80,6 +80,12 @@ extension PokeNotificationViewModel { self?.onNewFriendAdded?(userModel.name) }).store(in: cancelBag) + self.usecase + .pokedResponse + .sink { _ in + ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + }.store(in: cancelBag) + self.usecase .errorMessage .compactMap { $0 } diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift index 1c0c7fc9..56ac3d7d 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift @@ -101,5 +101,11 @@ extension PokeOnboardingViewModel { .sink(receiveValue: { value in output.pokedResult.send(value) }).store(in: cancelBag) + + self.usecase + .pokedResponse + .sink { _ in + ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + }.store(in: cancelBag) } } From ae48eae60ee7c0813de33773a26e32a4d3e3b559 Mon Sep 17 00:00:00 2001 From: Lee SeJin Date: Thu, 28 Dec 2023 21:31:32 +0900 Subject: [PATCH 06/13] =?UTF-8?q?[Fix]=20#344=20-=20=EC=B0=8C=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=98=A8=EB=B3=B4=EB=94=A9=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=BD=95=20=EC=B0=8C=EB=A5=B4=EA=B8=B0=20=EC=8B=A4=ED=8C=A8=20?= =?UTF-8?q?=EC=8B=9C=20=EA=B2=BD=EA=B3=A0=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/Sources/UseCase/PokeOnboardingUsecase.swift | 7 +++++++ .../ViewModel/PokeOnboardingViewModel.swift | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeOnboardingUsecase.swift b/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeOnboardingUsecase.swift index ec180d19..f32b47a6 100644 --- a/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeOnboardingUsecase.swift +++ b/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeOnboardingUsecase.swift @@ -16,6 +16,7 @@ public protocol PokeOnboardingUsecase { var randomAcquaintances: PassthroughSubject<[PokeUserModel], Never> { get } var pokedResponse: PassthroughSubject { get } + var errorMessage: PassthroughSubject { get } } public final class DefaultPokeOnboardingUsecase { @@ -24,6 +25,7 @@ public final class DefaultPokeOnboardingUsecase { public let randomAcquaintances = PassthroughSubject<[PokeUserModel], Never>() public let pokedResponse = PassthroughSubject() + public let errorMessage = PassthroughSubject() public init(repository: PokeOnboardingRepositoryInterface) { self.repository = repository @@ -45,6 +47,11 @@ extension DefaultPokeOnboardingUsecase: PokeOnboardingUsecase { public func poke(userId: Int, message: PokeMessageModel) { self.repository .poke(userId: userId, message: message.content) + .catch { [weak self] error in + let message = error.toastMessage + self?.errorMessage.send(message) + return Empty() + } .sink( receiveCompletion: { _ in }, receiveValue: { [weak self] value in diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift index 56ac3d7d..75b79b53 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeOnboardingScene/ViewModel/PokeOnboardingViewModel.swift @@ -107,5 +107,12 @@ extension PokeOnboardingViewModel { .sink { _ in ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) }.store(in: cancelBag) + + self.usecase + .errorMessage + .compactMap { $0 } + .sink { message in + ToastUtils.showMDSToast(type: .alert, text: message) + }.store(in: cancelBag) } } From 48721899cc453e352853b6bcf782b7fae7a0930a Mon Sep 17 00:00:00 2001 From: Lee SeJin Date: Sat, 30 Dec 2023 17:40:55 +0900 Subject: [PATCH 07/13] =?UTF-8?q?[Feat]=20#344=20-=20=EC=BD=95=20=EC=B0=8C?= =?UTF-8?q?=EB=A5=B4=EA=B8=B0=20=ED=94=BC=EC=B3=90=EC=9D=98=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EB=B7=B0=EC=97=90=EC=84=9C=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=EB=A5=BC=20=EC=B0=94=EB=A0=80=EB=8B=A4?= =?UTF-8?q?=EB=A9=B4=20=EB=A9=94=EC=9D=B8=20=EB=B7=B0=EC=97=90=EC=84=9C?= =?UTF-8?q?=EB=8F=84=20=ED=95=B4=EB=8B=B9=20=EC=9C=A0=EC=A0=80=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=B0=8C=EB=A5=B4=EA=B8=B0=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SOPT-iOS/Projects/Core/Sources/Literals/NotiList.swift | 2 +- .../PokeMainScene/ViewModel/PokeMainViewModel.swift | 7 +++++++ .../ViewModel/PokeMyFriendsListViewModel.swift | 4 +++- .../ViewModel/PokeMyFriendsViewModel.swift | 4 +++- .../ViewModel/PokeNotificationViewModel.swift | 5 ++++- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/SOPT-iOS/Projects/Core/Sources/Literals/NotiList.swift b/SOPT-iOS/Projects/Core/Sources/Literals/NotiList.swift index a7b7f247..61337b18 100644 --- a/SOPT-iOS/Projects/Core/Sources/Literals/NotiList.swift +++ b/SOPT-iOS/Projects/Core/Sources/Literals/NotiList.swift @@ -11,7 +11,7 @@ import Foundation /// enum형 NotiList를 Notification.Name으로 return /// - ex) NotificationCenter.default.post(name: NotiList.makeNotiName(list: ), object: <>, userInfo: <>) public enum NotiList: String { - case sample + case pokedResponse public static func makeNotiName(list: NotiList) -> NSNotification.Name { return Notification.Name(String(describing: list)) diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift index 95bda59d..e8a741e5 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift @@ -166,6 +166,13 @@ extension PokeMainViewModel { .subscribe(output.pokeResponse) .store(in: cancelBag) + // 다른 뷰에서 찌르기를 했을 때 메인 뷰의 해당 유저의 찌르기 버튼을 비활성화 하기 위해 NotificationCenter로 찌르기 이벤트를 받아온다. + let notiName = NotiList.makeNotiName(list: .pokedResponse) + NotificationCenter.default.publisher(for: notiName) + .compactMap { $0.object as? PokeUserModel } + .subscribe(output.pokeResponse) + .store(in: cancelBag) + useCase.pokedResponse .sink { _ in ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift index 32d58a1d..81a6afd1 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsListScene/ViewModel/PokeMyFriendsListViewModel.swift @@ -122,8 +122,10 @@ extension PokeMyFriendsListViewModel { }.store(in: cancelBag) useCase.pokedResponse - .sink { _ in + .sink { user in ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + let notiName = NotiList.makeNotiName(list: .pokedResponse) + NotificationCenter.default.post(name: notiName, object: user) }.store(in: cancelBag) useCase.errorMessage diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift index aff989f2..ccb08bf2 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMyFriendsScene/ViewModel/PokeMyFriendsViewModel.swift @@ -106,8 +106,10 @@ extension PokeMyFriendsViewModel { }.store(in: cancelBag) useCase.pokedResponse - .sink { _ in + .sink { user in ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + let notiName = NotiList.makeNotiName(list: .pokedResponse) + NotificationCenter.default.post(name: notiName, object: user) }.store(in: cancelBag) useCase.errorMessage diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift index a0051e93..1143cbf9 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeNotificationScene/ViewModel/PokeNotificationViewModel.swift @@ -6,6 +6,7 @@ // Copyright © 2023 SOPT-iOS. All rights reserved. // +import Foundation import Combine import Core @@ -82,8 +83,10 @@ extension PokeNotificationViewModel { self.usecase .pokedResponse - .sink { _ in + .sink { user in ToastUtils.showMDSToast(type: .success, text: I18N.Poke.pokeSuccess) + let notiName = NotiList.makeNotiName(list: .pokedResponse) + NotificationCenter.default.post(name: notiName, object: user) }.store(in: cancelBag) self.usecase From 147d7ff90464e5eae166088fe15a90bb46d048ff Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Sat, 30 Dec 2023 23:35:43 +0900 Subject: [PATCH 08/13] =?UTF-8?q?[Feat]=20#344=20-=20PokeNotificationList?= =?UTF-8?q?=20=EB=B7=B0=EB=A1=9C=EC=9D=98=20=EB=94=A5=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8C=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PokeNotificationListDeepLink.swift | 25 +++++++++++++++++++ .../Sources/Coordinator/PokeCoordinator.swift | 4 +-- .../Sources/ApplicationCoordinator.swift | 13 +++++++--- .../Sources/DeepLinks/HomeDeepLink.swift | 2 +- .../Sources/DeepLinks/PokeDeepLink.swift | 22 ++++++++++++++++ 5 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift create mode 100644 SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift new file mode 100644 index 00000000..0ef824e3 --- /dev/null +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift @@ -0,0 +1,25 @@ +// +// PokeNotificationListDeepLink.swift +// PokeFeature +// +// Created by sejin on 12/30/23. +// Copyright © 2023 SOPT-iOS. All rights reserved. +// + +import Foundation +import BaseFeatureDependency + +public struct PokeNotificationListDeepLink: DeepLinkExecutable { + public let name = "notification-list" + public let children: [DeepLinkExecutable] = [] + + public init() {} + + public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { + guard let coordinator = coordinator as? PokeCoordinator else { return nil } + + coordinator.runPokeNotificationListFlow() + + return nil + } +} diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift index a9b0eb2d..fb5caebb 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift @@ -70,10 +70,10 @@ final class PokeCoordinator: DefaultCoordinator { router.present(rootController, animated: true, modalPresentationSytle: .overFullScreen) } - private func runPokeNotificationListFlow() { + internal func runPokeNotificationListFlow() { let pokeNotificationListCoordinator = PokeNotificationListCoordinator( router: Router( - rootController: rootController! + rootController: rootController ?? self.router.asNavigationController ), factory: factory ) diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift index ece5c062..91c994e4 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift @@ -229,6 +229,16 @@ extension ApplicationCoordinator { @discardableResult internal func runPokeFlow() -> PokeCoordinator { + let coordinator = makePokeCoordinator() + + addDependency(coordinator) + coordinator.start() + + return coordinator + } + + @discardableResult + internal func makePokeCoordinator() -> PokeCoordinator { let coordinator = PokeCoordinator( router: Router(rootController: UIWindow.getRootNavigationController), factory: PokeBuilder() @@ -239,9 +249,6 @@ extension ApplicationCoordinator { self?.removeDependency(coordinator) } - addDependency(coordinator) - coordinator.start() - return coordinator } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift index 5711af2c..bf14126d 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift @@ -11,7 +11,7 @@ import BaseFeatureDependency public struct HomeDeepLink: DeepLinkExecutable { public let name = "home" - public let children: [DeepLinkExecutable] = [NotificationDeepLink(), SoptampDeepLink(), MyPageDeepLink(), AttendanceDeepLink()] + public let children: [DeepLinkExecutable] = [NotificationDeepLink(), SoptampDeepLink(), MyPageDeepLink(), AttendanceDeepLink(), PokeDeepLink()] public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift new file mode 100644 index 00000000..fee34f9c --- /dev/null +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift @@ -0,0 +1,22 @@ +// +// PokeDeepLink.swift +// RootFeature +// +// Created by sejin on 12/30/23. +// Copyright © 2023 SOPT-iOS. All rights reserved. +// + +import Foundation +import BaseFeatureDependency +import PokeFeature + +public struct PokeDeepLink: DeepLinkExecutable { + public let name = "poke" + public let children: [DeepLinkExecutable] = [PokeNotificationListDeepLink()] + + public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { + guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } + // 현재 Poke 메인 뷰로의 라우팅은 요구사항에 없지만 추후에 추가된다면 온보딩 뷰 대상 유저인지 파악이 필요해서 기획적인 논의가 필요 + return coordinator.makePokeCoordinator() + } +} From e810aa9a0118b825685638612436b7384d2f911a Mon Sep 17 00:00:00 2001 From: Lee SeJin Date: Sun, 31 Dec 2023 01:13:40 +0900 Subject: [PATCH 09/13] =?UTF-8?q?[Fix]=20#344=20-=20PokeCoordinator?= =?UTF-8?q?=EC=9D=98=20=EC=B0=B8=EC=A1=B0=EB=A5=BC=20=EC=9C=A0=EC=A7=80?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PokeCoordinator가 메모리에서 사라져 바텀 시트가 올라오지 않는 문제 해결 --- .../Features/RootFeature/Sources/ApplicationCoordinator.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift index 91c994e4..0d34c03b 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/ApplicationCoordinator.swift @@ -249,6 +249,8 @@ extension ApplicationCoordinator { self?.removeDependency(coordinator) } + addDependency(coordinator) + return coordinator } From 23b74c2976de53ac9b9ee3d83eed0a6f02120fd4 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Sun, 31 Dec 2023 15:37:01 +0900 Subject: [PATCH 10/13] =?UTF-8?q?[Fix]=20#344=20-=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=83=9D=EC=84=B1=20=EC=9A=94=EC=B2=AD=20=EC=8B=9C?= =?UTF-8?q?=20=EA=B8=B0=EC=A1=B4=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=ED=95=98=EA=B3=A0=20=EC=83=88=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Projects/Modules/DSKit/Sources/Components/Toast.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift index 7b259d3f..89f7ef09 100644 --- a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift +++ b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/Toast.swift @@ -59,12 +59,14 @@ public class Toast { } public static func showMDSToast(type: MDSToast.ToastType, text: String, actionButtonAction: (() -> Void)? = nil) { - let toast = MDSToast(type: type, text: text, actionButtonAction: actionButtonAction) - guard let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene else { return } guard let window = scene.windows.first(where: { $0.isKeyWindow }) else { return } - guard !window.subviews.contains(where: { $0 is MDSToast }) else { return } // 토스트가 중복으로 나오지 않도록 방지 + let toast = MDSToast(type: type, text: text, actionButtonAction: actionButtonAction) + + // 토스트가 중복으로 나오지 않도록 방지 + let previousToast = window.subviews.first { $0 is MDSToast } + previousToast?.removeFromSuperview() window.addSubview(toast) From 0db10baf0c1a179f8c88eed38019984ad3db4f5c Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 1 Jan 2024 20:57:38 +0900 Subject: [PATCH 11/13] =?UTF-8?q?[Feat]=20#344=20-=20DeepLinkTreeNode?= =?UTF-8?q?=EC=97=90=20=ED=95=B4=EB=8B=B9=20=EB=94=A5=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=B2=B4=EA=B0=80=20=EC=A2=85=EC=B0=A9?= =?UTF-8?q?=EC=A7=80=20=EB=B7=B0=EC=9D=B8=EC=A7=80=EB=A5=BC=20=EB=82=98?= =?UTF-8?q?=ED=83=80=EB=82=B4=EB=8A=94=20Bool=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Coordinator/DeepLink/DeepLinkExecutable.swift | 1 + .../Coordinator/NotificationDetailDeepLink.swift | 1 + .../DeepLinks/PokeNotificationListDeepLink.swift | 1 + .../Sources/DeepLinks/AttendanceDeepLink.swift | 1 + .../RootFeature/Sources/DeepLinks/HomeDeepLink.swift | 1 + .../RootFeature/Sources/DeepLinks/MyPageDeepLink.swift | 1 + .../Sources/DeepLinks/NotificationDeepLink.swift | 1 + .../RootFeature/Sources/DeepLinks/PokeDeepLink.swift | 10 +++++++++- .../Sources/DeepLinks/SoptampDeepLink.swift | 1 + .../NotificationHelpers/Parser/DeepLinkParser.swift | 4 ++++ .../SoptampCurrentGenerationRankingDeepLink.swift | 1 + .../DeepLinks/SoptampEntireRankingDeepLink.swift | 1 + 12 files changed, 23 insertions(+), 1 deletion(-) diff --git a/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Coordinator/DeepLink/DeepLinkExecutable.swift b/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Coordinator/DeepLink/DeepLinkExecutable.swift index 6f17baee..46b4bdbc 100644 --- a/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Coordinator/DeepLink/DeepLinkExecutable.swift +++ b/SOPT-iOS/Projects/Features/BaseFeatureDependency/Sources/Coordinator/DeepLink/DeepLinkExecutable.swift @@ -11,6 +11,7 @@ import Foundation public protocol DeepLinkTreeNode { var name: String { get } var children: [DeepLinkExecutable] { get } + var isDestination: Bool { get set } func findChild(name: String) -> DeepLinkExecutable? } diff --git a/SOPT-iOS/Projects/Features/NotificationFeature/Sources/Coordinator/NotificationDetailDeepLink.swift b/SOPT-iOS/Projects/Features/NotificationFeature/Sources/Coordinator/NotificationDetailDeepLink.swift index b16ce238..758c8424 100644 --- a/SOPT-iOS/Projects/Features/NotificationFeature/Sources/Coordinator/NotificationDetailDeepLink.swift +++ b/SOPT-iOS/Projects/Features/NotificationFeature/Sources/Coordinator/NotificationDetailDeepLink.swift @@ -12,6 +12,7 @@ import BaseFeatureDependency public struct NotificationDetailDeepLink: DeepLinkExecutable { public let name = "detail" public let children: [DeepLinkExecutable] = [] + public var isDestination: Bool = false public init() {} diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift index 0ef824e3..f013cebb 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/DeepLinks/PokeNotificationListDeepLink.swift @@ -12,6 +12,7 @@ import BaseFeatureDependency public struct PokeNotificationListDeepLink: DeepLinkExecutable { public let name = "notification-list" public let children: [DeepLinkExecutable] = [] + public var isDestination: Bool = false public init() {} diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/AttendanceDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/AttendanceDeepLink.swift index 9af982e7..71cfe400 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/AttendanceDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/AttendanceDeepLink.swift @@ -13,6 +13,7 @@ import AttendanceFeature public struct AttendanceDeepLink: DeepLinkExecutable { public let name = "attendance" public let children: [DeepLinkExecutable] = [AttendanceModalDeepLink()] + public var isDestination: Bool = false public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift index bf14126d..4837b4bd 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/HomeDeepLink.swift @@ -12,6 +12,7 @@ import BaseFeatureDependency public struct HomeDeepLink: DeepLinkExecutable { public let name = "home" public let children: [DeepLinkExecutable] = [NotificationDeepLink(), SoptampDeepLink(), MyPageDeepLink(), AttendanceDeepLink(), PokeDeepLink()] + public var isDestination: Bool = false public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/MyPageDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/MyPageDeepLink.swift index 3041b1f7..16cd718f 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/MyPageDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/MyPageDeepLink.swift @@ -14,6 +14,7 @@ import Core public struct MyPageDeepLink: DeepLinkExecutable { public let name = "mypage" public let children: [DeepLinkExecutable] = [] + public var isDestination: Bool = false public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/NotificationDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/NotificationDeepLink.swift index c302d8f7..fcdfa4f9 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/NotificationDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/NotificationDeepLink.swift @@ -13,6 +13,7 @@ import NotificationFeature public struct NotificationDeepLink: DeepLinkExecutable { public let name = "notification" public let children: [DeepLinkExecutable] = [NotificationDetailDeepLink()] + public var isDestination: Bool = false public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift index fee34f9c..32c451e6 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift @@ -13,10 +13,18 @@ import PokeFeature public struct PokeDeepLink: DeepLinkExecutable { public let name = "poke" public let children: [DeepLinkExecutable] = [PokeNotificationListDeepLink()] + public var isDestination: Bool = false public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } // 현재 Poke 메인 뷰로의 라우팅은 요구사항에 없지만 추후에 추가된다면 온보딩 뷰 대상 유저인지 파악이 필요해서 기획적인 논의가 필요 - return coordinator.makePokeCoordinator() + + let pokeCoordinator = coordinator.makePokeCoordinator() + + if self.isDestination == true { + pokeCoordinator.start() + } + + return pokeCoordinator } } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/SoptampDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/SoptampDeepLink.swift index c1e4ea52..6be6e210 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/SoptampDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/SoptampDeepLink.swift @@ -13,6 +13,7 @@ import StampFeature public struct SoptampDeepLink: DeepLinkExecutable { public let name = "soptamp" public let children: [DeepLinkExecutable] = [SoptampEntireRankingDeepLink(), SoptampCurrentGenerationRankingDeepLink()] + public var isDestination: Bool = false public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/NotificationHelpers/Parser/DeepLinkParser.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/NotificationHelpers/Parser/DeepLinkParser.swift index 43fcbc0e..0e49f68a 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/NotificationHelpers/Parser/DeepLinkParser.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/NotificationHelpers/Parser/DeepLinkParser.swift @@ -56,6 +56,10 @@ struct DeepLinkParser: NotificationLinkParser { deepLinks.append(child) } + if !deepLinks.isEmpty { + deepLinks[deepLinks.count-1].isDestination = true + } + return deepLinks } diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampCurrentGenerationRankingDeepLink.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampCurrentGenerationRankingDeepLink.swift index 73e9332c..ddac76ca 100644 --- a/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampCurrentGenerationRankingDeepLink.swift +++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampCurrentGenerationRankingDeepLink.swift @@ -13,6 +13,7 @@ import Domain public struct SoptampCurrentGenerationRankingDeepLink: DeepLinkExecutable { public let name = "current-generation-ranking" public let children: [DeepLinkExecutable] = [] + public var isDestination: Bool = false public init() {} diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampEntireRankingDeepLink.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampEntireRankingDeepLink.swift index 82bd4bf4..e5eb230f 100644 --- a/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampEntireRankingDeepLink.swift +++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/DeepLinks/SoptampEntireRankingDeepLink.swift @@ -12,6 +12,7 @@ import BaseFeatureDependency public struct SoptampEntireRankingDeepLink: DeepLinkExecutable { public let name = "entire-ranking" public let children: [DeepLinkExecutable] = [] + public var isDestination: Bool = false public init() {} From d260dcbbd197b9db8b2b1cd4c4cb723786a1ebe4 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 1 Jan 2024 21:42:29 +0900 Subject: [PATCH 12/13] =?UTF-8?q?[Feat]=20#344=20-=20=EB=94=A5=EB=A7=81?= =?UTF-8?q?=ED=81=AC=EB=A1=9C=EB=B6=80=ED=84=B0=20PokeMain=20=EB=B7=B0?= =?UTF-8?q?=EA=B0=80=20=EC=97=B4=EB=A6=AC=EB=A9=B4=20=EC=98=A8=EB=B3=B4?= =?UTF-8?q?=EB=94=A9=20=EB=8C=80=EC=83=81=EC=9D=B8=EC=A7=80=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=ED=95=98=EA=B3=A0=20=ED=95=B4=EB=8B=B9=EB=90=98?= =?UTF-8?q?=EB=A9=B4=20=EC=98=A8=EB=B3=B4=EB=94=A9=20=EB=B7=B0=EB=A1=9C=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/PokeMainRepository.swift | 6 ++++ .../PokeMainRepositoryInterface.swift | 1 + .../Sources/UseCase/PokeMainUseCase.swift | 17 +++++++++-- .../Sources/PokeFeatureBuildable.swift | 2 +- .../Sources/PokeMainPresentable.swift | 1 + .../Sources/Coordinator/PokeBuilder.swift | 4 +-- .../Sources/Coordinator/PokeCoordinator.swift | 28 +++++++++++++++++-- .../PokeOnboardingCoordinator.swift | 19 +++++++++++-- .../Sources/PokeMainScene/VC/PokeMainVC.swift | 5 ++++ .../ViewModel/PokeMainViewModel.swift | 25 ++++++++++++++++- .../Sources/DeepLinks/PokeDeepLink.swift | 3 +- 11 files changed, 97 insertions(+), 14 deletions(-) diff --git a/SOPT-iOS/Projects/Data/Sources/Repository/PokeMainRepository.swift b/SOPT-iOS/Projects/Data/Sources/Repository/PokeMainRepository.swift index 33ac5bf2..4ec4b460 100644 --- a/SOPT-iOS/Projects/Data/Sources/Repository/PokeMainRepository.swift +++ b/SOPT-iOS/Projects/Data/Sources/Repository/PokeMainRepository.swift @@ -48,4 +48,10 @@ extension PokeMainRepository: PokeMainRepositoryInterface { .map { $0.toDomain() } .eraseToAnyPublisher() } + + public func checkPokeNewUser() -> AnyPublisher { + pokeService.isNewUser() + .map { $0.isNew } + .eraseToAnyPublisher() + } } diff --git a/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/PokeMainRepositoryInterface.swift b/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/PokeMainRepositoryInterface.swift index 95c1804a..f2e8abd2 100644 --- a/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/PokeMainRepositoryInterface.swift +++ b/SOPT-iOS/Projects/Domain/Sources/RepositoryInterface/PokeMainRepositoryInterface.swift @@ -12,4 +12,5 @@ public protocol PokeMainRepositoryInterface: PokeRepositoryInterface { func getWhoPokeToMe() -> AnyPublisher func getFriend() -> AnyPublisher<[PokeUserModel], Error> func getFriendRandomUser() -> AnyPublisher<[PokeFriendRandomUserModel], Error> + func checkPokeNewUser() -> AnyPublisher } diff --git a/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift b/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift index e9036cf6..3136eb34 100644 --- a/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift +++ b/SOPT-iOS/Projects/Domain/Sources/UseCase/PokeMainUseCase.swift @@ -17,11 +17,13 @@ public protocol PokeMainUseCase { var pokedResponse: PassthroughSubject { get } var madeNewFriend: PassthroughSubject { get } var errorMessage: PassthroughSubject { get } - + var isPokeNewUser: PassthroughSubject { get set } + func getWhoPokedToMe() func getFriend() func getFriendRandomUser() func poke(userId: Int, message: PokeMessageModel, willBeNewFriend: Bool) + func checkPokeNewUser() } public class DefaultPokeMainUseCase { @@ -34,7 +36,8 @@ public class DefaultPokeMainUseCase { public let pokedResponse = PassthroughSubject() public let madeNewFriend = PassthroughSubject() public let errorMessage = PassthroughSubject() - + public var isPokeNewUser = PassthroughSubject() + public init(repository: PokeMainRepositoryInterface) { self.repository = repository } @@ -85,4 +88,14 @@ extension DefaultPokeMainUseCase: PokeMainUseCase { } }.store(in: self.cancelBag) } + + public func checkPokeNewUser() { + repository.checkPokeNewUser() + .catch { error in + print("CheckPokeNewUser State: \(error)") + return Just(false) + }.sink { [weak self] isNewUser in + self?.isPokeNewUser.send(isNewUser) + }.store(in: cancelBag) + } } diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeFeatureBuildable.swift b/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeFeatureBuildable.swift index d101332c..895177cc 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeFeatureBuildable.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeFeatureBuildable.swift @@ -11,7 +11,7 @@ import Foundation import Domain public protocol PokeFeatureBuildable { - func makePokeMain() -> PokeMainPresentable + func makePokeMain(isRouteFromRoot: Bool) -> PokeMainPresentable func makePokeMyFriends() -> PokeMyFriendsPresentable func makePokeMyFriendsList(relation: PokeRelation) -> PokeMyFriendsListPresentable func makePokeOnboarding() -> PokeOnboardingPresentable diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeMainPresentable.swift b/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeMainPresentable.swift index 4549776a..7aa88806 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeMainPresentable.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Interface/Sources/PokeMainPresentable.swift @@ -19,6 +19,7 @@ public protocol PokeMainCoordinatable { var onProfileImageTapped: ((Int) -> Void)? { get set } var onPokeButtonTapped: ((PokeUserModel) -> Driver<(PokeUserModel, PokeMessageModel)>)? { get set } var onNewFriendMade: ((String) -> Void)? { get set } + var switchToOnboarding: (() -> Void)? { get set } } public typealias PokeMainViewModelType = ViewModelType & PokeMainCoordinatable diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeBuilder.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeBuilder.swift index df8c3920..368f6ba8 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeBuilder.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeBuilder.swift @@ -20,9 +20,9 @@ public final class PokeBuilder { } extension PokeBuilder: PokeFeatureBuildable { - public func makePokeMain() -> PokeFeatureInterface.PokeMainPresentable { + public func makePokeMain(isRouteFromRoot: Bool) -> PokeFeatureInterface.PokeMainPresentable { let useCase = DefaultPokeMainUseCase(repository: pokeMainRepository) - let viewModel = PokeMainViewModel(useCase: useCase) + let viewModel = PokeMainViewModel(useCase: useCase, isRouteFromRoot: isRouteFromRoot) let pokeMainVC = PokeMainVC(viewModel: viewModel) return (pokeMainVC, viewModel) } diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift index fb5caebb..c1011ed9 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift @@ -28,11 +28,11 @@ final class PokeCoordinator: DefaultCoordinator { } public override func start() { - showPokeMain() + showPokeMain(isRouteFromRoot: false) } - private func showPokeMain() { - var pokeMain = factory.makePokeMain() + public func showPokeMain(isRouteFromRoot: Bool) { + var pokeMain = factory.makePokeMain(isRouteFromRoot: isRouteFromRoot) pokeMain.vm.onNaviBackTap = { [weak self] in self?.router.dismissModule(animated: true) @@ -66,10 +66,32 @@ final class PokeCoordinator: DefaultCoordinator { pokeMain.vc.viewController.present(pokeMakingFriendCompletedVC, animated: false) } + pokeMain.vm.switchToOnboarding = { [weak self] in + guard let self = self else { return } + self.runPokeOnboardingFlow() + } + rootController = pokeMain.vc.asNavigationController router.present(rootController, animated: true, modalPresentationSytle: .overFullScreen) } + internal func runPokeOnboardingFlow() { + let pokeOnboardingCoordinator = PokeOnboardingCoordinator( + router: Router( + rootController: rootController ?? self.router.asNavigationController + ), + factory: factory + ) + + pokeOnboardingCoordinator.finishFlow = { [weak self, weak pokeOnboardingCoordinator] in + pokeOnboardingCoordinator?.childCoordinators = [] + self?.removeDependency(pokeOnboardingCoordinator) + } + + addDependency(pokeOnboardingCoordinator) + pokeOnboardingCoordinator.switchToPokeOnboardingView() + } + internal func runPokeNotificationListFlow() { let pokeNotificationListCoordinator = PokeNotificationListCoordinator( router: Router( diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeOnboardingCoordinator.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeOnboardingCoordinator.swift index 6fb34ac2..c9d7d4a2 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeOnboardingCoordinator.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeOnboardingCoordinator.swift @@ -32,6 +32,20 @@ public final class PokeOnboardingCoordinator: DefaultCoordinator { extension PokeOnboardingCoordinator { private func showPokeOnboardingView() { + var pokeOnboarding = makePokeOnboardingView() + + self.rootController = pokeOnboarding.vc.asNavigationController + self.router.present(self.rootController, animated: true, modalPresentationSytle: .overFullScreen) + } + + func switchToPokeOnboardingView() { + var pokeOnboarding = makePokeOnboardingView() + + self.rootController = router.asNavigationController + self.router.setRootModule(pokeOnboarding.vc, hideBar: true, animated: false) + } + + func makePokeOnboardingView() -> PokeOnboardingPresentable { var pokeOnboarding = self.factory.makePokeOnboarding() pokeOnboarding.vm.onNaviBackTapped = { [weak self] in @@ -71,8 +85,7 @@ extension PokeOnboardingCoordinator { let webView = SOPTWebView(startWith: url) self?.rootController?.pushViewController(webView, animated: true) } - - self.rootController = pokeOnboarding.vc.asNavigationController - self.router.present(self.rootController, animated: true, modalPresentationSytle: .overFullScreen) + + return pokeOnboarding } } diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift index 916d51ed..8192a08a 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift @@ -291,5 +291,10 @@ extension PokeMainVC { pokeUserView.changeUIAfterPoke(newUserModel: updatedUser) } }.store(in: cancelBag) + + output.isLoading + .sink { [weak self] isLoading in + isLoading ? self?.showLoading() : self?.stopLoading() + }.store(in: self.cancelBag) } } diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift index e8a741e5..8519179f 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/ViewModel/PokeMainViewModel.swift @@ -26,10 +26,12 @@ public class PokeMainViewModel: public var onProfileImageTapped: ((Int) -> Void)? public var onPokeButtonTapped: ((PokeUserModel) -> Driver<(PokeUserModel, PokeMessageModel)>)? public var onNewFriendMade: ((String) -> Void)? + public var switchToOnboarding: (() -> Void)? // MARK: - Properties private let useCase: PokeMainUseCase + private let isRouteFromRoot: Bool private var cancelBag = CancelBag() // MARK: - Inputs @@ -57,12 +59,14 @@ public class PokeMainViewModel: let friendRandomUsers = PassthroughSubject<[PokeFriendRandomUserModel], Never>() let endRefreshLoading = PassthroughSubject() let pokeResponse = PassthroughSubject() + let isLoading = PassthroughSubject() } // MARK: - initialization - public init(useCase: PokeMainUseCase) { + public init(useCase: PokeMainUseCase, isRouteFromRoot: Bool = false) { self.useCase = useCase + self.isRouteFromRoot = isRouteFromRoot } } @@ -78,6 +82,17 @@ extension PokeMainViewModel { self?.useCase.getFriendRandomUser() }.store(in: cancelBag) + input.viewDidLoad + .map { [weak self] _ in + self?.isRouteFromRoot + } + .compactMap { $0 } + .filter { $0 == true } + .sink { [weak self] _ in + output.isLoading.send(true) + self?.useCase.checkPokeNewUser() + }.store(in: cancelBag) + input.naviBackButtonTap .sink { [weak self] _ in self?.onNaviBackTap?() @@ -188,5 +203,13 @@ extension PokeMainViewModel { .sink { message in ToastUtils.showMDSToast(type: .alert, text: message) }.store(in: cancelBag) + + useCase.isPokeNewUser + .sink { [weak self] isNewUser in + output.isLoading.send(false) + if isNewUser { + self?.switchToOnboarding?() + } + }.store(in: cancelBag) } } diff --git a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift index 32c451e6..39575fa9 100644 --- a/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift +++ b/SOPT-iOS/Projects/Features/RootFeature/Sources/DeepLinks/PokeDeepLink.swift @@ -17,12 +17,11 @@ public struct PokeDeepLink: DeepLinkExecutable { public func execute(with coordinator: Coordinator, queryItems: [URLQueryItem]?) -> Coordinator? { guard let coordinator = coordinator as? ApplicationCoordinator else { return nil } - // 현재 Poke 메인 뷰로의 라우팅은 요구사항에 없지만 추후에 추가된다면 온보딩 뷰 대상 유저인지 파악이 필요해서 기획적인 논의가 필요 let pokeCoordinator = coordinator.makePokeCoordinator() if self.isDestination == true { - pokeCoordinator.start() + pokeCoordinator.showPokeMain(isRouteFromRoot: true) } return pokeCoordinator From 2de24a8584699175e3ee2ba268b6bc4f82f6b1f6 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 1 Jan 2024 22:05:14 +0900 Subject: [PATCH 13/13] =?UTF-8?q?[Fix]=20#344=20-=20isDestination=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=9D=B4=20=EB=88=84=EB=9D=BD=EB=90=9C=20?= =?UTF-8?q?=EA=B3=B3=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Coordinator/AttendanceModalDeepLink.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/Coordinator/AttendanceModalDeepLink.swift b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/Coordinator/AttendanceModalDeepLink.swift index f3ac6493..8263ccec 100644 --- a/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/Coordinator/AttendanceModalDeepLink.swift +++ b/SOPT-iOS/Projects/Features/AttendanceFeature/Sources/Coordinator/AttendanceModalDeepLink.swift @@ -13,6 +13,7 @@ import Domain public struct AttendanceModalDeepLink: DeepLinkExecutable { public let name = "attendance-modal" public let children: [DeepLinkExecutable] = [] + public var isDestination: Bool = false public init() {}