From 0ee0d14cbf16f8de38a3ca38a6692c5b40be6fe8 Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 12 Dec 2025 22:27:28 +0900 Subject: [PATCH 01/31] =?UTF-8?q?fix/#273:=20=EB=B6=81=EB=A7=88=ED=81=AC?= =?UTF-8?q?=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesignSystem/Components/Tabbar/BottomTabBarController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBarController.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBarController.swift index adfb9941..1a89a6b0 100644 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBarController.swift +++ b/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBarController.swift @@ -17,7 +17,7 @@ public final class BottomTabBarController: UITabBarController { public init(viewControllers: [UIViewController], initialIndex: Int = 0) { tabItems = [ TabItem(title: "도감", icon: .dictionary), - TabItem(title: "북마크", icon: .bookmark), + TabItem(title: "북마크", icon: .bookmarkList), TabItem(title: "MY", icon: .mypage) ] customTabBar = BottomTabBar(tabItems: tabItems, selectedIndex: initialIndex) From 8b0e9c1e91ecec6be4c0db0adf2511fc92fa35f7 Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 12 Dec 2025 22:50:36 +0900 Subject: [PATCH 02/31] =?UTF-8?q?fix/#273:=20=EB=B6=81=EB=A7=88=ED=81=AC?= =?UTF-8?q?=20=EC=A0=84=EC=B2=B4=ED=83=AD=20=EC=A0=95=EB=A0=AC=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 --- .../Entity/Filter/SortType.swift | 4 +- .../BookmarkList/BookmarkListReactor.swift | 44 +++++++++---------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/MLS/Domain/DomainInterface/Entity/Filter/SortType.swift b/MLS/Domain/DomainInterface/Entity/Filter/SortType.swift index 56949996..0adf976c 100644 --- a/MLS/Domain/DomainInterface/Entity/Filter/SortType.swift +++ b/MLS/Domain/DomainInterface/Entity/Filter/SortType.swift @@ -16,6 +16,8 @@ public enum SortType: String { // 정렬 키 - 이름, 레벨, 경험치 public var sortKey: String { switch self { + case .latest: + return "createdAt" case .korean: return "name" case .levelASC, .levelDESC: @@ -35,7 +37,7 @@ public enum SortType: String { switch self { case .expASC, .levelASC, .korean: return "asc" - case .expDESC, .levelDESC, .mostDrop, .mostAppear: + case .expDESC, .levelDESC, .mostDrop, .mostAppear, .latest: return "desc" default: return "" diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift index de507057..6b508860 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift @@ -159,7 +159,7 @@ public final class BookmarkListReactor: Reactor { case let .sortOptionSelected(sort): return Observable.concat([ .just(.setSort(sort)), - fetchList() + fetchList(sort: sort) ]) case let .filterOptionSelected(startLevel, endLevel): @@ -180,7 +180,7 @@ public final class BookmarkListReactor: Reactor { .just(.setLastDeletedBookmark(nil)) ]) ) - case .dataTapped(let index): + case let .dataTapped(index): let item = currentState.items[index] guard let type = item.type.toDictionaryType else { return .empty() } return .just(.toNavagate(.detail(type, item.originalId))) @@ -192,34 +192,34 @@ public final class BookmarkListReactor: Reactor { } case .editButtonTapped: return .just(.toNavagate(.edit)) - case .itemFilterOptionSelected(let results): + case let .itemFilterOptionSelected(results): let criteria = parseItemFilterResultUseCase.execute(results: results) - return .concat([ - .just(.setJobId(criteria.jobIds)), - .just(.setFilter(start: criteria.startLevel, end: criteria.endLevel)), - .just(.setCategoryId(criteria.categoryIds)) - ]) - .concat(Observable.deferred { [weak self] in - guard let self = self else { return .empty() } - return self.fetchList() - }) + return .concat([ + .just(.setJobId(criteria.jobIds)), + .just(.setFilter(start: criteria.startLevel, end: criteria.endLevel)), + .just(.setCategoryId(criteria.categoryIds)) + ]) + .concat(Observable.deferred { [weak self] in + guard let self = self else { return .empty() } + return self.fetchList() + }) } } // MARK: - Fetch List - private func fetchList() -> Observable { + private func fetchList(sort: SortType? = nil) -> Observable { switch currentState.type { case .total: return fetchTotalBookmarkUseCase.execute( - sort: currentState.sort + sort: sort ?? currentState.sort ).map { .setItems($0) } case .monster: return fetchMonsterBookmarkUseCase.execute( minLevel: currentState.startLevel ?? 1, maxLevel: currentState.endLevel ?? 200, - sort: currentState.sort + sort: sort ?? currentState.sort ).map { .setItems($0) } case .item: @@ -228,19 +228,19 @@ public final class BookmarkListReactor: Reactor { minLevel: currentState.startLevel, maxLevel: currentState.endLevel, categoryIds: nil, - sort: currentState.sort + sort: sort ?? currentState.sort ).map { .setItems($0) } case .npc: - return fetchNPCBookmarkUseCase.execute(sort: currentState.sort) + return fetchNPCBookmarkUseCase.execute(sort: sort ?? currentState.sort) .map { .setItems($0) } case .quest: - return fetchQuestBookmarkUseCase.execute(sort: currentState.sort) + return fetchQuestBookmarkUseCase.execute(sort: sort ?? currentState.sort) .map { .setItems($0) } case .map: - return fetchMapBookmarkUseCase.execute(sort: currentState.sort) + return fetchMapBookmarkUseCase.execute(sort: sort ?? currentState.sort) .map { .setItems($0) } default: @@ -264,11 +264,11 @@ public final class BookmarkListReactor: Reactor { newState.endLevel = end case let .setLastDeletedBookmark(item): newState.lastDeletedBookmark = item - case .toNavagate(let route): + case let .toNavagate(route): newState.route = route - case .setJobId(let ids): + case let .setJobId(ids): newState.jobId = ids - case .setCategoryId(let ids): + case let .setCategoryId(ids): newState.categoryIds = ids } From cc8dbc5ad69f4dbb9da0cfa86957f2206ee4e584 Mon Sep 17 00:00:00 2001 From: p2glet Date: Sat, 13 Dec 2025 00:15:05 +0900 Subject: [PATCH 03/31] =?UTF-8?q?fix/#273:=20=EC=97=B0=EC=86=8D=ED=83=88?= =?UTF-8?q?=ED=87=B4=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift | 3 +-- MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift | 6 +++--- MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift | 2 +- .../Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift | 4 ++-- .../Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift | 3 +-- .../DomainInterface/Repository/AuthAPIRepository.swift | 2 +- .../UseCase/AuthAPI/PutFCMTokenUseCase.swift | 2 +- .../AuthFeature/AuthFeature/Login/LoginReactor.swift | 4 ++-- 8 files changed, 12 insertions(+), 14 deletions(-) diff --git a/MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift b/MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift index 2e45ebbd..854eb68e 100644 --- a/MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift +++ b/MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift @@ -61,12 +61,11 @@ public enum AuthEndPoint { ) } - public static func fcmToken(credential: String, body: Encodable) -> ResponsableEndPoint { + public static func fcmToken(body: Encodable) -> ResponsableEndPoint { .init( baseURL: base, path: "/api/v1/auth/member/fcm-token", method: .PUT, - headers: ["Authorization": "Bearer \(credential)"], body: body ) } diff --git a/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift index 0cec54a0..bfe4da70 100644 --- a/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift @@ -81,9 +81,9 @@ public class AuthAPIRepositoryImpl: AuthAPIRepository { return provider.requestData(endPoint: endPoint, interceptor: authInterceptor).map { $0.toLoginDomain() } } - public func fcmToken(credential: String, fcmToken: String?) -> Completable { - let endPoint = AuthEndPoint.fcmToken(credential: credential, body: FCMTokenBody(fcmToken: fcmToken)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) + public func fcmToken(fcmToken: String?) -> Completable { + let endPoint = AuthEndPoint.fcmToken(body: FCMTokenBody(fcmToken: fcmToken)) + return provider.requestData(endPoint: endPoint, interceptor: authInterceptor) } public func fetchJobList() -> Observable { diff --git a/MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift b/MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift index 587b54f9..2e524dbd 100644 --- a/MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift +++ b/MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift @@ -36,7 +36,7 @@ public class AuthAPIRepositoryMock: AuthAPIRepository { return Observable.just(.init(accessToken: "testToken", refreshToken: "testToken")) } - public func fcmToken(credential: String, fcmToken: String?) -> Completable { + public func fcmToken(fcmToken: String?) -> Completable { return .empty() } diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift index 38138859..8f08eba0 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift @@ -11,7 +11,7 @@ public class PutFCMTokenUseCaseImpl: PutFCMTokenUseCase { self.repository = repository } - public func execute(credential: String, fcmToken: String?) -> Completable { - return repository.fcmToken(credential: credential, fcmToken: fcmToken) + public func execute(fcmToken: String?) -> Completable { + return repository.fcmToken(fcmToken: fcmToken) } } diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift index 3ac9a5e8..fc6b314d 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift @@ -20,8 +20,7 @@ public class WithdrawUseCaseImpl: WithdrawUseCase { let results: [Result] = [ self.tokenRepository.deleteToken(type: .accessToken), - self.tokenRepository.deleteToken(type: .refreshToken), - self.tokenRepository.deleteToken(type: .fcmToken) + self.tokenRepository.deleteToken(type: .refreshToken) ] for result in results { diff --git a/MLS/Domain/DomainInterface/Repository/AuthAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/AuthAPIRepository.swift index 1b0b28c6..2e8b1224 100644 --- a/MLS/Domain/DomainInterface/Repository/AuthAPIRepository.swift +++ b/MLS/Domain/DomainInterface/Repository/AuthAPIRepository.swift @@ -54,7 +54,7 @@ public protocol AuthAPIRepository { /// - Returns: 토큰 갱신 응답을 담은 Observable func reissueToken(refreshToken: String) -> Observable - func fcmToken(credential: String, fcmToken: String?) -> Completable + func fcmToken(fcmToken: String?) -> Completable func updateMarketingAgreement(credential: String, isMarketingAgreement: Bool) -> Completable diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/PutFCMTokenUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/PutFCMTokenUseCase.swift index b3fd3347..283f676c 100644 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/PutFCMTokenUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/AuthAPI/PutFCMTokenUseCase.swift @@ -1,5 +1,5 @@ import RxSwift public protocol PutFCMTokenUseCase { - func execute(credential: String, fcmToken: String?) -> Completable + func execute(fcmToken: String?) -> Completable } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift index 5aa15ac3..a5cca781 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift @@ -102,7 +102,7 @@ private extension LoginReactor { .flatMap { response -> Observable in if response.isRegister { // 3. 회원가입된 유저면 FCM 토큰 등록 후 홈으로 이동 - return owner.putFCMTokenUseCase.execute(credential: response.accessToken, fcmToken: fcmToken) + return owner.putFCMTokenUseCase.execute(fcmToken: fcmToken) .andThen(.just(.navigateTo(route: .dismiss))) } else { // 4. 미가입 유저면 약관 동의 화면으로 이동 @@ -139,7 +139,7 @@ private extension LoginReactor { .flatMap { response -> Observable in if response.isRegister { // 3. 회원가입된 유저면 FCM 토큰 등록 후 홈으로 이동 - return owner.putFCMTokenUseCase.execute(credential: response.accessToken, fcmToken: fcmToken) + return owner.putFCMTokenUseCase.execute(fcmToken: fcmToken) .andThen(.just(.navigateTo(route: .dismiss))) } else { // 4. 미가입 유저면 약관 동의 화면으로 이동 From 478bf8032b80afde588c4cb24a3975de8d42abab Mon Sep 17 00:00:00 2001 From: p2glet Date: Sat, 13 Dec 2025 00:26:35 +0900 Subject: [PATCH 04/31] =?UTF-8?q?feat/#273:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B8=B0=20?= =?UTF-8?q?=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 --- .../AuthFeature/Login/LoginReactor.swift | 8 ++++++-- .../AuthFeature/Login/LoginView.swift | 8 ++++++++ .../AuthFeature/Login/LoginViewController.swift | 16 +++++++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift index a5cca781..7bf0b45d 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift @@ -9,6 +9,7 @@ public final class LoginReactor: Reactor { case none case termsAgreements(credential: Credential, platform: LoginPlatform) case error + case home case dismiss } @@ -18,6 +19,7 @@ public final class LoginReactor: Reactor { case kakaoLoginButtonTapped case appleLoginButtonTapped case guestLoginButtonTapped + case backButtonTapped } public enum Mutation { @@ -72,6 +74,8 @@ public final class LoginReactor: Reactor { case .appleLoginButtonTapped: return handleAppleLogin() case .guestLoginButtonTapped: + return .just(.navigateTo(route: .home)) + case .backButtonTapped: return .just(.navigateTo(route: .dismiss)) } } @@ -103,7 +107,7 @@ private extension LoginReactor { if response.isRegister { // 3. 회원가입된 유저면 FCM 토큰 등록 후 홈으로 이동 return owner.putFCMTokenUseCase.execute(fcmToken: fcmToken) - .andThen(.just(.navigateTo(route: .dismiss))) + .andThen(.just(.navigateTo(route: .home))) } else { // 4. 미가입 유저면 약관 동의 화면으로 이동 return .just(.navigateTo(route: .termsAgreements( @@ -140,7 +144,7 @@ private extension LoginReactor { if response.isRegister { // 3. 회원가입된 유저면 FCM 토큰 등록 후 홈으로 이동 return owner.putFCMTokenUseCase.execute(fcmToken: fcmToken) - .andThen(.just(.navigateTo(route: .dismiss))) + .andThen(.just(.navigateTo(route: .home))) } else { // 4. 미가입 유저면 약관 동의 화면으로 이동 return .just(.navigateTo(route: .termsAgreements( diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift index 51437863..213b90f0 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift @@ -21,6 +21,8 @@ final class LoginView: UIView { } // MARK: - Properties + public let header = NavigationBar(type: .arrowLeft) + private let loginImageView: UIImageView = { let image = DesignSystemAsset.image(named: "Login_KV_img") let view = UIImageView(image: image) @@ -119,9 +121,15 @@ private extension LoginView { kakaoLoginButton.addSubview(kakaoLoginLabel) appleLoginButton.addSubview(appleLogoImageView) appleLoginButton.addSubview(appleLoginLabel) + + addSubview(header) } func setupConstraints() { + header.snp.makeConstraints { make in + make.top.horizontalEdges.equalTo(safeAreaLayoutGuide) + } + loginImageView.snp.makeConstraints { make in make.width.equalToSuperview() make.height.equalTo(UIScreen.main.bounds.width * 1.49) diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift index 5a1ba53e..3bbfca74 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift @@ -58,6 +58,13 @@ private extension LoginViewController { func configureUI() { view.backgroundColor = .systemBackground + + if let navigationController = navigationController, + navigationController.viewControllers.count > 1 { + mainView.header.leftButton.isHidden = false + } else { + mainView.header.leftButton.isHidden = true + } } } @@ -115,6 +122,11 @@ public extension LoginViewController { .map { Reactor.Action.guestLoginButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) + + mainView.header.leftButton.rx.tap + .map { Reactor.Action.backButtonTapped } + .bind(to: reactor.action) + .disposed(by: disposeBag) } func bindViewState(reactor: Reactor) { @@ -138,13 +150,15 @@ public extension LoginViewController { case .termsAgreements(let credential, let platform): let controller = owner.termsAgreementsFactory.make(credential: credential, platform: platform) owner.navigationController?.pushViewController(controller, animated: true) - case .dismiss: + case .home: owner.routeToHome.accept(()) case .error: DispatchQueue.main.async { let controller = BaseErrorViewController() owner.present(controller, animated: true) } + case .dismiss: + owner.navigationController?.popViewController(animated: true) default: break } From 172c77bbe3a6f70ae502328833c3aa1c39272a16 Mon Sep 17 00:00:00 2001 From: p2glet Date: Sat, 13 Dec 2025 00:33:21 +0900 Subject: [PATCH 05/31] =?UTF-8?q?fix/#273:=20=EC=95=BD=EA=B4=80=20?= =?UTF-8?q?=EB=A7=90=EC=A4=84=EC=9E=84=ED=91=9C=EC=8B=9C=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 --- .../CustomerSupport/Policy/PolicyView.swift | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyView.swift index 743a3894..df7f7fba 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyView.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyView.swift @@ -15,7 +15,13 @@ final class PolicyView: UIView { private let titleLabel = UILabel() - private let contentTextView = UITextView() + private let contentTextView: UITextView = { + let view = UITextView() + view.isScrollEnabled = true + view.isEditable = false + view.isSelectable = false + return view + }() // MARK: - Init init(type: PolicyType) { @@ -61,6 +67,20 @@ private extension PolicyView { headerView.addButton.isHidden = true headerView.setTitle(title: type.title) titleLabel.attributedText = .makeStyledString(font: .h_xxxl_sb, text: "메랜사 \(type.title)", alignment: .left) - contentTextView.attributedText = .makeStyledString(font: .b_s_r, text: type.content, alignment: .left) + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineBreakMode = .byWordWrapping + paragraphStyle.alignment = .left + + let attrString = NSAttributedString( + string: type.content, + attributes: [ + .font: UIFont.b_s_r ?? .systemFont(ofSize: 12), + .foregroundColor: UIColor.textColor, + .paragraphStyle: paragraphStyle + ] + ) + + contentTextView.attributedText = attrString } } From 693d7bcae4c36b5813e2cd1f73d250d699d706ef Mon Sep 17 00:00:00 2001 From: p2glet Date: Sat, 13 Dec 2025 01:45:55 +0900 Subject: [PATCH 06/31] =?UTF-8?q?fix/#273:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=9C=A0=EB=8F=84=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EB=85=B8=EC=B6=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 --- MLS/MLS/Application/AppDelegate.swift | 2 +- .../DictionaryNotificationFactoryImpl.swift | 6 ++- .../DictionaryNotificationReactor.swift | 39 +++++++++++++------ .../DictionaryNotificationView.swift | 8 ++-- ...DictionaryNotificationViewController.swift | 8 ++-- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 0ffa7712..80816276 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -899,7 +899,7 @@ extension AppDelegate { ), fetchProfileUseCase: DIContainer.resolve( type: FetchProfileUseCase.self - ) + ), checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self) ) } DIContainer.register(type: DictionaryMainViewFactory.self) { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift index bfaa367c..21418ee9 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift @@ -8,15 +8,17 @@ public final class DictionaryNotificationFactoryImpl: DictionaryNotificationFact private let fetchAllAlarmUseCase: FetchAllAlarmUseCase private let fetchProfileUseCase: FetchProfileUseCase + private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase - public init(notificationSettingFactory: NotificationSettingFactory, fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase) { + public init(notificationSettingFactory: NotificationSettingFactory, fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase, checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase) { self.notificationSettingFactory = notificationSettingFactory self.fetchAllAlarmUseCase = fetchAllAlarmUseCase self.fetchProfileUseCase = fetchProfileUseCase + self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase } public func make() -> BaseViewController { - let reactor = DictionaryNotificationReactor(fetchAllAlarmUseCase: fetchAllAlarmUseCase, fetchProfileUseCase: fetchProfileUseCase) + let reactor = DictionaryNotificationReactor(fetchAllAlarmUseCase: fetchAllAlarmUseCase, fetchProfileUseCase: fetchProfileUseCase, checkNotificationPermissionUseCase: checkNotificationPermissionUseCase) let viewController = DictionaryNotificationViewController(notificationSettingFactory: notificationSettingFactory) viewController.reactor = reactor return viewController diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift index 1e3e3653..d7bcd124 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift @@ -24,6 +24,7 @@ public final class DictionaryNotificationReactor: Reactor { case setLoading(Bool) case setProfile(MyPageResponse?) case navigateTo(Route) + case setPermission(Bool) } public struct State { @@ -32,6 +33,7 @@ public final class DictionaryNotificationReactor: Reactor { var profile: MyPageResponse? var hasMore: Bool = false var isLoading: Bool = false + var permission = false } // MARK: - Properties @@ -39,45 +41,57 @@ public final class DictionaryNotificationReactor: Reactor { private let disposeBag = DisposeBag() private let fetchAllAlarmUseCase: FetchAllAlarmUseCase private let fetchProfileUseCase: FetchProfileUseCase + private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase // MARK: - Init - public init(fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase) { + public init(fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase, checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase) { self.initialState = State() self.fetchAllAlarmUseCase = fetchAllAlarmUseCase self.fetchProfileUseCase = fetchProfileUseCase + self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase } // MARK: - Mutate public func mutate(action: Action) -> Observable { switch action { case .viewWillAppear: - return .concat([ - fetchProfileUseCase.execute() - .map { .setProfile($0) }, - .just(.setLoading(true)), + let profileStream: Observable = fetchProfileUseCase.execute() + .map { Mutation.setProfile($0) } + + let notificationStream: Observable = Observable.concat([ + Observable.just(.setLoading(true)), fetchAllAlarmUseCase.execute(cursor: nil, pageSize: 20) .map { paged in - .setNotifications(paged.items, hasMore: paged.hasMore, reset: true) + Mutation.setNotifications(paged.items, hasMore: paged.hasMore, reset: true) }, - .just(.setLoading(false)) + Observable.just(.setLoading(false)) ]) + + let permissionStream: Observable = checkNotificationPermissionUseCase.execute() + .asObservable() + .map { Mutation.setPermission($0) } + + return Observable.merge(profileStream, notificationStream, permissionStream) + case .loadMore: guard currentState.hasMore, !currentState.isLoading else { return .empty() } let cursor = currentState.notifications.last?.date - return .concat([ - .just(.setLoading(true)), + return Observable.concat([ + Observable.just(.setLoading(true)), fetchAllAlarmUseCase.execute(cursor: cursor, pageSize: 20) .map { paged in - .setNotifications(paged.items, hasMore: paged.hasMore, reset: false) + Mutation.setNotifications(paged.items, hasMore: paged.hasMore, reset: false) }, - .just(.setLoading(false)) + Observable.just(.setLoading(false)) ]) case .backButtonTapped: return .just(.navigateTo(.dismiss)) + case .settingButtonTapped: return .just(.navigateTo(.setting)) + case .notificationTapped(let notification): return .just(.navigateTo(.notification(notification))) } @@ -104,6 +118,9 @@ public final class DictionaryNotificationReactor: Reactor { case let .navigateTo(route): newState.route = route + + case let .setPermission(granted): + newState.permission = granted } return newState diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationView.swift index 2788458f..49602afe 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationView.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationView.swift @@ -83,9 +83,9 @@ private extension DictionaryNotificationView { } public extension DictionaryNotificationView { - func setEmpty(isEmpty: Bool) { - emptyView.isHidden = !isEmpty - titleLabel.isHidden = isEmpty - notificationCollectionView.isHidden = isEmpty + func setEmpty(hasPermission: Bool) { + emptyView.isHidden = hasPermission + titleLabel.isHidden = !hasPermission + notificationCollectionView.isHidden = !hasPermission } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift index 0a85b474..2d848da2 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift @@ -58,7 +58,6 @@ private extension DictionaryNotificationViewController { func configureUI() { isBottomTabbarHidden = true - guard let reactor = reactor else { return } mainView.notificationCollectionView.delegate = self mainView.notificationCollectionView.dataSource = self @@ -128,13 +127,12 @@ public extension DictionaryNotificationViewController { .disposed(by: disposeBag) reactor.state - .compactMap { $0.profile } + .map { $0.permission } .distinctUntilChanged() .withUnretained(self) .observe(on: MainScheduler.instance) - .subscribe { owner, profile in - let isEmpty = profile.noticeAgreement == false && profile.eventAgreement == false && profile.patchNoteAgreement == false - owner.mainView.setEmpty(isEmpty: isEmpty) + .subscribe { owner, permission in + owner.mainView.setEmpty(hasPermission: permission) } .disposed(by: disposeBag) } From 37937c45cefd406424778414fa0aafb509a6a6ad Mon Sep 17 00:00:00 2001 From: p2glet Date: Sat, 13 Dec 2025 03:11:36 +0900 Subject: [PATCH 07/31] =?UTF-8?q?feat/#273:=20=EC=B5=9C=EA=B7=BC=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=94=8C=EB=9E=AB=ED=8F=BC=20?= =?UTF-8?q?=ED=8C=90=EB=B3=84=20/=20FCM=20=ED=86=A0=ED=81=B0=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=8B=9C=EC=A0=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80(=EC=95=B1=20=EC=A7=84=EC=9E=85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UserDefaultsRepositoryImpl.swift | 3 +- .../AuthAPI/LoginWithKakaoUseCaseImpl.swift | 2 - .../AuthAPI/SignUpWithAppleUseCaseImpl.swift | 42 +++++- .../AuthAPI/SignUpWithKakaoUseCaseImpl.swift | 44 ++++-- MLS/MLS/Application/AppDelegate.swift | 128 ++++++++++-------- .../AuthFeature/Login/LoginView.swift | 29 +++- .../TermsAgreementFactoryImpl.swift | 4 - .../TermsAgreementReactor.swift | 51 ++----- .../recentLoginLogo.imageset/Contents.json | 21 +++ .../recentLoginLogo.png | Bin 0 -> 3454 bytes 10 files changed, 206 insertions(+), 118 deletions(-) create mode 100644 MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/Contents.json create mode 100644 MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/recentLoginLogo.png diff --git a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift b/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift index e8ea829f..991699f3 100644 --- a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift @@ -1,6 +1,7 @@ -import DomainInterface import Foundation +import DomainInterface + import RxSwift public final class UserDefaultsRepositoryImpl: UserDefaultsRepository { diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift index b19f1f53..8f44c74d 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift @@ -15,7 +15,6 @@ public class LoginWithKakaoUseCaseImpl: LoginWithKakaoUseCase { self.userDefaultsRepository = userDefaultsRepository } - // 로그인할때 토큰 저장 필요 public func execute(credential: Credential) -> Observable { return authRepository.loginWithKakao(credential: credential) .flatMap { response -> Observable in @@ -23,7 +22,6 @@ public class LoginWithKakaoUseCaseImpl: LoginWithKakaoUseCase { let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) let savePlatform = self.userDefaultsRepository.savePlatform(platform: .kakao) - // ✅ 모든 저장 결과 확인 switch (saveAccess, saveRefresh) { case (.success, .success): return savePlatform.andThen(Observable.just(response)) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift index 2aa72b99..5d416e14 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift @@ -4,14 +4,44 @@ import DomainInterface import RxSwift -public class SignUpWithAppleUseCaseImpl: SignUpWithAppleUseCase { - private var repository: AuthAPIRepository +public final class SignUpWithAppleUseCaseImpl: SignUpWithAppleUseCase { + private let authRepository: AuthAPIRepository + private let tokenRepository: TokenRepository + private let userDefaultsRepository: UserDefaultsRepository - public init(repository: AuthAPIRepository) { - self.repository = repository + public init( + authRepository: AuthAPIRepository, + tokenRepository: TokenRepository, + userDefaultsRepository: UserDefaultsRepository + ) { + self.authRepository = authRepository + self.tokenRepository = tokenRepository + self.userDefaultsRepository = userDefaultsRepository } - public func execute(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable { - return repository.signUpWithApple(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) + public func execute( + credential: Credential, + isMarketingAgreement: Bool, + fcmToken: String? + ) -> Observable { + return authRepository + .signUpWithKakao(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) + .flatMap { response -> Observable in + let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) + let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) + let savePlatform = self.userDefaultsRepository.savePlatform(platform: .apple) + + switch (saveAccess, saveRefresh) { + case (.success, .success): + return savePlatform.andThen(Observable.just(response)) + default: + return Observable.error( + TokenRepositoryError.dataConversionError(message: "Failed to save tokens") + ) + } + } + .catch { error in + Observable.error(error) + } } } diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift index bcf61e64..0584d346 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift @@ -1,17 +1,45 @@ import Foundation - import DomainInterface - import RxSwift -public class SignUpWithKakaoUseCaseImpl: SignUpWithKakaoUseCase { - private var repository: AuthAPIRepository +public final class SignUpWithKakaoUseCaseImpl: SignUpWithKakaoUseCase { + private let authRepository: AuthAPIRepository + private let tokenRepository: TokenRepository + private let userDefaultsRepository: UserDefaultsRepository - public init(repository: AuthAPIRepository) { - self.repository = repository + public init( + authRepository: AuthAPIRepository, + tokenRepository: TokenRepository, + userDefaultsRepository: UserDefaultsRepository + ) { + self.authRepository = authRepository + self.tokenRepository = tokenRepository + self.userDefaultsRepository = userDefaultsRepository } - public func execute(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable { - return repository.signUpWithKakao(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) + public func execute( + credential: Credential, + isMarketingAgreement: Bool, + fcmToken: String? + ) -> Observable { + return authRepository + .signUpWithKakao(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) + .flatMap { response -> Observable in + let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) + let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) + let savePlatform = self.userDefaultsRepository.savePlatform(platform: .kakao) + + switch (saveAccess, saveRefresh) { + case (.success, .success): + return savePlatform.andThen(Observable.just(response)) + default: + return Observable.error( + TokenRepositoryError.dataConversionError(message: "Failed to save tokens") + ) + } + } + .catch { error in + Observable.error(error) + } } } diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 80816276..4579cf74 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -30,13 +30,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { .LaunchOptionsKey: Any]? ) -> Bool { // MARK: - UserNotification Set - FirebaseApp.configure() // Firebase Set - Messaging.messaging().delegate = self // 파이어베이스 Meesaging 설정 - UNUserNotificationCenter.current().delegate = self // NotificationCenter Delegate + FirebaseApp.configure() // Firebase Set + Messaging.messaging().delegate = self // 파이어베이스 Meesaging 설정 + UNUserNotificationCenter.current().delegate = self // NotificationCenter Delegate // MARK: - Modules Set - ImageLoader.shared.configure.diskCacheCountLimit = 10 // ImageLoader - FontManager.registerFonts() // FontManager + ImageLoader.shared.configure.diskCacheCountLimit = 10 // ImageLoader + FontManager.registerFonts() // FontManager // MARK: - KakaoSDK Set let kakaoNativeAppKey: String = @@ -70,9 +70,9 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: - @escaping ( - UNNotificationPresentationOptions - ) -> Void + @escaping ( + UNNotificationPresentationOptions + ) -> Void ) { completionHandler([.list, .banner]) } @@ -88,26 +88,37 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { object: nil, userInfo: dataDict ) - let tokenUseCase = DIContainer.resolve( - type: SaveTokenToLocalUseCase.self - ) - let result = tokenUseCase.execute( - type: .fcmToken, - value: fcmToken ?? "" - ) + guard let fcmToken = fcmToken else { + os_log("FCM token is nil") + return + } - switch result { + let saveTokenUseCase = DIContainer.resolve(type: SaveTokenToLocalUseCase.self) + let saveResult = saveTokenUseCase.execute(type: .fcmToken, value: fcmToken) + + switch saveResult { case .success: - os_log("✅ fcmToken Save Success Token: \(fcmToken ?? "")") + os_log("fcmToken Save Success: \(fcmToken)") case .failure: - os_log("⚠️ fcmToken Save Failure") + os_log("fcmToken Save Failure") + } + + let fetchTokenUseCase = DIContainer.resolve(type: FetchTokenFromLocalUseCase.self) + let putFCMTokenUseCase = DIContainer.resolve(type: PutFCMTokenUseCase.self) + + if case .success(let accessToken) = fetchTokenUseCase.execute(type: .accessToken), + !accessToken.isEmpty { + _ = putFCMTokenUseCase.execute(fcmToken: fcmToken) + os_log("Request to update FCM token on server") + } else { + os_log("Not logged in yet, skipping FCM update to server") } } } // MARK: - registerDependencies -extension AppDelegate { - fileprivate func registerDependencies() { +private extension AppDelegate { + func registerDependencies() { registerProvider() registerRepository() registerUseCase() @@ -130,7 +141,7 @@ extension AppDelegate { } } - fileprivate func registerProvider() { + func registerProvider() { DIContainer.register(type: NetworkProvider.self) { NetworkProviderImpl() } @@ -159,7 +170,7 @@ extension AppDelegate { } } - fileprivate func registerRepository() { + func registerRepository() { DIContainer.register(type: AuthAPIRepository.self) { AuthAPIRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), @@ -205,7 +216,7 @@ extension AppDelegate { } } - fileprivate func registerUseCase() { + func registerUseCase() { DIContainer.register( type: FetchSocialCredentialUseCase.self, name: "kakao" @@ -265,12 +276,16 @@ extension AppDelegate { } DIContainer.register(type: SignUpWithAppleUseCase.self) { SignUpWithAppleUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) + authRepository: DIContainer.resolve(type: AuthAPIRepository.self), + tokenRepository: DIContainer.resolve(type: TokenRepository.self), + userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self) ) } DIContainer.register(type: SignUpWithKakaoUseCase.self) { SignUpWithKakaoUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) + authRepository: DIContainer.resolve(type: AuthAPIRepository.self), + tokenRepository: DIContainer.resolve(type: TokenRepository.self), + userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self) ) } DIContainer.register(type: UpdateUserInfoUseCase.self) { @@ -674,7 +689,7 @@ extension AppDelegate { } } - fileprivate func registerFactory() { + func registerFactory() { DIContainer.register(type: ItemFilterBottomSheetFactory.self) { ItemFilterBottomSheetFactoryImpl() } @@ -821,7 +836,7 @@ extension AppDelegate { type: FetchDictionaryQuestListUseCase.self ), dictionaryNpcListItemUseCase: - DIContainer + DIContainer .resolve(type: FetchDictionaryNpcListUseCase.self), dictionaryListItemUseCase: DIContainer.resolve( type: FetchDictionaryMonsterListUseCase.self @@ -856,7 +871,7 @@ extension AppDelegate { type: FetchDictionaryListCountUseCase.self ), dictionaryMainListFactory: - DIContainer + DIContainer .resolve(type: DictionaryMainListFactory.self), dictionarySearchListUseCase: DIContainer.resolve( type: FetchDictionarySearchListUseCase.self @@ -872,7 +887,7 @@ extension AppDelegate { type: RecentSearchAddUseCase.self ), searchResultFactory: - DIContainer + DIContainer .resolve(type: DictionarySearchResultFactory.self), recentSearchFetchUseCase: DIContainer.resolve( type: RecentSearchFetchUseCase.self @@ -922,13 +937,13 @@ extension AppDelegate { DIContainer.register(type: OnBoardingNotificationSheetFactory.self) { OnBoardingNotificationSheetFactoryImpl( checkNotificationPermissionUseCase: - DIContainer + DIContainer .resolve(type: CheckNotificationPermissionUseCase.self), openNotificationSettingUseCase: - DIContainer + DIContainer .resolve(type: OpenNotificationSettingUseCase.self), updateNotificationAgreementUseCase: - DIContainer + DIContainer .resolve(type: UpdateNotificationAgreementUseCase.self), updateUserInfoUseCase: DIContainer.resolve( type: UpdateUserInfoUseCase.self @@ -980,9 +995,6 @@ extension AppDelegate { signUpWithAppleUseCase: DIContainer.resolve( type: SignUpWithAppleUseCase.self ), - saveTokenUseCase: DIContainer.resolve( - type: SaveTokenToLocalUseCase.self - ), fetchTokenUseCase: DIContainer.resolve( type: FetchTokenFromLocalUseCase.self ), @@ -1006,25 +1018,25 @@ extension AppDelegate { DIContainer.register(type: BookmarkMainFactory.self) { BookmarkMainFactoryImpl( setBookmarkUseCase: - DIContainer + DIContainer .resolve(type: SetBookmarkUseCase.self), checkLoginUseCase: - DIContainer + DIContainer .resolve(type: CheckLoginUseCase.self), fetchVisitBookmarkUseCase: - DIContainer + DIContainer .resolve(type: FetchVisitBookmarkUseCase.self), onBoardingFactory: - DIContainer + DIContainer .resolve(type: BookmarkOnBoardingFactory.self), bookmarkListFactory: - DIContainer + DIContainer .resolve(type: BookmarkListFactory.self), collectionListFactory: - DIContainer + DIContainer .resolve(type: CollectionListFactory.self), searchFactory: - DIContainer + DIContainer .resolve(type: DictionarySearchFactory.self), notificationFactory: DIContainer.resolve( type: DictionaryNotificationFactory.self @@ -1097,35 +1109,35 @@ extension AppDelegate { type: CollectionDetailFactory.self ), sortedBottomSheetFactory: - DIContainer + DIContainer .resolve(type: SortedBottomSheetFactory.self) ) } DIContainer.register(type: CollectionDetailFactory.self) { CollectionDetailFactoryImpl( bookmarkModalFactory: - DIContainer + DIContainer .resolve(type: BookmarkModalFactory.self), collectionSettingFactory: - DIContainer + DIContainer .resolve(type: CollectionSettingFactory.self), addCollectionFactory: - DIContainer + DIContainer .resolve(type: AddCollectionFactory.self), collectionEditFactory: - DIContainer + DIContainer .resolve(type: CollectionEditFactory.self), dictionaryDetailFactory: - DIContainer + DIContainer .resolve(type: DictionaryDetailFactory.self), setBookmarkUseCase: - DIContainer + DIContainer .resolve(type: SetBookmarkUseCase.self), fetchCollectionUseCase: DIContainer.resolve( type: FetchCollectionUseCase.self ), deleteCollectionUseCase: - DIContainer + DIContainer .resolve(type: DeleteCollectionUseCase.self), addCollectionAndBookmarkUseCase: DIContainer.resolve( type: AddCollectionAndBookmarkUseCase.self @@ -1149,16 +1161,16 @@ extension AppDelegate { MyPageMainFactoryImpl( loginFactory: DIContainer.resolve(type: LoginFactory.self), setProfileFactory: - DIContainer + DIContainer .resolve(type: SetProfileFactory.self), customerSupportFactory: - DIContainer + DIContainer .resolve(type: CustomerSupportFactory.self), notificationSettingFactory: - DIContainer + DIContainer .resolve(type: NotificationSettingFactory.self), setCharacterFactory: - DIContainer + DIContainer .resolve(type: SetCharacterFactory.self), fetchProfileUseCase: DIContainer.resolve( type: FetchProfileUseCase.self @@ -1207,16 +1219,16 @@ extension AppDelegate { DIContainer.register(type: SetCharacterFactory.self) { SetCharacterFactoryImpl( checkEmptyUseCase: - DIContainer + DIContainer .resolve(type: CheckEmptyLevelAndRoleUseCase.self), checkValidLevelUseCase: - DIContainer + DIContainer .resolve(type: CheckValidLevelUseCase.self), fetchJobListUseCase: - DIContainer + DIContainer .resolve(type: FetchJobListUseCase.self), updateUserInfoUseCase: - DIContainer + DIContainer .resolve(type: UpdateUserInfoUseCase.self) ) } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift index 213b90f0..b6f1aad4 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift @@ -18,6 +18,9 @@ final class LoginView: UIView { static let buttonCenterXInset: CGFloat = buttonLogoImageLeadingInset + buttonLogoImageSize static let labelHeight: CGFloat = 28 static let subTitleBottomSpacing: CGFloat = -25 + static let recentLogoWidth: CGFloat = 82 + static let recentLogoHeight: CGFloat = 30 + static let recentLogoInset: CGFloat = 8 } // MARK: - Properties @@ -93,6 +96,12 @@ final class LoginView: UIView { return label }() + private let recentLoginImageView: UIImageView = { + let view = UIImageView(image: DesignSystemAsset.image(named: "recentLoginLogo")) + view.isHidden = true + return view + }() + // MARK: - init init() { super.init(frame: .zero) @@ -113,6 +122,7 @@ private extension LoginView { func addViews() { addSubview(loginImageView) addSubview(buttonStackView) + addSubview(recentLoginImageView) buttonStackView.addArrangedSubview(kakaoLoginButton) buttonStackView.addArrangedSubview(appleLoginButton) @@ -197,12 +207,29 @@ extension LoginView { make.centerX.equalToSuperview() make.height.equalTo(Constant.labelHeight) } + + recentLoginImageView.isHidden = false + + recentLoginImageView.snp.remakeConstraints { make in + switch loginPlatform { + case .apple: + make.leading.equalTo(appleLoginButton).offset(Constant.recentLogoInset) + make.bottom.equalTo(appleLoginButton.snp.top).offset(Constant.recentLogoInset) + case .kakao: + make.leading.equalTo(kakaoLoginButton).offset(Constant.recentLogoInset) + make.bottom.equalTo(kakaoLoginButton.snp.top).offset(Constant.recentLogoInset) + default: + break + } + make.width.equalTo(Constant.recentLogoWidth) + make.height.equalTo(Constant.recentLogoHeight) + } case nil: buttonStackView.addArrangedSubview(guestLoginButton) guestLoginButton.snp.remakeConstraints { make in make.height.equalTo(Constant.buttonHeight) } - + recentLoginImageView.isHidden = true } setNeedsLayout() diff --git a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift index ef9763b0..e069897f 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift @@ -7,7 +7,6 @@ public struct TermsAgreementFactoryImpl: TermsAgreementFactory { private let signUpWithKakaoUseCase: SignUpWithKakaoUseCase private let signUpWithAppleUseCase: SignUpWithAppleUseCase - private let saveTokenUseCase: SaveTokenToLocalUseCase private let fetchTokenUseCase: FetchTokenFromLocalUseCase private let updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase @@ -15,14 +14,12 @@ public struct TermsAgreementFactoryImpl: TermsAgreementFactory { onBoardingQuestionFactory: OnBoardingQuestionFactory, signUpWithKakaoUseCase: SignUpWithKakaoUseCase, signUpWithAppleUseCase: SignUpWithAppleUseCase, - saveTokenUseCase: SaveTokenToLocalUseCase, fetchTokenUseCase: FetchTokenFromLocalUseCase, updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase ) { self.onBoardingQuestionFactory = onBoardingQuestionFactory self.signUpWithKakaoUseCase = signUpWithKakaoUseCase self.signUpWithAppleUseCase = signUpWithAppleUseCase - self.saveTokenUseCase = saveTokenUseCase self.fetchTokenUseCase = fetchTokenUseCase self.updateMarketingAgreementUseCase = updateMarketingAgreementUseCase } @@ -35,7 +32,6 @@ public struct TermsAgreementFactoryImpl: TermsAgreementFactory { socialPlatform: platform, signUpWithKakaoUseCase: signUpWithKakaoUseCase, signUpWithAppleUseCase: signUpWithAppleUseCase, - saveTokenUseCase: saveTokenUseCase, fetchTokenUseCase: fetchTokenUseCase, updateMarketingAgreementUseCase: updateMarketingAgreementUseCase ) return viewController diff --git a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementReactor.swift index 5674bddf..3aeb36ce 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementReactor.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementReactor.swift @@ -52,7 +52,6 @@ public final class TermsAgreementReactor: Reactor { private let socialPlatform: LoginPlatform private let signUpWithKakaoUseCase: SignUpWithKakaoUseCase private let signUpWithAppleUseCase: SignUpWithAppleUseCase - private let saveTokenUseCase: SaveTokenToLocalUseCase private let fetchTokenUseCase: FetchTokenFromLocalUseCase private let updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase @@ -62,7 +61,6 @@ public final class TermsAgreementReactor: Reactor { socialPlatform: LoginPlatform, signUpWithKakaoUseCase: SignUpWithKakaoUseCase, signUpWithAppleUseCase: SignUpWithAppleUseCase, - saveTokenUseCase: SaveTokenToLocalUseCase, fetchTokenUseCase: FetchTokenFromLocalUseCase, updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase ) { @@ -70,7 +68,6 @@ public final class TermsAgreementReactor: Reactor { self.socialPlatform = socialPlatform self.signUpWithKakaoUseCase = signUpWithKakaoUseCase self.signUpWithAppleUseCase = signUpWithAppleUseCase - self.saveTokenUseCase = saveTokenUseCase self.fetchTokenUseCase = fetchTokenUseCase self.updateMarketingAgreementUseCase = updateMarketingAgreementUseCase self.initialState = State() @@ -97,40 +94,25 @@ public final class TermsAgreementReactor: Reactor { } return .just(.setAgreeState(type: type, isOn: isOn)) case .bottomButtonTapped: - var fcmToken: String? - - UNUserNotificationCenter.current().getNotificationSettings { [weak self] settings in - guard let self else { return } - switch settings.authorizationStatus { - case .authorized, .provisional, .ephemeral: - if case .success(let token) = fetchTokenUseCase.execute(type: .fcmToken) { - fcmToken = token - } - default: - fcmToken = nil + let fcmToken: String? = { + if case .success(let token) = fetchTokenUseCase.execute(type: .fcmToken) { + return token + } else { + return nil } - } + }() switch socialPlatform { case .kakao: - return signUpWithKakaoUseCase.execute(credential: credential, isMarketingAgreement: currentState.isMarketingAgree, fcmToken: fcmToken) - .withUnretained(self) - .map { owner, response in - let accessTokenResult = owner.saveTokenUseCase.execute(type: .accessToken, value: response.accessToken) - let refreshTokenResult = owner.saveTokenUseCase.execute(type: .refreshToken, value: response.refreshToken) - let isTokenSaveSuccess = owner.isTokenSaveSuccess(access: accessTokenResult, refresh: refreshTokenResult) - return isTokenSaveSuccess ? .navigateTo(route: .onBoarding) : .navigateTo(route: .error) - } + return signUpWithKakaoUseCase + .execute(credential: credential, isMarketingAgreement: currentState.isMarketingAgree, fcmToken: fcmToken) + .map { _ in .navigateTo(route: .onBoarding) } .catchAndReturn(.navigateTo(route: .error)) + case .apple: - return signUpWithAppleUseCase.execute(credential: credential, isMarketingAgreement: currentState.isMarketingAgree, fcmToken: fcmToken) - .withUnretained(self) - .map { owner, response in - let accessTokenResult = owner.saveTokenUseCase.execute(type: .accessToken, value: response.accessToken) - let refreshTokenResult = owner.saveTokenUseCase.execute(type: .refreshToken, value: response.refreshToken) - let isTokenSaveSuccess = owner.isTokenSaveSuccess(access: accessTokenResult, refresh: refreshTokenResult) - return isTokenSaveSuccess ? .navigateTo(route: .onBoarding) : .navigateTo(route: .error) - } + return signUpWithAppleUseCase + .execute(credential: credential, isMarketingAgreement: currentState.isMarketingAgree, fcmToken: fcmToken) + .map { _ in .navigateTo(route: .onBoarding) } .catchAndReturn(.navigateTo(route: .error)) } @@ -170,11 +152,4 @@ public final class TermsAgreementReactor: Reactor { return newState } - - private func isTokenSaveSuccess(access: Result, refresh: Result) -> Bool { - if case .success = access, case .success = refresh { - return true - } - return false - } } diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/Contents.json new file mode 100644 index 00000000..c1fb5668 --- /dev/null +++ b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "recentLoginLogo.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/recentLoginLogo.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/recentLoginLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..4afde34f61cfe2190cfb197aa90cd08fa0bd3365 GIT binary patch literal 3454 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 literal 0 HcmV?d00001 From efa8e6eb47516214f876cdecc928c96b1f8ed21e Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 17:40:14 +0900 Subject: [PATCH 08/31] =?UTF-8?q?fix/#273:=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=B6=81=EB=A7=88=ED=81=AC=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20/=20=EC=95=8C?= =?UTF-8?q?=EB=9E=8C=20=EC=9D=91=EB=8B=B5=20=EB=AA=A8=EB=8D=B8=20date=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DTO/AlarmDTO/AlarmResponseDTO.swift | 2 +- .../Repository/AlarmAPIRepositoryImpl.swift | 12 +++---- .../Domain/Interceptor/AuthInterceptor.swift | 2 +- .../Alarm/FetchAllAlarmUseCaseImpl.swift | 2 +- .../Alarm/FetchNoticesUseCaseImpl.swift | 2 +- .../Alarm/FetchOngoingEventsUseCaseImpl.swift | 2 +- .../FetchOutdatedEventsUseCaseImpl.swift | 2 +- .../Alarm/FetchPatchNotesUseCaseImpl.swift | 2 +- .../AuthAPI/LoginWithKakaoUseCaseImpl.swift | 20 ++++++++---- .../Entity/Alarm/AlarmResponse.swift | 8 ++--- .../Repository/AlarmAPIRepository.swift | 10 +++--- .../UseCase/Alarm/FetchAllAlarmUseCase.swift | 2 +- .../UseCase/Alarm/FetchNoticesUseCase.swift | 2 +- .../Alarm/FetchOngoingEventsUseCase.swift | 2 +- .../Alarm/FetchOutdatedEventsUseCase.swift | 2 +- .../Alarm/FetchPatchNotesUseCase.swift | 2 +- .../OnBoardingNotificationFactoryImpl.swift | 1 - .../Utills/Extension/String+.swift | 14 ++++++++ .../DictionaryDetailBaseViewController.swift | 9 +++--- .../ItemDictionaryDetailViewController.swift | 1 - .../MapDictionaryDetailViewController.swift | 1 - ...onsterDictionaryDetailViewController.swift | 1 - .../NpcDictionaryDetailViewController.swift | 1 - .../QuestDictionaryDetailViewController.swift | 1 - .../DictionaryListReactor.swift | 26 +++++++++++++-- .../DictionaryListViewController.swift | 3 +- ...DictionaryNotificationViewController.swift | 2 +- .../CustomerSupportBaseView.swift | 32 ++++++++++++++++--- .../CustomerSupportBaseViewController.swift | 2 +- .../CustomerSupport/Event/EventReactor.swift | 19 ++++++++--- .../Event/EventViewController.swift | 7 +++- 31 files changed, 132 insertions(+), 62 deletions(-) diff --git a/MLS/Data/Data/Network/DTO/AlarmDTO/AlarmResponseDTO.swift b/MLS/Data/Data/Network/DTO/AlarmDTO/AlarmResponseDTO.swift index 2b343a23..c531c810 100644 --- a/MLS/Data/Data/Network/DTO/AlarmDTO/AlarmResponseDTO.swift +++ b/MLS/Data/Data/Network/DTO/AlarmDTO/AlarmResponseDTO.swift @@ -35,7 +35,7 @@ public struct AlarmResponseDTO: Decodable { public let type: String public let title: String public let link: String - public let date: [Int] + public let date: String } public struct AllContent: Decodable { diff --git a/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift index 56449af0..fb3d32ac 100644 --- a/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift @@ -13,31 +13,31 @@ public class AlarmAPIRepositoryImpl: AlarmAPIRepository { self.tokenInterceptor = interceptor } - public func fetchPatchNotes(cursor: [Int]?, pageSize: Int) -> Observable> { + public func fetchPatchNotes(cursor: String?, pageSize: Int) -> Observable> { let endpoint = AlarmEndPoint.fetchPatchNotes(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } - public func fetchNotices(cursor: [Int]?, pageSize: Int) -> Observable> { + public func fetchNotices(cursor: String?, pageSize: Int) -> Observable> { let endpoint = AlarmEndPoint.fetchNotices(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } - public func fetchOutdatedEvents(cursor: [Int]?, pageSize: Int) -> Observable> { + public func fetchOutdatedEvents(cursor: String?, pageSize: Int) -> Observable> { let endpoint = AlarmEndPoint.fetchOutdatedEvents(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } - public func fetchOngoingEvents(cursor: [Int]?, pageSize: Int) -> Observable> { + public func fetchOngoingEvents(cursor: String?, pageSize: Int) -> Observable> { let endpoint = AlarmEndPoint.fetchOngoingEvents(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } - public func fetchAll(cursor: [Int]?, pageSize: Int) -> Observable> { + public func fetchAll(cursor: String?, pageSize: Int) -> Observable> { let endpoint = AlarmEndPoint.fetchAll(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAllAlarmDomain() } @@ -52,7 +52,7 @@ public class AlarmAPIRepositoryImpl: AlarmAPIRepository { private extension AlarmAPIRepositoryImpl { struct AlarmQuery: Encodable { - let cursor: [Int]? + let cursor: String? let pageSize: Int } diff --git a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift b/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift index 5496655d..9b82c6e6 100644 --- a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift +++ b/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift @@ -33,7 +33,7 @@ public final class AuthInterceptor: Interceptor { let repo = authRepository() repo.reissueToken(refreshToken: refreshToken) .subscribe(onNext: { _ in - print("✅ reissue 완료 (저장은 UseCase 쪽에서 처리)") + print("✅ reissue 완료") }, onError: { error in print("❌ reissue 실패: \(error)") }) diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchAllAlarmUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchAllAlarmUseCaseImpl.swift index 60f51b83..47060dfb 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchAllAlarmUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchAllAlarmUseCaseImpl.swift @@ -11,7 +11,7 @@ public class FetchAllAlarmUseCaseImpl: FetchAllAlarmUseCase { self.repository = repository } - public func execute(cursor: [Int]?, pageSize: Int) -> Observable> { + public func execute(cursor: String?, pageSize: Int) -> Observable> { return repository.fetchAll(cursor: cursor, pageSize: pageSize) } } diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchNoticesUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchNoticesUseCaseImpl.swift index f144a80b..410913be 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchNoticesUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchNoticesUseCaseImpl.swift @@ -11,7 +11,7 @@ public class FetchNoticesUseCaseImpl: FetchNoticesUseCase { self.repository = repository } - public func execute(cursor: [Int]?, pageSize: Int) -> Observable> { + public func execute(cursor: String?, pageSize: Int) -> Observable> { return repository.fetchNotices(cursor: cursor, pageSize: pageSize) } } diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOngoingEventsUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOngoingEventsUseCaseImpl.swift index d76991c1..dd28aa8d 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOngoingEventsUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOngoingEventsUseCaseImpl.swift @@ -11,7 +11,7 @@ public class FetchOngoingEventsUseCaseImpl: FetchOngoingEventsUseCase { self.repository = repository } - public func execute(cursor: [Int]?, pageSize: Int) -> Observable> { + public func execute(cursor: String?, pageSize: Int) -> Observable> { return repository.fetchOngoingEvents(cursor: cursor, pageSize: pageSize) } } diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOutdatedEventsUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOutdatedEventsUseCaseImpl.swift index 7fb8f1cd..f3571532 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOutdatedEventsUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOutdatedEventsUseCaseImpl.swift @@ -11,7 +11,7 @@ public class FetchOutdatedEventsUseCaseImpl: FetchOutdatedEventsUseCase { self.repository = repository } - public func execute(cursor: [Int]?, pageSize: Int) -> Observable> { + public func execute(cursor: String?, pageSize: Int) -> Observable> { return repository.fetchOutdatedEvents(cursor: cursor, pageSize: pageSize) } } diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchPatchNotesUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchPatchNotesUseCaseImpl.swift index 345fca46..2817b0ef 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchPatchNotesUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchPatchNotesUseCaseImpl.swift @@ -11,7 +11,7 @@ public class FetchPatchNotesUseCaseImpl: FetchPatchNotesUseCase { self.repository = repository } - public func execute(cursor: [Int]?, pageSize: Int) -> Observable> { + public func execute(cursor: String?, pageSize: Int) -> Observable> { return repository.fetchPatchNotes(cursor: cursor, pageSize: pageSize) } } diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift index 8f44c74d..1a456fce 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift @@ -22,14 +22,20 @@ public class LoginWithKakaoUseCaseImpl: LoginWithKakaoUseCase { let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) let savePlatform = self.userDefaultsRepository.savePlatform(platform: .kakao) - switch (saveAccess, saveRefresh) { - case (.success, .success): - return savePlatform.andThen(Observable.just(response)) - default: - return Observable.error( - TokenRepositoryError.dataConversionError(message: "Failed to save tokens") - ) + guard case (.success, .success) = (saveAccess, saveRefresh) else { + return Observable.error(TokenRepositoryError.dataConversionError(message: "Failed to save tokens")) } + + var fcmToken: String? + if case .success(let token) = self.tokenRepository.fetchToken(type: .fcmToken) { + fcmToken = token + } + + if let fcmToken { + _ = self.authRepository.fcmToken(fcmToken: fcmToken) + } + + return savePlatform.andThen(Observable.just(response)) } .catch { error in Observable.error(error) diff --git a/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift b/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift index 365d0e59..952215d0 100644 --- a/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift @@ -4,9 +4,9 @@ public struct AlarmResponse: Equatable { public let type: String public let title: String public let link: String - public let date: [Int] + public let date: String - public init(type: String, title: String, link: String, date: [Int]) { + public init(type: String, title: String, link: String, date: String) { self.type = type self.title = title self.link = link @@ -18,10 +18,10 @@ public struct AllAlarmResponse: Equatable { public let type: String public let title: String public let link: String - public let date: [Int] + public let date: String public let alreadyRead: Bool - public init(type: String, title: String, link: String, date: [Int], alreadyRead: Bool) { + public init(type: String, title: String, link: String, date: String, alreadyRead: Bool) { self.type = type self.title = title self.link = link diff --git a/MLS/Domain/DomainInterface/Repository/AlarmAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/AlarmAPIRepository.swift index ea980b26..4c3c303b 100644 --- a/MLS/Domain/DomainInterface/Repository/AlarmAPIRepository.swift +++ b/MLS/Domain/DomainInterface/Repository/AlarmAPIRepository.swift @@ -3,15 +3,15 @@ import Foundation import RxSwift public protocol AlarmAPIRepository { - func fetchPatchNotes(cursor: [Int]?, pageSize: Int) -> Observable> + func fetchPatchNotes(cursor: String?, pageSize: Int) -> Observable> - func fetchNotices(cursor: [Int]?, pageSize: Int) -> Observable> + func fetchNotices(cursor: String?, pageSize: Int) -> Observable> - func fetchOutdatedEvents(cursor: [Int]?, pageSize: Int) -> Observable> + func fetchOutdatedEvents(cursor: String?, pageSize: Int) -> Observable> - func fetchOngoingEvents(cursor: [Int]?, pageSize: Int) -> Observable> + func fetchOngoingEvents(cursor: String?, pageSize: Int) -> Observable> - func fetchAll(cursor: [Int]?, pageSize: Int) -> Observable> + func fetchAll(cursor: String?, pageSize: Int) -> Observable> func setRead(alarmLink: String) -> Completable } diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchAllAlarmUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchAllAlarmUseCase.swift index 72a34087..41206233 100644 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchAllAlarmUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchAllAlarmUseCase.swift @@ -1,5 +1,5 @@ import RxSwift public protocol FetchAllAlarmUseCase { - func execute(cursor: [Int]?, pageSize: Int) -> Observable> + func execute(cursor: String?, pageSize: Int) -> Observable> } diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchNoticesUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchNoticesUseCase.swift index 9a3d4a0f..f5d75581 100644 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchNoticesUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchNoticesUseCase.swift @@ -1,5 +1,5 @@ import RxSwift public protocol FetchNoticesUseCase { - func execute(cursor: [Int]?, pageSize: Int) -> Observable> + func execute(cursor: String?, pageSize: Int) -> Observable> } diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOngoingEventsUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOngoingEventsUseCase.swift index 31d6427f..80303048 100644 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOngoingEventsUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOngoingEventsUseCase.swift @@ -1,5 +1,5 @@ import RxSwift public protocol FetchOngoingEventsUseCase { - func execute(cursor: [Int]?, pageSize: Int) -> Observable> + func execute(cursor: String?, pageSize: Int) -> Observable> } diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOutdatedEventsUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOutdatedEventsUseCase.swift index 34618f8a..959663ea 100644 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOutdatedEventsUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOutdatedEventsUseCase.swift @@ -1,5 +1,5 @@ import RxSwift public protocol FetchOutdatedEventsUseCase { - func execute(cursor: [Int]?, pageSize: Int) -> Observable> + func execute(cursor: String?, pageSize: Int) -> Observable> } diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchPatchNotesUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchPatchNotesUseCase.swift index b8dd6886..62d27587 100644 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchPatchNotesUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchPatchNotesUseCase.swift @@ -1,5 +1,5 @@ import RxSwift public protocol FetchPatchNotesUseCase { - func execute(cursor: [Int]?, pageSize: Int) -> Observable> + func execute(cursor: String?, pageSize: Int) -> Observable> } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift index dcba72ae..dbccc528 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift @@ -1,6 +1,5 @@ import AuthFeatureInterface import BaseFeature -import DictionaryFeatureInterface public struct OnBoardingNotificationFactoryImpl: OnBoardingNotificationFactory { private let onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift index d27b345e..f448d1b5 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift @@ -1,7 +1,21 @@ +import Foundation + extension String { public func isOnlyKorean() -> Bool { let initialConsonants = "ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ" return self.allSatisfy { initialConsonants.contains($0) } } + public func toDisplayDateString() -> String { + let inputFormatter = ISO8601DateFormatter() + inputFormatter.formatOptions = [.withInternetDateTime] + + guard let date = inputFormatter.date(from: self) else { return self } + + let outputFormatter = DateFormatter() + outputFormatter.locale = Locale(identifier: "ko_KR") + outputFormatter.dateFormat = "yyyy.MM.dd HH:mm" + + return outputFormatter.string(from: date) + } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index d37a776d..8e109d4f 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -273,7 +273,6 @@ extension DictionaryDetailBaseViewController { imageUrl: @escaping (T) -> String?, backgroundColor: UIColor, isBookmarked: @escaping (T) -> Bool, - toggleBookmark: @escaping (Bool) -> Void, undoLastDeleted: @escaping () -> Void, bookmarkId: Observable ) -> Disposable { @@ -299,8 +298,8 @@ extension DictionaryDetailBaseViewController { let itemId = id(item) if isBookmarked(item) { - toggleBookmark(true) - self.bookmarkRelay?.accept((itemId, false)) + mainView.setBookmark(isBookmarked: false) + self.bookmarkRelay?.accept((itemId, true)) SnackBarFactory.createSnackBar( type: .delete, imageUrl: imageUrl(item), @@ -310,8 +309,8 @@ extension DictionaryDetailBaseViewController { buttonAction: { undoLastDeleted() } ) } else { - toggleBookmark(false) - self.bookmarkRelay?.accept((itemId, true)) + mainView.setBookmark(isBookmarked: true) + self.bookmarkRelay?.accept((itemId, false)) SnackBarFactory.createSnackBar( type: .normal, imageUrl: imageUrl(item), diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index 27b25de1..b5ce7b66 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -236,7 +236,6 @@ extension ItemDictionaryDetailViewController { imageUrl: { $0.imgUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - toggleBookmark: { isDeleting in reactor.action.onNext(.toggleBookmark(isDeleting)) }, undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.itemDetailInfo.bookmarkId) ) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index da01bef7..c7a3ee4b 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -179,7 +179,6 @@ extension MapDictionaryDetailViewController { imageUrl: { $0.mapUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - toggleBookmark: { isDeleting in reactor.action.onNext(.toggleBookmark(isDeleting)) }, undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.mapDetailInfo.bookmarkId) ) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift index c386e132..314651a7 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift @@ -222,7 +222,6 @@ extension MonsterDictionaryDetailViewController { imageUrl: { $0.imageUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - toggleBookmark: { isDeleting in reactor.action.onNext(.toggleBookmark(isDeleting)) }, undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.monsterDetailInfo.bookmarkId) ) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift index b5aef1f7..d317149c 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift @@ -171,7 +171,6 @@ extension NpcDictionaryDetailViewController { imageUrl: { $0.iconUrlDetail }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - toggleBookmark: { isDeleting in reactor.action.onNext(.toggleBookmark(isDeleting)) }, undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.npcDetailInfo.bookmarkId) ) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift index 3eea7f99..9e641bcf 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift @@ -186,7 +186,6 @@ extension QuestDictionaryDetailViewController { imageUrl: { $0.iconUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - toggleBookmark: { isDeleting in reactor.action.onNext(.toggleBookmark(isDeleting)) }, undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.detailInfo.bookmarkId) ) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift index 2e9648e5..e8838d0f 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift @@ -42,6 +42,7 @@ public final class DictionaryListReactor: Reactor { case setCategoryId([Int]) case updateBookmarkState(id: Int, isSelected: Bool) case updateBookmarkStates([Int: Bool]) // 새 Mutation: 여러 북마크 반영 + case setFirstFetch(Bool) } // MARK: - State @@ -62,7 +63,8 @@ public final class DictionaryListReactor: Reactor { var isLogin: Bool var lastDeletedBookmark: DictionaryMainItemResponse? - var isBookmarkUpdateOnly: Bool = false + var isBookmarkUpdateOnly = false + var isFirstFetch = true } public var initialState: State @@ -187,6 +189,8 @@ public final class DictionaryListReactor: Reactor { newState.listItems[index].bookmarkId = isSelected ? (newState.listItems[index].bookmarkId ?? -1) : nil } } + case let .setFirstFetch(isFirstFetch): + newState.isFirstFetch = isFirstFetch } return newState } @@ -273,7 +277,25 @@ private extension DictionaryListReactor { func handleViewWillAppear() -> Observable { let loginState = checkLoginUseCase.execute() .map { Mutation.setLoginState($0) } - let fetchMutation = fetchList(sort: currentState.sort, startLevel: currentState.startLevel, endLevel: currentState.endLevel) + + let fetchMutation: Observable + + if currentState.isFirstFetch { + let _ = Mutation.setFirstFetch(false) + fetchMutation = fetchList( + sort: currentState.sort, + startLevel: currentState.startLevel, + endLevel: currentState.endLevel + ) + } else { + fetchMutation = fetchList( + sort: currentState.sort, + startLevel: currentState.startLevel, + endLevel: currentState.endLevel, + updateBookmarkOnly: true + ) + } + return .merge([loginState, fetchMutation]) } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index 0fed74a2..b83227c7 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -191,7 +191,6 @@ extension DictionaryListViewController { }) .disposed(by: disposeBag) - // 기존 bookmarkChangeRelay 사용 대신 reactor.state.map(\.listItems) .observe(on: MainScheduler.instance) .withUnretained(self) @@ -218,7 +217,7 @@ extension DictionaryListViewController { indexPath.item < items.count, let cell = cell as? DictionaryListCell { let item = items[indexPath.item] - cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) + cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil && item.bookmarkId != -1) } } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift index 2d848da2..3efd9631 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift @@ -149,7 +149,7 @@ extension DictionaryNotificationViewController: UICollectionViewDelegate, UIColl guard let reactor = reactor else { return UICollectionViewCell() } guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DictionaryNotificationCell.identifier, for: indexPath) as? DictionaryNotificationCell else { return UICollectionViewCell() } let item = reactor.currentState.notifications[indexPath.row] - cell.inject(input: DictionaryNotificationCell.Input(title: item.title, subTitle: item.date.changeKoreanDate(), isChecked: item.alreadyRead)) + cell.inject(input: DictionaryNotificationCell.Input(title: item.title, subTitle: item.date.toDisplayDateString(), isChecked: item.alreadyRead)) return cell } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift index 5ff7b1a1..e212614d 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift @@ -18,6 +18,8 @@ final class CustomerSupportBaseView: UIView { static let textWidth: CGFloat = 300 static let viewHeight: CGFloat = 86 static let dateTopMargin: CGFloat = 4 + static let emptyLabelHeight: CGFloat = 86 + static let emptyLabelInset: CGFloat = 16 static let menuTabBarButtonInset: NSDirectionalEdgeInsets = .init(top: 9, leading: 4, bottom: 9, trailing: 4) static let menuTabBarHorizontalInset: UIEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16) @@ -63,11 +65,13 @@ final class CustomerSupportBaseView: UIView { stackView.layoutMargins = Constant.menuTabBarHorizontalInset return stackView }() + let bottomLineView: UIView = { let view = UIView() view.backgroundColor = .neutral300 return view }() + // 메뉴 스택뷰 왼쪽 정렬을 위해서 let emptyView = UIView() @@ -76,6 +80,7 @@ final class CustomerSupportBaseView: UIView { let scrollView = UIScrollView() return scrollView }() + // 아이템 담을 스택 뷰 let detailItemStackView: UIStackView = { let stackView = UIStackView() @@ -102,7 +107,6 @@ final class CustomerSupportBaseView: UIView { // MARK: - SetUp private extension CustomerSupportBaseView { - func addViews() { [backButton, titleLabel].forEach { headerView.addSubview($0) } [headerView, menuContainerView, scrollView].forEach { addSubview($0) } @@ -133,7 +137,6 @@ private extension CustomerSupportBaseView { make.top.equalTo(headerView.snp.bottom).offset(Constant.topMargin) make.width.equalToSuperview() make.height.equalTo(Constant.menuStackViewHeight) - } menuStackView.snp.makeConstraints { make in make.width.equalToSuperview() @@ -161,6 +164,7 @@ private extension CustomerSupportBaseView { } } } + extension CustomerSupportBaseView { func createMenuButton(title: String, tag: Int) -> UIButton { let config = setupConfig() @@ -211,7 +215,7 @@ extension CustomerSupportBaseView { view.snp.makeConstraints { make in make.height.equalTo(Constant.viewHeight) } - if let dateText = dateText { + if dateText != nil { title.snp.makeConstraints { make in make.top.equalToSuperview().inset(Constant.topMargin) // 임의 너비 설정 @@ -257,8 +261,26 @@ extension CustomerSupportBaseView { } setMenuHidden(true) // menuContainer뷰 숨기기 } + // menuContainerView Encapsulation func setMenuHidden(_ hidden: Bool) { - menuContainerView.isHidden = hidden - } + menuContainerView.isHidden = hidden + } + + func setEmpty (text: String) { + let label = UILabel() + label.attributedText = .makeStyledString(font: .b_m_r, text: text, color: .neutral700, alignment: .left) + let view = UIView() + + view.addSubview(label) + + view.snp.makeConstraints { make in + make.height.equalTo(Constant.emptyLabelHeight) + } + label.snp.makeConstraints { make in + make.horizontalEdges.equalToSuperview().inset(Constant.emptyLabelInset) + make.centerY.equalToSuperview() + } + detailItemStackView.addArrangedSubview(view) + } } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift index 1f3c19ef..fb4b6f0d 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift @@ -55,7 +55,7 @@ class CustomerSupportBaseViewController: BaseViewController { func createDetailItem(items: [AlarmResponse]) { for (index, item) in items.enumerated() { - let view = mainView.createDetailItem(titleText: item.title, dateText: item.date.changeKoreanDate()) + let view = mainView.createDetailItem(titleText: item.title, dateText: item.date.toDisplayDateString()) view.tag = index urlStrings.append(item.link) diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventReactor.swift index 41e842cf..654c0dab 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventReactor.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventReactor.swift @@ -44,12 +44,21 @@ public final class EventReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case let .selectTab(index): + let fetchObservable = (index == 0 + ? fetchOngoingEventsUseCase.execute(cursor: nil, pageSize: 20) + : fetchOutdatedEventsUseCase.execute(cursor: nil, pageSize: 20)) + .map { paged -> Mutation in + .setAlarms(paged.items, hasMore: paged.hasMore, reset: true) + } + .catch { error -> Observable in + print("Fetch error: \(error)") + return .just(.setLoading(false)) + } + return .concat([ .just(.setIndex(index)), - .just(.setLoading(true)), (index == 0 ? fetchOngoingEventsUseCase.execute(cursor: nil, pageSize: 20) : fetchOutdatedEventsUseCase.execute(cursor: nil, pageSize: 20)) - .map { paged in - .setAlarms(paged.items, hasMore: paged.hasMore, reset: true) - }, + .just(.setLoading(true)), + fetchObservable, .just(.setLoading(false)) ]) @@ -65,7 +74,7 @@ public final class EventReactor: Reactor { }, .just(.setLoading(false)) ]) - case .itemTapped(let index): + case let .itemTapped(index): return setReadUseCase.execute(alarmLink: currentState.alarms[index].link) .andThen(.empty()) } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift index 1a842c98..3c6984c2 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift @@ -66,7 +66,12 @@ extension EventViewController { self.mainView.detailItemStackView.removeArrangedSubview(subview) subview.removeFromSuperview() } - self.createDetailItem(items: items) + let eventType = reactor.currentState.selectedIndex == 0 ? "진행중인" : "종료된" + if items.isEmpty { + self.mainView.setEmpty(text: "\(eventType) 이벤트가 없습니다.") + } else { + self.createDetailItem(items: items) + } } .disposed(by: disposeBag) } From 5f3801219318f5191767a92db1f8915d64e12170 Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 18:28:25 +0900 Subject: [PATCH 09/31] =?UTF-8?q?fix/#273:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=9D=BD=EC=9D=8C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/AlarmAPIRepositoryImpl.swift | 10 ++-- .../Entity/Alarm/AlarmResponse.swift | 2 +- MLS/MLS/Application/AppDelegate.swift | 4 +- .../Shared}/WebViewController.swift | 8 +-- .../Utills/Extension/String+.swift | 6 ++- .../DictionaryNotificationFactoryImpl.swift | 12 ++++- .../DictionaryNotificationReactor.swift | 49 ++++++++++++------- ...DictionaryNotificationViewController.swift | 9 ++++ 8 files changed, 68 insertions(+), 32 deletions(-) rename MLS/Presentation/{MyPageFeature/MyPageFeature => BaseFeature/BaseFeature/Shared}/WebViewController.swift (72%) diff --git a/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift index fb3d32ac..6e2763d7 100644 --- a/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift @@ -14,31 +14,31 @@ public class AlarmAPIRepositoryImpl: AlarmAPIRepository { } public func fetchPatchNotes(cursor: String?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchPatchNotes(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) + let endpoint = AlarmEndPoint.fetchPatchNotes(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } public func fetchNotices(cursor: String?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchNotices(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) + let endpoint = AlarmEndPoint.fetchNotices(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } public func fetchOutdatedEvents(cursor: String?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchOutdatedEvents(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) + let endpoint = AlarmEndPoint.fetchOutdatedEvents(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } public func fetchOngoingEvents(cursor: String?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchOngoingEvents(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) + let endpoint = AlarmEndPoint.fetchOngoingEvents(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAlarmDomain() } } public func fetchAll(cursor: String?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchAll(query: AlarmQuery(cursor: cursor, pageSize: 999/*pageSize*/)) + let endpoint = AlarmEndPoint.fetchAll(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) .map { $0.toAllAlarmDomain() } } diff --git a/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift b/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift index 952215d0..78b27ee3 100644 --- a/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift @@ -19,7 +19,7 @@ public struct AllAlarmResponse: Equatable { public let title: String public let link: String public let date: String - public let alreadyRead: Bool + public var alreadyRead: Bool public init(type: String, title: String, link: String, date: String, alreadyRead: Bool) { self.type = type diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 4579cf74..7d9cf303 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -914,7 +914,9 @@ private extension AppDelegate { ), fetchProfileUseCase: DIContainer.resolve( type: FetchProfileUseCase.self - ), checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self) + ), checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self), + setReadUseCase: DIContainer.resolve( + type: SetReadUseCase.self) ) } DIContainer.register(type: DictionaryMainViewFactory.self) { diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/WebViewController.swift b/MLS/Presentation/BaseFeature/BaseFeature/Shared/WebViewController.swift similarity index 72% rename from MLS/Presentation/MyPageFeature/MyPageFeature/WebViewController.swift rename to MLS/Presentation/BaseFeature/BaseFeature/Shared/WebViewController.swift index fbfd97f1..6a9dfd4c 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/WebViewController.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/Shared/WebViewController.swift @@ -1,11 +1,11 @@ import UIKit import WebKit -class WebViewController: UIViewController { +public final class WebViewController: UIViewController { private let urlString: String private let webView = WKWebView() - init(urlString: String) { + public init(urlString: String) { self.urlString = urlString super.init(nibName: nil, bundle: nil) } @@ -14,11 +14,11 @@ class WebViewController: UIViewController { fatalError("init(coder:) has not been implemented") } - override func loadView() { + public override func loadView() { self.view = webView } - override func viewDidLoad() { + public override func viewDidLoad() { super.viewDidLoad() if let url = URL(string: urlString) { webView.load(URLRequest(url: url)) diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift index f448d1b5..62240e21 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift @@ -7,8 +7,10 @@ extension String { } public func toDisplayDateString() -> String { - let inputFormatter = ISO8601DateFormatter() - inputFormatter.formatOptions = [.withInternetDateTime] + let inputFormatter = DateFormatter() + inputFormatter.locale = Locale(identifier: "ko_KR") + inputFormatter.timeZone = TimeZone(identifier: "Asia/Seoul") + inputFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" guard let date = inputFormatter.date(from: self) else { return self } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift index 21418ee9..2543eac8 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift @@ -9,16 +9,24 @@ public final class DictionaryNotificationFactoryImpl: DictionaryNotificationFact private let fetchAllAlarmUseCase: FetchAllAlarmUseCase private let fetchProfileUseCase: FetchProfileUseCase private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase + private let setReadUseCase: SetReadUseCase - public init(notificationSettingFactory: NotificationSettingFactory, fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase, checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase) { + public init( + notificationSettingFactory: NotificationSettingFactory, + fetchAllAlarmUseCase: FetchAllAlarmUseCase, + fetchProfileUseCase: FetchProfileUseCase, + checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, + setReadUseCase: SetReadUseCase + ) { self.notificationSettingFactory = notificationSettingFactory self.fetchAllAlarmUseCase = fetchAllAlarmUseCase self.fetchProfileUseCase = fetchProfileUseCase self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase + self.setReadUseCase = setReadUseCase } public func make() -> BaseViewController { - let reactor = DictionaryNotificationReactor(fetchAllAlarmUseCase: fetchAllAlarmUseCase, fetchProfileUseCase: fetchProfileUseCase, checkNotificationPermissionUseCase: checkNotificationPermissionUseCase) + let reactor = DictionaryNotificationReactor(fetchAllAlarmUseCase: fetchAllAlarmUseCase, fetchProfileUseCase: fetchProfileUseCase, checkNotificationPermissionUseCase: checkNotificationPermissionUseCase, setReadUseCase: setReadUseCase) let viewController = DictionaryNotificationViewController(notificationSettingFactory: notificationSettingFactory) viewController.reactor = reactor return viewController diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift index d7bcd124..76bb5b93 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift @@ -8,7 +8,7 @@ public final class DictionaryNotificationReactor: Reactor { case none case dismiss case setting - case notification(String) + case notification(url: String) } public enum Action { @@ -16,7 +16,7 @@ public final class DictionaryNotificationReactor: Reactor { case loadMore case backButtonTapped case settingButtonTapped - case notificationTapped(String) + case notificationTapped(index: Int) } public enum Mutation { @@ -25,6 +25,7 @@ public final class DictionaryNotificationReactor: Reactor { case setProfile(MyPageResponse?) case navigateTo(Route) case setPermission(Bool) + case checkAlarm(link: String) } public struct State { @@ -42,13 +43,15 @@ public final class DictionaryNotificationReactor: Reactor { private let fetchAllAlarmUseCase: FetchAllAlarmUseCase private let fetchProfileUseCase: FetchProfileUseCase private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase + private let setReadUseCase: SetReadUseCase // MARK: - Init - public init(fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase, checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase) { + public init(fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase, checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, setReadUseCase: SetReadUseCase) { self.initialState = State() self.fetchAllAlarmUseCase = fetchAllAlarmUseCase self.fetchProfileUseCase = fetchProfileUseCase self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase + self.setReadUseCase = setReadUseCase } // MARK: - Mutate @@ -57,7 +60,7 @@ public final class DictionaryNotificationReactor: Reactor { case .viewWillAppear: let profileStream: Observable = fetchProfileUseCase.execute() .map { Mutation.setProfile($0) } - + let notificationStream: Observable = Observable.concat([ Observable.just(.setLoading(true)), fetchAllAlarmUseCase.execute(cursor: nil, pageSize: 20) @@ -66,17 +69,17 @@ public final class DictionaryNotificationReactor: Reactor { }, Observable.just(.setLoading(false)) ]) - + let permissionStream: Observable = checkNotificationPermissionUseCase.execute() .asObservable() .map { Mutation.setPermission($0) } - + return Observable.merge(profileStream, notificationStream, permissionStream) - + case .loadMore: guard currentState.hasMore, !currentState.isLoading else { return .empty() } let cursor = currentState.notifications.last?.date - + return Observable.concat([ Observable.just(.setLoading(true)), fetchAllAlarmUseCase.execute(cursor: cursor, pageSize: 20) @@ -85,15 +88,23 @@ public final class DictionaryNotificationReactor: Reactor { }, Observable.just(.setLoading(false)) ]) - + case .backButtonTapped: return .just(.navigateTo(.dismiss)) - + case .settingButtonTapped: return .just(.navigateTo(.setting)) - - case .notificationTapped(let notification): - return .just(.navigateTo(.notification(notification))) + + case let .notificationTapped(index): + let notification = currentState.notifications[index] + + return setReadUseCase.execute(alarmLink: notification.link) + .andThen( + Observable.concat([ + .just(.checkAlarm(link: notification.link)), + .just(.navigateTo(.notification(url: notification.link))) + ]) + ) } } @@ -109,18 +120,22 @@ public final class DictionaryNotificationReactor: Reactor { newState.notifications.append(contentsOf: newItems) } newState.hasMore = hasMore - + case let .setLoading(isLoading): newState.isLoading = isLoading - + case let .setProfile(profile): newState.profile = profile - + case let .navigateTo(route): newState.route = route - + case let .setPermission(granted): newState.permission = granted + case let .checkAlarm(link): + if let index = newState.notifications.firstIndex(where: { $0.link == link }) { + newState.notifications[index].alreadyRead = true + } } return newState diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift index 3efd9631..9161ff32 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift @@ -102,6 +102,7 @@ public extension DictionaryNotificationViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case .dismiss: @@ -111,6 +112,9 @@ public extension DictionaryNotificationViewController { let profile = reactor.currentState.profile else { return } let viewController = owner.notificationSettingFactory.make(isAgreeEventNotification: profile.eventAgreement, isAgreeNoticeNotification: profile.noticeAgreement, isAgreePatchNoteNotification: profile.patchNoteAgreement) owner.navigationController?.pushViewController(viewController, animated: true) + case let .notification(url): + let webViewController = WebViewController(urlString: url) + owner.present(webViewController, animated: true) default: break } @@ -153,6 +157,11 @@ extension DictionaryNotificationViewController: UICollectionViewDelegate, UIColl return cell } + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + guard let reactor = reactor else { return } + reactor.action.onNext(.notificationTapped(index: indexPath.row)) + } + public func scrollViewDidScroll(_ scrollView: UIScrollView) { let now = Date() guard now.timeIntervalSince(lastPagingTime) > 0.5 else { return } From ea1cfd937dcb5b96506ccd416b77fb05644d7563 Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 18:44:25 +0900 Subject: [PATCH 10/31] =?UTF-8?q?fix/#273:=20=EC=97=B0=EC=86=8D=EA=B2=80?= =?UTF-8?q?=EC=83=89=EC=8B=9C=20=EC=B4=88=EC=84=B1=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EB=B6=88=EA=B0=80=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Utills/Extension/String+.swift | 6 ++++-- ...DictionarySearchResultViewController.swift | 21 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift index 62240e21..12d07a00 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift @@ -2,8 +2,10 @@ import Foundation extension String { public func isOnlyKorean() -> Bool { - let initialConsonants = "ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ" - return self.allSatisfy { initialConsonants.contains($0) } + return !self.isEmpty && self.allSatisfy { char in + guard let scalar = char.unicodeScalars.first else { return false } + return !(0xAC00...0xD7A3).contains(scalar.value) + } } public func toDisplayDateString() -> String { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift index 0fba890e..e7ed81b5 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift @@ -44,7 +44,6 @@ public final class DictionarySearchResultViewController: BaseViewController, Vie @MainActor required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - } // MARK: - Life Cycle @@ -54,8 +53,8 @@ public extension DictionarySearchResultViewController { addViews() setupConstraints() configureUI() - } + override func viewDidAppear(_ animated: Bool) { guard !didSetInitialIndex else { return } didSetInitialIndex = true @@ -73,7 +72,7 @@ public extension DictionarySearchResultViewController { } // 새로운 viewControllers 생성 - self.viewControllers = type.pageTabList.map { dictionaryListFactory.make(type: $0, listType: type, keyword: keyword) } + viewControllers = type.pageTabList.map { dictionaryListFactory.make(type: $0, listType: type, keyword: keyword) } // PageViewController에 첫 번째 뷰컨트롤러 설정 if !viewControllers.isEmpty { @@ -99,7 +98,6 @@ public extension DictionarySearchResultViewController { } } } - } // MARK: - SetUp @@ -197,17 +195,23 @@ public extension DictionarySearchResultViewController { .disposed(by: disposeBag) reactor.state - .compactMap { $0.keyword } + .map(\.keyword) + .filter { $0 != nil } + .map { $0! } .distinctUntilChanged() .skip(1) .observe(on: MainScheduler.instance) .bind(with: self) { owner, newKeyword in - owner.updateViewControllers(keyword: newKeyword) + if newKeyword.isOnlyKorean(), newKeyword != "" { + GuideAlertFactory.show(mainText: "초성은 검색할 수 없습니다.", ctaText: "확인", ctaAction: {}) + } else { + owner.updateViewControllers(keyword: newKeyword) + } } .disposed(by: disposeBag) rx.viewWillAppear - .map {_ in Reactor.Action.viewWillAppear } + .map { _ in Reactor.Action.viewWillAppear } .bind(to: reactor.action) .disposed(by: disposeBag) @@ -238,7 +242,8 @@ extension DictionarySearchResultViewController: UIPageViewControllerDataSource, public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { if completed, let visibleViewController = pageViewController.viewControllers?.first, - let newIndex = viewControllers.firstIndex(of: visibleViewController) { + let newIndex = viewControllers.firstIndex(of: visibleViewController) + { currentPageIndex.accept(newIndex) mainView.tabCollectionView.selectItem(at: IndexPath(item: newIndex, section: 0), animated: true, scrollPosition: .centeredHorizontally) underLineController.animateIndicatorToSelectedItem() From ba530dbefc515a0e7177a43ce212eea977675e1e Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 18:47:08 +0900 Subject: [PATCH 11/31] =?UTF-8?q?fix/#273:=20=EC=97=B0=EC=86=8D=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=97=94=ED=84=B0=20=ED=97=88=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DictionarySearchResultViewController.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift index e7ed81b5..4240c53d 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift @@ -1,6 +1,7 @@ import UIKit import BaseFeature +import DesignSystem import DictionaryFeatureInterface import DomainInterface @@ -116,6 +117,9 @@ private extension DictionarySearchResultViewController { } func configureUI() { + mainView.searchBar.searchDelegate = self + mainView.searchBar.textField.becomeFirstResponder() + mainView.pageViewController.delegate = self mainView.pageViewController.dataSource = self configureTabCollectionView() @@ -242,8 +246,7 @@ extension DictionarySearchResultViewController: UIPageViewControllerDataSource, public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { if completed, let visibleViewController = pageViewController.viewControllers?.first, - let newIndex = viewControllers.firstIndex(of: visibleViewController) - { + let newIndex = viewControllers.firstIndex(of: visibleViewController) { currentPageIndex.accept(newIndex) mainView.tabCollectionView.selectItem(at: IndexPath(item: newIndex, section: 0), animated: true, scrollPosition: .centeredHorizontally) underLineController.animateIndicatorToSelectedItem() @@ -289,3 +292,9 @@ extension DictionarySearchResultViewController: UICollectionViewDataSource, UICo underLineController.animateIndicatorToSelectedItem() } } + +extension DictionarySearchResultViewController: SearchBarDelegate { + public func searchBarDidReturn(_ searchBar: SearchBar, text: String) { + reactor?.action.onNext(.searchButtonTapped(text)) + } +} From b4d453384eb0a9374192c4df066beac62af444d7 Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 18:57:45 +0900 Subject: [PATCH 12/31] =?UTF-8?q?fix/#273:=20=EC=97=B0=EC=86=8D=EA=B2=80?= =?UTF-8?q?=EC=83=89=EC=8B=9C=20=EC=B5=9C=EA=B7=BC=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=EC=96=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RecentSearch/RecentSearchAddUseCaseImpl.swift | 2 +- MLS/MLS/Application/AppDelegate.swift | 3 ++- .../DictionaryNotificationReactor.swift | 8 ++++---- .../DictionarySearch/DictionarySearchViewController.swift | 1 - .../DictionarySearchResultFactoryImpl.swift | 7 +++++-- .../DictionarySearchResultReactor.swift | 8 +++++--- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchAddUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchAddUseCaseImpl.swift index a56d8544..929ec5f6 100644 --- a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchAddUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchAddUseCaseImpl.swift @@ -11,7 +11,7 @@ public class RecentSearchAddUseCaseImpl: RecentSearchAddUseCase { } public func add(keyword: String) -> Completable { + guard !keyword.isEmpty else { return .empty() } return repository.addRecentSearch(keyword: keyword) } - } diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 7d9cf303..faf03bfb 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -875,7 +875,8 @@ private extension AppDelegate { .resolve(type: DictionaryMainListFactory.self), dictionarySearchListUseCase: DIContainer.resolve( type: FetchDictionarySearchListUseCase.self - ) + ), recentSearchAddUseCase: DIContainer.resolve( + type: RecentSearchAddUseCase.self) ) } DIContainer.register(type: DictionarySearchFactory.self) { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift index 76bb5b93..6e5df32f 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift @@ -120,16 +120,16 @@ public final class DictionaryNotificationReactor: Reactor { newState.notifications.append(contentsOf: newItems) } newState.hasMore = hasMore - + case let .setLoading(isLoading): newState.isLoading = isLoading - + case let .setProfile(profile): newState.profile = profile - + case let .navigateTo(route): newState.route = route - + case let .setPermission(granted): newState.permission = granted case let .checkAlarm(link): diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift index 49dbaf8f..a66f62ad 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift @@ -117,7 +117,6 @@ extension DictionarySearchViewController { func bindUserActions(reactor: Reactor) { rx.viewWillAppear - .take(1) .map { Reactor.Action.viewWillAppear } .bind(to: reactor.action) .disposed(by: disposeBag) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultFactoryImpl.swift index 5ebe6e86..eb07655e 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultFactoryImpl.swift @@ -6,14 +6,17 @@ public final class DictionarySearchResultFactoryImpl: DictionarySearchResultFact private let dictionaryListCountUseCase: FetchDictionaryListCountUseCase private let dictionaryMainListFactory: DictionaryMainListFactory private let dictionarySearchListUseCase: FetchDictionarySearchListUseCase - public init(dictionaryListCountUseCase: FetchDictionaryListCountUseCase, dictionaryMainListFactory: DictionaryMainListFactory, dictionarySearchListUseCase: FetchDictionarySearchListUseCase) { + private let recentSearchAddUseCase: RecentSearchAddUseCase + + public init(dictionaryListCountUseCase: FetchDictionaryListCountUseCase, dictionaryMainListFactory: DictionaryMainListFactory, dictionarySearchListUseCase: FetchDictionarySearchListUseCase, recentSearchAddUseCase: RecentSearchAddUseCase) { self.dictionaryListCountUseCase = dictionaryListCountUseCase self.dictionaryMainListFactory = dictionaryMainListFactory self.dictionarySearchListUseCase = dictionarySearchListUseCase + self.recentSearchAddUseCase = recentSearchAddUseCase } public func make(keyword: String?) -> BaseViewController { - let reactor = DictionarySearchResultReactor(keyword: keyword, dictionarySearchUseCase: dictionarySearchListUseCase, dictionarySearchCountUseCase: dictionaryListCountUseCase) + let reactor = DictionarySearchResultReactor(keyword: keyword, dictionarySearchUseCase: dictionarySearchListUseCase, dictionarySearchCountUseCase: dictionaryListCountUseCase, recentSearchAddUseCase: recentSearchAddUseCase) let viewController = DictionarySearchResultViewController(dictionaryListFactory: dictionaryMainListFactory, reactor: reactor) return viewController } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultReactor.swift index 6e3dc4a0..70019158 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultReactor.swift @@ -41,12 +41,14 @@ public final class DictionarySearchResultReactor: Reactor { // MARK: - UseCases private let dictionarySearchUseCase: FetchDictionarySearchListUseCase private let dictionarySearchCountUseCase: FetchDictionaryListCountUseCase + private let recentSearchAddUseCase: RecentSearchAddUseCase // MARK: - init - public init(keyword: String?, dictionarySearchUseCase: FetchDictionarySearchListUseCase, dictionarySearchCountUseCase: FetchDictionaryListCountUseCase) { + public init(keyword: String?, dictionarySearchUseCase: FetchDictionarySearchListUseCase, dictionarySearchCountUseCase: FetchDictionaryListCountUseCase, recentSearchAddUseCase: RecentSearchAddUseCase) { self.initialState = State(keyword: keyword) self.dictionarySearchUseCase = dictionarySearchUseCase self.dictionarySearchCountUseCase = dictionarySearchCountUseCase + self.recentSearchAddUseCase = recentSearchAddUseCase } // MARK: - Reactor Methods @@ -67,8 +69,8 @@ public final class DictionarySearchResultReactor: Reactor { // 검색 결과 화면에서 재검색 시 case .searchButtonTapped(let keyword): let keyword = keyword ?? "" - - return Observable.just(.setKeyword(keyword)) + return recentSearchAddUseCase.add(keyword: keyword) + .andThen(.just(.setKeyword(keyword))) } } From ef93d2ba6d28f5f867d546f094bdaba8598ff38c Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 22:23:16 +0900 Subject: [PATCH 13/31] =?UTF-8?q?fix/#273:=20=EC=95=A0=ED=94=8C=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift index 5d416e14..6a1ed88a 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift @@ -25,7 +25,7 @@ public final class SignUpWithAppleUseCaseImpl: SignUpWithAppleUseCase { fcmToken: String? ) -> Observable { return authRepository - .signUpWithKakao(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) + .signUpWithApple(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) .flatMap { response -> Observable in let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) From bf4886ee705414434fa127b60f2be2ea4527037e Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 22:52:49 +0900 Subject: [PATCH 14/31] =?UTF-8?q?fix/#273:=20=EB=B6=81=EB=A8=80=ED=81=AC?= =?UTF-8?q?=ED=83=AD=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BookmarkMain/BookmarkMainViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainViewController.swift index 8c36fc05..d1fd9e50 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainViewController.swift @@ -187,7 +187,7 @@ public extension BookmarkMainViewController { .observe(on: MainScheduler.instance) .bind { owner, isLogin in owner.mainView.updateLoginState(isLogin: isLogin) - owner.underLineController.setHidden(hidden: true) + owner.underLineController.setHidden(hidden: !isLogin) } .disposed(by: disposeBag) From 9f686a81aaf90354444bc945783fda43ee3a8172 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 14 Dec 2025 14:10:51 +0000 Subject: [PATCH 15/31] style/#273: Apply SwiftLint autocorrect --- .../AuthAPI/SignUpWithKakaoUseCaseImpl.swift | 2 +- .../Login/LoginViewController.swift | 4 ++-- .../DictionaryList/DictionaryListReactor.swift | 2 +- .../DictionaryNotificationReactor.swift | 18 +++++++++--------- .../DictionarySearchResultViewController.swift | 2 +- .../CustomerSupportBaseView.swift | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift index 0584d346..7316776b 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift @@ -1,5 +1,5 @@ -import Foundation import DomainInterface +import Foundation import RxSwift public final class SignUpWithKakaoUseCaseImpl: SignUpWithKakaoUseCase { diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift index 3bbfca74..0fc4c2ba 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift @@ -58,7 +58,7 @@ private extension LoginViewController { func configureUI() { view.backgroundColor = .systemBackground - + if let navigationController = navigationController, navigationController.viewControllers.count > 1 { mainView.header.leftButton.isHidden = false @@ -122,7 +122,7 @@ public extension LoginViewController { .map { Reactor.Action.guestLoginButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) - + mainView.header.leftButton.rx.tap .map { Reactor.Action.backButtonTapped } .bind(to: reactor.action) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift index e8838d0f..6b76dc3b 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift @@ -281,7 +281,7 @@ private extension DictionaryListReactor { let fetchMutation: Observable if currentState.isFirstFetch { - let _ = Mutation.setFirstFetch(false) + _ = Mutation.setFirstFetch(false) fetchMutation = fetchList( sort: currentState.sort, startLevel: currentState.startLevel, diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift index 6e5df32f..305f8bf7 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift @@ -60,7 +60,7 @@ public final class DictionaryNotificationReactor: Reactor { case .viewWillAppear: let profileStream: Observable = fetchProfileUseCase.execute() .map { Mutation.setProfile($0) } - + let notificationStream: Observable = Observable.concat([ Observable.just(.setLoading(true)), fetchAllAlarmUseCase.execute(cursor: nil, pageSize: 20) @@ -69,17 +69,17 @@ public final class DictionaryNotificationReactor: Reactor { }, Observable.just(.setLoading(false)) ]) - + let permissionStream: Observable = checkNotificationPermissionUseCase.execute() .asObservable() .map { Mutation.setPermission($0) } - + return Observable.merge(profileStream, notificationStream, permissionStream) - + case .loadMore: guard currentState.hasMore, !currentState.isLoading else { return .empty() } let cursor = currentState.notifications.last?.date - + return Observable.concat([ Observable.just(.setLoading(true)), fetchAllAlarmUseCase.execute(cursor: cursor, pageSize: 20) @@ -88,16 +88,16 @@ public final class DictionaryNotificationReactor: Reactor { }, Observable.just(.setLoading(false)) ]) - + case .backButtonTapped: return .just(.navigateTo(.dismiss)) - + case .settingButtonTapped: return .just(.navigateTo(.setting)) - + case let .notificationTapped(index): let notification = currentState.notifications[index] - + return setReadUseCase.execute(alarmLink: notification.link) .andThen( Observable.concat([ diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift index 4240c53d..ba48b686 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift @@ -119,7 +119,7 @@ private extension DictionarySearchResultViewController { func configureUI() { mainView.searchBar.searchDelegate = self mainView.searchBar.textField.becomeFirstResponder() - + mainView.pageViewController.delegate = self mainView.pageViewController.dataSource = self configureTabCollectionView() diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift index e212614d..9ba80e06 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift @@ -267,7 +267,7 @@ extension CustomerSupportBaseView { menuContainerView.isHidden = hidden } - func setEmpty (text: String) { + func setEmpty(text: String) { let label = UILabel() label.attributedText = .makeStyledString(font: .b_m_r, text: text, color: .neutral700, alignment: .left) let view = UIView() From 5433f4b6ee13347f9c438bcf42fe5f2d8186849c Mon Sep 17 00:00:00 2001 From: p2glet Date: Sun, 14 Dec 2025 23:33:09 +0900 Subject: [PATCH 16/31] =?UTF-8?q?fix/#273:=20=ED=82=A4=EB=B3=B4=EB=93=9C?= =?UTF-8?q?=20=EC=95=A1=EC=84=B8=EC=84=9C=EB=A6=AC=EB=B7=B0=20->=20?= =?UTF-8?q?=EB=8B=89=EB=84=A4=EC=9E=84=20=EC=88=98=EC=A0=95=20=EC=95=A1?= =?UTF-8?q?=EC=84=B8=EC=84=9C=EB=A6=AC=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyPageFeature/SetProfile/SetProfileView.swift | 7 ++++--- .../SetProfile/SetProfileViewController.swift | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileView.swift index 95503d80..07655712 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileView.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileView.swift @@ -248,9 +248,9 @@ public final class SetProfileView: UIView { fatalError("init(coder:) has not been implemented") } - public override var inputAccessoryView: UIView? { - return errorMessageContentView - } +// public override var inputAccessoryView: UIView? { +// return errorMessageContentView +// } public override var canBecomeFirstResponder: Bool { return true @@ -316,6 +316,7 @@ private extension SetProfileView { func configureUI() { backgroundColor = .whiteMLS cancelTextView.delegate = self + nickNameInputBox.textField.inputAccessoryView = errorMessageContentView } func bindImageGesture() { diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileViewController.swift index 5edac989..fd8264d2 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileViewController.swift @@ -138,6 +138,7 @@ extension SetProfileViewController { .bind(onNext: { owner, profile in owner.mainView.setImage(imageUrl: profile.profileUrl) owner.mainView.setPlatform(platform: profile.platform) + owner.mainView.nickNameInputBox.textField.text = profile.nickname }) .disposed(by: disposeBag) From d13984fe159710b8db11931a14378b02cef54eaa Mon Sep 17 00:00:00 2001 From: p2glet Date: Mon, 15 Dec 2025 01:58:49 +0900 Subject: [PATCH 17/31] =?UTF-8?q?fix/#273:=20=EB=B6=81=EB=A7=88=ED=81=AC?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EC=88=98=EC=A0=95=20=ED=95=84=EC=9A=94?= =?UTF-8?q?=20+=20=EB=B6=81=EB=A7=88=ED=81=AC=20/=20=EB=8F=84=EA=B0=90=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=8F=99=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MLS/.swiftlint.yml | 4 +- .../BookmarkListViewController.swift | 45 +++++- .../CollectionDetailViewController.swift | 10 +- .../DictionaryDetailBaseView.swift | 1 + .../DictionaryDetailBaseViewController.swift | 136 ++++++++++++++---- .../DictionaryDetailFactoryImpl.swift | 22 ++- .../ItemDictionaryDetailViewController.swift | 4 +- .../MapDictionaryDetailViewController.swift | 4 +- ...onsterDictionaryDetailViewController.swift | 4 +- .../NpcDictionaryDetailViewController.swift | 4 +- .../QuestDictionaryDetailViewController.swift | 4 +- .../DictionaryListReactor.swift | 26 +--- .../DictionaryListViewController.swift | 100 ++++++++----- ...DictionarySearchResultViewController.swift | 3 +- .../DictionaryDetailFactory.swift | 2 +- 15 files changed, 265 insertions(+), 104 deletions(-) diff --git a/MLS/.swiftlint.yml b/MLS/.swiftlint.yml index 6fa49957..16cb8d52 100644 --- a/MLS/.swiftlint.yml +++ b/MLS/.swiftlint.yml @@ -7,8 +7,8 @@ line_length: error: 300 function_body_length: - warning: 80 - error: 120 + warning: 100 + error: 150 disabled_rules: - force_cast diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift index d0ec0e6c..f8d9cef3 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift @@ -15,6 +15,10 @@ public final class BookmarkListViewController: BaseViewController, View { // MARK: - Properties public var disposeBag = DisposeBag() + + private let bookmarkChangeRelay = PublishRelay<(Int, Bool)>() + private var undoRelay = PublishRelay() + private var addCollectionRelay = PublishRelay() private let itemFilterFactory: ItemFilterBottomSheetFactory private let monsterFilterFactory: MonsterFilterBottomSheetFactory @@ -180,7 +184,7 @@ extension BookmarkListViewController { break } case .detail(let type, let id): - let viewcontroller = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: nil) + let viewcontroller = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkChangeRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) owner.navigationController?.pushViewController(viewcontroller, animated: true) case .login: let viewcontroller = owner.loginFactory.make(exitRoute: .pop) @@ -209,6 +213,45 @@ extension BookmarkListViewController { owner.mainView.updateFilter(sortType: type.bookmarkSortedFilter.first) }) .disposed(by: disposeBag) + + bookmarkChangeRelay + .withUnretained(self) + .observe(on: MainScheduler.instance) + .bind(onNext: { owner, bookmarkData in + let (id, isBookmarked) = bookmarkData + owner.reactor?.action.onNext(.toggleBookmark(id, isBookmarked)) + }) + .disposed(by: disposeBag) + + undoRelay + .withUnretained(self) + .subscribe(onNext: { owner, _ in + owner.reactor?.action.onNext(.undoLastDeletedBookmark) + }) + .disposed(by: disposeBag) + + addCollectionRelay + .withUnretained(self) + .subscribe(onNext: { owner, originId in + let items = reactor.currentState.items + guard let index = items.firstIndex(where: { $0.originalId == originId }) else { return } + let bookmarkId = items[index].bookmarkId + let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in + if isAdd { + ToastFactory.createToast( + message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." + ) + } + } + vc.modalPresentationStyle = .pageSheet + if let sheet = vc.sheetPresentationController { + sheet.detents = [.medium(), .large()] + sheet.prefersGrabberVisible = true + sheet.preferredCornerRadius = 16 + } + owner.present(vc, animated: true) + }) + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift index e7b7b81b..0c2211d9 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift @@ -16,6 +16,8 @@ public final class CollectionDetailViewController: BaseViewController, View { // MARK: - Properties public var disposeBag = DisposeBag() + private var undoRelay = PublishRelay() + private let bookmarkModalFactory: BookmarkModalFactory private let collectionSettingFactory: CollectionSettingFactory private let addCollectionFactory: AddCollectionFactory @@ -197,13 +199,19 @@ extension CollectionDetailViewController { }) owner.presentModal(viewController) case .detail(let type, let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: nil) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: nil, undoRelay: self.undoRelay, addCollectionRelay: nil) owner.navigationController?.pushViewController(viewController, animated: true) default: break } } .disposed(by: disposeBag) + + undoRelay + .subscribe(onNext: { [weak self] _ in + self?.reactor?.action.onNext(.undoLastDeletedBookmark) + }) + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseView.swift index 2336b3c8..eb3e4c90 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseView.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseView.swift @@ -482,6 +482,7 @@ extension DictionaryDetailBaseView { } func setBookmark(isBookmarked: Bool) { + bookmarkButton.isSelected = isBookmarked bookmarkButton.setImage(DesignSystemAsset.image(named: isBookmarked ? "bookmark" : "bookmarkGrayBorder"), for: .normal) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index 8e109d4f..b9ed39bf 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -17,6 +17,8 @@ class DictionaryDetailBaseViewController: BaseViewController { private var didSelectInitialTab = false var selectedIndex = 0 var bookmarkRelay: PublishRelay<(Int, Bool)>? + var undoRelay: PublishRelay? + var addCollectionRelay: PublishRelay? /// 각 탭에 해당하는 콘텐츠 뷰들을 담는 배열 public var contentViews: [UIView] = [] { @@ -52,7 +54,9 @@ class DictionaryDetailBaseViewController: BaseViewController { detailOnBoardingFactory: DetailOnBoardingFactory, appCoordinator: AppCoordinatorProtocol, fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase, - bookmarkRelay: PublishRelay<(Int, Bool)>? + bookmarkRelay: PublishRelay<(Int, Bool)>?, + undoRelay: PublishRelay?, + addCollectionRelay: PublishRelay? ) { self.type = type self.bookmarkModalFactory = bookmarkModalFactory @@ -63,6 +67,8 @@ class DictionaryDetailBaseViewController: BaseViewController { self.fetchVisitDictionaryDetailUseCase = fetchVisitDictionaryDetailUseCase mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) self.bookmarkRelay = bookmarkRelay + self.undoRelay = undoRelay + self.addCollectionRelay = addCollectionRelay super.init() } @@ -265,6 +271,88 @@ extension DictionaryDetailBaseViewController { currentTabIndex = index } +// func bindBookmarkButton( +// buttonTap: ControlEvent, +// currentItem: Observable, +// isLogin: @escaping () -> Bool, +// id: @escaping (T) -> Int, +// imageUrl: @escaping (T) -> String?, +// backgroundColor: UIColor, +// isBookmarked: @escaping (T) -> Bool, +// undoLastDeleted: @escaping () -> Void, +// bookmarkId: Observable +// ) -> Disposable { +// buttonTap +// .withLatestFrom(Observable.combineLatest(currentItem, bookmarkId)) +// .observe(on: MainScheduler.instance) +// .bind { [weak self] item, bookmarkId in +// guard let self else { return } +// guard isLogin() else { +// GuideAlertFactory.show( +// mainText: "북마크를 하려면 로그인이 필요해요.", +// ctaText: "로그인 하기", +// cancelText: "취소", +// ctaAction: { +// let viewController = self.loginFactory.make(exitRoute: .pop) +// self.navigationController?.pushViewController(viewController, animated: true) +// }, +// cancelAction: nil +// ) +// return +// } +// +// let itemId = id(item) +// +// if isBookmarked(item) { +// mainView.setBookmark(isBookmarked: false) +// self.bookmarkRelay?.accept((itemId, true)) +// SnackBarFactory.createSnackBar( +// type: .delete, +// imageUrl: imageUrl(item), +// imageBackgroundColor: backgroundColor, +// text: "아이템을 북마크에서 삭제했어요.", +// buttonText: "되돌리기", +// buttonAction: { [weak self] in +// self?.mainView.setBookmark(isBookmarked: true) +// undoLastDeleted() +// } +// ) +// } else { +// mainView.setBookmark(isBookmarked: true) +// self.bookmarkRelay?.accept((itemId, false)) +// SnackBarFactory.createSnackBar( +// type: .normal, +// imageUrl: imageUrl(item), +// imageBackgroundColor: backgroundColor, +// text: "아이템을 북마크에 추가했어요.", +// buttonText: "컬렉션 추가", +// buttonAction: { [weak self] in +// guard let self, +// let id = bookmarkId else { return } +// let viewController = self.bookmarkModalFactory.make(bookmarkIds: [id], onComplete: { isAdd in +// if isAdd { +// DispatchQueue.main.async { +// ToastFactory.createToast( +// message: +// "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." +// ) +// } +// } +// }) +// +// viewController.modalPresentationStyle = .pageSheet +// if let sheet = viewController.sheetPresentationController { +// sheet.detents = [.medium(), .large()] +// sheet.prefersGrabberVisible = true +// sheet.preferredCornerRadius = 16 +// } +// self.present(viewController, animated: true) +// } +// ) +// } +// } +// } + func bindBookmarkButton( buttonTap: ControlEvent, currentItem: Observable, @@ -273,7 +361,7 @@ extension DictionaryDetailBaseViewController { imageUrl: @escaping (T) -> String?, backgroundColor: UIColor, isBookmarked: @escaping (T) -> Bool, - undoLastDeleted: @escaping () -> Void, +// undoLastDeleted: @escaping () -> Void, bookmarkId: Observable ) -> Disposable { buttonTap @@ -287,8 +375,8 @@ extension DictionaryDetailBaseViewController { ctaText: "로그인 하기", cancelText: "취소", ctaAction: { - let viewController = self.loginFactory.make(exitRoute: .pop) - self.navigationController?.pushViewController(viewController, animated: true) + let vc = self.loginFactory.make(exitRoute: .pop) + self.navigationController?.pushViewController(vc, animated: true) }, cancelAction: nil ) @@ -297,7 +385,10 @@ extension DictionaryDetailBaseViewController { let itemId = id(item) - if isBookmarked(item) { + let currentlyBookmarked = self.mainView.bookmarkButton.isSelected + + if currentlyBookmarked { + // 🔹 북마크 해제 mainView.setBookmark(isBookmarked: false) self.bookmarkRelay?.accept((itemId, true)) SnackBarFactory.createSnackBar( @@ -306,7 +397,10 @@ extension DictionaryDetailBaseViewController { imageBackgroundColor: backgroundColor, text: "아이템을 북마크에서 삭제했어요.", buttonText: "되돌리기", - buttonAction: { undoLastDeleted() } + buttonAction: { + self.mainView.setBookmark(isBookmarked: true) + self.undoRelay?.accept(itemId) + } ) } else { mainView.setBookmark(isBookmarked: true) @@ -316,29 +410,13 @@ extension DictionaryDetailBaseViewController { imageUrl: imageUrl(item), imageBackgroundColor: backgroundColor, text: "아이템을 북마크에 추가했어요.", - buttonText: "컬렉션 추가", - buttonAction: { [weak self] in - guard let self, - let id = bookmarkId else { return } - let viewController = self.bookmarkModalFactory.make(bookmarkIds: [id], onComplete: { isAdd in - if isAdd { - DispatchQueue.main.async { - ToastFactory.createToast( - message: - "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." - ) - } - } - }) - - viewController.modalPresentationStyle = .pageSheet - if let sheet = viewController.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 - } - self.present(viewController, animated: true) - } + buttonText: "", + buttonAction: {} + // 임시 비활성화 +// buttonText: "컬렉션 추가", +// buttonAction: { +// self.addCollectionRelay?.accept(itemId) +// } ) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift index f07eeb2e..d8428c8d 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift @@ -77,7 +77,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { self.fetchVisitDictionaryDetailUseCase = fetchVisitDictionaryDetailUseCase } - public func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(Int, Bool)>?) -> BaseViewController { + public func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(Int, Bool)>?, undoRelay: PublishRelay?, addCollectionRelay: PublishRelay?) -> BaseViewController { var viewController = BaseViewController() switch type { case .total: @@ -92,7 +92,9 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { dictionaryDetailFactory: dictionaryDetailFactory(), detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay + bookmarkRelay: bookmarkRelay, + undoRelay: undoRelay, + addCollectionRelay: addCollectionRelay ) let reactor = ItemDictionaryDetailReactor( dictionaryDetailItemUseCase: dictionaryDetailItemUseCase, @@ -112,7 +114,9 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { dictionaryDetailFactory: dictionaryDetailFactory(), detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay + bookmarkRelay: bookmarkRelay, + undoRelay: undoRelay, + addCollectionRelay: addCollectionRelay ) let reactor = MonsterDictionaryDetailReactor( dictionaryDetailMonsterUseCase: dictionaryDetailMonsterUseCase, @@ -133,7 +137,9 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { dictionaryDetailFactory: dictionaryDetailFactory(), detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay + bookmarkRelay: bookmarkRelay, + undoRelay: undoRelay, + addCollectionRelay: addCollectionRelay ) let reactor = MapDictionaryDetailReactor( dictionaryDetailMapUseCase: dictionaryDetailMapUseCase, @@ -154,7 +160,9 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { dictionaryDetailFactory: dictionaryDetailFactory(), detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay + bookmarkRelay: bookmarkRelay, + undoRelay: undoRelay, + addCollectionRelay: addCollectionRelay ) let reactor = NpcDictionaryDetailReactor( dictionaryDetailNpcUseCase: dictionaryDetailNpcUseCase, @@ -175,7 +183,9 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { dictionaryDetailFactory: dictionaryDetailFactory(), detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay + bookmarkRelay: bookmarkRelay, + undoRelay: undoRelay, + addCollectionRelay: addCollectionRelay ) let reactor = QuestDictionaryDetailReactor( dictionaryDetailQuestUseCase: dictionaryDetailQuestUseCase, diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index b5ce7b66..129387b0 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -222,7 +222,7 @@ extension ItemDictionaryDetailViewController { case .none: break case .detail(let id): - let viewController = owner.dictionaryDetailFactory.make(type: .monster, id: id, bookmarkRelay: self.bookmarkRelay) + let viewController = owner.dictionaryDetailFactory.make(type: .monster, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) owner.navigationController?.pushViewController(viewController, animated: true) } } @@ -236,7 +236,7 @@ extension ItemDictionaryDetailViewController { imageUrl: { $0.imgUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, +// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.itemDetailInfo.bookmarkId) ) .disposed(by: disposeBag) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index c7a3ee4b..3028e8e0 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -179,7 +179,7 @@ extension MapDictionaryDetailViewController { imageUrl: { $0.mapUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, +// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.mapDetailInfo.bookmarkId) ) .disposed(by: disposeBag) @@ -201,7 +201,7 @@ extension MapDictionaryDetailViewController { case .none: break case .detail(let type, let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: self.bookmarkRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) owner.navigationController?.pushViewController(viewController, animated: true) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift index 314651a7..285c4d6e 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift @@ -206,7 +206,7 @@ extension MonsterDictionaryDetailViewController { } owner.tabBarController?.presentModal(viewController, hideTabBar: true) case let .detail(type: type, id: id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: self.bookmarkRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) owner.navigationController?.pushViewController(viewController, animated: true) default: break @@ -222,7 +222,7 @@ extension MonsterDictionaryDetailViewController { imageUrl: { $0.imageUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, +// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.monsterDetailInfo.bookmarkId) ) .disposed(by: disposeBag) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift index d317149c..7bb4ea10 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift @@ -127,7 +127,7 @@ extension NpcDictionaryDetailViewController { } owner.tabBarController?.presentModal(viewController, hideTabBar: true) case .detail(type: let type, id: let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: self.bookmarkRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) owner.navigationController?.pushViewController(viewController, animated: true) default: break @@ -171,7 +171,7 @@ extension NpcDictionaryDetailViewController { imageUrl: { $0.iconUrlDetail }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, +// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.npcDetailInfo.bookmarkId) ) .disposed(by: disposeBag) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift index 9e641bcf..99f1af1b 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift @@ -186,7 +186,7 @@ extension QuestDictionaryDetailViewController { imageUrl: { $0.iconUrl }, backgroundColor: type.backgroundColor, isBookmarked: { $0.bookmarkId != nil }, - undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, +// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, bookmarkId: reactor.state.map(\.detailInfo.bookmarkId) ) .disposed(by: disposeBag) @@ -198,7 +198,7 @@ extension QuestDictionaryDetailViewController { .subscribe { owner, route in switch route { case let .detail(type, id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: self.bookmarkRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) owner.navigationController?.pushViewController(viewController, animated: true) default: break diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift index e8838d0f..3de66343 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift @@ -5,7 +5,6 @@ import ReactorKit import RxSwift public final class DictionaryListReactor: Reactor { - // MARK: - Route public enum Route { case none @@ -184,7 +183,7 @@ public final class DictionaryListReactor: Reactor { newState.listItems[index].bookmarkId = isSelected ? (newState.listItems[index].bookmarkId ?? -1) : nil } case let .updateBookmarkStates(dict): - for index in 0.. Observable { let response: Observable @@ -256,22 +254,7 @@ private extension DictionaryListReactor { return .empty() } - return response.map { response in - if updateBookmarkOnly { - let merged = self.currentState.listItems.map { item in - if let updated = response.contents.first(where: { $0.id == item.id }) { - var copy = item - copy.bookmarkId = updated.bookmarkId ?? item.bookmarkId - return copy - } else { return item } - } - var newResponse = response - newResponse.contents = merged - return .setListItem(newResponse, updateBookmarkOnly: true) - } else { - return .setListItem(response) - } - } + return response.map { .setListItem($0, updateBookmarkOnly: updateBookmarkOnly) } } func handleViewWillAppear() -> Observable { @@ -281,12 +264,13 @@ private extension DictionaryListReactor { let fetchMutation: Observable if currentState.isFirstFetch { - let _ = Mutation.setFirstFetch(false) - fetchMutation = fetchList( + let firstFetch = Observable.just(Mutation.setFirstFetch(false)) + let fetch = fetchList( sort: currentState.sort, startLevel: currentState.startLevel, endLevel: currentState.endLevel ) + fetchMutation = .concat([firstFetch, fetch]) } else { fetchMutation = fetchList( sort: currentState.sort, diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index b83227c7..ca82050f 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -24,6 +24,8 @@ public final class DictionaryListViewController: BaseViewController, View { private var selectedSortIndex = 0 public let itemCountRelay = PublishRelay() private let bookmarkChangeRelay = PublishRelay<(Int, Bool)>() + private var undoRelay = PublishRelay() + private var addCollectionRelay = PublishRelay() private var lastPagingTime: Date = .distantPast // MARK: - Components @@ -185,14 +187,45 @@ extension DictionaryListViewController { .disposed(by: disposeBag) bookmarkChangeRelay + .withUnretained(self) .observe(on: MainScheduler.instance) - .bind(onNext: { [weak self] id, isBookmarked in - self?.reactor?.action.onNext(.toggleBookmark(id: id, isSelected: isBookmarked)) + .bind(onNext: { owner, bookmarkData in + let (id, isBookmarked) = bookmarkData + owner.reactor?.action.onNext(.toggleBookmark(id: id, isSelected: isBookmarked)) + }) + .disposed(by: disposeBag) + + undoRelay + .withUnretained(self) + .subscribe(onNext: { owner, _ in + owner.reactor?.action.onNext(.undoLastDeletedBookmark) + }) + .disposed(by: disposeBag) + + addCollectionRelay + .withUnretained(self) + .subscribe(onNext: { owner, originId in + let items = reactor.currentState.listItems + guard let index = items.firstIndex(where: { $0.id == originId }), + let bookmarkId = items[index].bookmarkId else { return } + let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in + if isAdd { + ToastFactory.createToast( + message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." + ) + } + } + vc.modalPresentationStyle = .pageSheet + if let sheet = vc.sheetPresentationController { + sheet.detents = [.medium(), .large()] + sheet.prefersGrabberVisible = true + sheet.preferredCornerRadius = 16 + } + owner.present(vc, animated: true) }) .disposed(by: disposeBag) reactor.state.map(\.listItems) - .observe(on: MainScheduler.instance) .withUnretained(self) .observe(on: MainScheduler.instance) .bind { owner, items in @@ -217,7 +250,7 @@ extension DictionaryListViewController { indexPath.item < items.count, let cell = cell as? DictionaryListCell { let item = items[indexPath.item] - cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil && item.bookmarkId != -1) + cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) } } } @@ -287,32 +320,35 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi imageUrl: item.imageUrl, imageBackgroundColor: item.type.backgroundColor, text: "아이템을 북마크에 추가했어요.", - buttonText: "컬렉션 추가", - buttonAction: { - self.reactor?.state.map(\.listItems) - .compactMap { list in - list.first(where: { $0.id == item.id })?.bookmarkId - } - .take(1) - .observe(on: MainScheduler.instance) - .subscribe(onNext: { bookmarkId in - let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in - if isAdd { - ToastFactory.createToast( - message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." - ) - } - } - vc.modalPresentationStyle = .pageSheet - if let sheet = vc.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 - } - self.present(vc, animated: true) - }) - .disposed(by: self.disposeBag) - } + buttonText: "", + buttonAction: {} + // 임시 비활성화 +// buttonText: "컬렉션 추가", +// buttonAction: { +// self.reactor?.state.map(\.listItems) +// .compactMap { list in +// list.first(where: { $0.id == item.id })?.bookmarkId +// } +// .take(1) +// .observe(on: MainScheduler.instance) +// .subscribe(onNext: { bookmarkId in +// let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in +// if isAdd { +// ToastFactory.createToast( +// message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." +// ) +// } +// } +// vc.modalPresentationStyle = .pageSheet +// if let sheet = vc.sheetPresentationController { +// sheet.detents = [.medium(), .large()] +// sheet.prefersGrabberVisible = true +// sheet.preferredCornerRadius = 16 +// } +// self.present(vc, animated: true) +// }) +// .disposed(by: self.disposeBag) +// } ) } } @@ -331,11 +367,11 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi switch reactor.currentState.type { case .total: guard let type = item.type.toDictionaryType else { return } - viewController = detailFactory.make(type: type, id: item.id, bookmarkRelay: bookmarkChangeRelay) + viewController = detailFactory.make(type: type, id: item.id, bookmarkRelay: bookmarkChangeRelay, undoRelay: undoRelay, addCollectionRelay: addCollectionRelay) default: // 단일 타입일 경우 리액터 타입에 따라 처리 viewController = detailFactory.make( - type: reactor.currentState.type, id: item.id, bookmarkRelay: bookmarkChangeRelay + type: reactor.currentState.type, id: item.id, bookmarkRelay: bookmarkChangeRelay, undoRelay: undoRelay, addCollectionRelay: addCollectionRelay ) } navigationController?.pushViewController(viewController, animated: true) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift index 4240c53d..d04818a4 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift @@ -119,11 +119,12 @@ private extension DictionarySearchResultViewController { func configureUI() { mainView.searchBar.searchDelegate = self mainView.searchBar.textField.becomeFirstResponder() - + mainView.pageViewController.delegate = self mainView.pageViewController.dataSource = self configureTabCollectionView() isBottomTabbarHidden = true + mainView.searchBar.textField.resignFirstResponder() } func configureTabCollectionView() { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift index 4844a946..fb654c37 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift @@ -4,5 +4,5 @@ import DomainInterface import RxCocoa public protocol DictionaryDetailFactory { - func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(Int, Bool)>?) -> BaseViewController + func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(Int, Bool)>?, undoRelay: PublishRelay?, addCollectionRelay: PublishRelay?) -> BaseViewController } From 1553e604869332fc302472d1f6a3cb1e3e396f0e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 14 Dec 2025 17:02:30 +0000 Subject: [PATCH 18/31] style/#273: Apply SwiftLint autocorrect --- .../BookmarkList/BookmarkListViewController.swift | 2 +- .../DictionaryDetail/DictionaryDetailBaseViewController.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift index f8d9cef3..41116200 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift @@ -15,7 +15,7 @@ public final class BookmarkListViewController: BaseViewController, View { // MARK: - Properties public var disposeBag = DisposeBag() - + private let bookmarkChangeRelay = PublishRelay<(Int, Bool)>() private var undoRelay = PublishRelay() private var addCollectionRelay = PublishRelay() diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index b9ed39bf..f16db0cc 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -352,7 +352,7 @@ extension DictionaryDetailBaseViewController { // } // } // } - + func bindBookmarkButton( buttonTap: ControlEvent, currentItem: Observable, @@ -367,7 +367,7 @@ extension DictionaryDetailBaseViewController { buttonTap .withLatestFrom(Observable.combineLatest(currentItem, bookmarkId)) .observe(on: MainScheduler.instance) - .bind { [weak self] item, bookmarkId in + .bind { [weak self] item, _ in guard let self else { return } guard isLogin() else { GuideAlertFactory.show( From 591c95e5230913b6c8fb3e274bdfc2a727b6272f Mon Sep 17 00:00:00 2001 From: p2glet Date: Mon, 15 Dec 2025 02:07:22 +0900 Subject: [PATCH 19/31] =?UTF-8?q?fix/#273:=20=EC=83=81=EC=84=B8=20->=20?= =?UTF-8?q?=EC=BB=AC=EB=A0=89=EC=85=98=20=EC=B6=94=EA=B0=80=EB=A7=8C=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C=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 --- .../DictionaryListViewController.swift | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index ca82050f..c21bd03f 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -320,35 +320,32 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi imageUrl: item.imageUrl, imageBackgroundColor: item.type.backgroundColor, text: "아이템을 북마크에 추가했어요.", - buttonText: "", - buttonAction: {} - // 임시 비활성화 -// buttonText: "컬렉션 추가", -// buttonAction: { -// self.reactor?.state.map(\.listItems) -// .compactMap { list in -// list.first(where: { $0.id == item.id })?.bookmarkId -// } -// .take(1) -// .observe(on: MainScheduler.instance) -// .subscribe(onNext: { bookmarkId in -// let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in -// if isAdd { -// ToastFactory.createToast( -// message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." -// ) -// } -// } -// vc.modalPresentationStyle = .pageSheet -// if let sheet = vc.sheetPresentationController { -// sheet.detents = [.medium(), .large()] -// sheet.prefersGrabberVisible = true -// sheet.preferredCornerRadius = 16 -// } -// self.present(vc, animated: true) -// }) -// .disposed(by: self.disposeBag) -// } + buttonText: "컬렉션 추가", + buttonAction: { + self.reactor?.state.map(\.listItems) + .compactMap { list in + list.first(where: { $0.id == item.id })?.bookmarkId + } + .take(1) + .observe(on: MainScheduler.instance) + .subscribe(onNext: { bookmarkId in + let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in + if isAdd { + ToastFactory.createToast( + message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." + ) + } + } + vc.modalPresentationStyle = .pageSheet + if let sheet = vc.sheetPresentationController { + sheet.detents = [.medium(), .large()] + sheet.prefersGrabberVisible = true + sheet.preferredCornerRadius = 16 + } + self.present(vc, animated: true) + }) + .disposed(by: self.disposeBag) + } ) } } From d0386c2d87b187b12b8e3a63f9c03bf6d12bbcd2 Mon Sep 17 00:00:00 2001 From: p2glet Date: Mon, 15 Dec 2025 02:19:25 +0900 Subject: [PATCH 20/31] =?UTF-8?q?fix/#273:=20=EC=95=B1=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppIcon.appiconset/AppIcon.png | Bin 113872 -> 386305 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/MLS/MLS/Resource/Assets.xcassets/AppIcon.appiconset/AppIcon.png b/MLS/MLS/Resource/Assets.xcassets/AppIcon.appiconset/AppIcon.png index 7b4bfce1a4a792b7e53f3e801f9d51da092c5d1e..89a2578135be185275a36c33e475c6ac22cd2ea3 100644 GIT binary patch literal 386305 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 v*2%F2gl#XWo8r-yPobsPzK&VjK-y|i)Rykj_ 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

VN9?RsI(;F|L$fze9*E!?yC(D8P*FCfu}hwb&L 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

~uu8#*1 z{JiRvCguOG1=Vq1JsQln`JukZw~z+emWIAd0wf+PN(}vD&a$yacUClo{508mi}Tn$ zr%xnd(&u&72T1rLzv=H^zNZk`R$6_d?(}bxtS?}#0yD*{MF!0w&~7;u|C)#l(~QB*b?8NY$Tbw z$+<>*7*sxU2H!+wD7p>U+1bCrjjMFL{0$dOP`+2+`_b?8XOGheP6(j}G4t}K7)mmz z04c-9oYl#o7Q(HkFMco2lDA^|6-OBN!b8dJM;rI~A`9UcPtp7L0HuH!IO6{3pr3FjljU2^JPNx-%1x2o~CUhIkJm#P6Sb)r< zhx}R)OI79boMT$^I(`=G;8%*?meIdamZ`6QnrVFnc$jl{yH*;2aGrZHA%QU&KD7t| z?;Y)aGiBED^_?PY+T%HdwOLHj$yk#)P9^AAiiq=IKjY4p`pUzoIdYph=uILejJH9h zs)+>G^v3|6?J2i6c&=`s1-$G2>32P`j8xTtEB}@Pg~?d4#fF+-?MLBC^=&qD!@jju z7dd`}C)@XkY|&+J=Um$(#us?oJXOaVbm88Eln~$w!WC)sLC|;raia8^XqqZ~^<4mrU7fHj0jPGX*LgAo`|K*BYg)r>usBXYyQr!eeY!rxz$~F@d z&fsp0Poar%Fe+@smJ_Zw*;Z_Aps72hH7A$72`O|{!rsYYt$qaN)jr@L=c)PhM%Gnm zh>zTM5QVaIU^@5jcT16Dsdqe!<7JhB+B72 z228WZt*bWpzZ41CM0|4{Rj;uYctJ3jO1_9g}XZm^=i&=yAL z`FQKXX_zEqM2p~2gA(@SMopVr;)I3R&K~Cd`n3Ia*2GUwoV{WM~NF|pR?D*V(FT5GqQmz!x{9(Da@$#U4_a#4cbQK5W@I2}ft zxIH?rkmf>LVxRZL^@$l2;7>$V$up9+h_$nDG3wRr!*%*gRtIkqH=+!wjF3 zyrmgxvO396RJbhL%|pMgT1ydgy!8Ar`!Ep8Tyd4CA~6!zzk<p(eFUWxxrxr+^6jcJ~ zqKW|&FPtOd&1MwfDA-t)!E3sVlc(eA3{^OrOo0dkCPt>&I4HB%i z>%m(7==~Dw2fD7itd=$xAC|OV=2SPSbR)BtCPL+2dtk^mf3U(?ffd__=>>2a&wQ-!g??iqww3XA7V zbqyA`;%r2dcdeII`=nR@Zkj`L5IwLa%jfO9X{a_a%@rr{UFi#4D*68~on;^Ld*-7y zB*u0e#_ahUBTt6?QyWIKDpJQW*$tgaD)PtjpY61P-mw1=P2x@}{N;anaaNWsX@fT-Ltle!nvnnO#dXek)&4 zL_dg}C(PtAmReIOU4BzF8u#OdcGurf@-_Uf8$<1(^Ik0O{->wjQ(XXewI7XQud-bx zt61{byOrb~F0;Yk`;1FDjoCMIU!*z37lBd>B9pk#k_!6HTWd|!&n<)g&jahnc@l^_ zC6`6pQLMzGfoI$uMSoZrey1Rc7#)nl63++*kC&#WFPlG$XJSMbXo-%%4-J18Iq|EY z`g$yF;hA380j+%H+48Xb+)GNVC1%_~B%EtCidU!o)pDYxG&od@^Vvq0_@gdsL0R35 zbI@go0^Qzw3v3YW=m8MK$Dh+M;M>h4yQ9yuU-^9=V>JdjP7Zn*qMK$}m59Eil_lQ( zv5tg;4|;dM|KBi@(KqJ=TL$syYtZ|-7Us4F34kHORUbsG0(HZDISnE^Qaomo5~>g= zACAqPuPPw>+VEX?2B40|&iJ)~e_aTr8NnpDJ(?~Xv7jTz&x5y#aIR^7_FZC93OP%* z-da4)G(mCzWL{@9s!l;p-o>|}zC+ps$yH26NA&o7u{HkVh>k2G(ImGA)N|Z+9lYV@ z#(D1M7uTDhe$o01JY2m{ z4T3-AS&`m_nU>gV^+Zab4Q2m`P7}F=6#WTZJ^h+?+t!@p)1*ZQ$dQid_iCM&-*ygz zAhqZJL6?LQKHPB@VuGh55(hAE$yea*D##?OG^RE~>kGE>$Y|$92|vy03TI@8J#3QL zmzA2E9>*JyoWY@U{G*mA;}M@|XijZeM0HDuToY+0?356D4$ioRRCf}f@f(hpe;LS} zkGJw8kTt^91Wa6uJBVLz65ZE{^uk%aDUkNkEdLBBJ%FlOSD+i(GE}T~7lm9o7N0Ir z<~hM++&lvB=2|L&$}xgw)4J`=dc7M4ZIMO5>Ae&67v6G2yjWZ;I&5%tj}=L$@Hltk zCQ&2ZsJOnemkKi%(WHFKVR;4Rc>P=c#6{(xXNz%%aX!79+OFx=WQ=)CDz{@DZWJJm}fgLYG1uLZ%@)b8*k_m0vu$v$3T=Q)<2>H#@ z;eWjYd&uJqOgbgJW>}fPNao7#3wB#$$HTLVsK`&4Mv>N8$46;rTx_&Y-Zb9}?gJ9t z8GXUmY5M zmM(DJIvofKOfb0~HONM|=F(nL5#tkE+bvfFP32K%Pb#`bFw>qU%&@N#K48rzu}C< zDcp7Sk#4n_;U_RYiZ}{}<>98qg@v{W(gchjNPT#e@TELSYSm}6QkX2r=Osms%s;C% zu4$u{Qu1;9(_V!a`zVOHrCQNJJILQJOFB*b{?CH&T0NSmNC8ujw!l(!-u3DOiVJu+ zwGn2|>29wSx`c4B>8t}E&O(MRWNs9TVX)`G@9+%Bd|-X#mK}ovo7*#>`{(N(!mgdl z-N%YnyYEFKX*~i<#SH265KzW|^xVc+eXJmDj${DNhtL@3MnBHqtKUaAaP5`xd1@3h zR@wp*2f;s1DUVZ;OZ+nd3+37<2={dld<$l&Sbr8*`*i(@8N#2Yk|t({X93_t@6TTy zC+3q}zkVSOjT z3oa+SDWBH<1eRh?G6zs96-R$`RaQWLf`KMKp69=6_PN~c{=_V?J~P_*`N~Q4xO)`l z(ptMZsQ$jO;Im{A^ z^s={anu|_~{CmH<@ct>GcIkh1mct$-l3>d9`5cEtW=3Vw{MZ(?t^F>_)v~^lkJi$BQi`)!# zz03C3yP6{|OO2;($X>N9Bhu6dc3eAF?Yr-;ap%T)z3<&SxUNL^XXTM?l%)m*JDhcQ zX}M9=6PdcJE^(Z!0Y&O^&6(kZ@%=kvQd{E<#IP zSNU#puG`ZvUnQN}A`DdQ^-mNMq9c6QP&j%CWmT@)@64O89u&0uh+=;K*9{+DLB(Jp zdz-BtL}uwG5v_6?fcP#Xa%ZTWyy;RrcHhS~@L17!$H!SX>A=66Sx@wh*h9WrMHfH7&vIyxj&)NGaq`pzocL=P z#Cewz{oJQS-kq26H<5b7y-+3ajXykNNDGx!e@0>#n#)i*1Lp53xSq#pl2)svIt?`o z2T{&hD-(1V5(!oOVfT;s_9P@S*Ew*42P24Qf+(?H`S`#nWz0URlppt6uxhvz_*=`X>TK zKR?|xRkUg<|6DRUi997t1L8&#pwqM}YhREjrhRHAxXsQO$VK9B#FmBgY@)YuB7N8ghL_(dXn%F+gh}~~b%`9~`>V04zhO-J)k3H!n70Ivs`$pdzG)~8*<)K~ve1i5 zFOwc9@W0puKj3IR2Zl^hAbkP?GNJ{X%!_ptd?cC-z*N6@5?vl7@qgU51>qMeh8=k-K(eKIWy+>^vCYj5TaD1KVjs2eYQFxeN zoG2h4Idi&?#5J#dh3=(2$v>>?jpxEQlu94~h8zs?G*G248zL0-lDv>G94zv~BwMOC zeHx`fm6;l2xx=Cj{6SKX+D**84Is^*>)N>myNJF}n?1hG6DlQaJirfV@nT3>s5g zqHg#4zqV+(EFyFZBqS9}z2%Cdvzhkm{J~Hx&__uGw|1{*LjM1B^N4Vn1Ar}pcJ3hJ z=GVX+F`i2HU}yF33hzaj@F5&Sxx8aC-B8N|$=xi7Qx0Erif*l@!$f(^M(&gAlucZ$ zuu+u*<;RjYr3zSBJa45BXIkSMrBQdqTqg;h?HA~~M%80bQ_n9b0_sYI&W$!7#>2yBX_lXtI&ESdrQ5rrl(IdOX-(8Vni3 zF33g{tjU!tl}N8`xEX$CzWG;Voet7fqSh8V;3M3xCPr78cHpqlrXdrCJymY@vXJhr zNnZF{5OrIVvDK`YpMlc*ln%FTNh+0?`}v8ysk=DD2EJ^02tcLQB*jI+g@-JKL2+5b zX?z-fV~H|tE5PA1r`O&BY}%2xANdJ%JYl>Xi3xuYy>x=C|AX1PzxGnX$8xm0knF6$ z_61)P^onRAcIR*wqfrMVHYXR+6t8)K0c?)1pEUM<$>Pszo%6WrsmrmqW4b}#B?1|2 z(=*0*66&zCKK9#?R}P25Pl+{rf37sK(VHxeg9 zNht;Hek%`E<@;#DYxR50!ti+^IGk=xcz5RyGfz?(W5HScS+?zDNRUPU zbf9{;dT!#T3YqcpObC;Rw7>Tz%zvi~dP432&K*flfTFe@2(YBAGkkW_!|V7)6ffZO z%-!~(+9Nqgorm;bFSbz@i!`#SEeGaPEwl2-k!grtALY8lWifpL_XKkR{9uOF82uTh z(!NaF6v>Pj4z|C@3%G-x#65ZP+uMu4U%!bi38a$X2hln2d{I8Ppj4JP2U-)&ByCrdpW~~P-t*;#Fj6Y;@LehgA* zCrRpTk(sf;vOb%4Jp7j?)z-F!Qj}Z>A*gh|OYV~Q-`5p9>Z+mnA-42YsJ(ihJV8k^ z?s@}6s>`1kJDfK%#J9Ne*GJQ7W8(gTQ*>8bevq3Tlh-5kba zD5qjqF*wj&3iO>y?ae6PP0$o$eWz)86bi(CQ~}RMaMZ&=mQ>I0UxBx+9z0ASQle-| zLj(XKt206jQjXVUb6R4H#6=Vhe-O8f&6sMtLy~@LOek9gM^OdKQM@`>qXV@FN5(fQ=7Y=U(F|Lz=JgE}vi^^o;t*p_^Hp~yUb4H|gPR(5gztjS6j%xp9;efhC z;ZepTbYsk*@5TW|5yCLU;p};!dt94~Uhl_-*@VXKFJsP$`n+3^4$8GpQtNN(>Z88) z>53JyH=DWIMAVbrwp3s-k>Q?>TKW~UCCod9jf!xub<7GXM=@K{Js=iN&b4Tu_*(n# zTN9xp6VSR1y|l!89sjqwaMXMQRBYkigQ&3fy|9_Hs{omt`j1r>h65aU{-6VN|Kl_p(I(TGn`VF`UFWxY3Fh7c34| z4&zA*1e5{h!SnTK*wUBj8;HzSXN?2P^*1W^y&F~O@2@j#ZuR!NV@6u~u#D+GERHCD zD370D3N{J&_5enhIJ4bbWBs(7H5L_1g#};n=kY{DC6svmL$uHO*^0%XeSG)7i zeU5X$iSzcHv~+Y_vKr4wKfzUroo;-och#U0n+u0+MDQ4(r$PhueSYg*AkJ4%;$9~} z(_s?E8d|DLbN%CQp0bg@P!L^!t06I0S*EJ@(>RDk&ZTYBa(B)ykgO&vmf5wm8M)S0 zM+5vBzQEthb!&Q=v>5vyK&FhE0x};M&qRKeGCsqU zE{sKi!f4Ak=rOP3rM2F9-h+5mwPvC&zA?7SNQg?H=rb}eSx1ivgkWxz18U2;`crdkTb7Q}p`1$(pb8v@w5I_iq}pq&-t zSwOtJDtFmU3T-i%7TXr#06Rb+LNFggyF0q-`$=#0q}jIu1S^KgDhtgOf-Te`m;@%3I$+;0#s52LG4S#MF#fgn z))6}Lpek7wgPlh;F!??e9ph}W4oV-c*E1&h%p&QaaYK{6E>)A-=xmC^tx;Y59LBb| zpjONO#lYMxcJRhWYNw)Bgbz&l_cksr!EFy*2;XW=(ZX^MpW!HvV*yuaK|d~JXi3wlR&#BOLd{-% zR#m&(_RlF#C5)y!M-GY!V*y8FnjoWMubNYOH&xr9Ipnk)h%C-6)y+s2uoLGpVSwR1 zH%TojSilAF|7i4BXb)xkL>H{` zD8;iJFtQ^l>*?(`N|Zz%@MN4g84Mc|*3G<5&BBCYU=fNhsyQ~{y(p0O%Ewn89UIRY z(W?;YBWY;p%(S-=@7CWNIChRWrSjYMH2~8K-8F(L&Gz9|tl@10LKNe8BTIoj|B1>d zg10Hb6P;}@s5Tmyc;y=5_Sj3-?|(=C(tYpD!uFJZSCEKde`=hTBGlWV%PH4I%~WNg zyJX+%FIsJkf2O`g&tG{TQxSO9dp<#-=6*t&BLl>38=Dn}~rzlp=r zs_Dx@>K=In$C`Q+3*n@wH9U|z){mQ>Wh~@~7yA?88OVMBRE8TETWF#)L}er&{8{Ko z8k@icqyktq%la(a9b>)PoDj&WvziJ#_3I;d;#Cosd)(3eA43Zo;YORP|?GTU+VD zwcb0LjTS+WiqN}g=Y4%CX~=Ivse&`62gU;?)LFlf1SGV&X??Y9)=oNSSRBv{b-eA- zZ`>1Uuc3VE8M8f*Fw-X>lpaoc#L#_b^xEnAb+2J^@p%LB7jgxVfxK!6e270LVmc^( zO9c-Laky`E0_48kxU@a_89v9*QE&IZ0ZzSv07A@ znd!b4jptkPbDafYzT83p#(|qYnG*^XPTJ1EfrwQVinL{R}{%|S{CA^7k}&uc2+b0X*P?G=?l zF4P1A;3?A$<_w=>&++^H-)ITBy6Ogl0M;P97r}0a_upW>oDrMAZ&UprA)Kzrp3Khv zGMHv#81;AFZc_sWh5Fo!7D~CUh9Qz)(bCT9?TDjsFUTq+WV#KuWWQS=>H_SfInlKN zT-!!M{jccV_}O;)EgxE+ceCt88xp9eJ2g>pqMft=uNJTS7d9ZG5V0G(KitJpI45?` zf4qWBfU|+yJ7a{hA#3%E+xf66PR0GlD}(H=mZJ1Q24v%ra9F@P-i*MOTSMA`hJjsn$x1erwI??PUj;S0SdkpB#FBYtQTf z#{1NYQ?q|)t{6C@)OLZ(S^y*x=HK_$?S&4AwTr^PdHZEMQubp!Ied#b{Qj&Jr-Of! ze1&Lu#;E2lgVAa5%zB?5Wzp=D9F~)YYPV1+f@dFEfw#vgcdBV0ecdx=;da_oHbL6d z5)T&GUL7WsQhNnGBPmz33klzsTq4zBX=RBew5hgXUt?k@h!BBoh`Sw?5{qXDaouUnxjn-T)o|18z`@3>-c)Wd;G%#z^Ff;NF%!(( zHTk95Oc93Jy8WG?Vb6))RCqsq2T!AHM)ybtX2O2Z;(N7@@6f%qA5UK(deaillCa>& z%HAJVNvi(?!Rro^yEqbkArg2p;r8%Zn+)sDbrKlbw&(p@w z7tdU$OARm*+$BTKSgwmJrc1uEarZ|`zqu;k)c_Ih2-{w z=zgJhALHCM(%~-tGiD|K2Zt+*fuL#F*R43-b!IUx{X;i&)>bR-P61L`#8d-fLarXz zZoxNjb*@0kbnVZTggrck75Po(6PZJYHF1rvkIrGSN>kMBe;xo>9pMi5cDEEY|rsg{X5y);L36*^S6Al>Ghrx#MqA>_rd7w zk~&w+k^>h=6(;>VB(?L#JG=Ny@h2kH=W38|>ZcO1ms|e%DJJ35f_C6IvwO|KKC-ez z0PfGx1LYvH9!{5`rx;@FcsAwlfXZXqLR0_!x8UJXKc_NCn3Q8FVDY! z)-+&K)V~&keo@TymXFiSg?0TVW&WlmYjCZWb-jpx2 z<+BJ%VIr)B9;^tp^^v`)fML%k3_Y_s3_`3Yui6iEzHzYI9f}vc=vK88iDt!YYZBM$ z*dxkIuKWF7la4~}_=%sEg4%e!`vC!QDw1H!2f5+296ZTBBuI?|6-KE` z6{Xna?5FbO*Ljji7sWs7JEZMT5Ez0tibNSzz!W9?{K!evMycDCl2FLdJ zCc2G=fP}wdJ4fp9KHz>B5gfVDy#*PRdIWsd#<#${5sPZXt%F#4WtCB>K&(U=hr_eF z>x~zS9#G4c`1#t3px;UG+}5N+4fmxVi{nM7m+=!PPk!tymRLp^y{+4|C_Qe}8+9+f zr0?`;y(ZkZP>xpmD=&y>bbG(y3|juf3La^CdZjGQ7^6{6lVwwG4TrO|Vl`5&%q!XG z%ag)zmSl%t@g-GddJRDERFV31i1COkRY4!7Hb49KuM7Ug$j43KN*|chn$?dt$@WYq{$?)MEJZj93(X_jQ+$q628n4>egl zzY>a+N}yPZ_sI9jv;M;*>U;8o#|j!xAO1M))#N5pfAq{V{!C$%8OKvE^A$}9-aH)n ze7-9t)8(!_nkZvhFudSzpTlo6=f1O(|K{_vhy;F^*$lbK<`EA~DArT!El4EVuAP_| zQ~ipYT0_LuLhp=G$dDZck3d4%3upNwy_B&tt>&UR6VPd@dF=xi|3yZpt-M{WdT8Fk z!=Xj=m&llK4wOJL7wNjkZa85=9dN^JQM!Xk4ScsdN*}jWR|y1sG9miW)!9DGL^%G4 z+88iGL=H zGT&be=#oW*ptn&Am1FKYU0c$=WUO%)ISq>v>u-*B+1iH*n6UFxSJIvyUk{=geIWx7HIB{ z_d2j5JiQx^efm6c4cqhbeEA>i*F<;{zp`9KqH%2DryX1jJVU{$bCPYF>filPLSa#zf?E zPl|E}%LVV{nk9{;5H#+SBDHRN`v^FkC=~l6TMzLTU3RUkAJ6k(tIsL+MB$rQ zC;0bu*~j^&Pb~2_D-*W=_TgXyUE@a)^RK0v&R38))y;8Id1@Q6JO_avl`C_svyA!T zVwYu?r11qkTmP;50`aa?w*cnp-6EO`C2y{H(-orTrBREOT|DHkjG7+k!wUGJ9huSY zlLtsvH>~0QhHvu*z66$A&0E@!W*)INgAUzw?isZB7K!>%8WiVZ00u^yI(Wr{Typryw~lCp9W`m1G$Ob} zQg?-twi_j1G*r_Rx?S>8KfhMPZ#PW;b|42c4bzx&kP~_vmAXVawZw<|yo8?+~CVV6aJ)<)QVp994;l{-I@!iF+>&;J>*zx}VH z&ZK(9-XR=7A^gZ9bf`V~gNDdr>aXE;S`PC=vSwk196n%}U_dC` zJ=fj`wfEP|IRq44eBfbl4+}Q;(HA|%TdFSuj#Gn6{jn7l?L*LHWABIhJ%~we1~xst(yR5M|J4{UitcF4been=3G4Y)l9)j?Y&OA-7nccp+vOIGUQZ$tVgygtpJ_BDdi0?tV zH2^a}xR)k=U!F?5{<{Xqdo$ima%ycX6!wF(U^(5==z33(X4IwW5!xh}9B((Hg00ty zxbZHiN}2wy{>ZbG(cfQl@CXkb!t7ha7qoJ=P@~g9Bs=i3FdTtMSbQ_CZDEop7YyIF zd3+YpeJ4R1u2Sn}+bH~+7v$>DM7lhr-odOOVK1r|Tt6+Mguu#N<0Ovqd~$yYqi0T@ z;=otsKVzU-xFIa|asYDbT_q0|d$H;xIbQjS+1OWWaInm*VXTb~ z7<8wX0^t9~s%s(ndF@Z_l@*ok43TQ*Ml;er*Ph)DuC1aBF;n3)@V8lLk3xyBJpI;4 z2b8*1z#ft8HTU@vvV87Ez4eXeHG<&S?i?=8c-#%Hq7tZj*j^oF-;Ljkt>G@es1L5H zo!M%O);&D(!$4e;EXlkep9f02SqHub#l~J1jui)kgTZE)f3tc_l)YRFcRwIcpXv`s|m!cK~nQ z??@laQWaPd%Y9NUSO&XxOH&A3uazoPRf4~e9XwAIDdELn!kfXy8OvtYD%=ny`i{u0 z+`sDzL?}c)0;4CV)JsZ8*@81Tz&GJ(I%A9nZ!0Rh42{g1?&yYID;^a<1}^zXYe`|= z;Iag?VG#1lk}>~{*$v1K@8_*8#~@2{)5SSGP^5wIdF%t z!krx!o#Z>d1BTYG$j~%R;`E2;FKqasf7i4&Bo@2@1XChb#NHqO?E2{3{D{U&VLlz` zXZ0gfDvhYIRRj}k8!59?hHZ`MMb6XH@aUr$TZa^*{|scrMGsL}U+N0yVr^ogU{GU~ zoy9?f?<%udshB@JnkcWE5&FbR!EjNZPgwy&aXW3?I;vRAI$eMeU;S>^7chx_&qDIg zbZRv|?UL75+Rcpd*pf!U)S*sNWg&E#>l2DeX^lN9-Mg9dk7`2doS^}ZS8_nGx1hxW z@4^3}H*e8_t^r7O2S85ZI768-M~x{gGqOH)1WNb`YR00s;=g9Yz49OQ&sh%9Nk(r~U|Mpt}IuU~uL-&jh)b}5z!wx+ROp?N<){^Zcm=0LA47HdyMB!SZQOlJVeZ>HRwis_(6awU)H;J$6EiH&^`t+*<891?2KSqR z{BDy6CicZ4;tPm6v4VE+v)6nQ{B@;A(Cx#>rTq89`$Ht17A;pVcw{@?5yb2I6QML# zkKw+|aXx8DMOB4C{nEm(KDi$Q5BEfozaS=ZaEh}x#KH;-|I7SPpnRpZ8@aw#CpB6h zV`ft;0#Yfn+d#QM;zS3F!aG>tyQ9jp9H`Jg00qGKe;OIcC{+MlVaNe23-y4b&sqXl zgcppCzd#d(yb$sv6geb=Ev zhe2Qw#;{LH<0~z|oTU;BrZ$-ubS(efmU7R2}X} z>B$l59=(_bI!O_5Z?D#NKE#BdFgux^uP!k=xM0;RI!i!mFKnZ)3Klf_hw+mdrovlPN`XUM; zg~m5!p~!nzkgYh75+84J`Bh2rK%BDe*V}pcRRnqp!d)cB3f?cOAR8sWV$fXiFy%X^|$?n0{1K9zAVggPDkS zGc^egBZr8peVRG`TKhl!5hZySfYl4xhWU0B&E{FsofHw%ReV~D?LFb41Fz=%PfbuP zv%38!N$b_Vz}A>k$$qW60^eR`!J_Hu{R@F6%>miau~7|{!6~@yIbpkGvrpN8cW1`w z2i11c<8^h6LE+s?Sltv*s5trNpShxkT!X&ny|vI40~EZ$Di>M|sv`2=!jZ(rTvrF) z7G){Ew+7H|qq~uQuJ-TRSH|xe^KrF}O^=5~{iv&iZ5OJ37MYdC!l%Qz2>a zq{4`}ySJ*6I6zPRa4(ApXic2jpz_5o@Q3XNXR&}ohD6k|iQtU@1F6(o$SW29oyXaQ z5i(h!^v&S%q{7FW* zADC$bmZ!H?0&6*S@ys?hPH>bl^h`m*E8j)R8jZ|l^o?sbRe?84!T;d_qTWZXf|log zLkWlH!m-yd#*VU@P#u@%m}Vw{Z-p2EN)!B$4IWT4+fOLk{C>yD#yEh%g=Gs|4T>qgDB-O&4YV^kwTWQcTTOc z4m#gu18?v=|FS{Q7_uY%fsuxZ)u09VyNB2BB-LheK~#j2g_(HbxPSi`sn@2K4y@iq z>?}{`*f!6epJR_HkB)o~fs$BQ`{{Tt2|^ursK#%SMId*}=)%0aD=8|3Mm-#^n8x!! z?J#k!EH!qR82@eV?NuI(wyY~(#5)%>UoK>{Z6*t%5q{>HIV9;H$3Zbp{{DA9s`=OP zQ_EB1KS@y4ML3o!kIg>M7W_5_KyMRE6UR1;nsc)7Pm~XMCPxXq{njxj#r3oFZj>!P z%*Je?(pzSpwslqra$6j2)qM{0;o!n(@DGLD#EiNL4|4A8+n*%r0J4#o7O-7DFU}8Z zp+4-QRIXPYqrP59_>&xLFsHr1zHuS**hO&A4hRo^DKG$ z8uOhJaB|PUbd5iyUA%uy$ZS`MlE`tP_vd}BIC>vZhP(9*_acipjzV~5&k1U3AIapvbttKeNfKD;W8A)OLgSxT3=qqr#Ps1#) z8sETdoZH0|j3#8J7akQT0J4Rb6yx&gw0TFp5hiTmo9JEFVvBi>x=KiU9T9+!@&d65 z7j*mQE&zIk*?C)U?1w!diKi5hvk5FQ95AcI<`Uuuq|FGZZ>MUciRA(V*;mKR!MzW2 zFoFT`1NGL-8so^}H{ifiqYjaZs15hsrNw9}uL_{t+9eY?`J0T;l-XO5mf;$FnScDl zm_U`3!`9fBYR5N9Mw+kYK$V;H>!s40R+#Yo22|DHxonro@gr*ak88gfsKNpNyROoT z#-p8IoZ8}-uyaR$Y8oWx*UKum z+pD_1{ve@48F=#%&NFgtL=QYw2bC2*I^{y)p?*xwOr_83VP4cuX4PHwq`sf{z6mcl zWh71D;8#S&mj0Th}XKu_hh+e_A;8=x~@(q>l)c z+m`fuD*9vtOrQ1qr?w4j`p>cPb_9k$$U~xx410FO19?Qp;H<$154^7elUjZq1ra-A zAEKgO%?=Vkm64EIVC!>7*E2-(&+`q|82hFyeB?Fz+k%432Tr$a`2xB9ZBQmII|aQN znwdPn4+QB(z=yrj766@RIbRv!6a~-f1H29yF{2wXZX6HhS_z95I%1^uDw$1@V^e+< z$xn?}Xa-`}jDI(IN80A~Sd$5-bk|KRegQ=_aSraS@k)vV_oOg&4HGF<`QmXcq*Bp2 zVf3_l@BAK{9Z_ZR5+C}r*iNq_?_$ifR1{SMY*mQdlM38z8nwRtdSbdp!98S_!c2`~ zSSn$~=@VXQm#d@vF6gt#3H=%jk3E{~fGe?zw(>PHsIBXpyeGFm*ZWVQVMakp^6x^_ zIGq^JwSp(a2W`}f(Hl?EO-cRg9I4dH6%!IcXu7!-Q6X) z2c6l6_y5lMpL4VC_C43Ea8g*HFFKrOn+$eqvZ&N32XQ z#hO+wpkOku?<~wR`*j}giDZGZV;gnoNf`$8#$j~WRSk%*?iZHi1Ch;KYX3~urkfJ( zmqe^X8cC`#-;!J+oqia^*WkAclK^{dFumJJf_C?QZh3MVq#B2_ot^ z6VjJvih3lW`H|+luW^Nl`kYgW>O8Z1^dH7)i7)!^Ea;qb&Mt&Q=rCTIU3RLCzjY|s zH0bTtcK`Ew!)ZwKQ$ARWbZ-7+ub{ho#8Q90o+$A}t0ry!!w*mUR01F46d~QH)i8fX-$2%HKj$ z^IO;9gl##%ZtBNB&+Nkri595<)Gjg6OZW6mUt{ai<}DHl>fWD&M=6$9zM!0?!LX>Q zjb(qA4WORYgVgZsnsN`3G0Xp)LEF<|1TOdkq+w*)rZExPqjeExIJVbNnt&Ba2OO5<0WCwz z`oG$6ysm3iQQh!(dTn2scO^E7soNTZqAg~)vV4D*48ulQ_ml?rx;!bbK~pIUX#o4* z@3gWjH5rYsxPc*a z7&#YI-&#&ZZ!)=B;dtIXidfxnjc2inidk1oGck2Z#=wEbfQ|kk;neT^$W)BhT~qkT zHKEIT@y$l>R_oOD8=J1TV8m5C^VLp+Gklp!Pfnq^(dov_uob=%B*<&f80Z0-&e_M< zBP^S08ej|6_LqN$cJ`si-1Sl%a~vLYe)&hBdRVG~0*!jNmC$E3nv)EEjE3+ZhXi_t zL2gbP5m3K+q-IBMdo>>l&A27mJ&F{B%r$rM{~>(QoeC8H3|0>~K%C(ReYwlO%>c~@ zfY_AD<@eL5^Xc>+WWSMsHG6H06FUxCh4ED7L?ATZ{{FahJ3~fD>Mhi%yx)~gQn8td&VAbl6Biw29(aLy{~D)Rpp-ebUL#QsfB%}TUt2muq3F%;jW~>piogYZ z5z(Euo)^qDXHGlcrM7F;9(ITkX=dw{P+}?4rH88GntueB-*lyFcrnZ9$Z#*+yR#AYB4YTh8y&%O=q|tw2pgU^%nE@{%N`l`7%PZWlu;4>E1~4$a+Mjsl83@ zL1j_=xL8St@FH)+!JYRT2*O&W6HG}sWzwSu-8n;tY6~X#sahSPj0|S9)#a; zM$g~oU-6iNNZ+@(w$9L1UI)~f;Nc5DB|RrgHDu(yVO0_lwh@pF&U<52Vu;FDZHOy58#jv(XQ#mRCj3n-CK zWG{Jz^kolkd@(TO*$&f!NQj0C##GK)aqN~pSSo-n_LPx65uYi1RkL}6m$=Xn%!aq^ z(eHI2>6nJUd%mjPio@peTF7W%IY@}D0V=}lD4x)(#;%$@n6Z}W%o;_LD(

Fwi^%z@%gJZ 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

hFj`1IT7+`1wC!mb#kZZw(m`KzG< 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

or?-G& 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

?IkH+tTilLMbs9$_ph~|4({-NelPg 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 N002ovPDHLkV1gtKJlg;O literal 113872 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 q8>O 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 Date: Mon, 15 Dec 2025 02:30:28 +0900 Subject: [PATCH 21/31] =?UTF-8?q?fix/#273:=20=EB=B6=81=EB=A7=88=ED=81=AC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20=EB=B2=84=ED=8A=BC=20->=20=EB=8F=84?= =?UTF-8?q?=EA=B0=90(=EC=A0=84=EC=B2=B4)=ED=83=AD=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CollectionList/CollectionListViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift index b4ea36e7..b00517af 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift @@ -120,6 +120,7 @@ extension CollectionListViewController { let viewController = owner.detailFactory.make(collection: collection, onMoveToMain: { if let tabBarController = owner.tabBarController as? BottomTabBarController { tabBarController.selectTab(index: 0) + DictionaryTabRegistry.changeTab(index: 0) } }) owner.tabBarController?.navigationController?.pushViewController(viewController, animated: true) From 163a95defe129bcfa95ec9eb12955ac57699b033 Mon Sep 17 00:00:00 2001 From: p2glet Date: Thu, 18 Dec 2025 01:24:08 +0900 Subject: [PATCH 22/31] =?UTF-8?q?fix/#273:=20=EB=B6=81=EB=A7=88=ED=81=AC?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=8C=80=EB=8C=80=EC=A0=81=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0(=EC=8A=A4=EB=82=B5=EB=B0=94=20=EB=85=B8=EC=B6=9C=20?= =?UTF-8?q?=EC=8B=9C=EC=A0=90=20=EC=88=98=EC=A0=95=20+=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20/=20=EC=83=81=EC=84=B8=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EB=8F=99=EA=B8=B0=ED=99=94=20/=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EC=BB=AC=EB=A0=89=EC=85=98=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=9E=AC=ED=99=9C=EC=84=B1=ED=99=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DTO/BookmarkDTO/SetBookmarkDTO.swift | 11 + .../DictionaryDetailItemResponseDTO.swift | 2 +- .../Map/DictionaryDetailMapResponseDTO.swift | 2 +- .../DictionaryDetailQuestResponseDTO.swift | 2 +- .../Data/Network/DTO/EmptyResponseDTO.swift | 5 + .../Network/Endpoints/BookmarkEndPoint.swift | 4 +- .../Network/NetworkProviderImpl.swift | 13 +- .../Repository/AuthAPIRepositoryImpl.swift | 2 +- .../Repository/BookmarkRepositoryImpl.swift | 6 +- .../CollectionAPIRepositoryImpl.swift | 22 -- .../Domain/Interceptor/AuthInterceptor.swift | 1 + .../Bookmark/SetBookmarkUseCaseImpl.swift | 6 +- .../DictionaryDetailItemResponse.swift | 6 +- .../DictionaryDetailMapResponse.swift | 6 +- .../DictionaryDetailMonsterResponse.swift | 2 +- .../DictionaryDetailNpcResponse.swift | 2 +- .../DictionaryDetailQuestResponse.swift | 6 +- .../Repository/BookmarkRepository.swift | 4 +- .../Repository/CollectionAPIRepository.swift | 4 - .../UseCase/Bookmark/SetBookmarkUseCase.swift | 2 +- MLS/MLS/Application/SceneDelegate.swift | 1 + .../AuthFeatureDemo/SceneDelegate.swift | 20 -- .../BookmarkList/BookmarkListReactor.swift | 89 ++++-- .../BookmarkListViewController.swift | 146 +++++---- .../CollectionDetailReactor.swift | 46 +-- .../CollectionDetailViewController.swift | 10 +- .../CollectionListViewController.swift | 2 - .../DictionaryDetailBaseViewController.swift | 259 ++++++---------- .../DictionaryDetailFactoryImpl.swift | 17 +- .../Item/ItemDictionaryDetailReactor.swift | 103 ++++--- .../ItemDictionaryDetailViewController.swift | 53 +++- .../Map/MapDictionaryDetailReactor.swift | 101 ++++--- .../MapDictionaryDetailViewController.swift | 49 ++- .../MonsterDictionaryDetailReactor.swift | 90 ++++-- ...onsterDictionaryDetailViewController.swift | 47 ++- .../NPC/NpcDictionaryDetailReactor.swift | 94 ++++-- .../NpcDictionaryDetailViewController.swift | 47 ++- .../Quest/QuestDictionaryDetailReactor.swift | 112 ++++--- .../QuestDictionaryDetailViewController.swift | 51 +++- .../DictionaryListReactor.swift | 117 +++---- .../DictionaryListViewController.swift | 285 ++++++++++-------- .../DictionaryDetailFactory.swift | 2 +- 42 files changed, 1052 insertions(+), 797 deletions(-) create mode 100644 MLS/Data/Data/Network/DTO/BookmarkDTO/SetBookmarkDTO.swift create mode 100644 MLS/Data/Data/Network/DTO/EmptyResponseDTO.swift diff --git a/MLS/Data/Data/Network/DTO/BookmarkDTO/SetBookmarkDTO.swift b/MLS/Data/Data/Network/DTO/BookmarkDTO/SetBookmarkDTO.swift new file mode 100644 index 00000000..bb287fbb --- /dev/null +++ b/MLS/Data/Data/Network/DTO/BookmarkDTO/SetBookmarkDTO.swift @@ -0,0 +1,11 @@ +import DomainInterface + +public struct SetBookmarkDTO: Decodable { + public let bookmarkId: Int + public let bookmarkType: String + public let resourceId: Int + + public func toDomain() -> Int { + return self.bookmarkId + } +} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemResponseDTO.swift index 656b43fa..2cf32564 100644 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemResponseDTO.swift +++ b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemResponseDTO.swift @@ -1,7 +1,7 @@ import DomainInterface public struct DictionaryDetailItemResponseDTO: Decodable { - public let itemId: Int? + public let itemId: Int public let nameKr: String? public let nameEn: String? public let descriptionText: String? diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapResponseDTO.swift index 55d8b109..653158e9 100644 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapResponseDTO.swift +++ b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapResponseDTO.swift @@ -1,7 +1,7 @@ import DomainInterface public struct DictionaryDetailMapResponseDTO: Decodable { - public let mapId: Int? + public let mapId: Int public let nameKr: String? public let nameEn: String? public let regionName: String? diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestResponseDTO.swift index 2376ce48..e79a4294 100644 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestResponseDTO.swift +++ b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestResponseDTO.swift @@ -1,7 +1,7 @@ import DomainInterface public struct DictionaryDetailQuestResponseDTO: Decodable { - public let questId: Int? + public let questId: Int public let titlePrefix: String? public let nameKr: String? public let nameEn: String? diff --git a/MLS/Data/Data/Network/DTO/EmptyResponseDTO.swift b/MLS/Data/Data/Network/DTO/EmptyResponseDTO.swift new file mode 100644 index 00000000..2f92153f --- /dev/null +++ b/MLS/Data/Data/Network/DTO/EmptyResponseDTO.swift @@ -0,0 +1,5 @@ +public struct EmptyResponseDTO: Decodable { + func toBookmarkDomain() -> Int? { + return nil + } +} diff --git a/MLS/Data/Data/Network/Endpoints/BookmarkEndPoint.swift b/MLS/Data/Data/Network/Endpoints/BookmarkEndPoint.swift index e81ffa9f..8185672f 100644 --- a/MLS/Data/Data/Network/Endpoints/BookmarkEndPoint.swift +++ b/MLS/Data/Data/Network/Endpoints/BookmarkEndPoint.swift @@ -3,7 +3,7 @@ import DomainInterface public enum BookmarkEndPoint { static let base = "https://api.mapleland.kro.kr" - public static func setBookmark(body: Encodable) -> ResponsableEndPoint<[BookmarkDTO]> { + public static func setBookmark(body: Encodable) -> ResponsableEndPoint { .init( baseURL: base, path: "/api/v1/bookmarks", @@ -12,7 +12,7 @@ public enum BookmarkEndPoint { ) } - public static func deleteBookmark(bookmarkId: Int) -> ResponsableEndPoint<[BookmarkDTO]> { + public static func deleteBookmark(bookmarkId: Int) -> ResponsableEndPoint { .init( baseURL: base, path: "/api/v1/bookmarks/\(bookmarkId)", diff --git a/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift b/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift index f52e6e5d..eced66d6 100644 --- a/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift +++ b/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift @@ -28,11 +28,17 @@ public final class NetworkProviderImpl: NetworkProvider { print("✅ requestData: 응답 수신") if let data = data { - print("📦 requestData: 응답 데이터 있음 - \(String(data: data, encoding: .utf8) ?? "디코딩 실패")") +// print("📦 requestData: 응답 데이터 있음 - \(String(data: data, encoding: .utf8) ?? "디코딩 실패")") + print("📦 requestData: 응답 데이터 있음") do { let decoded = try JSONDecoder().decode(APIDefaultResponseDTO.self, from: data) - print("🎯 requestData: 디코딩 성공 - \(decoded)") - observer.onNext(decoded.data!) +// print("🎯 requestData: 디코딩 성공 - \(decoded)") + print("🎯 requestData: 디코딩 성공") + if let decodedData = decoded.data { + observer.onNext(decodedData) + } else { + observer.onNext(EmptyResponseDTO() as! T.Response) + } observer.onCompleted() } catch { print("❌ requestData: 디코딩 실패 - \(error)") @@ -115,6 +121,7 @@ private extension NetworkProviderImpl { completion(.success(data)) case .failure(let error): completion(.failure(error)) + print("API 통신에러 \(error)") } } task.resume() diff --git a/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift index bfe4da70..d5bef287 100644 --- a/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift @@ -78,7 +78,7 @@ public class AuthAPIRepositoryImpl: AuthAPIRepository { public func reissueToken(refreshToken: String) -> Observable { let endPoint = AuthEndPoint.reIssueToken(refreshToken: refreshToken) - return provider.requestData(endPoint: endPoint, interceptor: authInterceptor).map { $0.toLoginDomain() } + return provider.requestData(endPoint: endPoint, interceptor: nil).map { $0.toLoginDomain() } } public func fcmToken(fcmToken: String?) -> Completable { diff --git a/MLS/Data/Data/Repository/BookmarkRepositoryImpl.swift b/MLS/Data/Data/Repository/BookmarkRepositoryImpl.swift index e2a9c371..144b7b86 100644 --- a/MLS/Data/Data/Repository/BookmarkRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/BookmarkRepositoryImpl.swift @@ -13,14 +13,16 @@ public class BookmarkRepositoryImpl: BookmarkRepository { self.tokenInterceptor = interceptor } - public func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Completable { + public func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Observable { let endPoint = BookmarkEndPoint.setBookmark(body: SetBookmarkQuery(bookmarkType: type.rawValue, resourceId: bookmarkId)) return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) + .map { $0.toDomain() } } - public func deleteBookmark(bookmarkId: Int) -> Completable { + public func deleteBookmark(bookmarkId: Int) -> Observable { let endPoint = BookmarkEndPoint.deleteBookmark(bookmarkId: bookmarkId) return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) + .map { $0.toBookmarkDomain() } } public func fetchBookmark(sort: String?) -> Observable<[BookmarkResponse]> { diff --git a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift index c1bb3d5c..a6417fb9 100644 --- a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift @@ -31,28 +31,6 @@ public class CollectionAPIRepositoryImpl: CollectionAPIRepository { .map { $0.toDomain() } } -// public func addBookmarksToCollection(collectionId: Int, bookmarkIds: [Int]) -> Completable { -// let endPoint = CollectionEndPoint.addBookmarksToCollection(id: collectionId, body: AddBookmarkRequestBody(bookmarkIds: bookmarkIds)) -// return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) -// .catch { error in -// if let netErr = error as? NetworkError { -// switch netErr { -// case let .statusError(code, body): -// return .error(DomainHTTPError.httpStatus(code: code, message: body)) -// default: -// return .error(DomainHTTPError.unknown) -// } -// } else { -// return .error(DomainHTTPError.unknown) -// } -// } -// } -// -// public func addCollectionsToBookmark(bookmarkId: Int, collectionIds: [Int]) -> Completable { -// let endPoint = CollectionEndPoint.addCollectionsToBookmark(id: bookmarkId, body: AddCollectionRequestBody(collectionIds: collectionIds)) -// return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) -// } - public func setCollectionName(collectionId: Int, name: String) -> Completable { let endPoint = CollectionEndPoint.setCollectionName(id: collectionId, body: SetCollectionRequestBody(name: name)) return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) diff --git a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift b/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift index 9b82c6e6..b0e504e2 100644 --- a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift +++ b/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift @@ -14,6 +14,7 @@ public final class AuthInterceptor: Interceptor { public func adapt(_ request: URLRequest) -> URLRequest { var request = request if case .success(let token) = tokenRepository.fetchToken(type: .accessToken) { + print("accessToken: \(token)") request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") } return request diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/SetBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/SetBookmarkUseCaseImpl.swift index f7d1cb85..0a45e333 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/SetBookmarkUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Bookmark/SetBookmarkUseCaseImpl.swift @@ -9,10 +9,12 @@ public final class SetBookmarkUseCaseImpl: SetBookmarkUseCase { self.repository = repository } - public func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Completable { + public func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Observable { switch isBookmark { case .set(let type): - return repository.setBookmark(bookmarkId: bookmarkId, type: type) + return repository + .setBookmark(bookmarkId: bookmarkId, type: type) + .map { Optional($0) } case .delete: return repository.deleteBookmark(bookmarkId: bookmarkId) } diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemResponse.swift index 5ef9c4ff..bc1f2064 100644 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemResponse.swift @@ -1,5 +1,5 @@ public struct DictionaryDetailItemResponse: Equatable { - public let itemId: Int? + public let itemId: Int public let nameKr: String? public let nameEn: String? public let descriptionText: String? @@ -11,10 +11,10 @@ public struct DictionaryDetailItemResponse: Equatable { public let requiredStats: RequiredStats? // 요구 스탯 public let equipmentStats: EquipmentStats? // 착용하면 올라가는 스탯 public let scrollDetail: ScrollDetail? // 주문서 상세정보 - public let bookmarkId: Int? + public var bookmarkId: Int? public init( - itemId: Int?, + itemId: Int, nameKr: String?, nameEn: String?, descriptionText: String?, diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapResponse.swift index 8449d2d8..71881911 100644 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapResponse.swift @@ -1,5 +1,5 @@ public struct DictionaryDetailMapResponse: Equatable { - public let mapId: Int? + public let mapId: Int public let nameKr: String? public let nameEn: String? public let regionName: String? @@ -7,9 +7,9 @@ public struct DictionaryDetailMapResponse: Equatable { public let topRegionName: String? public let mapUrl: String? public let iconUrl: String? - public let bookmarkId: Int? + public var bookmarkId: Int? - public init(mapId: Int?, nameKr: String?, nameEn: String?, regionName: String?, detailName: String?, topRegionName: String?, mapUrl: String?, iconUrl: String?, bookmarkId: Int?) { + public init(mapId: Int, nameKr: String?, nameEn: String?, regionName: String?, detailName: String?, topRegionName: String?, mapUrl: String?, iconUrl: String?, bookmarkId: Int?) { self.mapId = mapId self.nameKr = nameKr self.nameEn = nameEn diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterResponse.swift index 751f1b17..90ced802 100644 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterResponse.swift @@ -19,7 +19,7 @@ public struct DictionaryDetailMonsterResponse: Equatable { public let mesoDropAmount: Int? public let mesoDropRate: Int? public let typeEffectiveness: Effectiveness? - public let bookmarkId: Int? + public var bookmarkId: Int? public init( monsterId: Int, diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcResponse.swift index 3c7cf79f..02962f19 100644 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcResponse.swift @@ -3,7 +3,7 @@ public struct DictionaryDetailNpcResponse: Equatable { public let nameKr: String public let nameEn: String public let iconUrlDetail: String? - public let bookmarkId: Int? + public var bookmarkId: Int? public init(npcId: Int, nameKr: String, nameEn: String, iconUrlDetail: String?, bookmarkId: Int?) { self.npcId = npcId diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestResponse.swift index 753fbc21..6c065792 100644 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestResponse.swift @@ -1,5 +1,5 @@ public struct DictionaryDetailQuestResponse: Equatable { - public let questId: Int? + public let questId: Int public let titlePrefix: String? public let nameKr: String? public let nameEn: String? @@ -16,10 +16,10 @@ public struct DictionaryDetailQuestResponse: Equatable { public let rewardItems: [RewardItem]? public let requirements: [Requirements]? public let allowedJobs: [AllowedJob]? - public let bookmarkId: Int? + public var bookmarkId: Int? public init( - questId: Int?, + questId: Int, titlePrefix: String?, nameKr: String?, nameEn: String?, diff --git a/MLS/Domain/DomainInterface/Repository/BookmarkRepository.swift b/MLS/Domain/DomainInterface/Repository/BookmarkRepository.swift index e1b7d1a7..7730602d 100644 --- a/MLS/Domain/DomainInterface/Repository/BookmarkRepository.swift +++ b/MLS/Domain/DomainInterface/Repository/BookmarkRepository.swift @@ -3,9 +3,9 @@ import Foundation import RxSwift public protocol BookmarkRepository { - func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Completable + func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Observable - func deleteBookmark(bookmarkId: Int) -> Completable + func deleteBookmark(bookmarkId: Int) -> Observable func fetchBookmark(sort: String?) -> Observable<[BookmarkResponse]> diff --git a/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift index ecdf7645..b4e646e6 100644 --- a/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift +++ b/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift @@ -10,10 +10,6 @@ public protocol CollectionAPIRepository { // 컬렉션 상세 조회 func fetchCollectionUseCase(id: Int) -> Observable<[BookmarkResponse]> -// func addBookmarksToCollection(collectionId: Int, bookmarkIds: [Int]) -> Completable - -// func addCollectionsToBookmark(bookmarkId: Int, collectionIds: [Int]) -> Completable - func setCollectionName(collectionId: Int, name: String) -> Completable func deleteCollection(collectionId: Int) -> Completable diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/SetBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/SetBookmarkUseCase.swift index e1180e62..94117213 100644 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/SetBookmarkUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/Bookmark/SetBookmarkUseCase.swift @@ -1,7 +1,7 @@ import RxSwift public protocol SetBookmarkUseCase { - func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Completable + func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Observable } public enum IsBookmark { diff --git a/MLS/MLS/Application/SceneDelegate.swift b/MLS/MLS/Application/SceneDelegate.swift index 7e183d01..5e0d0292 100644 --- a/MLS/MLS/Application/SceneDelegate.swift +++ b/MLS/MLS/Application/SceneDelegate.swift @@ -46,6 +46,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { switch fetchResult { case .success(let refreshToken): + print("refreshToken: \(refreshToken)") reissueUseCase.execute(refreshToken: refreshToken) .observe(on: MainScheduler.instance) .subscribe( diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/SceneDelegate.swift b/MLS/Presentation/AuthFeature/AuthFeatureDemo/SceneDelegate.swift index 228440bb..e4fcd4d6 100644 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/SceneDelegate.swift +++ b/MLS/Presentation/AuthFeature/AuthFeatureDemo/SceneDelegate.swift @@ -12,27 +12,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(windowScene: windowScene) window?.rootViewController = UINavigationController(rootViewController: ViewController()) window?.makeKeyAndVisible() - -// checkNotificationPermission() } -// -// private func checkNotificationPermission() { -// UNUserNotificationCenter.current().getNotificationSettings { settings in -// switch settings.authorizationStatus { -// case .notDetermined: -// UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, error in -// if let error = error { -// print(error) -// return -// } -// } -// case .denied, .authorized, .provisional, .ephemeral: -// print(settings.authorizationStatus) -// @unknown default: -// break -// } -// } -// } func sceneDidDisconnect(_ scene: UIScene) {} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift index 6b508860..8f5f87f5 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift @@ -15,6 +15,14 @@ public final class BookmarkListReactor: Reactor { case edit } + public enum UIEvent { + case none + case add(BookmarkResponse) + case delete(BookmarkResponse) + case undo + case login + } + enum ViewState: Equatable { case loginWithData case loginWithoutData @@ -24,7 +32,7 @@ public final class BookmarkListReactor: Reactor { // MARK: - Action public enum Action { case viewWillAppear - case toggleBookmark(Int, Bool) + case toggleBookmark(Int) case sortButtonTapped case filterButtonTapped case editButtonTapped @@ -35,6 +43,7 @@ public final class BookmarkListReactor: Reactor { case dataTapped(Int) case emptyButtonTapped case itemFilterOptionSelected([(String, String)]) + case showLogin } // MARK: - Mutation @@ -47,10 +56,12 @@ public final class BookmarkListReactor: Reactor { case toNavagate(Route) case setJobId([Int]) case setCategoryId([Int]) + case setEvent(UIEvent) } // MARK: - State public struct State { + @Pulse var uiEvent: UIEvent = .none @Pulse var route: Route var items: [BookmarkResponse] = [] var type: DictionaryType @@ -130,21 +141,8 @@ public final class BookmarkListReactor: Reactor { } } - case let .toggleBookmark(id, isSelected): - guard let bookmarkItem = currentState.items.first(where: { $0.originalId == id }) else { return .empty() } - - let saveDeletedMutation: Observable = - isSelected ? .just(.setLastDeletedBookmark(bookmarkItem)) - : .just(.setLastDeletedBookmark(nil)) - - return saveDeletedMutation - .concat( - setBookmarkUseCase.execute( - bookmarkId: isSelected ? bookmarkItem.bookmarkId : id, - isBookmark: isSelected ? .delete : .set(bookmarkItem.type) - ) - .andThen(fetchList()) - ) + case let .toggleBookmark(id): + return handleTogle(id: id) case .sortButtonTapped: return .just(.toNavagate(.sort(currentState.type))) @@ -169,17 +167,8 @@ public final class BookmarkListReactor: Reactor { ]) case .undoLastDeletedBookmark: - guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: lastDeleted.originalId, - isBookmark: .set(lastDeleted.type) - ) - .andThen( - Observable.concat([ - fetchList(), - .just(.setLastDeletedBookmark(nil)) - ]) - ) + return handleUndo() + case let .dataTapped(index): let item = currentState.items[index] guard let type = item.type.toDictionaryType else { return .empty() } @@ -204,6 +193,8 @@ public final class BookmarkListReactor: Reactor { guard let self = self else { return .empty() } return self.fetchList() }) + case .showLogin: + return .just(.setEvent(.login)) } } @@ -270,8 +261,52 @@ public final class BookmarkListReactor: Reactor { newState.jobId = ids case let .setCategoryId(ids): newState.categoryIds = ids + case let .setEvent(event): + newState.uiEvent = event } return newState } } + +private extension BookmarkListReactor { + func handleTogle(id: Int) -> Observable { + guard let index = currentState.items.firstIndex(where: { $0.originalId == id }) else { + return .empty() + } + + let targetItem = currentState.items[index] + + return setBookmarkUseCase.execute(bookmarkId: targetItem.bookmarkId, isBookmark: .delete) + .flatMap { _ -> Observable in + let lastItem = Mutation.setLastDeletedBookmark(targetItem) + + let eventMutation = Mutation.setEvent(.delete(targetItem)) + + return Observable.concat([ + .from([lastItem, eventMutation]), + self.fetchList() + ]) + } + } + + func handleUndo() -> Observable { + guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: lastDeleted.originalId, + isBookmark: .set(lastDeleted.type) + ) + .flatMap { _ -> Observable in + let lastItem = Mutation.setLastDeletedBookmark(nil) + + let event: UIEvent = .add(lastDeleted) + let eventMutation = Mutation.setEvent(event) + + return Observable.concat([ + .from([lastItem, eventMutation]), + self.fetchList() + ]) + } + } +} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift index 41116200..0b899ef6 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift @@ -5,6 +5,7 @@ import BaseFeature import BookmarkFeatureInterface import DesignSystem import DictionaryFeatureInterface +import DomainInterface import ReactorKit import RxCocoa @@ -16,8 +17,8 @@ public final class BookmarkListViewController: BaseViewController, View { // MARK: - Properties public var disposeBag = DisposeBag() - private let bookmarkChangeRelay = PublishRelay<(Int, Bool)>() - private var undoRelay = PublishRelay() + private let bookmarkChangeRelay = PublishRelay<(id: Int, newBookmarkId: Int?)>() + private var undoRelay = PublishRelay() private var addCollectionRelay = PublishRelay() private let itemFilterFactory: ItemFilterBottomSheetFactory @@ -184,7 +185,7 @@ extension BookmarkListViewController { break } case .detail(let type, let id): - let viewcontroller = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkChangeRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) + let viewcontroller = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkChangeRelay, loginRelay: nil) owner.navigationController?.pushViewController(viewcontroller, animated: true) case .login: let viewcontroller = owner.loginFactory.make(exitRoute: .pop) @@ -214,45 +215,89 @@ extension BookmarkListViewController { }) .disposed(by: disposeBag) - bookmarkChangeRelay - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, bookmarkData in - let (id, isBookmarked) = bookmarkData - owner.reactor?.action.onNext(.toggleBookmark(id, isBookmarked)) - }) - .disposed(by: disposeBag) - - undoRelay + rx.viewDidAppear + .take(1) + .flatMapLatest { _ in reactor.pulse(\.$uiEvent) } .withUnretained(self) - .subscribe(onNext: { owner, _ in - owner.reactor?.action.onNext(.undoLastDeletedBookmark) + .subscribe(onNext: { owner, event in + switch event { + case .add(let item): + owner.presentAddSnackBar(item: item) + case .delete(let item): + owner.presentDeleteSnackBar(item: item) + case .login: + owner.presentLoginGuide() + default: + break + } }) .disposed(by: disposeBag) + } - addCollectionRelay - .withUnretained(self) - .subscribe(onNext: { owner, originId in - let items = reactor.currentState.items - guard let index = items.firstIndex(where: { $0.originalId == originId }) else { return } - let bookmarkId = items[index].bookmarkId - let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in - if isAdd { - ToastFactory.createToast( - message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." - ) + private func presentAddSnackBar(item: BookmarkResponse) { + SnackBarFactory.createSnackBar( + type: .normal, + imageUrl: item.imageUrl, + imageBackgroundColor: item.type.backgroundColor, + text: "아이템을 북마크에 추가했어요.", + buttonText: "컬렉션 추가", + buttonAction: { [weak self] in + self?.reactor?.state.map(\.items) + .compactMap { items in + items.first(where: { $0.originalId == item.originalId })?.bookmarkId } - } - vc.modalPresentationStyle = .pageSheet - if let sheet = vc.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 - } - owner.present(vc, animated: true) - }) - .disposed(by: disposeBag) + .take(1) + .observe(on: MainScheduler.instance) + .subscribe(onNext: { [weak self] bookmarkId in + guard let self else { return } + let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in + if isAdd { + ToastFactory.createToast( + message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." + ) + } + } + vc.modalPresentationStyle = .pageSheet + if let sheet = vc.sheetPresentationController { + sheet.detents = [.medium(), .large()] + sheet.prefersGrabberVisible = true + sheet.preferredCornerRadius = 16 + } + self.present(vc, animated: true) + }) + .disposed(by: self?.disposeBag ?? DisposeBag()) + } + ) + } + + private func presentDeleteSnackBar(item: BookmarkResponse) { + SnackBarFactory.createSnackBar( + type: .delete, + imageUrl: item.imageUrl, + imageBackgroundColor: item.type.backgroundColor, + text: "아이템을 북마크에서 삭제했어요.", + buttonText: "되돌리기", + buttonAction: { [weak self] in + self?.undoRelay.accept(()) + self?.reactor?.action.onNext(.undoLastDeletedBookmark) + } + ) } + + private func presentLoginGuide() { + GuideAlertFactory.show( + mainText: "북마크를 하려면 로그인이 필요해요.", + ctaText: "로그인 하기", + cancelText: "취소", + ctaAction: { [weak self] in + guard let self else { return } + let vc = self.loginFactory.make(exitRoute: .pop) + self.navigationController?.pushViewController(vc, animated: true) + }, + cancelAction: nil + ) + } + } // MARK: - Delegate @@ -289,35 +334,12 @@ extension BookmarkListViewController: UICollectionViewDelegate, UICollectionView collectionView: collectionView, isMap: item.type == .map, onBookmarkTapped: { [weak self] isSelected in - guard let self = self else { return } - - // 로그인 상태 확인 + guard let self else { return } guard state.isLogin else { - GuideAlertFactory.show( - mainText: "북마크를 하려면 로그인이 필요해요.", - ctaText: "로그인 하기", - cancelText: "취소", - ctaAction: { - let viewController = self.loginFactory.make(exitRoute: .pop) - self.navigationController?.pushViewController(viewController, animated: true) - }, - cancelAction: nil - ) + self.reactor?.action.onNext(.showLogin) return } - - self.reactor?.action.onNext(.toggleBookmark(item.originalId, isSelected)) - - SnackBarFactory.createSnackBar( - type: .delete, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에서 삭제했어요.", - buttonText: "되돌리기", - buttonAction: { [weak self] in - self?.reactor?.action.onNext(.undoLastDeletedBookmark) - } - ) + self.reactor?.action.onNext(.toggleBookmark(item.originalId)) } ) diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift index 1df67134..397b4b37 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift @@ -73,13 +73,14 @@ public final class CollectionDetailReactor: Reactor { : .just(.setLastDeletedBookmark(nil)) return saveDeletedMutation - .concat( - setBookmarkUseCase.execute( - bookmarkId: isSelected ? bookmarkItem.bookmarkId : id, - isBookmark: isSelected ? .delete : .set(bookmarkItem.type) - ) - .andThen(fetchCollectionUseCase.execute(id: currentState.collection.collectionId).map { .setItems($0) }) - ) +// .concat( +// setBookmarkUseCase.execute( +// bookmarkId: isSelected ? bookmarkItem.bookmarkId : id, +// isBookmark: isSelected ? .delete : .set(bookmarkItem.type) +// ) +// .andThen(fetchCollectionUseCase.execute(id: currentState.collection.collectionId).map { .setItems($0) }) +// ) + return .empty() case .backButtonTapped: return .just(.navigateTo(.dismiss)) case .editButtonTapped: @@ -96,21 +97,22 @@ public final class CollectionDetailReactor: Reactor { case .changeName(let name): return .just(.setName(name)) case .undoLastDeletedBookmark: - guard let lastDeleted = currentState.lastDeletedBookmark, - let lastDeletedBookmarkId = currentState.lastDeletedBookmark?.bookmarkId else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: lastDeleted.originalId, - isBookmark: .set(lastDeleted.type) - ) - // 북마크 다시 설정시 이전 collection을 전부 추적해야하고 새로 바뀐 북마크ID가 필요하여 현재는 원할하게 동작하지 않음 - .andThen(addCollectionAndBookmarkUseCase.execute(collectionIds: [currentState.collection.collectionId], bookmarkIds: [lastDeletedBookmarkId])) - .andThen( - Observable.concat([ - fetchCollectionUseCase.execute(id: currentState.collection.collectionId) - .map { .setItems($0) }, - .just(.setLastDeletedBookmark(nil)) - ]) - ) +// guard let lastDeleted = currentState.lastDeletedBookmark, +// let lastDeletedBookmarkId = currentState.lastDeletedBookmark?.bookmarkId else { return .empty() } +// return setBookmarkUseCase.execute( +// bookmarkId: lastDeleted.originalId, +// isBookmark: .set(lastDeleted.type) +// ) +// // 북마크 다시 설정시 이전 collection을 전부 추적해야하고 새로 바뀐 북마크ID가 필요하여 현재는 원할하게 동작하지 않음 +// .andThen(addCollectionAndBookmarkUseCase.execute(collectionIds: [currentState.collection.collectionId], bookmarkIds: [lastDeletedBookmarkId])) +// .andThen( +// Observable.concat([ +// fetchCollectionUseCase.execute(id: currentState.collection.collectionId) +// .map { .setItems($0) }, +// .just(.setLastDeletedBookmark(nil)) +// ]) +// ) + return .empty() case .dataTapped(let index): let item = currentState.collection.recentBookmarks[index] guard let type = item.type.toDictionaryType else { return .empty() } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift index 0c2211d9..1c9ead1e 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift @@ -16,8 +16,6 @@ public final class CollectionDetailViewController: BaseViewController, View { // MARK: - Properties public var disposeBag = DisposeBag() - private var undoRelay = PublishRelay() - private let bookmarkModalFactory: BookmarkModalFactory private let collectionSettingFactory: CollectionSettingFactory private let addCollectionFactory: AddCollectionFactory @@ -199,19 +197,13 @@ extension CollectionDetailViewController { }) owner.presentModal(viewController) case .detail(let type, let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: nil, undoRelay: self.undoRelay, addCollectionRelay: nil) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: nil, loginRelay: nil) owner.navigationController?.pushViewController(viewController, animated: true) default: break } } .disposed(by: disposeBag) - - undoRelay - .subscribe(onNext: { [weak self] _ in - self?.reactor?.action.onNext(.undoLastDeletedBookmark) - }) - .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift index b00517af..f1175a4b 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift @@ -16,8 +16,6 @@ public final class CollectionListViewController: BaseViewController, View { public var disposeBag = DisposeBag() private var selectedSortIndex = 0 -// public var onDismissWithMessage: ((CollectionResponse?) -> Void)? - private let addCollectionFactory: AddCollectionFactory private let detailFactory: CollectionDetailFactory private let sortedBottomSheetFactory: SortedBottomSheetFactory diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index f16db0cc..a4892ce2 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -16,9 +16,8 @@ class DictionaryDetailBaseViewController: BaseViewController { private var didSelectInitialTab = false var selectedIndex = 0 - var bookmarkRelay: PublishRelay<(Int, Bool)>? - var undoRelay: PublishRelay? - var addCollectionRelay: PublishRelay? + var bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>? + var loginRelay: PublishRelay? /// 각 탭에 해당하는 콘텐츠 뷰들을 담는 배열 public var contentViews: [UIView] = [] { @@ -32,8 +31,8 @@ class DictionaryDetailBaseViewController: BaseViewController { /// 현재 보여지고 있는 뷰의 인덱스 private var currentTabIndex: Int? - private let bookmarkModalFactory: BookmarkModalFactory - private let loginFactory: LoginFactory + let bookmarkModalFactory: BookmarkModalFactory + let loginFactory: LoginFactory public let dictionaryDetailFactory: DictionaryDetailFactory private let detailOnBoardingFactory: DetailOnBoardingFactory private let appCoordinator: AppCoordinatorProtocol @@ -54,9 +53,8 @@ class DictionaryDetailBaseViewController: BaseViewController { detailOnBoardingFactory: DetailOnBoardingFactory, appCoordinator: AppCoordinatorProtocol, fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase, - bookmarkRelay: PublishRelay<(Int, Bool)>?, - undoRelay: PublishRelay?, - addCollectionRelay: PublishRelay? + bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>?, + loginRelay: PublishRelay? ) { self.type = type self.bookmarkModalFactory = bookmarkModalFactory @@ -67,8 +65,7 @@ class DictionaryDetailBaseViewController: BaseViewController { self.fetchVisitDictionaryDetailUseCase = fetchVisitDictionaryDetailUseCase mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) self.bookmarkRelay = bookmarkRelay - self.undoRelay = undoRelay - self.addCollectionRelay = addCollectionRelay + self.loginRelay = loginRelay super.init() } @@ -96,6 +93,18 @@ class DictionaryDetailBaseViewController: BaseViewController { didSelectInitialTab = true } } + + open func toggleBookmark() { + assertionFailure("Subclass should override toggleBookmark()") + } + + open func checkLogin() -> Bool? { + return nil + } + + open func undoBookmark() { + assertionFailure("Subclass should override undoBookmark()") + } } // MARK: - SetUp @@ -271,157 +280,6 @@ extension DictionaryDetailBaseViewController { currentTabIndex = index } -// func bindBookmarkButton( -// buttonTap: ControlEvent, -// currentItem: Observable, -// isLogin: @escaping () -> Bool, -// id: @escaping (T) -> Int, -// imageUrl: @escaping (T) -> String?, -// backgroundColor: UIColor, -// isBookmarked: @escaping (T) -> Bool, -// undoLastDeleted: @escaping () -> Void, -// bookmarkId: Observable -// ) -> Disposable { -// buttonTap -// .withLatestFrom(Observable.combineLatest(currentItem, bookmarkId)) -// .observe(on: MainScheduler.instance) -// .bind { [weak self] item, bookmarkId in -// guard let self else { return } -// guard isLogin() else { -// GuideAlertFactory.show( -// mainText: "북마크를 하려면 로그인이 필요해요.", -// ctaText: "로그인 하기", -// cancelText: "취소", -// ctaAction: { -// let viewController = self.loginFactory.make(exitRoute: .pop) -// self.navigationController?.pushViewController(viewController, animated: true) -// }, -// cancelAction: nil -// ) -// return -// } -// -// let itemId = id(item) -// -// if isBookmarked(item) { -// mainView.setBookmark(isBookmarked: false) -// self.bookmarkRelay?.accept((itemId, true)) -// SnackBarFactory.createSnackBar( -// type: .delete, -// imageUrl: imageUrl(item), -// imageBackgroundColor: backgroundColor, -// text: "아이템을 북마크에서 삭제했어요.", -// buttonText: "되돌리기", -// buttonAction: { [weak self] in -// self?.mainView.setBookmark(isBookmarked: true) -// undoLastDeleted() -// } -// ) -// } else { -// mainView.setBookmark(isBookmarked: true) -// self.bookmarkRelay?.accept((itemId, false)) -// SnackBarFactory.createSnackBar( -// type: .normal, -// imageUrl: imageUrl(item), -// imageBackgroundColor: backgroundColor, -// text: "아이템을 북마크에 추가했어요.", -// buttonText: "컬렉션 추가", -// buttonAction: { [weak self] in -// guard let self, -// let id = bookmarkId else { return } -// let viewController = self.bookmarkModalFactory.make(bookmarkIds: [id], onComplete: { isAdd in -// if isAdd { -// DispatchQueue.main.async { -// ToastFactory.createToast( -// message: -// "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." -// ) -// } -// } -// }) -// -// viewController.modalPresentationStyle = .pageSheet -// if let sheet = viewController.sheetPresentationController { -// sheet.detents = [.medium(), .large()] -// sheet.prefersGrabberVisible = true -// sheet.preferredCornerRadius = 16 -// } -// self.present(viewController, animated: true) -// } -// ) -// } -// } -// } - - func bindBookmarkButton( - buttonTap: ControlEvent, - currentItem: Observable, - isLogin: @escaping () -> Bool, - id: @escaping (T) -> Int, - imageUrl: @escaping (T) -> String?, - backgroundColor: UIColor, - isBookmarked: @escaping (T) -> Bool, -// undoLastDeleted: @escaping () -> Void, - bookmarkId: Observable - ) -> Disposable { - buttonTap - .withLatestFrom(Observable.combineLatest(currentItem, bookmarkId)) - .observe(on: MainScheduler.instance) - .bind { [weak self] item, _ in - guard let self else { return } - guard isLogin() else { - GuideAlertFactory.show( - mainText: "북마크를 하려면 로그인이 필요해요.", - ctaText: "로그인 하기", - cancelText: "취소", - ctaAction: { - let vc = self.loginFactory.make(exitRoute: .pop) - self.navigationController?.pushViewController(vc, animated: true) - }, - cancelAction: nil - ) - return - } - - let itemId = id(item) - - let currentlyBookmarked = self.mainView.bookmarkButton.isSelected - - if currentlyBookmarked { - // 🔹 북마크 해제 - mainView.setBookmark(isBookmarked: false) - self.bookmarkRelay?.accept((itemId, true)) - SnackBarFactory.createSnackBar( - type: .delete, - imageUrl: imageUrl(item), - imageBackgroundColor: backgroundColor, - text: "아이템을 북마크에서 삭제했어요.", - buttonText: "되돌리기", - buttonAction: { - self.mainView.setBookmark(isBookmarked: true) - self.undoRelay?.accept(itemId) - } - ) - } else { - mainView.setBookmark(isBookmarked: true) - self.bookmarkRelay?.accept((itemId, false)) - SnackBarFactory.createSnackBar( - type: .normal, - imageUrl: imageUrl(item), - imageBackgroundColor: backgroundColor, - text: "아이템을 북마크에 추가했어요.", - buttonText: "", - buttonAction: {} - // 임시 비활성화 -// buttonText: "컬렉션 추가", -// buttonAction: { -// self.addCollectionRelay?.accept(itemId) -// } - ) - } - } - } - func checkVisited() { fetchVisitDictionaryDetailUseCase.execute() .withUnretained(self) @@ -459,6 +317,13 @@ private extension DictionaryDetailBaseViewController { owner.appCoordinator.showMainTab() } .disposed(by: disposeBag) + + mainView.bookmarkButton.rx.tap + .withUnretained(self) + .subscribe(onNext: { owner, _ in + owner.handleBookmarkTapped() + }) + .disposed(by: disposeBag) } } @@ -485,3 +350,75 @@ extension DictionaryDetailBaseViewController { .disposed(by: disposeBag) } } + +extension DictionaryDetailBaseViewController { + func handleBookmarkTapped() { + guard let isLogin = checkLogin() else { return } + + if !isLogin { + presentLoginGuide() + loginRelay?.accept(()) + return + } + + toggleBookmark() + } +} + +extension DictionaryDetailBaseViewController { + func presentAddSnackBar(bookmarkId: Int?, imageUrl: String?, background: UIColor) { + guard let bookmarkId else { return } + SnackBarFactory.createSnackBar( + type: .normal, + imageUrl: imageUrl, + imageBackgroundColor: background, + text: "아이템을 북마크에 추가했어요.", + buttonText: "컬렉션 추가", + buttonAction: { [weak self] in + self?.presentCollectionModal(bookmarkId: bookmarkId) + } + ) + } + + func presentDeleteSnackBar(imageUrl: String?, background: UIColor) { + SnackBarFactory.createSnackBar( + type: .delete, + imageUrl: imageUrl, + imageBackgroundColor: background, + text: "아이템을 북마크에서 삭제했어요.", + buttonText: "되돌리기", + buttonAction: { [weak self] in + self?.undoBookmark() + } + ) + } + + private func presentCollectionModal(bookmarkId: Int) { + let viewController = bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in + if isAdd { + ToastFactory.createToast(message: "컬렉션에 추가되었어요.") + } + } + viewController.modalPresentationStyle = .pageSheet + if let sheet = viewController.sheetPresentationController { + sheet.detents = [.medium(), .large()] + sheet.prefersGrabberVisible = true + sheet.preferredCornerRadius = 16 + } + self.present(viewController, animated: true) + } + + func presentLoginGuide() { + GuideAlertFactory.show( + mainText: "북마크를 하려면 로그인이 필요해요.", + ctaText: "로그인 하기", + cancelText: "취소", + ctaAction: { [weak self] in + guard let self else { return } + let vc = self.loginFactory.make(exitRoute: .pop) + self.navigationController?.pushViewController(vc, animated: true) + }, + cancelAction: nil + ) + } +} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift index d8428c8d..c0f1a578 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift @@ -77,7 +77,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { self.fetchVisitDictionaryDetailUseCase = fetchVisitDictionaryDetailUseCase } - public func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(Int, Bool)>?, undoRelay: PublishRelay?, addCollectionRelay: PublishRelay?) -> BaseViewController { + public func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>?, loginRelay: PublishRelay?) -> BaseViewController { var viewController = BaseViewController() switch type { case .total: @@ -93,8 +93,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, bookmarkRelay: bookmarkRelay, - undoRelay: undoRelay, - addCollectionRelay: addCollectionRelay + loginRelay: loginRelay ) let reactor = ItemDictionaryDetailReactor( dictionaryDetailItemUseCase: dictionaryDetailItemUseCase, @@ -115,8 +114,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, bookmarkRelay: bookmarkRelay, - undoRelay: undoRelay, - addCollectionRelay: addCollectionRelay + loginRelay: loginRelay ) let reactor = MonsterDictionaryDetailReactor( dictionaryDetailMonsterUseCase: dictionaryDetailMonsterUseCase, @@ -138,8 +136,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, bookmarkRelay: bookmarkRelay, - undoRelay: undoRelay, - addCollectionRelay: addCollectionRelay + loginRelay: loginRelay ) let reactor = MapDictionaryDetailReactor( dictionaryDetailMapUseCase: dictionaryDetailMapUseCase, @@ -161,8 +158,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, bookmarkRelay: bookmarkRelay, - undoRelay: undoRelay, - addCollectionRelay: addCollectionRelay + loginRelay: loginRelay ) let reactor = NpcDictionaryDetailReactor( dictionaryDetailNpcUseCase: dictionaryDetailNpcUseCase, @@ -184,8 +180,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, bookmarkRelay: bookmarkRelay, - undoRelay: undoRelay, - addCollectionRelay: addCollectionRelay + loginRelay: loginRelay ) let reactor = QuestDictionaryDetailReactor( dictionaryDetailQuestUseCase: dictionaryDetailQuestUseCase, diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift index 9eece2b5..d95364e8 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift @@ -10,13 +10,20 @@ public final class ItemDictionaryDetailReactor: Reactor { case filter(DictionaryType) case detail(Int) } + + public enum UIEvent { + case none + case add(DictionaryDetailItemResponse) + case delete(DictionaryDetailItemResponse) + case undo + } // MARK: Action public enum Action { case filterButtonTapped case viewWillAppear case selectFilter(SortType) - case toggleBookmark(Bool) + case toggleBookmark case undoLastDeletedBookmark case dataTapped(index: Int) } @@ -26,20 +33,19 @@ public final class ItemDictionaryDetailReactor: Reactor { case toNavigate(Route) case setDetailData(DictionaryDetailItemResponse) case setDetailDropMonsterData([DictionaryDetailItemDropMonsterResponse]) - case setBookmark(DictionaryDetailItemResponse) - case setLastDeletedBookmark(DictionaryDetailItemResponse?) case setLoginState(Bool) + case setEvent(UIEvent) } // MARK: State public struct State { + @Pulse var event: UIEvent = .none @Pulse var route: Route = .none var itemDetailInfo: DictionaryDetailItemResponse var type: DictionaryType = .item var monsters: [DictionaryDetailItemDropMonsterResponse] var id: Int var isLogin = false - var lastDeletedBookmark: DictionaryDetailItemResponse? } public var initialState: State @@ -64,7 +70,7 @@ public final class ItemDictionaryDetailReactor: Reactor { self.setBookmarkUseCase = setBookmarkUseCase self.initialState = .init( itemDetailInfo: DictionaryDetailItemResponse( - itemId: nil, nameKr: nil, nameEn: nil, descriptionText: nil, + itemId: 0, nameKr: nil, nameEn: nil, descriptionText: nil, imgUrl: nil, npcPrice: nil, itemType: nil, categoryHierachy: nil, availableJobs: nil, requiredStats: nil, equipmentStats: nil, scrollDetail: nil, bookmarkId: nil @@ -89,38 +95,12 @@ public final class ItemDictionaryDetailReactor: Reactor { case let .selectFilter(type): return dictionaryDetailItemDropMonsterUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailDropMonsterData($0) } - case let .toggleBookmark(isSelected): - guard let itemId = currentState.itemDetailInfo.itemId else { return .empty() } - - let saveDeleted: Observable = isSelected - ? .just(.setLastDeletedBookmark(currentState.itemDetailInfo)) - : .just(.setLastDeletedBookmark(nil)) - - return saveDeleted.concat( - setBookmarkUseCase.execute( - bookmarkId: currentState.itemDetailInfo.bookmarkId ?? itemId, - isBookmark: isSelected ? .delete : .set(.item) - ) - .andThen( - dictionaryDetailItemUseCase.execute(id: currentState.id) - .map { .setDetailData($0) } - ) - ) + case .toggleBookmark: + return handleToggleBookmark() + case .undoLastDeletedBookmark: - guard let lastDeleted = currentState.lastDeletedBookmark, - let itemId = lastDeleted.itemId else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: itemId, - isBookmark: .set(.item) - ) - .andThen( - Observable.concat([ - dictionaryDetailItemUseCase.execute(id: currentState.id) - .map { .setDetailData($0) }, - .just(.setLastDeletedBookmark(nil)) - ]) - ) + return handleUndoLastDeletedBookmark() + case .dataTapped(let index): guard let id = currentState.monsters[index].monsterId else { return .empty() } return .just(.toNavigate(.detail(id))) @@ -135,15 +115,58 @@ public final class ItemDictionaryDetailReactor: Reactor { newState.itemDetailInfo = data case let .setDetailDropMonsterData(data): newState.monsters = data - case let .setBookmark(item): - newState.itemDetailInfo = item - case let .setLastDeletedBookmark(item): - newState.lastDeletedBookmark = item case let .setLoginState(isLogin): newState.isLogin = isLogin case .toNavigate(let route): newState.route = route + case let .setEvent(event): + newState.event = event } return newState } } + +private extension ItemDictionaryDetailReactor { + func handleToggleBookmark() -> Observable { + var item = currentState.itemDetailInfo + let isSelected = item.bookmarkId != nil + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: isSelected ? item.bookmarkId ?? item.itemId : item.itemId, + isBookmark: isSelected ? .delete : .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + item.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(item) : .add(item) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailItemUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } + + func handleUndoLastDeletedBookmark() -> Observable { + var item = currentState.itemDetailInfo + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: item.itemId, + isBookmark: .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + item.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(item))) + let refresh = self.dictionaryDetailItemUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } +} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index 129387b0..c1143237 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -14,6 +14,19 @@ final class ItemDictionaryDetailViewController: DictionaryDetailBaseViewControll private let detailInfoView = DetailStackInfoView(type: .item) private let monsterCardView = DetailStackCardView() private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() + + override func toggleBookmark() { + reactor?.action.onNext(.toggleBookmark) + } + + override func checkLogin() -> Bool { + guard let reactor = reactor else { return false } + return reactor.currentState.isLogin + } + + override func undoBookmark() { + reactor?.action.onNext(.undoLastDeletedBookmark) + } } // MARK: - Populate Data @@ -161,7 +174,7 @@ extension ItemDictionaryDetailViewController { bindUserAction(reactor: reactor) bindViewState(reactor: reactor) bindReportButton( - providerId: reactor.state.map { $0.itemDetailInfo.itemId ?? 0 }, + providerId: reactor.state.map { $0.itemDetailInfo.itemId }, itemName: reactor.state.map { $0.itemDetailInfo.nameKr ?? "" } ) } @@ -210,7 +223,7 @@ extension ItemDictionaryDetailViewController { .withUnretained(self) .subscribe { owner, route in switch route { - case .filter(let type): + case let .filter(type): guard let option = type.detailTypes.first else { return } let viewController = owner.sortedFactory.make(sortedOptions: option.sortFilter, selectedIndex: owner.selectedIndex) { index in owner.selectedIndex = index @@ -221,25 +234,33 @@ extension ItemDictionaryDetailViewController { owner.tabBarController?.presentModal(viewController, hideTabBar: true) case .none: break - case .detail(let id): - let viewController = owner.dictionaryDetailFactory.make(type: .monster, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) + case let .detail(id): + let viewController = owner.dictionaryDetailFactory.make(type: .monster, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) } } .disposed(by: disposeBag) - bindBookmarkButton( - buttonTap: mainView.bookmarkButton.rx.tap, - currentItem: reactor.state.map { $0.itemDetailInfo }, - isLogin: { reactor.currentState.isLogin }, - id: { _ in reactor.currentState.itemDetailInfo.itemId ?? 0 }, - imageUrl: { $0.imgUrl }, - backgroundColor: type.backgroundColor, - isBookmarked: { $0.bookmarkId != nil }, -// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, - bookmarkId: reactor.state.map(\.itemDetailInfo.bookmarkId) - ) - .disposed(by: disposeBag) + reactor.pulse(\.$event) + .bind(onNext: { [weak self] event in + switch event { + case let .add(item): + self?.presentAddSnackBar( + bookmarkId: item.bookmarkId, + imageUrl: item.imgUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.itemId, item.bookmarkId)) + case let .delete(item): + self?.presentDeleteSnackBar( + imageUrl: item.imgUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.itemId, item.bookmarkId)) + default: break + } + }) + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift index cc0a12b1..63f7b1c8 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift @@ -9,10 +9,18 @@ public final class MapDictionaryDetailReactor: Reactor { case filter([SortType]) case detail(type: DictionaryType, id: Int) } + + public enum UIEvent { + case none + case add(DictionaryDetailMapResponse) + case delete(DictionaryDetailMapResponse) + case undo + } + public enum Action { case monsterFilterButtonTapped case viewWillAppear - case toggleBookmark(Bool) + case toggleBookmark case undoLastDeletedBookmark case monsterTapped(index: Int) case npcTapped(index: Int) @@ -27,6 +35,7 @@ public final class MapDictionaryDetailReactor: Reactor { case setBookmark(DictionaryDetailMapResponse) case setLastDeletedBookmark(DictionaryDetailMapResponse?) case setLoginState(Bool) + case setEvent(UIEvent) } public let dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase @@ -36,6 +45,7 @@ public final class MapDictionaryDetailReactor: Reactor { private let setBookmarkUseCase: SetBookmarkUseCase public struct State { + @Pulse var event: UIEvent = .none @Pulse var route: Route = .none var mapDetailInfo: DictionaryDetailMapResponse var spawnMonsters: [DictionaryDetailMapSpawnMonsterResponse] @@ -62,7 +72,7 @@ public final class MapDictionaryDetailReactor: Reactor { ) { initialState = State( mapDetailInfo: DictionaryDetailMapResponse( - mapId: nil, + mapId: 0, nameKr: nil, nameEn: nil, regionName: nil, @@ -96,42 +106,18 @@ public final class MapDictionaryDetailReactor: Reactor { dictionaryDetailMapSpawnMonsterUseCase.execute(id: currentState.id, sort: nil).map {.setDetailSpawnMonsters($0)}, dictionaryDetailMapNpcUseCase.execute(id: currentState.id).map {.setDetailNpc($0)} ]) - case let .toggleBookmark(isSelected): - guard let itemId = currentState.mapDetailInfo.mapId else { return .empty() } - - let saveDeleted: Observable = isSelected - ? .just(.setLastDeletedBookmark(currentState.mapDetailInfo)) - : .just(.setLastDeletedBookmark(nil)) - - return saveDeleted.concat( - setBookmarkUseCase.execute( - bookmarkId: currentState.mapDetailInfo.bookmarkId ?? itemId, - isBookmark: isSelected ? .delete : .set(.map) - ) - .andThen( - dictionaryDetailMapUseCase.execute(id: currentState.id) - .map { .setDetailData($0) } - ) - ) + case .toggleBookmark: + return handleToggleBookmark() + + case .undoLastDeletedBookmark: + return handleUndoLastDeletedBookmark() + case let .selectFilter(type): return dictionaryDetailMapSpawnMonsterUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailSpawnMonsters($0) } - case .undoLastDeletedBookmark: - guard let lastDeleted = currentState.lastDeletedBookmark, - let mapId = lastDeleted.mapId else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: mapId, - isBookmark: .set(.map) - ) - .andThen( - Observable.concat([ - dictionaryDetailMapUseCase.execute(id: currentState.id) - .map { .setDetailData($0) }, - .just(.setLastDeletedBookmark(nil)) - ]) - ) + case .monsterTapped(index: let index): guard let id = currentState.spawnMonsters[index].monsterId else { return .empty() } + return .just(.toNavigate(.detail(type: .monster, id: id))) case .npcTapped(index: let index): guard let id = currentState.npcs[index].npcId else { return .empty() } @@ -157,7 +143,54 @@ public final class MapDictionaryDetailReactor: Reactor { newState.lastDeletedBookmark = map case let .setLoginState(isLogin): newState.isLogin = isLogin + case let .setEvent(event): + newState.event = event } return newState } } + +private extension MapDictionaryDetailReactor { + func handleToggleBookmark() -> Observable { + var map = currentState.mapDetailInfo + let isSelected = map.bookmarkId != nil + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: isSelected ? map.bookmarkId ?? map.mapId : map.mapId, + isBookmark: isSelected ? .delete : .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + map.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(map) : .add(map) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailMapUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } + + func handleUndoLastDeletedBookmark() -> Observable { + var map = currentState.mapDetailInfo + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: map.mapId, + isBookmark: .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + map.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(map))) + let refresh = self.dictionaryDetailMapUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } +} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index 3028e8e0..86cdd6e8 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -22,6 +22,19 @@ final class MapDictionaryDetailViewController: DictionaryDetailBaseViewControlle super.viewDidLoad() bindImageView() } + + override func toggleBookmark() { + reactor?.action.onNext(.toggleBookmark) + } + + override func checkLogin() -> Bool { + guard let reactor = reactor else { return false } + return reactor.currentState.isLogin + } + + override func undoBookmark() { + reactor?.action.onNext(.undoLastDeletedBookmark) + } } // MARK: - SetUp @@ -171,19 +184,6 @@ extension MapDictionaryDetailViewController { }) .disposed(by: disposeBag) - bindBookmarkButton( - buttonTap: mainView.bookmarkButton.rx.tap, - currentItem: reactor.state.map { $0.mapDetailInfo }, - isLogin: { reactor.currentState.isLogin }, - id: { _ in reactor.currentState.mapDetailInfo.mapId ?? 0 }, - imageUrl: { $0.mapUrl }, - backgroundColor: type.backgroundColor, - isBookmarked: { $0.bookmarkId != nil }, -// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, - bookmarkId: reactor.state.map(\.mapDetailInfo.bookmarkId) - ) - .disposed(by: disposeBag) - rx.viewDidAppear .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 @@ -201,10 +201,31 @@ extension MapDictionaryDetailViewController { case .none: break case .detail(let type, let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) } } .disposed(by: disposeBag) + + reactor.pulse(\.$event) + .bind(onNext: { [weak self] event in + switch event { + case let .add(item): + self?.presentAddSnackBar( + bookmarkId: item.bookmarkId, + imageUrl: item.iconUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.mapId, item.bookmarkId)) + case let .delete(item): + self?.presentDeleteSnackBar( + imageUrl: item.iconUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.mapId, item.bookmarkId)) + default: break + } + }) + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift index b355a781..0361f006 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift @@ -14,13 +14,20 @@ public final class MonsterDictionaryDetailReactor: Reactor { var name: String var desc: String } + + public enum UIEvent { + case none + case add(DictionaryDetailMonsterResponse) + case delete(DictionaryDetailMonsterResponse) + case undo + } // MARK: - Action public enum Action { case filterButtonTapped(DictionaryType) case viewWillAppear case selectFilter(SortType) - case toggleBookmark(Bool) + case toggleBookmark case undoLastDeletedBookmark case itemTapped(index: Int) case mapTapped(index: Int) @@ -35,10 +42,12 @@ public final class MonsterDictionaryDetailReactor: Reactor { case setBookmark(DictionaryDetailMonsterResponse) case setLastDeletedBookmark(DictionaryDetailMonsterResponse?) case setLoginState(Bool) + case setEvent(UIEvent) } // MARK: - State public struct State { + @Pulse var event: UIEvent = .none @Pulse var route: Route = .none var type: DictionaryType = .monster var id = 0 @@ -108,37 +117,15 @@ public final class MonsterDictionaryDetailReactor: Reactor { case let .selectFilter(type): return dictionaryDetailMonsterDropItemUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailDropItemData($0) } - case let .toggleBookmark(isSelected): - let monsterId = currentState.monsterDetailInfo.monsterId - - let saveDeleted: Observable = isSelected - ? .just(.setLastDeletedBookmark(currentState.monsterDetailInfo)) - : .just(.setLastDeletedBookmark(nil)) - - return saveDeleted.concat( - setBookmarkUseCase.execute( - bookmarkId: currentState.monsterDetailInfo.bookmarkId ?? monsterId, - isBookmark: isSelected ? .delete : .set(.monster) - ) - .andThen(dictionaryDetailMonsterUseCase.execute(id: currentState.id).map { .setDetailData($0) }) - ) + case .toggleBookmark: + return handleToggleBookmark() case .undoLastDeletedBookmark: - guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } - let monsterId = lastDeleted.monsterId - - return setBookmarkUseCase.execute( - bookmarkId: monsterId, - isBookmark: .set(.monster) - ) - .andThen( - Observable.concat([ - dictionaryDetailMonsterUseCase.execute(id: currentState.id).map { .setDetailData($0) }, - .just(.setLastDeletedBookmark(nil)) - ]) - ) + return handleUndoLastDeletedBookmark() + case .itemTapped(index: let index): return .just(.toNavigate(.detail(type: .item, id: currentState.dropItems[index].itemId))) + case .mapTapped(index: let index): return .just(.toNavigate(.detail(type: .map, id: currentState.spawnMaps[index].mapId))) } @@ -177,8 +164,55 @@ public final class MonsterDictionaryDetailReactor: Reactor { case let .setLoginState(isLogin): newState.isLogin = isLogin + case let .setEvent(event): + newState.event = event } return newState } } + +private extension MonsterDictionaryDetailReactor { + func handleToggleBookmark() -> Observable { + var monster = currentState.monsterDetailInfo + let isSelected = monster.bookmarkId != nil + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: isSelected ? monster.bookmarkId ?? monster.monsterId : monster.monsterId, + isBookmark: isSelected ? .delete : .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + monster.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(monster) : .add(monster) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailMonsterUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } + + func handleUndoLastDeletedBookmark() -> Observable { + var monster = currentState.monsterDetailInfo + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: monster.monsterId, + isBookmark: .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + monster.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(monster))) + let refresh = self.dictionaryDetailMonsterUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } +} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift index 285c4d6e..23240769 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift @@ -20,6 +20,19 @@ class MonsterDictionaryDetailViewController: DictionaryDetailBaseViewController, private var appearMapView = DetailStackCardView() private var dropItemView = DetailStackCardView() private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() + + override func toggleBookmark() { + reactor?.action.onNext(.toggleBookmark) + } + + override func checkLogin() -> Bool { + guard let reactor = reactor else { return false } + return reactor.currentState.isLogin + } + + override func undoBookmark() { + reactor?.action.onNext(.undoLastDeletedBookmark) + } } // MARK: - Populate Data @@ -206,7 +219,7 @@ extension MonsterDictionaryDetailViewController { } owner.tabBarController?.presentModal(viewController, hideTabBar: true) case let .detail(type: type, id: id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) default: break @@ -214,17 +227,25 @@ extension MonsterDictionaryDetailViewController { } .disposed(by: disposeBag) - bindBookmarkButton( - buttonTap: mainView.bookmarkButton.rx.tap, - currentItem: reactor.state.map { $0.monsterDetailInfo }, - isLogin: { reactor.currentState.isLogin }, - id: { _ in reactor.currentState.monsterDetailInfo.monsterId }, - imageUrl: { $0.imageUrl }, - backgroundColor: type.backgroundColor, - isBookmarked: { $0.bookmarkId != nil }, -// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, - bookmarkId: reactor.state.map(\.monsterDetailInfo.bookmarkId) - ) - .disposed(by: disposeBag) + reactor.pulse(\.$event) + .bind(onNext: { [weak self] event in + switch event { + case let .add(item): + self?.presentAddSnackBar( + bookmarkId: item.bookmarkId, + imageUrl: item.imageUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.monsterId, item.bookmarkId)) + case let .delete(item): + self?.presentDeleteSnackBar( + imageUrl: item.imageUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.monsterId, item.bookmarkId)) + default: break + } + }) + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift index d643633f..10a8cec2 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift @@ -9,13 +9,20 @@ public final class NpcDictionaryDetailReactor: Reactor { case filter([SortType]) case detail(type: DictionaryType, id: Int) } + + public enum UIEvent { + case none + case add(DictionaryDetailNpcResponse) + case delete(DictionaryDetailNpcResponse) + case undo + } // MARK: - Action public enum Action { case filterButtonTapped case viewWillAppear case selectFilter(SortType) - case toggleBookmark(Bool) + case toggleBookmark case undoLastDeletedBookmark case mapTapped(index: Int) case questTapped(index: Int) @@ -29,10 +36,12 @@ public final class NpcDictionaryDetailReactor: Reactor { case setDetailQuests([DictionaryDetailNpcQuestResponse]) case setLoginState(Bool) case setLastDeletedBookmark(DictionaryDetailNpcResponse?) + case setEvent(UIEvent) } // MARK: - State public struct State { + @Pulse var event: UIEvent = .none @Pulse var route: Route = .none var npcDetailInfo: DictionaryDetailNpcResponse var type: DictionaryType = .npc @@ -95,41 +104,15 @@ public final class NpcDictionaryDetailReactor: Reactor { case let .selectFilter(type): return dictionaryDetailNpcQuestUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailQuests($0) } - case let .toggleBookmark(isSelected): - let npcId = currentState.npcDetailInfo.npcId - - let saveDeleted: Observable = isSelected - ? .just(.setLastDeletedBookmark(currentState.npcDetailInfo)) - : .just(.setLastDeletedBookmark(nil)) - - return saveDeleted.concat( - setBookmarkUseCase.execute( - bookmarkId: currentState.npcDetailInfo.bookmarkId ?? npcId, - isBookmark: isSelected ? .delete : .set(.npc) - ) - .andThen( - dictionaryDetailNpcUseCase.execute(id: currentState.id) - .map { .setDetailData($0) } - ) - ) + case .toggleBookmark: + return handleToggleBookmark() case .undoLastDeletedBookmark: - guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } - let npcId = lastDeleted.npcId - - return setBookmarkUseCase.execute( - bookmarkId: npcId, - isBookmark: .set(.npc) - ) - .andThen( - Observable.concat([ - dictionaryDetailNpcUseCase.execute(id: currentState.id) - .map { .setDetailData($0) }, - .just(.setLastDeletedBookmark(nil)) - ]) - ) + return handleUndoLastDeletedBookmark() + case .mapTapped(index: let index): return .just(.toNavigate(.detail(type: .map, id: currentState.maps[index].mapId))) + case .questTapped(index: let index): return .just(.toNavigate(.detail(type: .quest, id: currentState.quests[index].questId))) } @@ -151,7 +134,54 @@ public final class NpcDictionaryDetailReactor: Reactor { newState.isLogin = isLogin case let .setLastDeletedBookmark(map): newState.lastDeletedBookmark = map + case let .setEvent(event): + newState.event = event } return newState } } + +private extension NpcDictionaryDetailReactor { + func handleToggleBookmark() -> Observable { + var npc = currentState.npcDetailInfo + let isSelected = npc.bookmarkId != nil + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: isSelected ? npc.bookmarkId ?? npc.npcId : npc.npcId, + isBookmark: isSelected ? .delete : .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + npc.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(npc) : .add(npc) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailNpcUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } + + func handleUndoLastDeletedBookmark() -> Observable { + var npc = currentState.npcDetailInfo + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: npc.npcId, + isBookmark: .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + npc.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(npc))) + let refresh = self.dictionaryDetailNpcUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } +} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift index 7bb4ea10..4a886d0e 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift @@ -15,6 +15,19 @@ final class NpcDictionaryDetailViewController: DictionaryDetailBaseViewControlle private var appearMapView = DetailStackCardView() private var questView = DetailStackCardView() private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() + + override func toggleBookmark() { + reactor?.action.onNext(.toggleBookmark) + } + + override func checkLogin() -> Bool { + guard let reactor = reactor else { return false } + return reactor.currentState.isLogin + } + + override func undoBookmark() { + reactor?.action.onNext(.undoLastDeletedBookmark) + } } // MARK: - SetUp @@ -127,7 +140,7 @@ extension NpcDictionaryDetailViewController { } owner.tabBarController?.presentModal(viewController, hideTabBar: true) case .detail(type: let type, id: let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) default: break @@ -163,17 +176,25 @@ extension NpcDictionaryDetailViewController { }) .disposed(by: disposeBag) - bindBookmarkButton( - buttonTap: mainView.bookmarkButton.rx.tap, - currentItem: reactor.state.map { $0.npcDetailInfo }, - isLogin: { reactor.currentState.isLogin }, - id: { _ in reactor.currentState.npcDetailInfo.npcId }, - imageUrl: { $0.iconUrlDetail }, - backgroundColor: type.backgroundColor, - isBookmarked: { $0.bookmarkId != nil }, -// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, - bookmarkId: reactor.state.map(\.npcDetailInfo.bookmarkId) - ) - .disposed(by: disposeBag) + reactor.pulse(\.$event) + .bind(onNext: { [weak self] event in + switch event { + case let .add(item): + self?.presentAddSnackBar( + bookmarkId: item.bookmarkId, + imageUrl: item.iconUrlDetail, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.npcId, item.bookmarkId)) + case let .delete(item): + self?.presentDeleteSnackBar( + imageUrl: item.iconUrlDetail, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.npcId, item.bookmarkId)) + default: break + } + }) + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift index 42a0835f..b75db540 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift @@ -20,9 +20,16 @@ public final class QuestDictionaryDetailReactor: Reactor { case detail(type: DictionaryType, id: Int) } + public enum UIEvent { + case none + case add(DictionaryDetailQuestResponse) + case delete(DictionaryDetailQuestResponse) + case undo + } + public enum Action { case viewWillAppear - case toggleBookmark(Bool) + case toggleBookmark case undoLastDeletedBookmark case questTapped(index: Int) case infoTapped(type: DictionaryType, id: Int) @@ -34,9 +41,11 @@ public final class QuestDictionaryDetailReactor: Reactor { case setLinkedQuests(DictionaryDetailQuestLinkedQuestsResponse) case setLoginState(Bool) case setLastDeletedBookmark(DictionaryDetailQuestResponse?) + case setEvent(UIEvent) } public struct State { + @Pulse var event: UIEvent = .none @Pulse var route: Route = .none var type: DictionaryType = .quest var id: Int @@ -69,7 +78,7 @@ public final class QuestDictionaryDetailReactor: Reactor { self.initialState = .init( id: id, detailInfo: .init( - questId: nil, + questId: 0, titlePrefix: nil, nameKr: nil, nameEn: nil, @@ -101,44 +110,18 @@ public final class QuestDictionaryDetailReactor: Reactor { dictionaryDetailQuestLinkedQuestUseCase.execute(id: currentState.id).map { .setLinkedQuests($0) } ]) - case let .toggleBookmark(isSelected): - guard let questId = currentState.detailInfo.questId else { return .empty() } - - let saveDeleted: Observable = isSelected - ? .just(.setLastDeletedBookmark(currentState.detailInfo)) - : .just(.setLastDeletedBookmark(nil)) - - return saveDeleted.concat( - setBookmarkUseCase.execute( - bookmarkId: currentState.detailInfo.bookmarkId ?? questId, - isBookmark: isSelected ? .delete : .set(.quest) - ) - .andThen( - dictionaryDetailQuestUseCase.execute(id: currentState.id) - .map { .setDetailData($0) } - ) - ) + case .toggleBookmark: + return handleToggleBookmark() case .undoLastDeletedBookmark: - guard let lastDeleted = currentState.lastDeletedBookmark, - let questId = lastDeleted.questId else { return .empty() } + return handleUndoLastDeletedBookmark() - return setBookmarkUseCase.execute( - bookmarkId: questId, - isBookmark: .set(.quest) - ) - .andThen( - Observable.concat([ - dictionaryDetailQuestUseCase.execute(id: currentState.id) - .map { .setDetailData($0) }, - .just(.setLastDeletedBookmark(nil)) - ]) - ) case let .questTapped(index): let tappedQuestInfo = currentState.totalQuest[index] guard let id = tappedQuestInfo.quest.questId, tappedQuestInfo.type != .current else { return .empty() } return .just(.toNavigate(.detail(type: .quest, id: id))) + case let .infoTapped(type: type, id: id): return .just(.toNavigate(.detail(type: type, id: id))) } @@ -165,6 +148,8 @@ public final class QuestDictionaryDetailReactor: Reactor { newState.lastDeletedBookmark = data case let .toNavigate(route): newState.route = route + case let .setEvent(event): + newState.event = event } return newState } @@ -182,16 +167,14 @@ extension QuestDictionaryDetailReactor { quests.append(contentsOf: mapped) } - if let currentId = detailInfo.questId { - let currentQuest = Quest( - questId: currentId, - name: detailInfo.nameKr ?? "", - minLevel: detailInfo.minLevel, - maxLevel: detailInfo.maxLevel, - iconUrl: detailInfo.iconUrl - ) - quests.append(QuestInfo(quest: currentQuest, type: .current)) - } + let currentQuest = Quest( + questId: detailInfo.questId, + name: detailInfo.nameKr ?? "", + minLevel: detailInfo.minLevel, + maxLevel: detailInfo.maxLevel, + iconUrl: detailInfo.iconUrl + ) + quests.append(QuestInfo(quest: currentQuest, type: .current)) if let next = linkedInfo.nextQuests { let mapped = next.map { QuestInfo(quest: $0, type: .next) } @@ -201,3 +184,48 @@ extension QuestDictionaryDetailReactor { return quests } } + +private extension QuestDictionaryDetailReactor { + func handleToggleBookmark() -> Observable { + var quest = currentState.detailInfo + let isSelected = quest.bookmarkId != nil + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: isSelected ? quest.bookmarkId ?? quest.questId : quest.questId, + isBookmark: isSelected ? .delete : .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + quest.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(quest) : .add(quest) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailQuestUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } + + func handleUndoLastDeletedBookmark() -> Observable { + var quest = currentState.detailInfo + guard let type = currentState.type.toItemType else { return .empty() } + + return setBookmarkUseCase.execute( + bookmarkId: quest.questId, + isBookmark: .set(type) + ) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + quest.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(quest))) + let refresh = self.dictionaryDetailQuestUseCase.execute(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + } +} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift index 99f1af1b..6ceaf245 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift @@ -12,6 +12,19 @@ final class QuestDictionaryDetailViewController: DictionaryDetailBaseViewControl // MARK: - Components private var detailInfoView = DetailStackInfoView(type: .quest) private var linkedQuestView = DetailStackCardView() + + override func toggleBookmark() { + reactor?.action.onNext(.toggleBookmark) + } + + override func checkLogin() -> Bool { + guard let reactor = reactor else { return false } + return reactor.currentState.isLogin + } + + override func undoBookmark() { + reactor?.action.onNext(.undoLastDeletedBookmark) + } } // MARK: - Populate Data @@ -142,7 +155,7 @@ extension QuestDictionaryDetailViewController { public func bind(reactor: Reactor) { bindUserAction(reactor: reactor) bindViewState(reactor: reactor) - bindReportButton(providerId: reactor.state.map { $0.detailInfo.questId ?? 0 }, itemName: reactor.state.map { $0.detailInfo.nameKr ?? "" }) + bindReportButton(providerId: reactor.state.map { $0.detailInfo.questId }, itemName: reactor.state.map { $0.detailInfo.nameKr ?? "" }) } private func bindUserAction(reactor: Reactor) { @@ -178,19 +191,6 @@ extension QuestDictionaryDetailViewController { }) .disposed(by: disposeBag) - bindBookmarkButton( - buttonTap: mainView.bookmarkButton.rx.tap, - currentItem: reactor.state.map { $0.detailInfo }, - isLogin: { reactor.currentState.isLogin }, - id: { _ in reactor.currentState.detailInfo.questId ?? 0 }, - imageUrl: { $0.iconUrl }, - backgroundColor: type.backgroundColor, - isBookmarked: { $0.bookmarkId != nil }, -// undoLastDeleted: { reactor.action.onNext(.undoLastDeletedBookmark) }, - bookmarkId: reactor.state.map(\.detailInfo.bookmarkId) - ) - .disposed(by: disposeBag) - rx.viewDidAppear .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } @@ -198,12 +198,33 @@ extension QuestDictionaryDetailViewController { .subscribe { owner, route in switch route { case let .detail(type, id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, undoRelay: owner.undoRelay, addCollectionRelay: owner.addCollectionRelay) + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) default: break } } .disposed(by: disposeBag) + + reactor.pulse(\.$event) + .bind(onNext: { [weak self] event in + switch event { + case let .add(item): + self?.presentAddSnackBar( + bookmarkId: item.bookmarkId, + imageUrl: item.iconUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.questId, item.bookmarkId)) + case let .delete(item): + self?.presentDeleteSnackBar( + imageUrl: item.iconUrl, + background: DictionaryItemType.item.backgroundColor + ) + self?.bookmarkRelay?.accept((item.questId, item.bookmarkId)) + default: break + } + }) + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift index 3de66343..be98e357 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift @@ -5,13 +5,21 @@ import ReactorKit import RxSwift public final class DictionaryListReactor: Reactor { - // MARK: - Route + // MARK: - Type public enum Route { case none case sort(DictionaryType) case filter(DictionaryType) } + public enum UIEvent { + case none + case add(DictionaryMainItemResponse) + case delete(DictionaryMainItemResponse) + case undo + case login + } + // MARK: - Action public enum Action { case viewWillAppear @@ -23,7 +31,9 @@ public final class DictionaryListReactor: Reactor { case setCurrentPage case fetchList case undoLastDeletedBookmark - case toggleBookmark(id: Int, isSelected: Bool) + case toggleBookmark(id: Int) + case showLogin + case updateBookmark(id: Int, newBookmarkId: Int?) } // MARK: - Mutation @@ -39,13 +49,14 @@ public final class DictionaryListReactor: Reactor { case setLastDeletedBookmark(DictionaryMainItemResponse?) case setJobId([Int]) case setCategoryId([Int]) - case updateBookmarkState(id: Int, isSelected: Bool) - case updateBookmarkStates([Int: Bool]) // 새 Mutation: 여러 북마크 반영 + case updateBookmarkId(id: Int, newBookmarkId: Int?) case setFirstFetch(Bool) + case setEvent(UIEvent) } // MARK: - State public struct State { + @Pulse var uiEvent: UIEvent = .none @Pulse var route: Route public var listItems: [DictionaryMainItemResponse] = [] public var type: DictionaryType @@ -126,10 +137,14 @@ public final class DictionaryListReactor: Reactor { return fetchList(sort: currentState.sort, startLevel: currentState.startLevel, endLevel: currentState.endLevel) case .undoLastDeletedBookmark: return handleUndoLastDeletedBookmark() - case let .toggleBookmark(id, isSelected): - return handleToggleBookmark(id: id, isSelected: isSelected) + case let .toggleBookmark(id): + return handleToggleBookmark(id: id) case let .itemFilterOptionSelected(results): return handleItemFilterOptionSelected(results: results) + case .showLogin: + return .just(.setEvent(.login)) + case let .updateBookmark(id, newBookmarkId): + return handleUpdateBookmark(id: id, newBookmarkId: newBookmarkId) } } @@ -148,7 +163,7 @@ public final class DictionaryListReactor: Reactor { newState.listItems = newState.listItems.map { item in if let updated = items.contents.first(where: { $0.id == item.id }) { var copy = item - copy.bookmarkId = updated.bookmarkId ?? item.bookmarkId + copy.bookmarkId = updated.bookmarkId return copy } else { return item } } @@ -178,18 +193,14 @@ public final class DictionaryListReactor: Reactor { newState.jobId = id case let .setCategoryId(id): newState.categoryIds = id - case let .updateBookmarkState(id, isSelected): - if let index = newState.listItems.firstIndex(where: { $0.id == id }) { - newState.listItems[index].bookmarkId = isSelected ? (newState.listItems[index].bookmarkId ?? -1) : nil - } - case let .updateBookmarkStates(dict): - for index in 0 ..< newState.listItems.count { - if let isSelected = dict[newState.listItems[index].id] { - newState.listItems[index].bookmarkId = isSelected ? (newState.listItems[index].bookmarkId ?? -1) : nil - } - } case let .setFirstFetch(isFirstFetch): newState.isFirstFetch = isFirstFetch + case let .updateBookmarkId(id, newBookmarkId): + if let index = newState.listItems.firstIndex(where: { $0.id == id }) { + newState.listItems[index].bookmarkId = newBookmarkId + } + case let .setEvent(event): + newState.uiEvent = event } return newState } @@ -283,39 +294,39 @@ private extension DictionaryListReactor { return .merge([loginState, fetchMutation]) } - func handleToggleBookmark(id: Int, isSelected: Bool) -> Observable { - guard let index = currentState.listItems.firstIndex(where: { $0.id == id }) else { return .empty() } - let targetItem = currentState.listItems[index] - - let optimistic: Observable - - if isSelected { - // 삭제되는 경우, undo를 위해 lastDeletedBookmark 저장 - optimistic = Observable.concat([ - // UI 반영 - .just(.updateBookmarkState(id: id, isSelected: false)), - // undo 저장 - .just(.setLastDeletedBookmark(targetItem)) - ]) - } else { - // 북마크 추가 - optimistic = .just(.updateBookmarkState(id: id, isSelected: true)) + func handleToggleBookmark(id: Int) -> Observable { + guard let index = currentState.listItems.firstIndex(where: { $0.id == id }) else { + return .empty() } - // 서버 호출 + bookmark 확정 - let api = setBookmarkUseCase.execute( + let targetItem = currentState.listItems[index] + let isSelected = targetItem.bookmarkId != nil + + return setBookmarkUseCase.execute( bookmarkId: isSelected ? targetItem.bookmarkId ?? targetItem.id : targetItem.id, isBookmark: isSelected ? .delete : .set(targetItem.type) ) - .andThen(fetchList( - sort: currentState.sort, - startLevel: currentState.startLevel, - endLevel: currentState.endLevel, - updateBookmarkOnly: true - )) - .observe(on: MainScheduler.asyncInstance) - - return .concat([optimistic, api]) + .flatMap { newBookmarkId -> Observable in + let lastItem = Mutation.setLastDeletedBookmark(targetItem) + + let event: UIEvent = isSelected ? .delete(targetItem) : .add(targetItem) + let eventMutation = Mutation.setEvent(event) + + let updateMutation = Mutation.updateBookmarkId(id: id, newBookmarkId: newBookmarkId) + return .from([lastItem, updateMutation, eventMutation]) + } + } + + func handleUpdateBookmark(id: Int, newBookmarkId: Int?) -> Observable { + guard let index = currentState.listItems.firstIndex(where: { $0.id == id }) else { + return .empty() + } + + guard currentState.listItems[index].bookmarkId != newBookmarkId else { + return .empty() + } + + return .just(.updateBookmarkId(id: id, newBookmarkId: newBookmarkId)) } func handleSortOptionSelected(sort: SortType) -> Observable { @@ -343,17 +354,19 @@ private extension DictionaryListReactor { func handleUndoLastDeletedBookmark() -> Observable { guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } - let optimistic = Observable.just(Mutation.updateBookmarkState(id: lastDeleted.id, isSelected: true)) - .observe(on: MainScheduler.asyncInstance) - - let apiCall = setBookmarkUseCase.execute( + return setBookmarkUseCase.execute( bookmarkId: lastDeleted.id, isBookmark: .set(lastDeleted.type) ) - .andThen(Observable.just(Mutation.setLastDeletedBookmark(nil))) - .observe(on: MainScheduler.asyncInstance) + .flatMap { newBookmarkId -> Observable in + let lastItem = Mutation.setLastDeletedBookmark(nil) + + let event: UIEvent = .add(lastDeleted) + let eventMutation = Mutation.setEvent(event) - return .concat([optimistic, apiCall]) + let updateMutation = Mutation.updateBookmarkId(id: lastDeleted.id, newBookmarkId: newBookmarkId) + return .from([lastItem, updateMutation, eventMutation]) + } } func handleItemFilterOptionSelected(results: [(String, String)]) -> Observable { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index c21bd03f..5515f0ab 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -23,9 +23,8 @@ public final class DictionaryListViewController: BaseViewController, View { private var selectedSortIndex = 0 public let itemCountRelay = PublishRelay() - private let bookmarkChangeRelay = PublishRelay<(Int, Bool)>() - private var undoRelay = PublishRelay() - private var addCollectionRelay = PublishRelay() + private let bookmarkChangeRelay = PublishRelay<(id: Int, newBookmarkId: Int?)>() + private var loginRelay = PublishRelay() private var lastPagingTime: Date = .distantPast // MARK: - Components @@ -121,51 +120,72 @@ extension DictionaryListViewController { } func bindViewState(reactor: Reactor) { + bindItemCount(reactor: reactor) + bindLifecycle(reactor: reactor) + bindRoute(reactor: reactor) + bindTypeChanges(reactor: reactor) + bindBookmarkChange() + bindListItems() + bindUIEvents(reactor: reactor) + } + + // MARK: - Sub-binds + + private func bindItemCount(reactor: Reactor) { reactor.state .map { $0.totalCounts } .distinctUntilChanged() .bind(to: itemCountRelay) .disposed(by: disposeBag) + } + private func bindLifecycle(reactor: Reactor) { rx.viewWillAppear .map { _ in Reactor.Action.viewWillAppear } .bind(to: reactor.action) .disposed(by: disposeBag) + } + private func bindRoute(reactor: Reactor) { rx.viewDidAppear .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } .withUnretained(self) - .subscribe { owner, route in + .subscribe(onNext: { owner, route in switch route { case .sort(let type): let viewController = owner.sortedFactory.make( sortedOptions: type.bookmarkSortedFilter, selectedIndex: owner.selectedSortIndex - ) { index in - owner.selectedSortIndex = index + ) { [weak self, weak reactor] index in + guard let self, let reactor else { return } + self.selectedSortIndex = index let selectedFilter = reactor.currentState.type.bookmarkSortedFilter[index] reactor.action.onNext(.sortOptionSelected(selectedFilter)) - owner.mainView.selectSort(selectedType: selectedFilter) + self.mainView.selectSort(selectedType: selectedFilter) } owner.tabBarController?.presentModal(viewController) case .filter(let type): switch type { case .item: - let viewController = owner.itemFilterFactory.make { results in + let viewController = owner.itemFilterFactory.make { [weak self, weak reactor] results in + guard let self, let reactor else { return } reactor.action.onNext(.itemFilterOptionSelected(results)) if results.isEmpty { - owner.mainView.resetFilter() + self.mainView.resetFilter() } else { - owner.mainView.selectFilter() + self.mainView.selectFilter() } } owner.present(viewController, animated: true) case .monster: - let viewController = owner.monsterFilterFactory.make(startLevel: reactor.currentState.startLevel ?? 0, endLevel: reactor.currentState.endLevel ?? 200) { startLevel, endLevel in - owner.mainView.selectFilter() - reactor.action.onNext(.filterOptionSelected(startLevel: startLevel, endLevel: endLevel)) + let viewController = owner.monsterFilterFactory.make( + startLevel: reactor.currentState.startLevel ?? 0, + endLevel: reactor.currentState.endLevel ?? 200 + ) { [weak self, weak reactor] startLevel, endLevel in + self?.mainView.selectFilter() + reactor?.action.onNext(.filterOptionSelected(startLevel: startLevel, endLevel: endLevel)) } owner.tabBarController?.presentModal(viewController) default: @@ -174,9 +194,11 @@ extension DictionaryListViewController { default: break } - } + }) .disposed(by: disposeBag) + } + private func bindTypeChanges(reactor: Reactor) { reactor.state .map(\.type) .distinctUntilChanged() @@ -185,77 +207,138 @@ extension DictionaryListViewController { owner.mainView.updateFilter(sortType: type.sortedFilter.first) }) .disposed(by: disposeBag) + } + private func bindBookmarkChange() { bookmarkChangeRelay .withUnretained(self) .observe(on: MainScheduler.instance) - .bind(onNext: { owner, bookmarkData in - let (id, isBookmarked) = bookmarkData - owner.reactor?.action.onNext(.toggleBookmark(id: id, isSelected: isBookmarked)) + .bind(onNext: { owner, bookmarkResult in + let (id, newBookmarkId) = bookmarkResult + owner.reactor?.action.onNext(.updateBookmark(id: id, newBookmarkId: newBookmarkId)) }) .disposed(by: disposeBag) + } - undoRelay + private func bindListItems() { + reactor?.state.map(\.listItems) .withUnretained(self) - .subscribe(onNext: { owner, _ in - owner.reactor?.action.onNext(.undoLastDeletedBookmark) - }) + .observe(on: MainScheduler.instance) + .bind { owner, items in + owner.updateCollectionView(items: items) + } .disposed(by: disposeBag) + } - addCollectionRelay + private func bindUIEvents(reactor: Reactor) { + rx.viewDidAppear + .take(1) + .flatMapLatest { _ in reactor.pulse(\.$uiEvent) } .withUnretained(self) - .subscribe(onNext: { owner, originId in - let items = reactor.currentState.listItems - guard let index = items.firstIndex(where: { $0.id == originId }), - let bookmarkId = items[index].bookmarkId else { return } - let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in - if isAdd { - ToastFactory.createToast( - message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." - ) - } - } - vc.modalPresentationStyle = .pageSheet - if let sheet = vc.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 + .subscribe(onNext: { owner, event in + switch event { + case .add(let item): + owner.presentAddSnackBar(item: item) + case .delete(let item): + owner.presentDeleteSnackBar(item: item) + case .login: + owner.presentLoginGuide() + default: + break } - owner.present(vc, animated: true) }) .disposed(by: disposeBag) + } - reactor.state.map(\.listItems) - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind { owner, items in - let collectionView = owner.mainView.listCollectionView - owner.mainView.checkEmptyData(isEmpty: items.isEmpty) - - guard let reactor = owner.reactor else { return } - if reactor.currentState.currentPage == 0, !reactor.currentState.isBookmarkUpdateOnly { - collectionView.reloadData() - } else { - let startIndex = collectionView.numberOfItems(inSection: 0) - let endIndex = items.count - if endIndex > startIndex { - let indexPaths = (startIndex ..< endIndex).map { IndexPath(item: $0, section: 0) } - collectionView.performBatchUpdates { - collectionView.insertItems(at: indexPaths) - } + private func presentAddSnackBar(item: DictionaryMainItemResponse) { + SnackBarFactory.createSnackBar( + type: .normal, + imageUrl: item.imageUrl, + imageBackgroundColor: item.type.backgroundColor, + text: "아이템을 북마크에 추가했어요.", + buttonText: "컬렉션 추가", + buttonAction: { [weak self] in + self?.reactor?.state.map(\.listItems) + .compactMap { list in + list.first(where: { $0.id == item.id })?.bookmarkId } - - for cell in collectionView.visibleCells { - if let indexPath = collectionView.indexPath(for: cell), - indexPath.item < items.count, - let cell = cell as? DictionaryListCell { - let item = items[indexPath.item] - cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) + .take(1) + .observe(on: MainScheduler.instance) + .subscribe(onNext: { [weak self] bookmarkId in + guard let self else { return } + let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in + if isAdd { + ToastFactory.createToast( + message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." + ) + } } - } + vc.modalPresentationStyle = .pageSheet + if let sheet = vc.sheetPresentationController { + sheet.detents = [.medium(), .large()] + sheet.prefersGrabberVisible = true + sheet.preferredCornerRadius = 16 + } + self.present(vc, animated: true) + }) + .disposed(by: self?.disposeBag ?? DisposeBag()) + } + ) + } + + private func presentDeleteSnackBar(item: DictionaryMainItemResponse) { + SnackBarFactory.createSnackBar( + type: .delete, + imageUrl: item.imageUrl, + imageBackgroundColor: item.type.backgroundColor, + text: "아이템을 북마크에서 삭제했어요.", + buttonText: "되돌리기", + buttonAction: { [weak self] in + self?.reactor?.action.onNext(.undoLastDeletedBookmark) + } + ) + } + + private func presentLoginGuide() { + GuideAlertFactory.show( + mainText: "북마크를 하려면 로그인이 필요해요.", + ctaText: "로그인 하기", + cancelText: "취소", + ctaAction: { [weak self] in + guard let self else { return } + let vc = self.loginFactory.make(exitRoute: .pop) + self.navigationController?.pushViewController(vc, animated: true) + }, + cancelAction: nil + ) + } + + private func updateCollectionView(items: [DictionaryMainItemResponse]) { + let collectionView = mainView.listCollectionView + mainView.checkEmptyData(isEmpty: items.isEmpty) + + guard let reactor = reactor else { return } + if reactor.currentState.currentPage == 0, !reactor.currentState.isBookmarkUpdateOnly { + collectionView.reloadData() + } else { + let startIndex = collectionView.numberOfItems(inSection: 0) + let endIndex = items.count + if endIndex > startIndex { + let indexPaths = (startIndex ..< endIndex).map { IndexPath(item: $0, section: 0) } + collectionView.performBatchUpdates { + collectionView.insertItems(at: indexPaths) } } - .disposed(by: disposeBag) + + for cell in collectionView.visibleCells { + if let indexPath = collectionView.indexPath(for: cell), + indexPath.item < items.count, + let cell = cell as? DictionaryListCell { + let item = items[indexPath.item] + cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) + } + } + } } } @@ -284,70 +367,13 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi indexPath: indexPath, collectionView: collectionView, isMap: item.type == .map, - onBookmarkTapped: { [weak self] isSelected in - guard let self = self else { return } - + onBookmarkTapped: { [weak self] _ in + guard let self else { return } guard state.isLogin else { - GuideAlertFactory.show( - mainText: "북마크를 하려면 로그인이 필요해요.", - ctaText: "로그인 하기", - cancelText: "취소", - ctaAction: { - let vc = self.loginFactory.make(exitRoute: .pop) - self.navigationController?.pushViewController(vc, animated: true) - }, - cancelAction: nil - ) + self.reactor?.action.onNext(.showLogin) return } - - self.reactor?.action.onNext(.toggleBookmark(id: item.id, isSelected: isSelected)) - - if isSelected { - SnackBarFactory.createSnackBar( - type: .delete, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에서 삭제했어요.", - buttonText: "되돌리기", - buttonAction: { [weak self] in - self?.reactor?.action.onNext(.undoLastDeletedBookmark) - } - ) - } else { - SnackBarFactory.createSnackBar( - type: .normal, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에 추가했어요.", - buttonText: "컬렉션 추가", - buttonAction: { - self.reactor?.state.map(\.listItems) - .compactMap { list in - list.first(where: { $0.id == item.id })?.bookmarkId - } - .take(1) - .observe(on: MainScheduler.instance) - .subscribe(onNext: { bookmarkId in - let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in - if isAdd { - ToastFactory.createToast( - message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." - ) - } - } - vc.modalPresentationStyle = .pageSheet - if let sheet = vc.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 - } - self.present(vc, animated: true) - }) - .disposed(by: self.disposeBag) - } - ) - } + self.reactor?.action.onNext(.toggleBookmark(id: item.id)) } ) @@ -364,12 +390,11 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi switch reactor.currentState.type { case .total: guard let type = item.type.toDictionaryType else { return } - viewController = detailFactory.make(type: type, id: item.id, bookmarkRelay: bookmarkChangeRelay, undoRelay: undoRelay, addCollectionRelay: addCollectionRelay) + viewController = detailFactory.make(type: type, id: item.id, bookmarkRelay: bookmarkChangeRelay, loginRelay: loginRelay) default: // 단일 타입일 경우 리액터 타입에 따라 처리 viewController = detailFactory.make( - type: reactor.currentState.type, id: item.id, bookmarkRelay: bookmarkChangeRelay, undoRelay: undoRelay, addCollectionRelay: addCollectionRelay - ) + type: reactor.currentState.type, id: item.id, bookmarkRelay: bookmarkChangeRelay, loginRelay: loginRelay) } navigationController?.pushViewController(viewController, animated: true) } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift index fb654c37..562bfe32 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift @@ -4,5 +4,5 @@ import DomainInterface import RxCocoa public protocol DictionaryDetailFactory { - func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(Int, Bool)>?, undoRelay: PublishRelay?, addCollectionRelay: PublishRelay?) -> BaseViewController + func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>?, loginRelay: PublishRelay?) -> BaseViewController } From c99d7c432c828fe775809f149d8442355de3e478 Mon Sep 17 00:00:00 2001 From: p2glet Date: Thu, 18 Dec 2025 01:40:37 +0900 Subject: [PATCH 23/31] =?UTF-8?q?fix/#273:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=EC=8B=9C=20refreshToken=20/=20FCMToken=EB=8F=84=20?= =?UTF-8?q?=ED=95=A8=EA=BB=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthAPI/LogoutUseCaseImpl.swift | 21 ++++++++++++++----- .../DictionaryMainViewController.swift | 1 - 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LogoutUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LogoutUseCaseImpl.swift index ad8f2054..0ece074f 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LogoutUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LogoutUseCaseImpl.swift @@ -18,13 +18,24 @@ public class LogoutUseCaseImpl: LogoutUseCase { return Disposables.create() } - switch self.repository.deleteToken(type: .accessToken) { - case .success: - completable(.completed) - case .failure(let error): - completable(.error(error)) + let deleteAccess = self.repository.deleteToken(type: .accessToken) + let deleteRefresh = self.repository.deleteToken(type: .refreshToken) + + guard case .success = deleteAccess, case .success = deleteRefresh else { + completable(.error(NSError(domain: "LogoutError", code: -1, userInfo: nil))) + return Disposables.create() + } + + var fcmToken: String? + if case .success(let token) = self.repository.fetchToken(type: .fcmToken) { + fcmToken = token + } + + if fcmToken != nil { + _ = self.repository.deleteToken(type: .fcmToken) } + completable(.completed) return Disposables.create() } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewController.swift index c4c1a01c..c7abe68b 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewController.swift @@ -17,7 +17,6 @@ public final class DictionaryMainViewController: BaseViewController, View, Dicti public var disposeBag = DisposeBag() private let initialIndex: Int -// private lazy var currentPageIndex = BehaviorRelay(value: initialIndex) private let searchFactory: DictionarySearchFactory private let notificationFactory: DictionaryNotificationFactory From ee3e86dffdac00dc4c43ec90b80f2792e1ea87a1 Mon Sep 17 00:00:00 2001 From: p2glet Date: Thu, 18 Dec 2025 03:10:58 +0900 Subject: [PATCH 24/31] =?UTF-8?q?fix/#273:=20POST=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=EC=8B=9C=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20(Toast=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Endpoints/CollectionEndPoint.swift | 18 --------------- .../CollectionAPIRepositoryImpl.swift | 2 +- .../AddBookmarksToCollectionUseCaseImpl.swift | 15 ------------ .../AddCollectionsToBookmarkUseCaseImpl.swift | 14 ----------- ...wift => UpdateCollectionUseCaseImpl.swift} | 4 ++-- .../Repository/CollectionAPIRepository.swift | 2 +- ...se.swift => UpdateCollectionUseCase.swift} | 2 +- MLS/MLS/Application/AppDelegate.swift | 6 ++--- .../AddCollectionFactoryImpl.swift | 4 ++-- .../AddCollection/AddCollectionReactor.swift | 12 ++++++++-- .../AddCollectionViewController.swift | 4 ++++ .../BookmarkList/BookmarkListReactor.swift | 23 ++++++++++++------- .../BookmarkListViewController.swift | 3 +++ .../BookmarkModal/BookmarkModalReactor.swift | 14 +++++++---- .../BookmarkModalViewController.swift | 2 ++ .../DictionaryDetailBaseViewController.swift | 2 +- .../Item/ItemDictionaryDetailReactor.swift | 17 ++++++++++---- .../ItemDictionaryDetailViewController.swift | 7 ++++-- .../Map/MapDictionaryDetailReactor.swift | 17 ++++++++++---- .../MapDictionaryDetailViewController.swift | 7 ++++-- .../MonsterDictionaryDetailReactor.swift | 17 ++++++++++---- ...onsterDictionaryDetailViewController.swift | 8 +++++-- .../NPC/NpcDictionaryDetailReactor.swift | 17 ++++++++++---- .../NpcDictionaryDetailViewController.swift | 4 ++++ .../Quest/QuestDictionaryDetailReactor.swift | 15 ++++++++---- .../QuestDictionaryDetailViewController.swift | 4 ++++ .../DictionaryListReactor.swift | 20 +++++++++------- .../DictionaryListViewController.swift | 9 ++++++-- 28 files changed, 156 insertions(+), 113 deletions(-) delete mode 100644 MLS/Domain/Domain/UseCaseImpl/Collection/AddBookmarksToCollectionUseCaseImpl.swift delete mode 100644 MLS/Domain/Domain/UseCaseImpl/Collection/AddCollectionsToBookmarkUseCaseImpl.swift rename MLS/Domain/Domain/UseCaseImpl/Collection/{SetCollectionUseCaseImpl.swift => UpdateCollectionUseCaseImpl.swift} (62%) rename MLS/Domain/DomainInterface/UseCase/Collection/{SetCollectionUseCase.swift => UpdateCollectionUseCase.swift} (66%) diff --git a/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift b/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift index 5d2a22b2..2d87de65 100644 --- a/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift +++ b/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift @@ -24,24 +24,6 @@ public enum CollectionEndPoint { ) } - public static func addBookmarksToCollection(id: Int, body: Encodable) -> EndPoint { - .init( - baseURL: base, - path: "/api/v1/collections/\(id)/bookmarks", - method: .POST, - body: body - ) - } - - public static func addCollectionsToBookmark(id: Int, body: Encodable) -> EndPoint { - .init( - baseURL: base, - path: "/api/v1/bookmarks/\(id)/collections", - method: .POST, - body: body - ) - } - public static func setCollectionName(id: Int, body: Encodable) -> EndPoint { .init( baseURL: base, diff --git a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift index a6417fb9..e3f7ad2a 100644 --- a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift @@ -31,7 +31,7 @@ public class CollectionAPIRepositoryImpl: CollectionAPIRepository { .map { $0.toDomain() } } - public func setCollectionName(collectionId: Int, name: String) -> Completable { + public func updateCollectionName(collectionId: Int, name: String) -> Completable { let endPoint = CollectionEndPoint.setCollectionName(id: collectionId, body: SetCollectionRequestBody(name: name)) return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) } diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/AddBookmarksToCollectionUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/AddBookmarksToCollectionUseCaseImpl.swift deleted file mode 100644 index ea42c345..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/AddBookmarksToCollectionUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -// import DomainInterface -// -// import RxSwift -// -// public final class AddBookmarksToCollectionUseCaseImpl: AddBookmarksToCollectionUseCase { -// private let repository: CollectionAPIRepository -// -// public init(repository: CollectionAPIRepository) { -// self.repository = repository -// } -// -// public func execute(collectionId: Int, bookmarkIds: [Int]) -> Completable { -// return repository.addBookmarksToCollection(collectionId: collectionId, bookmarkIds: bookmarkIds) -// } -// } diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/AddCollectionsToBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/AddCollectionsToBookmarkUseCaseImpl.swift deleted file mode 100644 index f1ea702a..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/AddCollectionsToBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -// import DomainInterface -// import RxSwift -// -// public final class AddCollectionsToBookmarkUseCaseImpl: AddCollectionsToBookmarkUseCase { -// private let repository: CollectionAPIRepository -// -// public init(repository: CollectionAPIRepository) { -// self.repository = repository -// } -// -// public func execute(bookmarkId: Int, collectionIds: [Int]) -> Completable { -// return repository.addCollectionsToBookmark(bookmarkId: bookmarkId, collectionIds: collectionIds) -// } -// } diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/SetCollectionUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/UpdateCollectionUseCaseImpl.swift similarity index 62% rename from MLS/Domain/Domain/UseCaseImpl/Collection/SetCollectionUseCaseImpl.swift rename to MLS/Domain/Domain/UseCaseImpl/Collection/UpdateCollectionUseCaseImpl.swift index 7e9912ac..f8dc3727 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/SetCollectionUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Collection/UpdateCollectionUseCaseImpl.swift @@ -2,7 +2,7 @@ import DomainInterface import RxSwift -public final class SetCollectionUseCaseImpl: SetCollectionUseCase { +public final class UpdateCollectionUseCaseImpl: UpdateCollectionUseCase { private let repository: CollectionAPIRepository public init(repository: CollectionAPIRepository) { @@ -10,6 +10,6 @@ public final class SetCollectionUseCaseImpl: SetCollectionUseCase { } public func execute(collectionId: Int, name: String) -> Completable { - return repository.setCollectionName(collectionId: collectionId, name: name) + return repository.updateCollectionName(collectionId: collectionId, name: name) } } diff --git a/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift index b4e646e6..a6033351 100644 --- a/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift +++ b/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift @@ -10,7 +10,7 @@ public protocol CollectionAPIRepository { // 컬렉션 상세 조회 func fetchCollectionUseCase(id: Int) -> Observable<[BookmarkResponse]> - func setCollectionName(collectionId: Int, name: String) -> Completable + func updateCollectionName(collectionId: Int, name: String) -> Completable func deleteCollection(collectionId: Int) -> Completable diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/SetCollectionUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/UpdateCollectionUseCase.swift similarity index 66% rename from MLS/Domain/DomainInterface/UseCase/Collection/SetCollectionUseCase.swift rename to MLS/Domain/DomainInterface/UseCase/Collection/UpdateCollectionUseCase.swift index 39cea79d..efeb3308 100644 --- a/MLS/Domain/DomainInterface/UseCase/Collection/SetCollectionUseCase.swift +++ b/MLS/Domain/DomainInterface/UseCase/Collection/UpdateCollectionUseCase.swift @@ -1,5 +1,5 @@ import RxSwift -public protocol SetCollectionUseCase { +public protocol UpdateCollectionUseCase { func execute(collectionId: Int, name: String) -> Completable } diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index faf03bfb..909c3fae 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -656,8 +656,8 @@ private extension AppDelegate { ) ) } - DIContainer.register(type: SetCollectionUseCase.self) { - SetCollectionUseCaseImpl( + DIContainer.register(type: UpdateCollectionUseCase.self) { + UpdateCollectionUseCaseImpl( repository: DIContainer.resolve( type: CollectionAPIRepository.self ) @@ -705,7 +705,7 @@ private extension AppDelegate { type: CreateCollectionListUseCase.self ), setCollectionUseCase: DIContainer.resolve( - type: SetCollectionUseCase.self + type: UpdateCollectionUseCase.self ) ) } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionFactoryImpl.swift index d261c38b..dd6e1a8f 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionFactoryImpl.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionFactoryImpl.swift @@ -4,9 +4,9 @@ import DomainInterface public final class AddCollectionFactoryImpl: AddCollectionFactory { private let createCollectionListUseCase: CreateCollectionListUseCase - private let setCollectionUseCase: SetCollectionUseCase + private let setCollectionUseCase: UpdateCollectionUseCase - public init(createCollectionListUseCase: CreateCollectionListUseCase, setCollectionUseCase: SetCollectionUseCase) { + public init(createCollectionListUseCase: CreateCollectionListUseCase, setCollectionUseCase: UpdateCollectionUseCase) { self.createCollectionListUseCase = createCollectionListUseCase self.setCollectionUseCase = setCollectionUseCase } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift index 4f2cd581..e15aafb1 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift @@ -8,6 +8,8 @@ public final class AddCollectionModalReactor: Reactor { public enum Route { case dismiss case dismissWithData + case createError + case updateError } // MARK: - Action @@ -38,10 +40,10 @@ public final class AddCollectionModalReactor: Reactor { public var initialState = State(collection: nil) private let createCollectionListUseCase: CreateCollectionListUseCase - private let setCollectionUseCase: SetCollectionUseCase + private let setCollectionUseCase: UpdateCollectionUseCase // MARK: - Init - public init(collection: CollectionResponse?, createCollectionListUseCase: CreateCollectionListUseCase, setCollectionUseCase: SetCollectionUseCase) { + public init(collection: CollectionResponse?, createCollectionListUseCase: CreateCollectionListUseCase, setCollectionUseCase: UpdateCollectionUseCase) { self.initialState = State(collection: collection, inputText: collection?.name) self.createCollectionListUseCase = createCollectionListUseCase self.setCollectionUseCase = setCollectionUseCase @@ -71,6 +73,9 @@ public final class AddCollectionModalReactor: Reactor { if currentState.collection == nil { return createCollectionListUseCase.execute(name: trimmed) .andThen(.just(.toNavigate(.dismissWithData))) + .catch { error in + return .just(.toNavigate(.createError)) + } } else { guard let id = currentState.collection?.collectionId else { return .empty() } return setCollectionUseCase.execute( @@ -78,6 +83,9 @@ public final class AddCollectionModalReactor: Reactor { name: trimmed ) .andThen(.just(.toNavigate(.dismissWithData))) + .catch { error in + return .just(.toNavigate(.updateError)) + } } } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionViewController.swift index 91f3f2e3..fd32d227 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionViewController.swift @@ -183,6 +183,10 @@ extension AddCollectionViewController { owner.dismissWithAnimation(withData: true) { owner.dismiss(animated: false) } + case .updateError: + ToastFactory.createToast(message: "컬렉션 수정에 실패했어요. 다시 시도해주세요.") + case .createError: + ToastFactory.createToast(message: "컬렉션 생성에 실패했어요. 다시 시도해주세요.") default: break } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift index 8f5f87f5..38e19e26 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift @@ -13,6 +13,7 @@ public final class BookmarkListReactor: Reactor { case dictionary case login case edit + case bookmarkError } public enum UIEvent { @@ -53,7 +54,7 @@ public final class BookmarkListReactor: Reactor { case setSort(SortType) case setFilter(start: Int?, end: Int?) case setLastDeletedBookmark(BookmarkResponse?) - case toNavagate(Route) + case navigatTo(Route) case setJobId([Int]) case setCategoryId([Int]) case setEvent(UIEvent) @@ -145,10 +146,10 @@ public final class BookmarkListReactor: Reactor { return handleTogle(id: id) case .sortButtonTapped: - return .just(.toNavagate(.sort(currentState.type))) + return .just(.navigatTo(.sort(currentState.type))) case .filterButtonTapped: - return .just(.toNavagate(.filter(currentState.type))) + return .just(.navigatTo(.filter(currentState.type))) case .fetchList: guard currentState.isLogin else { return .empty() } @@ -172,15 +173,15 @@ public final class BookmarkListReactor: Reactor { case let .dataTapped(index): let item = currentState.items[index] guard let type = item.type.toDictionaryType else { return .empty() } - return .just(.toNavagate(.detail(type, item.originalId))) + return .just(.navigatTo(.detail(type, item.originalId))) case .emptyButtonTapped: if currentState.viewState == .logout { - return .just(.toNavagate(.login)) + return .just(.navigatTo(.login)) } else { - return .just(.toNavagate(.dictionary)) + return .just(.navigatTo(.dictionary)) } case .editButtonTapped: - return .just(.toNavagate(.edit)) + return .just(.navigatTo(.edit)) case let .itemFilterOptionSelected(results): let criteria = parseItemFilterResultUseCase.execute(results: results) @@ -255,7 +256,7 @@ public final class BookmarkListReactor: Reactor { newState.endLevel = end case let .setLastDeletedBookmark(item): newState.lastDeletedBookmark = item - case let .toNavagate(route): + case let .navigatTo(route): newState.route = route case let .setJobId(ids): newState.jobId = ids @@ -288,6 +289,9 @@ private extension BookmarkListReactor { self.fetchList() ]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleUndo() -> Observable { @@ -308,5 +312,8 @@ private extension BookmarkListReactor { self.fetchList() ]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift index 0b899ef6..f7893d1a 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift @@ -152,6 +152,7 @@ extension BookmarkListViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case .sort(let type): @@ -199,6 +200,8 @@ extension BookmarkListViewController { case .edit: let viewController = owner.collectionEditFactory.make(bookmarks: reactor.currentState.items) owner.navigationController?.pushViewController(viewController, animated: true) + case .bookmarkError: + ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") default: break } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalReactor.swift index 121ff92b..88011427 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalReactor.swift @@ -10,6 +10,7 @@ public final class BookmarkModalReactor: Reactor { case dismiss case dismissWithData case addCollection + case collectionError } public enum Action { @@ -22,7 +23,7 @@ public final class BookmarkModalReactor: Reactor { } public enum Mutation { - case toNavigate(Route) + case navigatTo(Route) case checkCollection([CollectionResponse]) case setCollection([CollectionResponse]) } @@ -59,13 +60,16 @@ public final class BookmarkModalReactor: Reactor { collectionIds: currentState.selectedItems.map { $0.collectionId }, bookmarkIds: currentState.bookmarkIds ) - .andThen(.just(.toNavigate(.dismissWithData))) + .andThen(.just(.navigatTo(.dismissWithData))) + .catch { _ in + .just(.navigatTo(.collectionError)) + } case .backButtonTapped: - return .just(.toNavigate(.dismiss)) + return .just(.navigatTo(.dismiss)) case .addCollectionTapped: - return .just(.toNavigate(.addCollection)) + return .just(.navigatTo(.addCollection)) case .selectItem(let id): var newItems = currentState.selectedItems @@ -81,7 +85,7 @@ public final class BookmarkModalReactor: Reactor { public func reduce(state: State, mutation: Mutation) -> State { var newState = state switch mutation { - case .toNavigate(let route): + case .navigatTo(let route): newState.route = route case .checkCollection(let collections): newState.selectedItems = collections diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalViewController.swift index 2711e246..ce1d4aa3 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalViewController.swift @@ -138,6 +138,8 @@ extension BookmarkModalViewController { .disposed(by: owner.disposeBag) owner.present(viewController, animated: true) + case .collectionError: + ToastFactory.createToast(message: "컬렉션 저장에 실패했어요. 다시 시도해주세요.") default: break } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index a4892ce2..4b11662a 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -396,7 +396,7 @@ extension DictionaryDetailBaseViewController { private func presentCollectionModal(bookmarkId: Int) { let viewController = bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in if isAdd { - ToastFactory.createToast(message: "컬렉션에 추가되었어요.") + ToastFactory.createToast(message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요.") } } viewController.modalPresentationStyle = .pageSheet diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift index d95364e8..b9e31a13 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift @@ -9,8 +9,9 @@ public final class ItemDictionaryDetailReactor: Reactor { case none case filter(DictionaryType) case detail(Int) + case bookmarkError } - + public enum UIEvent { case none case add(DictionaryDetailItemResponse) @@ -30,7 +31,7 @@ public final class ItemDictionaryDetailReactor: Reactor { // MARK: Mutation public enum Mutation { - case toNavigate(Route) + case navigatTo(Route) case setDetailData(DictionaryDetailItemResponse) case setDetailDropMonsterData([DictionaryDetailItemDropMonsterResponse]) case setLoginState(Bool) @@ -85,7 +86,7 @@ public final class ItemDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case .filterButtonTapped: - return .just(.toNavigate(.filter(currentState.type))) + return .just(.navigatTo(.filter(currentState.type))) case .viewWillAppear: return .merge([ checkLoginUseCase.execute().map { .setLoginState($0) }, @@ -103,7 +104,7 @@ public final class ItemDictionaryDetailReactor: Reactor { case .dataTapped(let index): guard let id = currentState.monsters[index].monsterId else { return .empty() } - return .just(.toNavigate(.detail(id))) + return .just(.navigatTo(.detail(id))) } } @@ -117,7 +118,7 @@ public final class ItemDictionaryDetailReactor: Reactor { newState.monsters = data case let .setLoginState(isLogin): newState.isLogin = isLogin - case .toNavigate(let route): + case .navigatTo(let route): newState.route = route case let .setEvent(event): newState.event = event @@ -148,6 +149,9 @@ private extension ItemDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { @@ -168,5 +172,8 @@ private extension ItemDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index c1143237..9841d029 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -221,6 +221,7 @@ extension ItemDictionaryDetailViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case let .filter(type): @@ -232,11 +233,13 @@ extension ItemDictionaryDetailViewController { reactor.action.onNext(.selectFilter(selectedFilter)) } owner.tabBarController?.presentModal(viewController, hideTabBar: true) - case .none: - break case let .detail(id): let viewController = owner.dictionaryDetailFactory.make(type: .monster, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) + case .bookmarkError: + ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") + default: + break } } .disposed(by: disposeBag) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift index 63f7b1c8..477cf612 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift @@ -8,6 +8,7 @@ public final class MapDictionaryDetailReactor: Reactor { case none case filter([SortType]) case detail(type: DictionaryType, id: Int) + case bookmarkError } public enum UIEvent { @@ -28,7 +29,7 @@ public final class MapDictionaryDetailReactor: Reactor { } public enum Mutation { - case toNavigate(Route) + case navigatTo(Route) case setDetailData(DictionaryDetailMapResponse) case setDetailSpawnMonsters([DictionaryDetailMapSpawnMonsterResponse]) case setDetailNpc([DictionaryDetailMapNpcResponse]) @@ -98,7 +99,7 @@ public final class MapDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case .monsterFilterButtonTapped: - return Observable.just(.toNavigate(.filter(currentState.monsterFilter))) + return Observable.just(.navigatTo(.filter(currentState.monsterFilter))) case .viewWillAppear: return .merge([ checkLoginUseCase.execute().map { .setLoginState($0) }, @@ -118,10 +119,10 @@ public final class MapDictionaryDetailReactor: Reactor { case .monsterTapped(index: let index): guard let id = currentState.spawnMonsters[index].monsterId else { return .empty() } - return .just(.toNavigate(.detail(type: .monster, id: id))) + return .just(.navigatTo(.detail(type: .monster, id: id))) case .npcTapped(index: let index): guard let id = currentState.npcs[index].npcId else { return .empty() } - return .just(.toNavigate(.detail(type: .npc, id: id))) + return .just(.navigatTo(.detail(type: .npc, id: id))) } } @@ -129,7 +130,7 @@ public final class MapDictionaryDetailReactor: Reactor { var newState = state switch mutation { - case .toNavigate(let route): + case .navigatTo(let route): newState.route = route case let .setDetailData(data): newState.mapDetailInfo = data @@ -172,6 +173,9 @@ private extension MapDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { @@ -192,5 +196,8 @@ private extension MapDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index 86cdd6e8..8ed80ee1 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -188,6 +188,7 @@ extension MapDictionaryDetailViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case .filter(let sort): @@ -198,11 +199,13 @@ extension MapDictionaryDetailViewController { reactor.action.onNext(.selectFilter(selectedFilter)) } owner.tabBarController?.presentModal(viewController, hideTabBar: true) - case .none: - break case .detail(let type, let id): let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) + case .bookmarkError: + ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") + default: + break } } .disposed(by: disposeBag) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift index 0361f006..13d6e5f4 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift @@ -8,6 +8,7 @@ public final class MonsterDictionaryDetailReactor: Reactor { case none case filter(type: DictionaryType, sort: [SortType]) case detail(type: DictionaryType, id: Int) + case bookmarkError } public struct Info: Equatable { @@ -35,7 +36,7 @@ public final class MonsterDictionaryDetailReactor: Reactor { // MARK: - Mutation public enum Mutation { - case toNavigate(Route) + case navigatTo(Route) case setDetailData(DictionaryDetailMonsterResponse) case setDetailDropItemData([DictionaryDetailMonsterDropItemResponse]) case setDetailMapData([DictionaryDetailMonsterMapResponse]) @@ -104,7 +105,7 @@ public final class MonsterDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case let .filterButtonTapped(type): - return .just(.toNavigate(.filter(type: type, sort: type == .map ? currentState.mapFilter : currentState.itemFilter))) + return .just(.navigatTo(.filter(type: type, sort: type == .map ? currentState.mapFilter : currentState.itemFilter))) case .viewWillAppear: return .merge([ @@ -124,10 +125,10 @@ public final class MonsterDictionaryDetailReactor: Reactor { return handleUndoLastDeletedBookmark() case .itemTapped(index: let index): - return .just(.toNavigate(.detail(type: .item, id: currentState.dropItems[index].itemId))) + return .just(.navigatTo(.detail(type: .item, id: currentState.dropItems[index].itemId))) case .mapTapped(index: let index): - return .just(.toNavigate(.detail(type: .map, id: currentState.spawnMaps[index].mapId))) + return .just(.navigatTo(.detail(type: .map, id: currentState.spawnMaps[index].mapId))) } } @@ -136,7 +137,7 @@ public final class MonsterDictionaryDetailReactor: Reactor { var newState = state switch mutation { - case let .toNavigate(route): + case let .navigatTo(route): newState.route = route case let .setDetailData(data): @@ -194,6 +195,9 @@ private extension MonsterDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { @@ -214,5 +218,8 @@ private extension MonsterDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift index 23240769..2e4e7ca7 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift @@ -1,5 +1,6 @@ import UIKit +import BaseFeature import DesignSystem import DictionaryFeatureInterface import DomainInterface @@ -20,7 +21,7 @@ class MonsterDictionaryDetailViewController: DictionaryDetailBaseViewController, private var appearMapView = DetailStackCardView() private var dropItemView = DetailStackCardView() private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() - + override func toggleBookmark() { reactor?.action.onNext(.toggleBookmark) } @@ -29,7 +30,7 @@ class MonsterDictionaryDetailViewController: DictionaryDetailBaseViewController, guard let reactor = reactor else { return false } return reactor.currentState.isLogin } - + override func undoBookmark() { reactor?.action.onNext(.undoLastDeletedBookmark) } @@ -199,6 +200,7 @@ extension MonsterDictionaryDetailViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case .filter(let type, let sort): @@ -221,6 +223,8 @@ extension MonsterDictionaryDetailViewController { case let .detail(type: type, id: id): let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) + case .bookmarkError: + ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") default: break } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift index 10a8cec2..2bfdd06a 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift @@ -8,6 +8,7 @@ public final class NpcDictionaryDetailReactor: Reactor { case none case filter([SortType]) case detail(type: DictionaryType, id: Int) + case bookmarkError } public enum UIEvent { @@ -30,7 +31,7 @@ public final class NpcDictionaryDetailReactor: Reactor { // MARK: - Mutation public enum Mutation { - case toNavigate(Route) + case navigatTo(Route) case setDetailData(DictionaryDetailNpcResponse) case setDetailMaps([DictionaryDetailMonsterMapResponse]) case setDetailQuests([DictionaryDetailNpcQuestResponse]) @@ -93,7 +94,7 @@ public final class NpcDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case .filterButtonTapped: - return .just(.toNavigate(.filter(currentState.questFilter))) + return .just(.navigatTo(.filter(currentState.questFilter))) case .viewWillAppear: return .merge([ checkLoginUseCase.execute().map { .setLoginState($0) }, @@ -111,10 +112,10 @@ public final class NpcDictionaryDetailReactor: Reactor { return handleUndoLastDeletedBookmark() case .mapTapped(index: let index): - return .just(.toNavigate(.detail(type: .map, id: currentState.maps[index].mapId))) + return .just(.navigatTo(.detail(type: .map, id: currentState.maps[index].mapId))) case .questTapped(index: let index): - return .just(.toNavigate(.detail(type: .quest, id: currentState.quests[index].questId))) + return .just(.navigatTo(.detail(type: .quest, id: currentState.quests[index].questId))) } } @@ -122,7 +123,7 @@ public final class NpcDictionaryDetailReactor: Reactor { public func reduce(state: State, mutation: Mutation) -> State { var newState = state switch mutation { - case .toNavigate(let route): + case .navigatTo(let route): newState.route = route case let .setDetailData(data): newState.npcDetailInfo = data @@ -163,6 +164,9 @@ private extension NpcDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { @@ -183,5 +187,8 @@ private extension NpcDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift index 4a886d0e..ffa9cf6f 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift @@ -1,5 +1,6 @@ import UIKit +import BaseFeature import DesignSystem import DictionaryFeatureInterface import DomainInterface @@ -129,6 +130,7 @@ extension NpcDictionaryDetailViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case .filter(let type): @@ -142,6 +144,8 @@ extension NpcDictionaryDetailViewController { case .detail(type: let type, id: let id): let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) + case .bookmarkError: + ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") default: break } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift index b75db540..8e35deb5 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift @@ -18,6 +18,7 @@ public final class QuestDictionaryDetailReactor: Reactor { case none case filter(DictionaryType) case detail(type: DictionaryType, id: Int) + case bookmarkError } public enum UIEvent { @@ -36,7 +37,7 @@ public final class QuestDictionaryDetailReactor: Reactor { } public enum Mutation { - case toNavigate(Route) + case navigatTo(Route) case setDetailData(DictionaryDetailQuestResponse) case setLinkedQuests(DictionaryDetailQuestLinkedQuestsResponse) case setLoginState(Bool) @@ -120,10 +121,10 @@ public final class QuestDictionaryDetailReactor: Reactor { let tappedQuestInfo = currentState.totalQuest[index] guard let id = tappedQuestInfo.quest.questId, tappedQuestInfo.type != .current else { return .empty() } - return .just(.toNavigate(.detail(type: .quest, id: id))) + return .just(.navigatTo(.detail(type: .quest, id: id))) case let .infoTapped(type: type, id: id): - return .just(.toNavigate(.detail(type: type, id: id))) + return .just(.navigatTo(.detail(type: type, id: id))) } } @@ -146,7 +147,7 @@ public final class QuestDictionaryDetailReactor: Reactor { newState.isLogin = isLogin case let .setLastDeletedBookmark(data): newState.lastDeletedBookmark = data - case let .toNavigate(route): + case let .navigatTo(route): newState.route = route case let .setEvent(event): newState.event = event @@ -207,6 +208,9 @@ private extension QuestDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { @@ -227,5 +231,8 @@ private extension QuestDictionaryDetailReactor { return .concat([eventMutation, refresh]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift index 6ceaf245..5fcb1734 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift @@ -1,5 +1,6 @@ import UIKit +import BaseFeature import DesignSystem import DomainInterface @@ -195,11 +196,14 @@ extension QuestDictionaryDetailViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case let .detail(type, id): let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) owner.navigationController?.pushViewController(viewController, animated: true) + case .bookmarkError: + ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") default: break } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift index be98e357..7be1f4a9 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift @@ -10,6 +10,7 @@ public final class DictionaryListReactor: Reactor { case none case sort(DictionaryType) case filter(DictionaryType) + case bookmarkError } public enum UIEvent { @@ -38,9 +39,8 @@ public final class DictionaryListReactor: Reactor { // MARK: - Mutation public enum Mutation { + case navigatTo(Route) case setListItem(DictionaryMainResponse, updateBookmarkOnly: Bool = false) - case showSortFilter - case showFilter case setSort(String) case setFilter(start: Int?, end: Int?) case setCurrentPage @@ -124,9 +124,9 @@ public final class DictionaryListReactor: Reactor { case .viewWillAppear: return handleViewWillAppear() case .sortButtonTapped: - return .just(.showSortFilter) + return .just(.navigatTo(.sort(currentState.type))) case .filterButtonTapped: - return .just(.showFilter) + return .just(.navigatTo(.filter(currentState.type))) case let .sortOptionSelected(sort): return handleSortOptionSelected(sort: sort) case let .filterOptionSelected(startLevel, endLevel): @@ -152,10 +152,8 @@ public final class DictionaryListReactor: Reactor { public func reduce(state: State, mutation: Mutation) -> State { var newState = state switch mutation { - case .showSortFilter: - newState.route = .sort(newState.type) - case .showFilter: - newState.route = .filter(newState.type) + case let .navigatTo(route): + newState.route = route case let .setListItem(items, updateBookmarkOnly): newState.isBookmarkUpdateOnly = updateBookmarkOnly newState.totalCounts = items.totalElements @@ -315,6 +313,9 @@ private extension DictionaryListReactor { let updateMutation = Mutation.updateBookmarkId(id: id, newBookmarkId: newBookmarkId) return .from([lastItem, updateMutation, eventMutation]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleUpdateBookmark(id: Int, newBookmarkId: Int?) -> Observable { @@ -367,6 +368,9 @@ private extension DictionaryListReactor { let updateMutation = Mutation.updateBookmarkId(id: lastDeleted.id, newBookmarkId: newBookmarkId) return .from([lastItem, updateMutation, eventMutation]) } + .catch { _ in + .just(.navigatTo(.bookmarkError)) + } } func handleItemFilterOptionSelected(results: [(String, String)]) -> Observable { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index 5515f0ab..6a8d4fa6 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -151,6 +151,7 @@ extension DictionaryListViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe(onNext: { owner, route in switch route { case .sort(let type): @@ -191,6 +192,8 @@ extension DictionaryListViewController { default: break } + case .bookmarkError: + ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") default: break } @@ -333,7 +336,8 @@ extension DictionaryListViewController { for cell in collectionView.visibleCells { if let indexPath = collectionView.indexPath(for: cell), indexPath.item < items.count, - let cell = cell as? DictionaryListCell { + let cell = cell as? DictionaryListCell + { let item = items[indexPath.item] cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) } @@ -394,7 +398,8 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi default: // 단일 타입일 경우 리액터 타입에 따라 처리 viewController = detailFactory.make( - type: reactor.currentState.type, id: item.id, bookmarkRelay: bookmarkChangeRelay, loginRelay: loginRelay) + type: reactor.currentState.type, id: item.id, bookmarkRelay: bookmarkChangeRelay, loginRelay: loginRelay + ) } navigationController?.pushViewController(viewController, animated: true) } From 2233db7ba19df95eabb716527c73fcefba044035 Mon Sep 17 00:00:00 2001 From: p2glet Date: Thu, 18 Dec 2025 15:50:24 +0900 Subject: [PATCH 25/31] =?UTF-8?q?fix/#273:=20=EC=BB=AC=EB=A0=89=EC=85=98?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=20=EB=B6=81=EB=A7=88=ED=81=AC=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=EB=9E=99=EC=85=98=20=EB=B9=84=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CollectionDetailReactor.swift | 35 ------------------- .../CollectionDetailViewController.swift | 17 +-------- 2 files changed, 1 insertion(+), 51 deletions(-) diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift index 397b4b37..e7fee7dd 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift @@ -18,10 +18,8 @@ public final class CollectionDetailReactor: Reactor { case editButtonTapped case addButtonTapped case bookmarkButtonTapped - case toggleBookmark(Int, Bool) case selectSetting(CollectionSettingMenu) case changeName(String) - case undoLastDeletedBookmark case dataTapped(Int) case deleteCollection } @@ -65,22 +63,6 @@ public final class CollectionDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { - case .toggleBookmark(let id, let isSelected): - guard let bookmarkItem = currentState.collection.recentBookmarks.first(where: { $0.originalId == id }) else { return .empty() } - - let saveDeletedMutation: Observable = - isSelected ? .just(.setLastDeletedBookmark(bookmarkItem)) - : .just(.setLastDeletedBookmark(nil)) - - return saveDeletedMutation -// .concat( -// setBookmarkUseCase.execute( -// bookmarkId: isSelected ? bookmarkItem.bookmarkId : id, -// isBookmark: isSelected ? .delete : .set(bookmarkItem.type) -// ) -// .andThen(fetchCollectionUseCase.execute(id: currentState.collection.collectionId).map { .setItems($0) }) -// ) - return .empty() case .backButtonTapped: return .just(.navigateTo(.dismiss)) case .editButtonTapped: @@ -96,23 +78,6 @@ public final class CollectionDetailReactor: Reactor { return .just(.setMenu(menu)) case .changeName(let name): return .just(.setName(name)) - case .undoLastDeletedBookmark: -// guard let lastDeleted = currentState.lastDeletedBookmark, -// let lastDeletedBookmarkId = currentState.lastDeletedBookmark?.bookmarkId else { return .empty() } -// return setBookmarkUseCase.execute( -// bookmarkId: lastDeleted.originalId, -// isBookmark: .set(lastDeleted.type) -// ) -// // 북마크 다시 설정시 이전 collection을 전부 추적해야하고 새로 바뀐 북마크ID가 필요하여 현재는 원할하게 동작하지 않음 -// .andThen(addCollectionAndBookmarkUseCase.execute(collectionIds: [currentState.collection.collectionId], bookmarkIds: [lastDeletedBookmarkId])) -// .andThen( -// Observable.concat([ -// fetchCollectionUseCase.execute(id: currentState.collection.collectionId) -// .map { .setItems($0) }, -// .just(.setLastDeletedBookmark(nil)) -// ]) -// ) - return .empty() case .dataTapped(let index): let item = currentState.collection.recentBookmarks[index] guard let type = item.type.toDictionaryType else { return .empty() } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift index 1c9ead1e..7c5ccbbb 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift @@ -237,22 +237,7 @@ extension CollectionDetailViewController: UICollectionViewDelegate, UICollection ), indexPath: indexPath, collectionView: collectionView, - onBookmarkTapped: { [weak self] isSelected in - guard let self = self else { return } - - self.reactor?.action.onNext(.toggleBookmark(item.originalId, isSelected)) - - SnackBarFactory.createSnackBar( - type: .delete, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에서 삭제했어요.", - buttonText: "되돌리기", - buttonAction: { [weak self] in - self?.reactor?.action.onNext(.undoLastDeletedBookmark) - } - ) - } + onBookmarkTapped: { _ in } ) return cell } From 9ade95283d4b0435a69f4d79d451f231857f45a8 Mon Sep 17 00:00:00 2001 From: p2glet Date: Thu, 18 Dec 2025 16:04:52 +0900 Subject: [PATCH 26/31] =?UTF-8?q?fix/#273:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20/=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20/=20=ED=8C=A8?= =?UTF-8?q?=EC=B9=98=EB=85=B8=ED=8A=B8=20=ED=8E=98=EC=9D=B4=EC=A7=95=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AnnouncementViewController.swift | 4 ++++ .../CustomerSupportBaseViewController.swift | 20 +++++++++++++++++++ .../CustomerSupportBaseViewFactoryImpl.swift | 3 --- .../Event/EventViewController.swift | 4 ++++ .../PatchNote/PatchNoteViewController.swift | 4 ++++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift index a759a41c..e1abedb4 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift @@ -22,6 +22,10 @@ final class AnnouncementViewController: CustomerSupportBaseViewController, View onItemTapped = { [weak self] itemIndex in self?.reactor?.action.onNext(.itemTapped(itemIndex)) } + + onLoadMore = { [weak self] in + self?.reactor?.action.onNext(.loadMore) + } } } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift index fb4b6f0d..4271443d 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift @@ -19,6 +19,7 @@ class CustomerSupportBaseViewController: BaseViewController { public var currentTabIndex: Int? public var urlStrings: [String] = [] var onItemTapped: ((Int) -> Void)? + var onLoadMore: (() -> Void)? private let policyFactory: PolicyFactory? @@ -51,6 +52,7 @@ class CustomerSupportBaseViewController: BaseViewController { addViews() setupConstaraints() bindBackButton() + bindScrollPagination() } func createDetailItem(items: [AlarmResponse]) { @@ -137,4 +139,22 @@ extension CustomerSupportBaseViewController { } .disposed(by: disposeBag) } + + func bindScrollPagination() { + mainView.scrollView.rx.contentOffset + .throttle(.milliseconds(300), scheduler: MainScheduler.instance) + .map { [weak self] offset -> Bool in + guard let self = self else { return false } + let contentHeight = self.mainView.scrollView.contentSize.height + let height = self.mainView.scrollView.frame.size.height + let offsetY = offset.y + return offsetY > contentHeight - height - 100 + } + .distinctUntilChanged() + .filter { $0 } + .bind { [weak self] _ in + self?.onLoadMore?() + } + .disposed(by: disposeBag) + } } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewFactoryImpl.swift index 2a09be91..3507e671 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewFactoryImpl.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewFactoryImpl.swift @@ -48,9 +48,6 @@ public final class CustomerSupportBaseViewFactoryImpl: CustomerSupportFactory { } case .terms: viewController = TermsViewController(type: .terms, policyFactory: policyFactory) - if let viewController = viewController as? TermsViewController { - - } } viewController.isBottomTabbarHidden = true diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift index 3c6984c2..f49ec0cb 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift @@ -17,6 +17,10 @@ final class EventViewController: CustomerSupportBaseViewController, View { onItemTapped = { [weak self] itemIndex in self?.reactor?.action.onNext(.itemTapped(itemIndex)) } + + onLoadMore = { [weak self] in + self?.reactor?.action.onNext(.loadMore) + } } // MARK: - Setup diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift index b896c8b4..f74c5a1e 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift @@ -22,6 +22,10 @@ final class PatchNoteViewController: CustomerSupportBaseViewController, View { onItemTapped = { [weak self] itemIndex in self?.reactor?.action.onNext(.itemTapped(itemIndex)) } + + onLoadMore = { [weak self] in + self?.reactor?.action.onNext(.loadMore) + } } } From 79cfa0b1faaa502a16e573eafe33beedea182b1f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 18 Dec 2025 07:05:28 +0000 Subject: [PATCH 27/31] style/#273: Apply SwiftLint autocorrect --- .../AddCollection/AddCollectionReactor.swift | 4 ++-- .../BookmarkList/BookmarkListViewController.swift | 2 +- .../DictionaryDetailBaseViewController.swift | 2 +- .../Item/ItemDictionaryDetailViewController.swift | 2 +- .../DictionaryDetail/Map/MapDictionaryDetailReactor.swift | 4 ++-- .../Map/MapDictionaryDetailViewController.swift | 6 +++--- .../Monster/MonsterDictionaryDetailReactor.swift | 2 +- .../DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift | 2 +- .../NPC/NpcDictionaryDetailViewController.swift | 4 ++-- .../Quest/QuestDictionaryDetailViewController.swift | 2 +- .../DictionaryList/DictionaryListViewController.swift | 3 +-- .../Announcement/AnnouncementViewController.swift | 2 +- .../CustomerSupport/CustomerSupportBaseViewController.swift | 2 +- .../CustomerSupport/PatchNote/PatchNoteViewController.swift | 2 +- 14 files changed, 19 insertions(+), 20 deletions(-) diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift index e15aafb1..2a3c4952 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift @@ -73,7 +73,7 @@ public final class AddCollectionModalReactor: Reactor { if currentState.collection == nil { return createCollectionListUseCase.execute(name: trimmed) .andThen(.just(.toNavigate(.dismissWithData))) - .catch { error in + .catch { _ in return .just(.toNavigate(.createError)) } } else { @@ -83,7 +83,7 @@ public final class AddCollectionModalReactor: Reactor { name: trimmed ) .andThen(.just(.toNavigate(.dismissWithData))) - .catch { error in + .catch { _ in return .just(.toNavigate(.updateError)) } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift index f7893d1a..ebdf4b77 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift @@ -336,7 +336,7 @@ extension BookmarkListViewController: UICollectionViewDelegate, UICollectionView indexPath: indexPath, collectionView: collectionView, isMap: item.type == .map, - onBookmarkTapped: { [weak self] isSelected in + onBookmarkTapped: { [weak self] _ in guard let self else { return } guard state.isLogin else { self.reactor?.action.onNext(.showLogin) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index 4b11662a..4245a583 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -101,7 +101,7 @@ class DictionaryDetailBaseViewController: BaseViewController { open func checkLogin() -> Bool? { return nil } - + open func undoBookmark() { assertionFailure("Subclass should override undoBookmark()") } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index 9841d029..c4efe2c5 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -23,7 +23,7 @@ final class ItemDictionaryDetailViewController: DictionaryDetailBaseViewControll guard let reactor = reactor else { return false } return reactor.currentState.isLogin } - + override func undoBookmark() { reactor?.action.onNext(.undoLastDeletedBookmark) } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift index 477cf612..8ed34e3c 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift @@ -10,14 +10,14 @@ public final class MapDictionaryDetailReactor: Reactor { case detail(type: DictionaryType, id: Int) case bookmarkError } - + public enum UIEvent { case none case add(DictionaryDetailMapResponse) case delete(DictionaryDetailMapResponse) case undo } - + public enum Action { case monsterFilterButtonTapped case viewWillAppear diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index 8ed80ee1..7392c056 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -22,7 +22,7 @@ final class MapDictionaryDetailViewController: DictionaryDetailBaseViewControlle super.viewDidLoad() bindImageView() } - + override func toggleBookmark() { reactor?.action.onNext(.toggleBookmark) } @@ -31,7 +31,7 @@ final class MapDictionaryDetailViewController: DictionaryDetailBaseViewControlle guard let reactor = reactor else { return false } return reactor.currentState.isLogin } - + override func undoBookmark() { reactor?.action.onNext(.undoLastDeletedBookmark) } @@ -209,7 +209,7 @@ extension MapDictionaryDetailViewController { } } .disposed(by: disposeBag) - + reactor.pulse(\.$event) .bind(onNext: { [weak self] event in switch event { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift index 13d6e5f4..0f798445 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift @@ -15,7 +15,7 @@ public final class MonsterDictionaryDetailReactor: Reactor { var name: String var desc: String } - + public enum UIEvent { case none case add(DictionaryDetailMonsterResponse) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift index 2bfdd06a..1857182c 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift @@ -10,7 +10,7 @@ public final class NpcDictionaryDetailReactor: Reactor { case detail(type: DictionaryType, id: Int) case bookmarkError } - + public enum UIEvent { case none case add(DictionaryDetailNpcResponse) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift index ffa9cf6f..04d448ef 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift @@ -16,7 +16,7 @@ final class NpcDictionaryDetailViewController: DictionaryDetailBaseViewControlle private var appearMapView = DetailStackCardView() private var questView = DetailStackCardView() private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() - + override func toggleBookmark() { reactor?.action.onNext(.toggleBookmark) } @@ -25,7 +25,7 @@ final class NpcDictionaryDetailViewController: DictionaryDetailBaseViewControlle guard let reactor = reactor else { return false } return reactor.currentState.isLogin } - + override func undoBookmark() { reactor?.action.onNext(.undoLastDeletedBookmark) } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift index 5fcb1734..25e88982 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift @@ -22,7 +22,7 @@ final class QuestDictionaryDetailViewController: DictionaryDetailBaseViewControl guard let reactor = reactor else { return false } return reactor.currentState.isLogin } - + override func undoBookmark() { reactor?.action.onNext(.undoLastDeletedBookmark) } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index 6a8d4fa6..80061340 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -336,8 +336,7 @@ extension DictionaryListViewController { for cell in collectionView.visibleCells { if let indexPath = collectionView.indexPath(for: cell), indexPath.item < items.count, - let cell = cell as? DictionaryListCell - { + let cell = cell as? DictionaryListCell { let item = items[indexPath.item] cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift index e1abedb4..4261d67c 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift @@ -22,7 +22,7 @@ final class AnnouncementViewController: CustomerSupportBaseViewController, View onItemTapped = { [weak self] itemIndex in self?.reactor?.action.onNext(.itemTapped(itemIndex)) } - + onLoadMore = { [weak self] in self?.reactor?.action.onNext(.loadMore) } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift index 4271443d..4649e4f5 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift @@ -139,7 +139,7 @@ extension CustomerSupportBaseViewController { } .disposed(by: disposeBag) } - + func bindScrollPagination() { mainView.scrollView.rx.contentOffset .throttle(.milliseconds(300), scheduler: MainScheduler.instance) diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift index f74c5a1e..56397f22 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift @@ -22,7 +22,7 @@ final class PatchNoteViewController: CustomerSupportBaseViewController, View { onItemTapped = { [weak self] itemIndex in self?.reactor?.action.onNext(.itemTapped(itemIndex)) } - + onLoadMore = { [weak self] in self?.reactor?.action.onNext(.loadMore) } From 47bc673623fee4543a891e36e6d51d91876ccc83 Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 19 Dec 2025 14:58:38 +0900 Subject: [PATCH 28/31] =?UTF-8?q?fix/#273:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EC=8B=9C=20fcm=20=ED=86=A0=ED=81=B0=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=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 --- .../AuthAPI/LoginWithAppleUseCaseImpl.swift | 27 +++++++++++++------ .../AuthAPI/LoginWithKakaoUseCaseImpl.swift | 13 ++++++--- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift index fbff7c74..bc21334f 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift @@ -22,15 +22,26 @@ public class LoginWithAppleUseCaseImpl: LoginWithAppleUseCase { let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) let savePlatform = self.userDefaultsRepository.savePlatform(platform: .apple) - - switch (saveAccess, saveRefresh) { - case (.success, .success): - return savePlatform.andThen(Observable.just(response)) - default: - return Observable.error( - TokenRepositoryError.dataConversionError(message: "Failed to save tokens") - ) + + guard case (.success, .success) = (saveAccess, saveRefresh) else { + return Observable.error(TokenRepositoryError.dataConversionError(message: "Failed to save tokens")) + } + + var fcmToken: String? + if case .success(let token) = self.tokenRepository.fetchToken(type: .fcmToken) { + fcmToken = token + } + + let fcmUpdate = if let fcmToken { + self.authRepository.fcmToken(fcmToken: fcmToken) + .catch { error in + print("FCM token update failed: \(error)") + return .empty() + } + } else { + Completable.empty() } + return fcmUpdate.andThen(savePlatform).andThen(Observable.just(response)) } .catch { error in Observable.error(error) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift index 1a456fce..db4e8719 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift @@ -31,11 +31,16 @@ public class LoginWithKakaoUseCaseImpl: LoginWithKakaoUseCase { fcmToken = token } - if let fcmToken { - _ = self.authRepository.fcmToken(fcmToken: fcmToken) + let fcmUpdate = if let fcmToken { + self.authRepository.fcmToken(fcmToken: fcmToken) + .catch { error in + print("FCM token update failed: \(error)") + return .empty() + } + } else { + Completable.empty() } - - return savePlatform.andThen(Observable.just(response)) + return fcmUpdate.andThen(savePlatform).andThen(Observable.just(response)) } .catch { error in Observable.error(error) From ee80a3fae21bf8b2bad81d907c889511f4739947 Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 19 Dec 2025 15:13:55 +0900 Subject: [PATCH 29/31] =?UTF-8?q?reafcator/#273:=20swiftLint=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift | 6 +++--- .../CollectionViewCells/DictionaryListCell.swift | 8 ++++---- .../Utills/NotificationPermissionManager.swift | 3 +-- .../AddCollection/AddCollectionReactor.swift | 4 ++-- .../BookmarkList/BookmarkListViewController.swift | 2 +- .../CollectionDetail/CollectionDetailReactor.swift | 8 +++++++- .../CollectionDetail/CollectionDetailViewController.swift | 2 +- .../CollectionEdit/CollectionEditReactor.swift | 8 -------- .../CollectionEdit/CollectionEditViewController.swift | 2 +- .../DesignSystem/DesignSystem/Components/CardList.swift | 4 ++-- .../Item/ItemDictionaryDetailViewController.swift | 2 +- .../DictionaryDetail/Map/MapDictionaryDetailReactor.swift | 4 ++-- .../Map/MapDictionaryDetailViewController.swift | 2 +- .../DictionaryList/DictionaryListViewController.swift | 5 ++--- 14 files changed, 28 insertions(+), 32 deletions(-) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift index bc21334f..1819bf20 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift @@ -22,16 +22,16 @@ public class LoginWithAppleUseCaseImpl: LoginWithAppleUseCase { let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) let savePlatform = self.userDefaultsRepository.savePlatform(platform: .apple) - + guard case (.success, .success) = (saveAccess, saveRefresh) else { return Observable.error(TokenRepositoryError.dataConversionError(message: "Failed to save tokens")) } - + var fcmToken: String? if case .success(let token) = self.tokenRepository.fetchToken(type: .fcmToken) { fcmToken = token } - + let fcmUpdate = if let fcmToken { self.authRepository.fcmToken(fcmToken: fcmToken) .catch { error in diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryListCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryListCell.swift index 1909dfd9..33361c55 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryListCell.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryListCell.swift @@ -5,7 +5,7 @@ import DomainInterface public final class DictionaryListCell: UICollectionViewCell { // MARK: - Properties - private var onBookmarkTapped: ((Bool) -> Void)? + private var onBookmarkTapped: (() -> Void)? // MARK: - Components public let cellView = CardList() @@ -70,7 +70,7 @@ public extension DictionaryListCell { indexPath: IndexPath, collectionView: UICollectionView, isMap: Bool = false, - onBookmarkTapped: @escaping (Bool) -> Void + onBookmarkTapped: @escaping () -> Void ) { cellView.setType(type: type) cellView.setImage(image: UIImage(), backgroundColor: input.type.backgroundColor) // 초기화 @@ -94,8 +94,8 @@ public extension DictionaryListCell { cellView.setSubText(text: input.subText) cellView.setSelected(isSelected: input.isBookmarked) self.onBookmarkTapped = onBookmarkTapped - cellView.onIconTapped = { [weak self] isSelected in - self?.onBookmarkTapped?(isSelected) + cellView.onIconTapped = { [weak self] in + self?.onBookmarkTapped?() } } func updateBookmarkState(isBookmarked: Bool) { diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/NotificationPermissionManager.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/NotificationPermissionManager.swift index 6665635e..8f41e7cd 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/NotificationPermissionManager.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/Utills/NotificationPermissionManager.swift @@ -12,7 +12,6 @@ public final class NotificationPermissionManager { } } - @discardableResult public func requestIfNeeded( application: UIApplication = .shared, completion: ((Bool) -> Void)? = nil @@ -49,7 +48,7 @@ public final class NotificationPermissionManager { print("🚫 알림 권한 거부 상태입니다. 설정에서 변경해야 함") completion?(false) - @unknown default: + default: completion?(false) } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift index e15aafb1..2a3c4952 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift @@ -73,7 +73,7 @@ public final class AddCollectionModalReactor: Reactor { if currentState.collection == nil { return createCollectionListUseCase.execute(name: trimmed) .andThen(.just(.toNavigate(.dismissWithData))) - .catch { error in + .catch { _ in return .just(.toNavigate(.createError)) } } else { @@ -83,7 +83,7 @@ public final class AddCollectionModalReactor: Reactor { name: trimmed ) .andThen(.just(.toNavigate(.dismissWithData))) - .catch { error in + .catch { _ in return .just(.toNavigate(.updateError)) } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift index f7893d1a..35bea5fe 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift @@ -336,7 +336,7 @@ extension BookmarkListViewController: UICollectionViewDelegate, UICollectionView indexPath: indexPath, collectionView: collectionView, isMap: item.type == .map, - onBookmarkTapped: { [weak self] isSelected in + onBookmarkTapped: { [weak self] in guard let self else { return } guard state.isLogin else { self.reactor?.action.onNext(.showLogin) diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift index e7fee7dd..5dd270c7 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift @@ -53,7 +53,13 @@ public final class CollectionDetailReactor: Reactor { private let disposeBag = DisposeBag() - public init(collection: CollectionResponse, setBookmarkUseCase: SetBookmarkUseCase, fetchCollectionUseCase: FetchCollectionUseCase, deleteCollectionUseCase: DeleteCollectionUseCase, addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase) { + public init( + collection: CollectionResponse, + setBookmarkUseCase: SetBookmarkUseCase, + fetchCollectionUseCase: FetchCollectionUseCase, + deleteCollectionUseCase: DeleteCollectionUseCase, + addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase + ) { self.initialState = State(route: .none, collection: collection) self.setBookmarkUseCase = setBookmarkUseCase self.fetchCollectionUseCase = fetchCollectionUseCase diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift index 7c5ccbbb..9c11aa03 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift @@ -237,7 +237,7 @@ extension CollectionDetailViewController: UICollectionViewDelegate, UICollection ), indexPath: indexPath, collectionView: collectionView, - onBookmarkTapped: { _ in } + onBookmarkTapped: { } ) return cell } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditReactor.swift index 56e34e8e..c9616086 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditReactor.swift @@ -15,8 +15,6 @@ public final class CollectionEditReactor: Reactor { public enum Action { case backButtonTapped case addCollectionButtonTapped - case completeButtonTapped - case dismissAddCollection([CollectionResponse]) case itemTapped(Int) } @@ -48,12 +46,6 @@ public final class CollectionEditReactor: Reactor { return .just(.navigateTo(.dismiss)) case .addCollectionButtonTapped: return .just(.navigateTo(.collcectionList)) - case .completeButtonTapped: - // 선택된 북마크들을 선택된 컬렉션들에 저장 - return .empty() - case .dismissAddCollection(let collections): - // addCollection에서 선택된 컬렉션 목록 저장 - return .empty() case .itemTapped(let index): let item = currentState.bookmarks[index] var newItems = currentState.selectedItems diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditViewController.swift index add5f4c0..af476175 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditViewController.swift @@ -173,7 +173,7 @@ extension CollectionEditViewController: UICollectionViewDelegate, UICollectionVi ), indexPath: indexPath, collectionView: collectionView, - onBookmarkTapped: { [weak self] _ in + onBookmarkTapped: { [weak self] in self?.reactor?.action.onNext(.itemTapped(indexPath.row)) } ) diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/CardList.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/CardList.swift index 7e5b42ec..312ac972 100644 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/CardList.swift +++ b/MLS/Presentation/DesignSystem/DesignSystem/Components/CardList.swift @@ -70,7 +70,7 @@ public final class CardList: UIView { } } - public var onIconTapped: ((Bool) -> Void)? + public var onIconTapped: (() -> Void)? // MARK: - Components public let imageView = ItemImageView(image: nil, cornerRadius: Constant.imageRadius, inset: Constant.imageInset, backgroundColor: .listMap) @@ -193,7 +193,7 @@ private extension CardList { func bindButton() { iconButton.addAction(UIAction(handler: { [weak self] _ in guard let self = self else { return } - self.onIconTapped?(self.isIconSelected) + self.onIconTapped?() }), for: .touchUpInside) } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index 9841d029..c4efe2c5 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -23,7 +23,7 @@ final class ItemDictionaryDetailViewController: DictionaryDetailBaseViewControll guard let reactor = reactor else { return false } return reactor.currentState.isLogin } - + override func undoBookmark() { reactor?.action.onNext(.undoLastDeletedBookmark) } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift index 477cf612..8ed34e3c 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift @@ -10,14 +10,14 @@ public final class MapDictionaryDetailReactor: Reactor { case detail(type: DictionaryType, id: Int) case bookmarkError } - + public enum UIEvent { case none case add(DictionaryDetailMapResponse) case delete(DictionaryDetailMapResponse) case undo } - + public enum Action { case monsterFilterButtonTapped case viewWillAppear diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index 8ed80ee1..7d894cf6 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -129,7 +129,7 @@ extension MapDictionaryDetailViewController { func bind(reactor: Reactor) { bindUserActions(reactor: reactor) bindViewState(reactor: reactor) - bindReportButton(providerId: reactor.state.map { $0.mapDetailInfo.mapId ?? 0 }, itemName: reactor.state.map { $0.mapDetailInfo.nameKr ?? "" }) + bindReportButton(providerId: reactor.state.map { $0.mapDetailInfo.mapId }, itemName: reactor.state.map { $0.mapDetailInfo.nameKr ?? "" }) } private func bindUserActions(reactor: Reactor) { diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index 6a8d4fa6..6f22ceef 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -336,8 +336,7 @@ extension DictionaryListViewController { for cell in collectionView.visibleCells { if let indexPath = collectionView.indexPath(for: cell), indexPath.item < items.count, - let cell = cell as? DictionaryListCell - { + let cell = cell as? DictionaryListCell { let item = items[indexPath.item] cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) } @@ -371,7 +370,7 @@ extension DictionaryListViewController: UICollectionViewDelegate, UICollectionVi indexPath: indexPath, collectionView: collectionView, isMap: item.type == .map, - onBookmarkTapped: { [weak self] _ in + onBookmarkTapped: { [weak self] in guard let self else { return } guard state.isLogin else { self.reactor?.action.onNext(.showLogin) From 43c4a311229888be7aae05d6e7ac010098574724 Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 19 Dec 2025 16:45:31 +0900 Subject: [PATCH 30/31] =?UTF-8?q?fix/#dev:=20=EC=A0=9C=EB=AF=B8=EB=82=98?= =?UTF-8?q?=EC=9D=B4=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Data/Providers/Network/NetworkProviderImpl.swift | 12 +++++++----- MLS/Domain/Domain/Interceptor/AuthInterceptor.swift | 2 ++ MLS/MLS/Application/SceneDelegate.swift | 12 +++++++----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift b/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift index eced66d6..20a25e4e 100644 --- a/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift +++ b/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift @@ -28,16 +28,18 @@ public final class NetworkProviderImpl: NetworkProvider { print("✅ requestData: 응답 수신") if let data = data { -// print("📦 requestData: 응답 데이터 있음 - \(String(data: data, encoding: .utf8) ?? "디코딩 실패")") - print("📦 requestData: 응답 데이터 있음") + print("📦 requestData: 응답 데이터 있음 - \(String(data: data, encoding: .utf8) ?? "디코딩 실패")") do { let decoded = try JSONDecoder().decode(APIDefaultResponseDTO.self, from: data) -// print("🎯 requestData: 디코딩 성공 - \(decoded)") - print("🎯 requestData: 디코딩 성공") + print("🎯 requestData: 디코딩 성공 - \(decoded)") if let decodedData = decoded.data { observer.onNext(decodedData) } else { - observer.onNext(EmptyResponseDTO() as! T.Response) + if T.Response.self == EmptyResponseDTO.self { + observer.onNext(EmptyResponseDTO() as! T.Response) + } else { + observer.onError(NetworkError.invalidResponse) + } } observer.onCompleted() } catch { diff --git a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift b/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift index b0e504e2..26ce211a 100644 --- a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift +++ b/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift @@ -14,7 +14,9 @@ public final class AuthInterceptor: Interceptor { public func adapt(_ request: URLRequest) -> URLRequest { var request = request if case .success(let token) = tokenRepository.fetchToken(type: .accessToken) { + #if DEBUG print("accessToken: \(token)") + #endif request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") } return request diff --git a/MLS/MLS/Application/SceneDelegate.swift b/MLS/MLS/Application/SceneDelegate.swift index 5e0d0292..cf82223f 100644 --- a/MLS/MLS/Application/SceneDelegate.swift +++ b/MLS/MLS/Application/SceneDelegate.swift @@ -25,18 +25,18 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { let coordinator = DIContainer.resolve(type: AppCoordinatorProtocol.self) coordinator.window = window - self.appCoordinator = coordinator + appCoordinator = coordinator startScene(coordinator: coordinator) } func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - if let url = URLContexts.first?.url { - if AuthApi.isKakaoTalkLoginUrl(url) { - _ = AuthController.handleOpenUrl(url: url) - } + if let url = URLContexts.first?.url { + if AuthApi.isKakaoTalkLoginUrl(url) { + _ = AuthController.handleOpenUrl(url: url) } } + } private func startScene(coordinator: AppCoordinatorProtocol) { let fetchTokenUseCase = DIContainer.resolve(type: FetchTokenFromLocalUseCase.self) @@ -46,7 +46,9 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { switch fetchResult { case .success(let refreshToken): + #if DEBUG print("refreshToken: \(refreshToken)") + #endif reissueUseCase.execute(refreshToken: refreshToken) .observe(on: MainScheduler.instance) .subscribe( From 47ee13364347e39ff5182a52f30acd6c25042c09 Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 19 Dec 2025 16:55:24 +0900 Subject: [PATCH 31/31] =?UTF-8?q?fix/dev:=20=EC=B4=88=EC=84=B1=20=ED=8C=90?= =?UTF-8?q?=EB=B3=84=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 --- .../BaseFeature/BaseFeature/Utills/Extension/String+.swift | 4 ++-- .../DictionarySearch/DictionarySearchViewController.swift | 2 +- .../DictionarySearchResultViewController.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift index 12d07a00..59091f42 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift +++ b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift @@ -2,9 +2,9 @@ import Foundation extension String { public func isOnlyKorean() -> Bool { - return !self.isEmpty && self.allSatisfy { char in + return !self.contains { char in guard let scalar = char.unicodeScalars.first else { return false } - return !(0xAC00...0xD7A3).contains(scalar.value) + return (0x3131...0x3163).contains(scalar.value) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift index a66f62ad..a1b2dede 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift @@ -162,7 +162,7 @@ extension DictionarySearchViewController { case .dismiss: owner.navigationController?.popViewController(animated: true) case .search(let keyword): - if keyword.isOnlyKorean(), keyword != "" { + if !keyword.isOnlyKorean() { GuideAlertFactory.show(mainText: "초성은 검색할 수 없습니다.", ctaText: "확인", ctaAction: {}) } else { owner.mainView.searchBar.textField.text = "" diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift index d04818a4..b9bfe4ba 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift @@ -207,7 +207,7 @@ public extension DictionarySearchResultViewController { .skip(1) .observe(on: MainScheduler.instance) .bind(with: self) { owner, newKeyword in - if newKeyword.isOnlyKorean(), newKeyword != "" { + if !newKeyword.isOnlyKorean() { GuideAlertFactory.show(mainText: "초성은 검색할 수 없습니다.", ctaText: "확인", ctaAction: {}) } else { owner.updateViewControllers(keyword: newKeyword)