From 1a938b7ad8eb1b17aa40e7afd7dcb97e125302f0 Mon Sep 17 00:00:00 2001 From: p2glet Date: Thu, 27 Nov 2025 21:20:38 +0900 Subject: [PATCH 1/7] =?UTF-8?q?fix/#273:=20=ED=83=AD=EB=B0=94=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=88=98=EC=A0=95=20(AppCoordinator)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MLS/Core/Core/DIContainer/DIContainer.swift | 4 +- .../AuthAPI/WithdrawUseCaseImpl.swift | 24 ++- MLS/MLS/Application/AppCoordinator.swift | 10 +- MLS/MLS/Application/AppDelegate.swift | 195 +++++++++--------- MLS/MLS/Application/SceneDelegate.swift | 22 +- .../OnBoardingNotificationFactoryImpl.swift | 10 +- .../OnBoardingNotificationReactor.swift | 6 +- ...OnBoardingNotificationViewController.swift | 15 +- .../OnBoardingInputFactoryImpl.swift | 12 +- .../OnBoardingInputViewController.swift | 11 +- ...BoardingNotificationSheetFactoryImpl.swift | 1 + ...rdingNotificationSheetViewController.swift | 1 + .../OnBoardingQuestionFactoryImpl.swift | 1 + .../TermsAgreementFactoryImpl.swift | 1 + .../Interface/AppCoordinatorProtocol.swift | 7 + .../Interface}/LoginExitRoute.swift | 0 .../DictionaryMainViewFactoryImpl.swift | 1 + .../SetProfile/SetProfileReactor.swift | 2 +- 18 files changed, 186 insertions(+), 137 deletions(-) create mode 100644 MLS/Presentation/BaseFeature/BaseFeature/Interface/AppCoordinatorProtocol.swift rename MLS/Presentation/{AuthFeature/AuthFeatureInterface => BaseFeature/BaseFeature/Interface}/LoginExitRoute.swift (100%) diff --git a/MLS/Core/Core/DIContainer/DIContainer.swift b/MLS/Core/Core/DIContainer/DIContainer.swift index 58830dc9..c0fb129d 100644 --- a/MLS/Core/Core/DIContainer/DIContainer.swift +++ b/MLS/Core/Core/DIContainer/DIContainer.swift @@ -30,7 +30,7 @@ public final class DIContainer { private extension DIContainer { private func register(type: T.Type, name: String?, object: @escaping () -> T) { - serviceQueue.sync { +// serviceQueue.sync { let key = ObjectIdentifier(type) var namedServices = services[key] ?? [:] // 같은 식별자로 이미 저장되어있는 객체가 있다면 fatalError @@ -40,7 +40,7 @@ private extension DIContainer { // 문자열 식별자를 입력하지 않으면 default로 간주하여 저장 namedServices[name ?? "default"] = { object() } services[key] = namedServices - } +// } } private func resolve(type: T.Type, name: String?) -> T { diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift index 7e6b00ad..f0b6cc09 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift @@ -14,12 +14,24 @@ public class WithdrawUseCaseImpl: WithdrawUseCase { } public func execute() -> Completable { - switch tokenRepository.deleteToken(type: .accessToken) { - case .success: - return authRepository.withdraw() - case .failure(let error): - return .error(error) - } + return authRepository.withdraw() + .andThen(Completable.deferred { [weak self] in + guard let self = self else { return .empty() } + let results: [Result] = [ + self.tokenRepository.deleteToken(type: .accessToken), + self.tokenRepository.deleteToken(type: .refreshToken), + self.tokenRepository.deleteToken(type: .fcmToken) + ] + + if let error = results.compactMap({ result in + if case let .failure(error) = result { return error } + return nil + }).first { + return .error(error) + } else { + return .empty() + } + }) } } diff --git a/MLS/MLS/Application/AppCoordinator.swift b/MLS/MLS/Application/AppCoordinator.swift index 1877aed6..947e4dea 100644 --- a/MLS/MLS/Application/AppCoordinator.swift +++ b/MLS/MLS/Application/AppCoordinator.swift @@ -10,9 +10,9 @@ import MyPageFeatureInterface import RxSwift -public final class AppCoordinator { +public final class AppCoordinator: AppCoordinatorProtocol { // MARK: - Properties - private let window: UIWindow + public var window: UIWindow? private let dictionaryMainViewFactory: DictionaryMainViewFactory private let bookmarkMainFactory: BookmarkMainFactory private let myPageMainFactory: MyPageMainFactory @@ -22,7 +22,7 @@ public final class AppCoordinator { // MARK: - Init public init( - window: UIWindow, + window: UIWindow?, dictionaryMainViewFactory: DictionaryMainViewFactory, bookmarkMainFactory: BookmarkMainFactory, myPageMainFactory: MyPageMainFactory, @@ -64,7 +64,7 @@ public final class AppCoordinator { // MARK: - Private Helper private func setRoot(_ viewController: UIViewController) { - window.rootViewController = viewController - window.makeKeyAndVisible() + window?.rootViewController = viewController + window?.makeKeyAndVisible() } } diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 3312149e..16550131 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -28,23 +28,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication - .LaunchOptionsKey: Any]? - ) -> Bool { + .LaunchOptionsKey: Any]?) -> Bool + { // MARK: - UserNotification Set - FirebaseApp.configure() // Firebase Set - Messaging.messaging().delegate = self // 파이어베이스 Meesaging 설정 + FirebaseApp.configure() // Firebase Set + Messaging.messaging().delegate = self // 파이어베이스 Meesaging 설정 - UNUserNotificationCenter.current().delegate = self // NotificationCenter Delegate - let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정 + UNUserNotificationCenter.current().delegate = self // NotificationCenter Delegate + let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정 UNUserNotificationCenter.current().requestAuthorization( options: authOptions, - completionHandler: { _, _ in } - ) - application.registerForRemoteNotifications() // UNUserNotificationCenterDelegate를 구현한 메서드를 실행시킴 + completionHandler: { _, _ in }) + application.registerForRemoteNotifications() // UNUserNotificationCenterDelegate를 구현한 메서드를 실행시킴 // 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 = @@ -58,8 +57,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions - ) -> UISceneConfiguration { + options: UIScene.ConnectionOptions) -> UISceneConfiguration + { return UISceneConfiguration( name: "Default Configuration", sessionRole: connectingSceneSession.role) @@ -67,8 +66,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, - didDiscardSceneSessions sceneSessions: Set - ) {} + didDiscardSceneSessions sceneSessions: Set) {} } // MARK: - Notification Delegate, MessagingDelegate @@ -78,21 +76,20 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping ( UNNotificationPresentationOptions - ) -> Void - ) { + ) -> Void) + { completionHandler([.list, .banner]) } // 파이어베이스 MessagingDelegate 설정 func messaging( - _ messaging: Messaging, didReceiveRegistrationToken fcmToken: String? - ) { + _ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) + { let dataDict: [String: String] = ["token": fcmToken ?? ""] NotificationCenter.default.post( name: Notification.Name("FCMToken"), object: nil, - userInfo: dataDict - ) + userInfo: dataDict) let tokenUseCase = DIContainer.resolve( type: SaveTokenToLocalUseCase.self) let result = tokenUseCase.execute( @@ -108,26 +105,35 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { } // MARK: - registerDependencies -extension AppDelegate { - fileprivate func registerDependencies() { +private extension AppDelegate { + func registerDependencies() { registerProvider() registerRepository() registerUseCase() registerFactory() + + DIContainer.register(type: AppCoordinatorProtocol.self) { + AppCoordinator( + window: nil, + dictionaryMainViewFactory: DIContainer.resolve(type: DictionaryMainViewFactory.self), + bookmarkMainFactory: DIContainer.resolve(type: BookmarkMainFactory.self), + myPageMainFactory: DIContainer.resolve(type: MyPageMainFactory.self), + loginFactory: DIContainer.resolve(type: LoginFactory.self)) + } } - fileprivate func registerProvider() { + func registerProvider() { DIContainer.register(type: NetworkProvider.self) { NetworkProviderImpl() } DIContainer.register( - type: SocialAuthenticatableProvider.self, name: "kakao" - ) { + type: SocialAuthenticatableProvider.self, name: "kakao") + { KakaoLoginProviderImpl() } DIContainer.register( - type: SocialAuthenticatableProvider.self, name: "apple" - ) { + type: SocialAuthenticatableProvider.self, name: "apple") + { AppleLoginProviderImpl() } DIContainer.register(type: Interceptor.self) { @@ -137,12 +143,11 @@ extension AppDelegate { } } - fileprivate func registerRepository() { + func registerRepository() { DIContainer.register(type: AuthAPIRepository.self) { AuthAPIRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), - interceptor: DIContainer.resolve(type: Interceptor.self) - ) + interceptor: DIContainer.resolve(type: Interceptor.self)) } DIContainer.register(type: TokenRepository.self) { KeyChainRepositoryImpl() @@ -177,17 +182,17 @@ extension AppDelegate { } } - fileprivate func registerUseCase() { + func registerUseCase() { DIContainer.register( - type: FetchSocialCredentialUseCase.self, name: "kakao" - ) { + type: FetchSocialCredentialUseCase.self, name: "kakao") + { let provider = DIContainer.resolve( type: SocialAuthenticatableProvider.self, name: "kakao") return SocialLoginUseCaseImpl(provider: provider) } DIContainer.register( - type: FetchSocialCredentialUseCase.self, name: "apple" - ) { + type: FetchSocialCredentialUseCase.self, name: "apple") + { let provider = DIContainer.resolve( type: SocialAuthenticatableProvider.self, name: "apple") return SocialLoginUseCaseImpl(provider: provider) @@ -256,8 +261,7 @@ extension AppDelegate { UpdateMarketingAgreementUseCaseImpl( authRepository: DIContainer.resolve( type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self) - ) + tokenRepository: DIContainer.resolve(type: TokenRepository.self)) } DIContainer.register(type: CheckNotificationPermissionUseCase.self) { CheckNotificationPermissionUseCaseImpl() @@ -274,8 +278,7 @@ extension AppDelegate { CheckLoginUseCaseImpl( authRepository: DIContainer.resolve( type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self) - ) + tokenRepository: DIContainer.resolve(type: TokenRepository.self)) } DIContainer.register(type: FetchDictionaryAllListUseCase.self) { FetchDictionaryAllListUseCaseImpl( @@ -449,8 +452,7 @@ extension AppDelegate { DIContainer.register(type: FetchProfileUseCase.self) { FetchProfileUseCaseImpl( repository: DIContainer.resolve(type: AuthAPIRepository.self), - fetchJobUseCase: DIContainer.resolve(type: FetchJobUseCase.self) - ) + fetchJobUseCase: DIContainer.resolve(type: FetchJobUseCase.self)) } DIContainer.register(type: CheckNickNameUseCase.self) { CheckNickNameUseCaseImpl() @@ -467,8 +469,7 @@ extension AppDelegate { WithdrawUseCaseImpl( authRepository: DIContainer.resolve( type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self) - ) + tokenRepository: DIContainer.resolve(type: TokenRepository.self)) } DIContainer.register(type: FetchNoticesUseCase.self) { FetchNoticesUseCaseImpl( @@ -527,7 +528,7 @@ extension AppDelegate { } } - fileprivate func registerFactory() { + func registerFactory() { DIContainer.register(type: ItemFilterBottomSheetFactory.self) { ItemFilterBottomSheetFactoryImpl() } @@ -544,8 +545,7 @@ extension AppDelegate { BookmarkModalFactoryImpl( addCollectionFactory: DIContainer.resolve( type: AddCollectionFactory.self), fetchCollectionListUseCase: DIContainer.resolve(type: FetchCollectionListUseCase.self), - addCollectionAndBookmarkUseCase: DIContainer.resolve(type: AddCollectionAndBookmarkUseCase.self) - ) + addCollectionAndBookmarkUseCase: DIContainer.resolve(type: AddCollectionAndBookmarkUseCase.self)) } DIContainer.register(type: LoginFactory.self) { LoginFactoryImpl( @@ -564,8 +564,7 @@ extension AppDelegate { putFCMTokenUseCase: DIContainer.resolve( type: PutFCMTokenUseCase.self), fetchPlatformUseCase: DIContainer.resolve( - type: FetchPlatformUseCase.self) - ) + type: FetchPlatformUseCase.self)) } DIContainer.register(type: DictionaryDetailFactory.self) { DictionaryDetailFactoryImpl( @@ -616,7 +615,7 @@ extension AppDelegate { dictionaryQuestListItemUseCase: DIContainer.resolve( type: FetchDictionaryQuestListUseCase.self), dictionaryNpcListItemUseCase: - DIContainer + DIContainer .resolve(type: FetchDictionaryNpcListUseCase.self), dictionaryListItemUseCase: DIContainer.resolve( type: FetchDictionaryMonsterListUseCase.self), @@ -634,19 +633,17 @@ extension AppDelegate { type: BookmarkModalFactory.self), detailFactory: DIContainer.resolve( type: DictionaryDetailFactory.self), - loginFactory: { DIContainer.resolve(type: LoginFactory.self) } - ) + loginFactory: { DIContainer.resolve(type: LoginFactory.self) }) } DIContainer.register(type: DictionarySearchResultFactory.self) { DictionarySearchResultFactoryImpl( dictionaryListCountUseCase: DIContainer.resolve( type: FetchDictionaryListCountUseCase.self), dictionaryMainListFactory: - DIContainer + DIContainer .resolve(type: DictionaryMainListFactory.self), dictionarySearchListUseCase: DIContainer.resolve( - type: FetchDictionarySearchListUseCase.self) - ) + type: FetchDictionarySearchListUseCase.self)) } DIContainer.register(type: DictionarySearchFactory.self) { DictionarySearchFactoryImpl( @@ -655,7 +652,7 @@ extension AppDelegate { recentSearchAddUseCase: DIContainer.resolve( type: RecentSearchAddUseCase.self), searchResultFactory: - DIContainer + DIContainer .resolve(type: DictionarySearchResultFactory.self), recentSearchFetchUseCase: DIContainer.resolve( type: RecentSearchFetchUseCase.self)) @@ -679,33 +676,31 @@ extension AppDelegate { DIContainer.register(type: DictionaryMainViewFactory.self) { DictionaryMainViewFactoryImpl( dictionaryMainListFactory: - DIContainer + DIContainer .resolve(type: DictionaryMainListFactory.self), searchFactory: DIContainer.resolve( type: DictionarySearchFactory.self), notificationFactory: - DIContainer + DIContainer .resolve(type: DictionaryNotificationFactory.self), checkLoginUseCase: DIContainer.resolve( - type: CheckLoginUseCase.self) - ) + type: CheckLoginUseCase.self)) } 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), dictionaryMainViewFactory: DIContainer.resolve( - type: DictionaryMainViewFactory.self) - ) + type: DictionaryMainViewFactory.self)) } DIContainer.register(type: OnBoardingInputFactory.self) { OnBoardingInputFactoryImpl( @@ -718,8 +713,13 @@ extension AppDelegate { updateUserInfoUseCase: DIContainer.resolve( type: UpdateUserInfoUseCase.self), onBoardingNotificationFactory: DIContainer.resolve( - type: OnBoardingNotificationFactory.self) - ) + type: OnBoardingNotificationFactory.self), + dictionaryMainViewFactory: DIContainer.resolve( + type: DictionaryMainViewFactory.self + ), + appCoordinator: { + DIContainer.resolve(type: AppCoordinatorProtocol.self) + }) } DIContainer.register(type: OnBoardingQuestionFactory.self) { OnBoardingQuestionFactoryImpl( @@ -740,35 +740,39 @@ extension AppDelegate { fetchTokenUseCase: DIContainer.resolve( type: FetchTokenFromLocalUseCase.self), updateMarketingAgreementUseCase: DIContainer.resolve( - type: UpdateMarketingAgreementUseCase.self) - ) + type: UpdateMarketingAgreementUseCase.self)) } DIContainer.register(type: OnBoardingNotificationFactory.self) { OnBoardingNotificationFactoryImpl( onBoardingNotificationSheetFactory: DIContainer.resolve( - type: OnBoardingNotificationSheetFactory.self)) + type: OnBoardingNotificationSheetFactory.self), + dictionaryMainViewFactory: DIContainer.resolve( + type: DictionaryMainViewFactory.self + ), + appCoordinator: { DIContainer.resolve( + type: AppCoordinatorProtocol.self + ) }) } DIContainer.register(type: BookmarkMainFactory.self) { BookmarkMainFactoryImpl( setBookmarkUseCase: - DIContainer + DIContainer .resolve(type: SetBookmarkUseCase.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 - ) - ) + )) } DIContainer.register(type: BookmarkOnBoardingFactory.self) { BookmarkOnBoardingFactoryImpl() @@ -820,29 +824,28 @@ extension AppDelegate { 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 .resolve(type: DeleteCollectionUseCase.self), - addCollectionAndBookmarkUseCase: DIContainer.resolve(type: AddCollectionAndBookmarkUseCase.self) - ) + addCollectionAndBookmarkUseCase: DIContainer.resolve(type: AddCollectionAndBookmarkUseCase.self)) } DIContainer.register(type: CollectionSettingFactory.self) { CollectionSettingFactoryImpl() @@ -858,20 +861,19 @@ 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) - ) + type: FetchProfileUseCase.self)) } DIContainer.register(type: CustomerSupportFactory.self) { CustomerSupportBaseViewFactoryImpl( @@ -902,18 +904,17 @@ 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 - .resolve(type: UpdateUserInfoUseCase.self) - ) + DIContainer + .resolve(type: UpdateUserInfoUseCase.self)) } DIContainer.register(type: SelectImageFactory.self) { SelectImageFactoryImpl( diff --git a/MLS/MLS/Application/SceneDelegate.swift b/MLS/MLS/Application/SceneDelegate.swift index f30fc210..ead91387 100644 --- a/MLS/MLS/Application/SceneDelegate.swift +++ b/MLS/MLS/Application/SceneDelegate.swift @@ -1,6 +1,7 @@ import UIKit import AuthFeatureInterface +import BaseFeature import BookmarkFeatureInterface import Core import DictionaryFeatureInterface @@ -12,7 +13,7 @@ import RxSwift final class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - var appCoordinator: AppCoordinator? + var appCoordinator: AppCoordinatorProtocol? var disposeBag = DisposeBag() func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { @@ -21,19 +22,9 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { let window = UIWindow(windowScene: windowScene) window.makeKeyAndVisible() self.window = window - - let dictionaryMainViewFactory: DictionaryMainViewFactory = DIContainer.resolve(type: DictionaryMainViewFactory.self) - let bookmarkMainFactory: BookmarkMainFactory = DIContainer.resolve(type: BookmarkMainFactory.self) - let myPageMainFactory: MyPageMainFactory = DIContainer.resolve(type: MyPageMainFactory.self) - let loginFactory: LoginFactory = DIContainer.resolve(type: LoginFactory.self) - - let coordinator = AppCoordinator( - window: window, - dictionaryMainViewFactory: dictionaryMainViewFactory, - bookmarkMainFactory: bookmarkMainFactory, - myPageMainFactory: myPageMainFactory, - loginFactory: loginFactory - ) + + let coordinator = DIContainer.resolve(type: AppCoordinatorProtocol.self) + coordinator.window = window self.appCoordinator = coordinator startScene(coordinator: coordinator) @@ -47,7 +38,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { } } - private func startScene(coordinator: AppCoordinator) { + private func startScene(coordinator: AppCoordinatorProtocol) { let fetchTokenUseCase = DIContainer.resolve(type: FetchTokenFromLocalUseCase.self) let reissueUseCase = DIContainer.resolve(type: ReissueUseCase.self) let saveTokenUseCase = DIContainer.resolve(type: SaveTokenToLocalUseCase.self) @@ -71,7 +62,6 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { } }, onError: { error in - print(error) coordinator.showLogin(exitRoute: .home) } ) diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift index 8d0c92bf..c03d3a01 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift @@ -1,15 +1,21 @@ import AuthFeatureInterface import BaseFeature +import DictionaryFeatureInterface public struct OnBoardingNotificationFactoryImpl: OnBoardingNotificationFactory { private let onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory + private let dictionaryMainViewFactory: DictionaryMainViewFactory + private let appCoordinator: () -> AppCoordinatorProtocol - public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory) { + public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, dictionaryMainViewFactory: DictionaryMainViewFactory, appCoordinator: @escaping () -> AppCoordinatorProtocol) { self.onBoardingNotificationSheetFactory = onBoardingNotificationSheetFactory + self.dictionaryMainViewFactory = dictionaryMainViewFactory + self.appCoordinator = appCoordinator } public func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController { - let viewController = OnBoardingNotificationViewController(onBoardingNotificationSheetFactory: onBoardingNotificationSheetFactory) + let viewController = OnBoardingNotificationViewController(onBoardingNotificationSheetFactory: onBoardingNotificationSheetFactory, dictionaryMainViewFactory: dictionaryMainViewFactory, appCoordinator: appCoordinator()) + viewController.isBottomTabbarHidden = true viewController.reactor = OnBoardingNotificationReactor(selectedLevel: selectedLevel, selectedJobID: selectedJobID) return viewController } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationReactor.swift index 43ca062c..4d4029b4 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationReactor.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationReactor.swift @@ -6,10 +6,12 @@ public final class OnBoardingNotificationReactor: Reactor { public enum Route { case none case notificationAlert + case home } public enum Action { case nextButtonTapped + case skipButtonTapped } public enum Mutation { @@ -35,7 +37,9 @@ public final class OnBoardingNotificationReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case .nextButtonTapped: - return Observable.just(.navigateTo(route: .notificationAlert)) + return .just(.navigateTo(route: .notificationAlert)) + case .skipButtonTapped: + return .just(.navigateTo(route: .home)) } } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift index 4606d009..270e5292 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift @@ -3,6 +3,7 @@ import UserNotifications import AuthFeatureInterface import BaseFeature +import DictionaryFeatureInterface import ReactorKit import RxCocoa @@ -16,13 +17,17 @@ public class OnBoardingNotificationViewController: BaseViewController, View { public var disposeBag = DisposeBag() private let onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory + private let dictionaryMainViewFactory: DictionaryMainViewFactory + private let appCoordinator: AppCoordinatorProtocol // MARK: - Components private var mainView = OnBoardingNotificationView() - public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory) { + public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, dictionaryMainViewFactory: DictionaryMainViewFactory, appCoordinator: AppCoordinatorProtocol) { self.onBoardingNotificationSheetFactory = onBoardingNotificationSheetFactory + self.dictionaryMainViewFactory = dictionaryMainViewFactory + self.appCoordinator = appCoordinator super.init() } @@ -73,6 +78,11 @@ public extension OnBoardingNotificationViewController { .map { Reactor.Action.nextButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) + + mainView.headerView.underlineTextButton.rx.tap + .map { Reactor.Action.skipButtonTapped } + .bind(to: reactor.action) + .disposed(by: disposeBag) } func bindViewState(reactor: Reactor) { @@ -80,11 +90,14 @@ public extension OnBoardingNotificationViewController { .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } .withUnretained(self) + .observe(on: MainScheduler.instance) .subscribe { owner, route in switch route { case .notificationAlert: let viewController = owner.onBoardingNotificationSheetFactory.make(selectedLevel: reactor.currentState.selectedLevel, selectedJobID: reactor.currentState.selectedJobID) owner.presentModal(viewController) + case .home: + owner.appCoordinator.showMainTab() default: break } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift index 3267186e..bc5b47f6 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift @@ -1,5 +1,6 @@ import AuthFeatureInterface import BaseFeature +import DictionaryFeatureInterface import DomainInterface public struct OnBoardingInputFactoryImpl: OnBoardingInputFactory { @@ -8,23 +9,30 @@ public struct OnBoardingInputFactoryImpl: OnBoardingInputFactory { private let fetchJobListUseCase: FetchJobListUseCase private let updateUserInfoUseCase: UpdateUserInfoUseCase private let onBoardingNotificationFactory: OnBoardingNotificationFactory + private let dictionaryMainViewFactory: DictionaryMainViewFactory + private let appCoordinator: () -> AppCoordinatorProtocol public init( checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase, checkValidLevelUseCase: CheckValidLevelUseCase, fetchJobListUseCase: FetchJobListUseCase, updateUserInfoUseCase: UpdateUserInfoUseCase, - onBoardingNotificationFactory: OnBoardingNotificationFactory + onBoardingNotificationFactory: OnBoardingNotificationFactory, + dictionaryMainViewFactory: DictionaryMainViewFactory, + appCoordinator: @escaping () -> AppCoordinatorProtocol ) { self.checkEmptyUseCase = checkEmptyUseCase self.checkValidLevelUseCase = checkValidLevelUseCase self.fetchJobListUseCase = fetchJobListUseCase self.updateUserInfoUseCase = updateUserInfoUseCase self.onBoardingNotificationFactory = onBoardingNotificationFactory + self.dictionaryMainViewFactory = dictionaryMainViewFactory + self.appCoordinator = appCoordinator } public func make() -> BaseViewController { - let viewController = OnBoardingInputViewController(onBoardingNotificationFactory: onBoardingNotificationFactory) + let viewController = OnBoardingInputViewController(onBoardingNotificationFactory: onBoardingNotificationFactory, dictionaryMainViewFactory: dictionaryMainViewFactory, appCoordinator: appCoordinator()) + viewController.isBottomTabbarHidden = true viewController.reactor = OnBoardingInputReactor( checkEmptyUseCase: checkEmptyUseCase, checkValidLevelUseCase: checkValidLevelUseCase, diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift index 93ec8eb6..4d467fc1 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift @@ -3,6 +3,7 @@ import UIKit import AuthFeatureInterface import BaseFeature import DesignSystem +import DictionaryFeatureInterface import ReactorKit import RxCocoa @@ -17,13 +18,17 @@ public class OnBoardingInputViewController: BaseViewController, View { public var disposeBag = DisposeBag() private let onBoardingNotificationFactory: OnBoardingNotificationFactory + private let dictionaryMainViewFactory: DictionaryMainViewFactory + private let appCoordinator: AppCoordinatorProtocol // MARK: - Components private var mainView = OnBoardingInputView() - init(onBoardingNotificationFactory: OnBoardingNotificationFactory) { + init(onBoardingNotificationFactory: OnBoardingNotificationFactory, dictionaryMainViewFactory: DictionaryMainViewFactory, appCoordinator: AppCoordinatorProtocol) { self.onBoardingNotificationFactory = onBoardingNotificationFactory + self.dictionaryMainViewFactory = dictionaryMainViewFactory + self.appCoordinator = appCoordinator super.init() } } @@ -140,9 +145,7 @@ public extension OnBoardingInputViewController { case .dismiss: owner.navigationController?.popViewController(animated: true) case .home: - let controller = UIViewController() - controller.view.backgroundColor = .green - owner.navigationController?.pushViewController(controller, animated: true) + owner.appCoordinator.showMainTab() case .error: let errorViewController = BaseErrorViewController() owner.present(errorViewController, animated: true) diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift index 85de382f..b2ab803f 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift @@ -26,6 +26,7 @@ public struct OnBoardingNotificationSheetFactoryImpl: OnBoardingNotificationShee public func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController & ModalPresentable { let viewController = OnBoardingNotificationSheetViewController(dictionaryMainViewFactory: dictionaryMainViewFactory) + viewController.isBottomTabbarHidden = true viewController.reactor = OnBoardingNotificationSheetReactor( selectedLevel: selectedLevel, selectedJobID: selectedJobID, diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift index 5738ad10..dce5deee 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift @@ -113,6 +113,7 @@ extension OnBoardingNotificationSheetViewController { owner.dismissCurrentModal() case .home: let viewController = owner.dictionaryMainViewFactory.make() + viewController.isBottomTabbarHidden = false let navigationController = UINavigationController(rootViewController: viewController) AppRouter.setRoot(navigationController) case .setting: diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionFactoryImpl.swift index 133cf277..051cb8ba 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionFactoryImpl.swift @@ -11,6 +11,7 @@ public struct OnBoardingQuestionFactoryImpl: OnBoardingQuestionFactory { public func make() -> BaseViewController { let viewController = OnBoardingQuestionViewController(factory: onBoardingInputFactory) + viewController.isBottomTabbarHidden = true viewController.reactor = OnBoardingQuestionReactor() return viewController } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift index bf7a1e72..ef9763b0 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift @@ -29,6 +29,7 @@ public struct TermsAgreementFactoryImpl: TermsAgreementFactory { public func make(credential: Credential, platform: LoginPlatform) -> BaseViewController { let viewController = TermsAgreementViewController(onBoardingQuestionFactory: onBoardingQuestionFactory) + viewController.isBottomTabbarHidden = true viewController.reactor = TermsAgreementReactor( credential: credential, socialPlatform: platform, diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Interface/AppCoordinatorProtocol.swift b/MLS/Presentation/BaseFeature/BaseFeature/Interface/AppCoordinatorProtocol.swift new file mode 100644 index 00000000..24f9b2ca --- /dev/null +++ b/MLS/Presentation/BaseFeature/BaseFeature/Interface/AppCoordinatorProtocol.swift @@ -0,0 +1,7 @@ +import UIKit + +public protocol AppCoordinatorProtocol: AnyObject { + var window: UIWindow? { get set } + func showMainTab() + func showLogin(exitRoute: LoginExitRoute) +} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/LoginExitRoute.swift b/MLS/Presentation/BaseFeature/BaseFeature/Interface/LoginExitRoute.swift similarity index 100% rename from MLS/Presentation/AuthFeature/AuthFeatureInterface/LoginExitRoute.swift rename to MLS/Presentation/BaseFeature/BaseFeature/Interface/LoginExitRoute.swift diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewFactoryImpl.swift index 579cc17b..d490c9a3 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewFactoryImpl.swift @@ -18,6 +18,7 @@ public final class DictionaryMainViewFactoryImpl: DictionaryMainViewFactory { public func make() -> BaseViewController { let reactor = DictionaryMainReactor(checkLoginUseCase: checkLoginUseCase) let viewController = DictionaryMainViewController(dictionaryMainListFactory: dictionaryMainListFactory, searchFactory: searchFactory, notificationFactory: notificationFactory, reactor: reactor) + viewController.isBottomTabbarHidden = false viewController.reactor = reactor return viewController } diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileReactor.swift index b3670092..25141721 100644 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileReactor.swift +++ b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileReactor.swift @@ -109,7 +109,7 @@ public final class SetProfileReactor: Reactor { .andThen(.just(.toNavigate(.dismiss))) case .withdraw: return withdrawUseCase.execute() - .andThen(.empty()) + .andThen(.just(.toNavigate(.dismiss))) case .viewWillAppear: return fetchProfileUseCase.execute() .map { Mutation.setProfile($0)} From 301e02b713b6d89435528ccaddde153ca964b966 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Nov 2025 12:32:37 +0000 Subject: [PATCH 2/7] style/#273: Apply SwiftLint autocorrect --- MLS/MLS/Application/AppDelegate.swift | 24 ++++++++---------------- MLS/MLS/Application/SceneDelegate.swift | 4 ++-- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 16550131..a5a78959 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -28,8 +28,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication - .LaunchOptionsKey: Any]?) -> Bool - { + .LaunchOptionsKey: Any]?) -> Bool { // MARK: - UserNotification Set FirebaseApp.configure() // Firebase Set Messaging.messaging().delegate = self // 파이어베이스 Meesaging 설정 @@ -57,8 +56,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions) -> UISceneConfiguration - { + options: UIScene.ConnectionOptions) -> UISceneConfiguration { return UISceneConfiguration( name: "Default Configuration", sessionRole: connectingSceneSession.role) @@ -76,15 +74,13 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping ( UNNotificationPresentationOptions - ) -> Void) - { + ) -> Void) { completionHandler([.list, .banner]) } // 파이어베이스 MessagingDelegate 설정 func messaging( - _ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) - { + _ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { let dataDict: [String: String] = ["token": fcmToken ?? ""] NotificationCenter.default.post( name: Notification.Name("FCMToken"), @@ -127,13 +123,11 @@ private extension AppDelegate { NetworkProviderImpl() } DIContainer.register( - type: SocialAuthenticatableProvider.self, name: "kakao") - { + type: SocialAuthenticatableProvider.self, name: "kakao") { KakaoLoginProviderImpl() } DIContainer.register( - type: SocialAuthenticatableProvider.self, name: "apple") - { + type: SocialAuthenticatableProvider.self, name: "apple") { AppleLoginProviderImpl() } DIContainer.register(type: Interceptor.self) { @@ -184,15 +178,13 @@ private extension AppDelegate { func registerUseCase() { DIContainer.register( - type: FetchSocialCredentialUseCase.self, name: "kakao") - { + type: FetchSocialCredentialUseCase.self, name: "kakao") { let provider = DIContainer.resolve( type: SocialAuthenticatableProvider.self, name: "kakao") return SocialLoginUseCaseImpl(provider: provider) } DIContainer.register( - type: FetchSocialCredentialUseCase.self, name: "apple") - { + type: FetchSocialCredentialUseCase.self, name: "apple") { let provider = DIContainer.resolve( type: SocialAuthenticatableProvider.self, name: "apple") return SocialLoginUseCaseImpl(provider: provider) diff --git a/MLS/MLS/Application/SceneDelegate.swift b/MLS/MLS/Application/SceneDelegate.swift index ead91387..929185d5 100644 --- a/MLS/MLS/Application/SceneDelegate.swift +++ b/MLS/MLS/Application/SceneDelegate.swift @@ -22,7 +22,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { let window = UIWindow(windowScene: windowScene) window.makeKeyAndVisible() self.window = window - + let coordinator = DIContainer.resolve(type: AppCoordinatorProtocol.self) coordinator.window = window self.appCoordinator = coordinator @@ -61,7 +61,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { coordinator.showLogin(exitRoute: .home) } }, - onError: { error in + onError: { _ in coordinator.showLogin(exitRoute: .home) } ) From 75449a5489a7ce10c1ea4febfbfc2082cacd3fbd Mon Sep 17 00:00:00 2001 From: p2glet Date: Thu, 27 Nov 2025 22:12:17 +0900 Subject: [PATCH 3/7] =?UTF-8?q?fix/#273:=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=8F=84=EA=B0=90=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MLS/MLS/Application/AppDelegate.swift | 3 +++ .../DictionaryDetailBaseViewController.swift | 20 +++++++++++++++---- .../DictionaryDetailFactoryImpl.swift | 14 ++++++++----- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 16550131..f62232b4 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -571,6 +571,9 @@ private extension AppDelegate { loginFactory: { DIContainer.resolve(type: LoginFactory.self) }, bookmarkModalFactory: DIContainer.resolve( type: BookmarkModalFactory.self), + appCoordinator: { + DIContainer.resolve(type: AppCoordinatorProtocol.self) + }, dictionaryDetailMapUseCase: DIContainer.resolve( type: FetchDictionaryDetailMapUseCase.self), dictionaryDetailMapSpawnMonsterUseCase: DIContainer.resolve( diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index 7b65a1e8..f83ddc75 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -30,16 +30,19 @@ class DictionaryDetailBaseViewController: BaseViewController { private let bookmarkModalFactory: BookmarkModalFactory private let loginFactory: LoginFactory + private let appCoordinator: AppCoordinatorProtocol + // MARK: - Components public var mainView = DictionaryDetailBaseView() // 타입설정 public var type: DictionaryItemType - public init(type: DictionaryItemType, bookmarkModalFactory: BookmarkModalFactory, loginFactory: LoginFactory) { + public init(type: DictionaryItemType, bookmarkModalFactory: BookmarkModalFactory, loginFactory: LoginFactory, appCoordinator: AppCoordinatorProtocol) { self.type = type self.bookmarkModalFactory = bookmarkModalFactory self.loginFactory = loginFactory + self.appCoordinator = appCoordinator mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) super.init() isBottomTabbarHidden = true @@ -331,15 +334,24 @@ private extension DictionaryDetailBaseViewController { func bindBackButton() { mainView.backButton.rx.tap - .bind { [weak self] in - self?.navigationController?.popViewController(animated: true) + .observe(on: MainScheduler.instance) + .withUnretained(self) + .bind { owner, _ in + owner.navigationController?.popViewController(animated: true) + } + .disposed(by: disposeBag) + + mainView.dictButton.rx.tap + .observe(on: MainScheduler.instance) + .withUnretained(self) + .bind { owner, _ in + owner.appCoordinator.showMainTab() } .disposed(by: disposeBag) } } extension DictionaryDetailBaseViewController { - // DictionaryDetailBaseViewController public func bindReportButton(providerId: Observable, itemName: Observable) { mainView.reportButton.rx.tap .withLatestFrom(Observable.combineLatest(providerId, itemName)) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift index e69107a9..55386c60 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift @@ -7,6 +7,8 @@ import DomainInterface public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { private let loginFactory: () -> LoginFactory private let bookmarkModalFactory: BookmarkModalFactory + private let appCoordinator: () -> AppCoordinatorProtocol + private let dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase private let dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase private let dictionaryDetailMapNpcUseCase: FetchDictionaryDetailMapNpcUseCase @@ -27,6 +29,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { public init( loginFactory: @escaping () -> LoginFactory, bookmarkModalFactory: BookmarkModalFactory, + appCoordinator: @escaping () -> AppCoordinatorProtocol, dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase, dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase, dictionaryDetailMapNpcUseCase: FetchDictionaryDetailMapNpcUseCase, @@ -60,6 +63,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { self.dictionaryDetailMonsterMapUseCase = dictionaryDetailMonsterMapUseCase self.checkLoginUseCase = checkLoginUseCase self.setBookmarkUseCase = setBookmarkUseCase + self.appCoordinator = appCoordinator } public func make(type: DictionaryType, id: Int) -> BaseViewController { @@ -70,7 +74,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { case .collection: break case .item: - viewController = ItemDictionaryDetailViewController(type: .item, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory()) + viewController = ItemDictionaryDetailViewController(type: .item, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) let reactor = ItemDictionaryDetailReactor( dictionaryDetailItemUseCase: dictionaryDetailItemUseCase, dictionaryDetailItemDropMonsterUseCase: dictionaryDetailItemDropMonsterUseCase, @@ -82,7 +86,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { viewController.reactor = reactor } case .monster: - viewController = MonsterDictionaryDetailViewController(type: .monster, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory()) + viewController = MonsterDictionaryDetailViewController(type: .monster, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) let reactor = MonsterDictionaryDetailReactor( dictionaryDetailMonsterUseCase: dictionaryDetailMonsterUseCase, dictionaryDetailMonsterDropItemUseCase: dictionaryDetailMonsterDropItemUseCase, @@ -103,7 +107,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { setBookmarkUseCase: setBookmarkUseCase, id: id ) - viewController = MapDictionaryDetailViewController(type: .map, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory()) + viewController = MapDictionaryDetailViewController(type: .map, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) if let viewController = viewController as? MapDictionaryDetailViewController { viewController.reactor = reactor } @@ -116,12 +120,12 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { setBookmarkUseCase: setBookmarkUseCase, id: id ) - viewController = NpcDictionaryDetailViewController(type: .npc, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory()) + viewController = NpcDictionaryDetailViewController(type: .npc, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) if let viewController = viewController as? NpcDictionaryDetailViewController { viewController.reactor = reactor } case .quest: - viewController = QuestDictionaryDetailViewController(type: .quest, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory()) + viewController = QuestDictionaryDetailViewController(type: .quest, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) let reactor = QuestDictionaryDetailReactor( dictionaryDetailQuestUseCase: dictionaryDetailQuestUseCase, dictionaryDetailQuestLinkedQuestUseCase: dictionaryDetailQuestLinkedQuestsUseCase, From 91c1ed165b9e0a81a4653487851ad346d743fac4 Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 28 Nov 2025 00:51:48 +0900 Subject: [PATCH 4/7] =?UTF-8?q?fix/#273:=20=EC=83=81=EC=84=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20->=20=EC=83=81=EC=84=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MLS/Core/Core/DIContainer/DIContainer.swift | 4 +-- .../xcshareddata/swiftpm/Package.resolved | 6 ++-- MLS/MLS/Application/AppDelegate.swift | 2 ++ .../project.pbxproj | 17 ++++++++++ .../DictionaryDetailBaseViewController.swift | 5 ++- .../DictionaryDetailFactoryImpl.swift | 13 +++++--- .../Item/ItemDictionaryDetailReactor.swift | 13 +++++--- .../ItemDictionaryDetailViewController.swift | 8 +++++ .../Map/MapDictionaryDetailReactor.swift | 21 +++++++++--- .../MapDictionaryDetailViewController.swift | 33 +++++++++++++++++++ .../MonsterDictionaryDetailReactor.swift | 15 ++++++--- ...onsterDictionaryDetailViewController.swift | 15 ++++++++- .../NPC/NpcDictionaryDetailReactor.swift | 15 ++++++--- .../NpcDictionaryDetailViewController.swift | 15 ++++++++- .../Quest/QuestDictionaryDetailReactor.swift | 25 +++++++++++++- .../QuestDictionaryDetailViewController.swift | 20 +++++++++++ .../DetailStackCardView.swift | 25 ++++++++++++-- 17 files changed, 219 insertions(+), 33 deletions(-) diff --git a/MLS/Core/Core/DIContainer/DIContainer.swift b/MLS/Core/Core/DIContainer/DIContainer.swift index c0fb129d..58830dc9 100644 --- a/MLS/Core/Core/DIContainer/DIContainer.swift +++ b/MLS/Core/Core/DIContainer/DIContainer.swift @@ -30,7 +30,7 @@ public final class DIContainer { private extension DIContainer { private func register(type: T.Type, name: String?, object: @escaping () -> T) { -// serviceQueue.sync { + serviceQueue.sync { let key = ObjectIdentifier(type) var namedServices = services[key] ?? [:] // 같은 식별자로 이미 저장되어있는 객체가 있다면 fatalError @@ -40,7 +40,7 @@ private extension DIContainer { // 문자열 식별자를 입력하지 않으면 default로 간주하여 저장 namedServices[name ?? "default"] = { object() } services[key] = namedServices -// } + } } private func resolve(type: T.Type, name: String?) -> T { diff --git a/MLS/MLS.xcworkspace/xcshareddata/swiftpm/Package.resolved b/MLS/MLS.xcworkspace/xcshareddata/swiftpm/Package.resolved index f4ae71b6..c7f6a5b9 100644 --- a/MLS/MLS.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/MLS/MLS.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "f7b0491e2198bb3edde5fd2999d888cbedc1acb8555c5e1c2b384a269b2fb29d", + "originHash" : "ba8fe7771291f9a80fd693d31ec15a696e49e0d6060bae5c6576060534c1d5b4", "pins" : [ { "identity" : "abseil-cpp-binary", @@ -168,8 +168,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/ReactiveX/RxSwift", "state" : { - "revision" : "5dd1907d64f0d36f158f61a466bab75067224893", - "version" : "6.9.0" + "revision" : "5004a18539bd68905c5939aa893075f578f4f03d", + "version" : "6.9.1" } }, { diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index f62232b4..32457c9f 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -571,6 +571,8 @@ private extension AppDelegate { loginFactory: { DIContainer.resolve(type: LoginFactory.self) }, bookmarkModalFactory: DIContainer.resolve( type: BookmarkModalFactory.self), + dictionaryDetailFactory: { DIContainer + .resolve(type: DictionaryDetailFactory.self) }, appCoordinator: { DIContainer.resolve(type: AppCoordinatorProtocol.self) }, diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.pbxproj b/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.pbxproj index 32df0154..cd987481 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.pbxproj +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.pbxproj @@ -56,6 +56,7 @@ 77C755BA2E4B70C30081D80F /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C755B72E4B70C30081D80F /* AuthFeatureInterface.framework */; }; 77C755BB2E4B70C30081D80F /* AuthFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C755B72E4B70C30081D80F /* AuthFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 77C755C12E4B917F0081D80F /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 77C755C02E4B917F0081D80F /* RxKeyboard */; }; + 77C7F4E52ED88D14009559E1 /* RxGesture in Frameworks */ = {isa = PBXBuildFile; productRef = 77C7F4E42ED88D14009559E1 /* RxGesture */; }; 77C974732E376124007198DA /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C974722E376124007198DA /* BookmarkFeatureInterface.framework */; }; 77C97DAB2E37D4AC007198DA /* AuthFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97DAA2E37D4AC007198DA /* AuthFeature.framework */; }; 77DBD8BF2E1AD0C600529428 /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBD8BE2E1AD0C600529428 /* BookmarkFeatureInterface.framework */; }; @@ -190,6 +191,7 @@ 081D9DC52DF80E15004F850D /* DomainInterface.framework in Frameworks */, 081D9DDA2DF80E7E004F850D /* ReactorKit in Frameworks */, 77C974732E376124007198DA /* BookmarkFeatureInterface.framework in Frameworks */, + 77C7F4E52ED88D14009559E1 /* RxGesture in Frameworks */, 77FEEF1D2EC5B0870023197A /* AuthFeatureInterface.framework in Frameworks */, 081D9DD02DF80E5C004F850D /* RxCocoa in Frameworks */, 77C97DAB2E37D4AC007198DA /* AuthFeature.framework in Frameworks */, @@ -339,6 +341,7 @@ 081D9DD62DF80E69004F850D /* SnapKit */, 081D9DD92DF80E7E004F850D /* ReactorKit */, 772DC9962E55CA93005F92E3 /* RxKeyboard */, + 77C7F4E42ED88D14009559E1 /* RxGesture */, ); productName = DictionaryFeature; productReference = 081D9C192DF80854004F850D /* DictionaryFeature.framework */; @@ -435,6 +438,7 @@ 081D9DD52DF80E69004F850D /* XCRemoteSwiftPackageReference "SnapKit" */, 081D9DD82DF80E7E004F850D /* XCRemoteSwiftPackageReference "ReactorKit" */, 77C755BF2E4B917F0081D80F /* XCRemoteSwiftPackageReference "RxKeyboard" */, + 77C7F4E32ED88D14009559E1 /* XCRemoteSwiftPackageReference "RxGesture" */, ); preferredProjectObjectVersion = 77; productRefGroup = 081D9C1A2DF80854004F850D /* Products */; @@ -962,6 +966,14 @@ minimumVersion = 2.0.1; }; }; + 77C7F4E32ED88D14009559E1 /* XCRemoteSwiftPackageReference "RxGesture" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/RxSwiftCommunity/RxGesture.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.0.4; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1025,6 +1037,11 @@ package = 77C755BF2E4B917F0081D80F /* XCRemoteSwiftPackageReference "RxKeyboard" */; productName = RxKeyboard; }; + 77C7F4E42ED88D14009559E1 /* RxGesture */ = { + isa = XCSwiftPackageProductDependency; + package = 77C7F4E32ED88D14009559E1 /* XCRemoteSwiftPackageReference "RxGesture" */; + productName = RxGesture; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 081D9C102DF80854004F850D /* Project object */; diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index f83ddc75..20f66ee4 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -4,6 +4,7 @@ import AuthFeatureInterface import BaseFeature import BookmarkFeatureInterface import DesignSystem +import DictionaryFeatureInterface import DomainInterface import RxCocoa @@ -30,6 +31,7 @@ class DictionaryDetailBaseViewController: BaseViewController { private let bookmarkModalFactory: BookmarkModalFactory private let loginFactory: LoginFactory + public let dictionaryDetailFactory: DictionaryDetailFactory private let appCoordinator: AppCoordinatorProtocol // MARK: - Components @@ -38,11 +40,12 @@ class DictionaryDetailBaseViewController: BaseViewController { // 타입설정 public var type: DictionaryItemType - public init(type: DictionaryItemType, bookmarkModalFactory: BookmarkModalFactory, loginFactory: LoginFactory, appCoordinator: AppCoordinatorProtocol) { + public init(type: DictionaryItemType, bookmarkModalFactory: BookmarkModalFactory, loginFactory: LoginFactory, dictionaryDetailFactory: DictionaryDetailFactory, appCoordinator: AppCoordinatorProtocol) { self.type = type self.bookmarkModalFactory = bookmarkModalFactory self.loginFactory = loginFactory self.appCoordinator = appCoordinator + self.dictionaryDetailFactory = dictionaryDetailFactory mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) super.init() isBottomTabbarHidden = true diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift index 55386c60..3c7bb0a0 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift @@ -7,6 +7,7 @@ import DomainInterface public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { private let loginFactory: () -> LoginFactory private let bookmarkModalFactory: BookmarkModalFactory + private let dictionaryDetailFactory: () -> DictionaryDetailFactory private let appCoordinator: () -> AppCoordinatorProtocol private let dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase @@ -29,6 +30,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { public init( loginFactory: @escaping () -> LoginFactory, bookmarkModalFactory: BookmarkModalFactory, + dictionaryDetailFactory: @escaping () -> DictionaryDetailFactory, appCoordinator: @escaping () -> AppCoordinatorProtocol, dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase, dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase, @@ -64,6 +66,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { self.checkLoginUseCase = checkLoginUseCase self.setBookmarkUseCase = setBookmarkUseCase self.appCoordinator = appCoordinator + self.dictionaryDetailFactory = dictionaryDetailFactory } public func make(type: DictionaryType, id: Int) -> BaseViewController { @@ -74,7 +77,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { case .collection: break case .item: - viewController = ItemDictionaryDetailViewController(type: .item, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) + viewController = ItemDictionaryDetailViewController(type: .item, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), dictionaryDetailFactory: dictionaryDetailFactory(), appCoordinator: appCoordinator()) let reactor = ItemDictionaryDetailReactor( dictionaryDetailItemUseCase: dictionaryDetailItemUseCase, dictionaryDetailItemDropMonsterUseCase: dictionaryDetailItemDropMonsterUseCase, @@ -86,7 +89,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { viewController.reactor = reactor } case .monster: - viewController = MonsterDictionaryDetailViewController(type: .monster, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) + viewController = MonsterDictionaryDetailViewController(type: .monster, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), dictionaryDetailFactory: dictionaryDetailFactory(), appCoordinator: appCoordinator()) let reactor = MonsterDictionaryDetailReactor( dictionaryDetailMonsterUseCase: dictionaryDetailMonsterUseCase, dictionaryDetailMonsterDropItemUseCase: dictionaryDetailMonsterDropItemUseCase, @@ -107,7 +110,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { setBookmarkUseCase: setBookmarkUseCase, id: id ) - viewController = MapDictionaryDetailViewController(type: .map, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) + viewController = MapDictionaryDetailViewController(type: .map, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), dictionaryDetailFactory: dictionaryDetailFactory(), appCoordinator: appCoordinator()) if let viewController = viewController as? MapDictionaryDetailViewController { viewController.reactor = reactor } @@ -120,12 +123,12 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { setBookmarkUseCase: setBookmarkUseCase, id: id ) - viewController = NpcDictionaryDetailViewController(type: .npc, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) + viewController = NpcDictionaryDetailViewController(type: .npc, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), dictionaryDetailFactory: dictionaryDetailFactory(), appCoordinator: appCoordinator()) if let viewController = viewController as? NpcDictionaryDetailViewController { viewController.reactor = reactor } case .quest: - viewController = QuestDictionaryDetailViewController(type: .quest, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), appCoordinator: appCoordinator()) + viewController = QuestDictionaryDetailViewController(type: .quest, bookmarkModalFactory: bookmarkModalFactory, loginFactory: loginFactory(), dictionaryDetailFactory: dictionaryDetailFactory(), appCoordinator: appCoordinator()) let reactor = QuestDictionaryDetailReactor( dictionaryDetailQuestUseCase: dictionaryDetailQuestUseCase, dictionaryDetailQuestLinkedQuestUseCase: dictionaryDetailQuestLinkedQuestsUseCase, diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift index 83e8b92e..3531c85c 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift @@ -8,6 +8,7 @@ public final class ItemDictionaryDetailReactor: Reactor { public enum Route { case none case filter(DictionaryType) + case detail(Int) } // MARK: Action @@ -17,11 +18,12 @@ public final class ItemDictionaryDetailReactor: Reactor { case selectFilter(SortType) case toggleBookmark(Bool) case undoLastDeletedBookmark + case dataTapped(index: Int) } // MARK: Mutation public enum Mutation { - case showFilter + case toNavigate(Route) case setDetailData(DictionaryDetailItemResponse) case setDetailDropMonsterData([DictionaryDetailItemDropMonsterResponse]) case setBookmark(DictionaryDetailItemResponse) @@ -77,7 +79,7 @@ public final class ItemDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case .filterButtonTapped: - return .just(.showFilter) + return .just(.toNavigate(.filter(currentState.type))) case .viewWillAppear: return .merge([ checkLoginUseCase.execute().map { .setLoginState($0) }, @@ -127,6 +129,9 @@ public final class ItemDictionaryDetailReactor: Reactor { .just(.setLastDeletedBookmark(nil)) ]) ) + case .dataTapped(let index): + guard let id = currentState.monsters[index].monsterId else { return .empty() } + return .just(.toNavigate(.detail(id))) } } @@ -134,8 +139,6 @@ public final class ItemDictionaryDetailReactor: Reactor { public func reduce(state: State, mutation: Mutation) -> State { var newState = state switch mutation { - case .showFilter: - newState.route = .filter(newState.type) case let .setDetailData(data): newState.itemDetailInfo = data case let .setDetailDropMonsterData(data): @@ -146,6 +149,8 @@ public final class ItemDictionaryDetailReactor: Reactor { newState.lastDeletedBookmark = item case let .setLoginState(isLogin): newState.isLogin = isLogin + case .toNavigate(let route): + newState.route = route } return newState } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index 30936979..1af1acfc 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -170,6 +170,11 @@ extension ItemDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) + + monsterCardView.tap + .map { Reactor.Action.dataTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) } private func bindViewState(reactor: Reactor) { @@ -209,6 +214,9 @@ extension ItemDictionaryDetailViewController { owner.tabBarController?.presentModal(viewController) case .none: break + case .detail(let id): + let viewController = owner.dictionaryDetailFactory.make(type: .monster, id: id) + owner.navigationController?.pushViewController(viewController, animated: true) } } .disposed(by: disposeBag) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift index 926fae83..91afbae1 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift @@ -7,16 +7,20 @@ public final class MapDictionaryDetailReactor: Reactor { public enum Route { case none case filter(DictionaryType) + case detail(type: DictionaryType, id: Int) } public enum Action { case filterButtonTapped case viewWillAppear case toggleBookmark(Bool) case undoLastDeletedBookmark + case monsterTapped(index: Int) + case npcTapped(index: Int) + case selectFilter(SortType) } public enum Mutation { - case showFilter + case toNavigate(Route) case setDetailData(DictionaryDetailMapResponse) case setDetailSpawnMonsters([DictionaryDetailMapSpawnMonsterResponse]) case setDetailNpc([DictionaryDetailMapNpcResponse]) @@ -81,7 +85,7 @@ public final class MapDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case .filterButtonTapped: - return Observable.just(.showFilter) + return Observable.just(.toNavigate(.filter(currentState.type))) case .viewWillAppear: return .merge([ checkLoginUseCase.execute().map { .setLoginState($0) }, @@ -106,6 +110,9 @@ public final class MapDictionaryDetailReactor: Reactor { .map { .setDetailData($0) } ) ) + case let .selectFilter(type): +// return dictionaryDetailMapSpawnMonsterUseCase.execute(id: currentState.id, sort: ["level", "asc"]).map { .setDetailSpawnMonsters($0) } + return .empty() case .undoLastDeletedBookmark: guard let lastDeleted = currentState.lastDeletedBookmark, let mapId = lastDeleted.mapId else { return .empty() } @@ -121,6 +128,12 @@ public final class MapDictionaryDetailReactor: Reactor { .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() } + return .just(.toNavigate(.detail(type: .npc, id: id))) } } @@ -128,8 +141,8 @@ public final class MapDictionaryDetailReactor: Reactor { var newState = state switch mutation { - case .showFilter: - newState.route = .filter(newState.type) + case .toNavigate(let route): + newState.route = route case let .setDetailData(data): newState.mapDetailInfo = data case let .setDetailSpawnMonsters(data): diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index 65bda22b..a4fa8b61 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -118,6 +118,16 @@ extension MapDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) + + appearMonsterView.tap + .map { Reactor.Action.monsterTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) + + appearNpcView.tap + .map { Reactor.Action.npcTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) } private func bindViewState(reactor: Reactor) { @@ -162,5 +172,28 @@ extension MapDictionaryDetailViewController { bookmarkId: reactor.state.map(\.mapDetailInfo.bookmarkId) ) .disposed(by: disposeBag) + + rx.viewDidAppear + .take(1) + .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 + .withUnretained(self) + .subscribe { owner, route in + switch route { + case .filter(let type): + let viewController = owner.sortedFactory.make(sortedOptions: type.detailSortedFilter, selectedIndex: owner.selectedIndex) { index in + owner.selectedIndex = index + let selectedFilter = reactor.currentState.type.detailSortedFilter[index] + owner.appearMonsterView.selectFilter(selectedType: selectedFilter) + reactor.action.onNext(.selectFilter(selectedFilter)) + } + owner.tabBarController?.presentModal(viewController) + case .none: + break + case .detail(let type, let id): + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id) + owner.navigationController?.pushViewController(viewController, animated: true) + } + } + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift index 4ebd3c2f..b8315205 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift @@ -7,6 +7,7 @@ public final class MonsterDictionaryDetailReactor: Reactor { public enum Route { case none case filter(DictionaryType) + case detail(type: DictionaryType, id: Int) } public struct Info: Equatable { @@ -21,11 +22,13 @@ public final class MonsterDictionaryDetailReactor: Reactor { case selectFilter(SortType) case toggleBookmark(Bool) case undoLastDeletedBookmark + case itemTapped(index: Int) + case mapTapped(index: Int) } // MARK: - Mutation public enum Mutation { - case showFilter(DictionaryType) + case toNavigate(Route) case setDetailData(DictionaryDetailMonsterResponse) case setDetailDropItemData([DictionaryDetailMonsterDropItemResponse]) case setDetailMapData([DictionaryDetailMonsterMapResponse]) @@ -85,7 +88,7 @@ public final class MonsterDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case let .filterButtonTapped(type): - return .just(.showFilter(type)) + return .just(.toNavigate(.filter(type))) case .viewWillAppear: return .merge([ @@ -136,6 +139,10 @@ public final class MonsterDictionaryDetailReactor: Reactor { .just(.setLastDeletedBookmark(nil)) ]) ) + 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))) } } @@ -144,8 +151,8 @@ public final class MonsterDictionaryDetailReactor: Reactor { var newState = state switch mutation { - case let .showFilter(type): - newState.route = .filter(type) + case let .toNavigate(route): + newState.route = route case let .setDetailData(data): newState.monsterDetailInfo = data diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift index d66f6d37..92489d04 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift @@ -125,6 +125,16 @@ extension MonsterDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped(.map) } .bind(to: reactor.action) .disposed(by: disposeBag) + + dropItemView.tap + .map { Reactor.Action.itemTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) + + appearMapView.tap + .map { Reactor.Action.mapTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) } private func bindViewState(reactor: Reactor) { @@ -189,7 +199,10 @@ extension MonsterDictionaryDetailViewController { owner.isBottomTabbarHidden = true } owner.tabBarController?.presentModal(viewController) - case .none: + case let .detail(type: type, id: id): + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id) + owner.navigationController?.pushViewController(viewController, animated: true) + default: break } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift index 43a85137..8d42be45 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift @@ -7,6 +7,7 @@ public final class NpcDictionaryDetailReactor: Reactor { public enum Route { case none case filter(DictionaryType) + case detail(type: DictionaryType, id: Int) } // MARK: - Action @@ -16,11 +17,13 @@ public final class NpcDictionaryDetailReactor: Reactor { case selectFilter(SortType) case toggleBookmark(Bool) case undoLastDeletedBookmark + case mapTapped(index: Int) + case questTapped(index: Int) } // MARK: - Mutation public enum Mutation { - case showFilter + case toNavigate(Route) case setDetailData(DictionaryDetailNpcResponse) case setDetailMaps([DictionaryDetailMonsterMapResponse]) case setDetailQuests([DictionaryDetailNpcQuestResponse]) @@ -78,7 +81,7 @@ public final class NpcDictionaryDetailReactor: Reactor { public func mutate(action: Action) -> Observable { switch action { case .filterButtonTapped: - return .just(.showFilter) + return .just(.toNavigate(.filter(currentState.type))) case .viewWillAppear: return .merge([ checkLoginUseCase.execute().map { .setLoginState($0) }, @@ -129,6 +132,10 @@ public final class NpcDictionaryDetailReactor: Reactor { .just(.setLastDeletedBookmark(nil)) ]) ) + 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))) } } @@ -136,8 +143,8 @@ public final class NpcDictionaryDetailReactor: Reactor { public func reduce(state: State, mutation: Mutation) -> State { var newState = state switch mutation { - case .showFilter: - newState.route = .filter(newState.type) + case .toNavigate(let route): + newState.route = route case let .setDetailData(data): newState.npcDetailInfo = data case let .setDetailMaps(data): diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift index 9b64f6ce..90985175 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift @@ -93,6 +93,16 @@ extension NpcDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) + + questView.tap + .map { Reactor.Action.questTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) + + appearMapView.tap + .map { Reactor.Action.mapTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) } private func bindViewState(reactor: Reactor) { @@ -114,7 +124,10 @@ extension NpcDictionaryDetailViewController { reactor.action.onNext(.selectFilter(selectedFilter)) } owner.tabBarController?.presentModal(viewController) - case .none: + case .detail(type: let type, id: let id): + let viewController = owner.dictionaryDetailFactory.make(type: type, id: id) + owner.navigationController?.pushViewController(viewController, animated: true) + default: break } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift index ae407c66..61395512 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift @@ -3,14 +3,21 @@ import DomainInterface import ReactorKit public final class QuestDictionaryDetailReactor: Reactor { - // MARK: - Action / Mutation / State + public enum Route { + case none + case filter(DictionaryType) + case detail(id: Int) + } + public enum Action { case viewWillAppear case toggleBookmark(Bool) case undoLastDeletedBookmark + case questTapped(index: Int) } public enum Mutation { + case toNavigate(Route) case setDetailData(DictionaryDetailQuestResponse) case setLinkedQuests(DictionaryDetailQuestLinkedQuestsResponse) case setLoginState(Bool) @@ -18,6 +25,7 @@ public final class QuestDictionaryDetailReactor: Reactor { } public struct State { + @Pulse var route: Route = .none var type: DictionaryType = .quest var id: Int var detailInfo: DictionaryDetailQuestResponse @@ -113,6 +121,19 @@ public final class QuestDictionaryDetailReactor: Reactor { .just(.setLastDeletedBookmark(nil)) ]) ) + case let .questTapped(index): + if let previous = currentState.linkedQuestInfo.previousQuests, !previous.isEmpty { + if index == 0, let questId = previous.first?.questId { + return .just(.toNavigate(.detail(id: questId))) + } else if index == 1, let next = currentState.linkedQuestInfo.nextQuests?.first?.questId { + return .just(.toNavigate(.detail(id: next))) + } + } else { + if let next = currentState.linkedQuestInfo.nextQuests, index == 0, let questId = next.first?.questId { + return .just(.toNavigate(.detail(id: questId))) + } + } + return .empty() } } @@ -127,6 +148,8 @@ public final class QuestDictionaryDetailReactor: Reactor { newState.isLogin = isLogin case let .setLastDeletedBookmark(data): newState.lastDeletedBookmark = data + case .toNavigate(let route): + newState.route = route } return newState } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift index 1caf7486..fe3da8ea 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift @@ -127,6 +127,11 @@ extension QuestDictionaryDetailViewController { .map { Reactor.Action.viewWillAppear } .bind(to: reactor.action) .disposed(by: disposeBag) + + linkedQuestView.tap + .map { Reactor.Action.questTapped(index: $0) } + .bind(to: reactor.action) + .disposed(by: disposeBag) } private func bindViewState(reactor: Reactor) { @@ -162,6 +167,21 @@ extension QuestDictionaryDetailViewController { bookmarkId: reactor.state.map(\.detailInfo.bookmarkId) ) .disposed(by: disposeBag) + + rx.viewDidAppear + .take(1) + .flatMapLatest { _ in reactor.pulse(\.$route) } + .withUnretained(self) + .subscribe { owner, route in + switch route { + case .detail(let id): + let viewController = owner.dictionaryDetailFactory.make(type: .quest, id: id) + owner.navigationController?.pushViewController(viewController, animated: true) + default: + break + } + } + .disposed(by: disposeBag) } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift index 23b218bb..72f23275 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift @@ -4,6 +4,9 @@ import BaseFeature import DesignSystem import DomainInterface +import RxCocoa +import RxSwift +import RxGesture import SnapKit final class DetailStackCardView: UIStackView { @@ -19,7 +22,15 @@ final class DetailStackCardView: UIStackView { static let stackViewInset: UIEdgeInsets = .init(top: 12, left: 16, bottom: 0, right: 16) } + // MARK: - Properties + private let disposeBag = DisposeBag() + + private let tapSubject = PublishSubject() + var tap: Observable { tapSubject.asObservable() } + // MARK: - Components + private var cardViews: [CardList] = [] + private let filterContainerView = UIView() // 몬스터 순서 필터 버튼 public let filterButton: UIButton = { @@ -115,6 +126,8 @@ extension DetailStackCardView { // type별 필터 유무 setFilter(isHidden: input.type.sortFilter.isEmpty) let cardView = CardList() + cardViews.append(cardView) + let currentIndex = cardViews.count - 1 let spacer = UIView() addArrangedSubview(cardView) @@ -153,6 +166,12 @@ extension DetailStackCardView { default: break } + + cardView.rx.tapGesture() + .when(.recognized) + .map { _ in currentIndex } + .bind(to: tapSubject) + .disposed(by: disposeBag) } func setFilter(isHidden: Bool) { @@ -173,13 +192,13 @@ extension DetailStackCardView { } func reset() { + cardViews.removeAll() // 필터 뷰를 제외한 arrangedSubview만 제거 - for subview in self.arrangedSubviews { - + for subview in arrangedSubviews { if subview == filterContainerView { continue } if subview == spacer { continue } - self.removeArrangedSubview(subview) + removeArrangedSubview(subview) subview.removeFromSuperview() } } From 8a00dcda23938f460623b6e5c69a8055337059f5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Nov 2025 15:52:44 +0000 Subject: [PATCH 5/7] style/#273: Apply SwiftLint autocorrect --- .../DictionaryDetailBaseViewController.swift | 2 +- .../DictionaryDetail/DictionaryDetailFactoryImpl.swift | 2 +- .../Item/ItemDictionaryDetailViewController.swift | 2 +- .../Map/MapDictionaryDetailViewController.swift | 6 +++--- .../Monster/MonsterDictionaryDetailViewController.swift | 2 +- .../NPC/NpcDictionaryDetailViewController.swift | 4 ++-- .../Quest/QuestDictionaryDetailViewController.swift | 2 +- .../SectionStackView/DetailStackCardView.swift | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift index 20f66ee4..3c039007 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -33,7 +33,7 @@ class DictionaryDetailBaseViewController: BaseViewController { private let loginFactory: LoginFactory public let dictionaryDetailFactory: DictionaryDetailFactory private let appCoordinator: AppCoordinatorProtocol - + // MARK: - Components public var mainView = DictionaryDetailBaseView() diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift index 3c7bb0a0..7148e978 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift @@ -9,7 +9,7 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { private let bookmarkModalFactory: BookmarkModalFactory private let dictionaryDetailFactory: () -> DictionaryDetailFactory private let appCoordinator: () -> AppCoordinatorProtocol - + private let dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase private let dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase private let dictionaryDetailMapNpcUseCase: FetchDictionaryDetailMapNpcUseCase diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift index 1af1acfc..8354ee09 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift @@ -170,7 +170,7 @@ extension ItemDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) - + monsterCardView.tap .map { Reactor.Action.dataTapped(index: $0) } .bind(to: reactor.action) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift index a4fa8b61..83ae69d0 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift @@ -118,12 +118,12 @@ extension MapDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) - + appearMonsterView.tap .map { Reactor.Action.monsterTapped(index: $0) } .bind(to: reactor.action) .disposed(by: disposeBag) - + appearNpcView.tap .map { Reactor.Action.npcTapped(index: $0) } .bind(to: reactor.action) @@ -172,7 +172,7 @@ extension MapDictionaryDetailViewController { bookmarkId: reactor.state.map(\.mapDetailInfo.bookmarkId) ) .disposed(by: disposeBag) - + rx.viewDidAppear .take(1) .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift index 92489d04..b8a4102d 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift @@ -125,7 +125,7 @@ extension MonsterDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped(.map) } .bind(to: reactor.action) .disposed(by: disposeBag) - + dropItemView.tap .map { Reactor.Action.itemTapped(index: $0) } .bind(to: reactor.action) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift index 90985175..abe46a33 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift @@ -93,12 +93,12 @@ extension NpcDictionaryDetailViewController { .map { Reactor.Action.filterButtonTapped } .bind(to: reactor.action) .disposed(by: disposeBag) - + questView.tap .map { Reactor.Action.questTapped(index: $0) } .bind(to: reactor.action) .disposed(by: disposeBag) - + appearMapView.tap .map { Reactor.Action.mapTapped(index: $0) } .bind(to: reactor.action) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift index fe3da8ea..cbe66d63 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift @@ -127,7 +127,7 @@ extension QuestDictionaryDetailViewController { .map { Reactor.Action.viewWillAppear } .bind(to: reactor.action) .disposed(by: disposeBag) - + linkedQuestView.tap .map { Reactor.Action.questTapped(index: $0) } .bind(to: reactor.action) diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift index 72f23275..29fc15f1 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift @@ -5,8 +5,8 @@ import DesignSystem import DomainInterface import RxCocoa -import RxSwift import RxGesture +import RxSwift import SnapKit final class DetailStackCardView: UIStackView { @@ -24,7 +24,7 @@ final class DetailStackCardView: UIStackView { // MARK: - Properties private let disposeBag = DisposeBag() - + private let tapSubject = PublishSubject() var tap: Observable { tapSubject.asObservable() } From 260ff902a04174389933915ed2100682cf21225d Mon Sep 17 00:00:00 2001 From: p2glet Date: Fri, 28 Nov 2025 01:08:12 +0900 Subject: [PATCH 6/7] fix/#273: clean code --- .../AuthAPI/WithdrawUseCaseImpl.swift | 12 +- MLS/MLS/Application/AppDelegate.swift | 836 ++++++++++++------ .../OnBoardingNotificationFactoryImpl.swift | 6 +- ...OnBoardingNotificationViewController.swift | 4 +- .../OnBoardingInputFactoryImpl.swift | 5 +- .../OnBoardingInputViewController.swift | 4 +- ...BoardingNotificationSheetFactoryImpl.swift | 8 +- ...rdingNotificationSheetViewController.swift | 11 +- 8 files changed, 582 insertions(+), 304 deletions(-) diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift index f0b6cc09..3ac9a5e8 100644 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift @@ -24,14 +24,12 @@ public class WithdrawUseCaseImpl: WithdrawUseCase { self.tokenRepository.deleteToken(type: .fcmToken) ] - if let error = results.compactMap({ result in - if case let .failure(error) = result { return error } - return nil - }).first { - return .error(error) - } else { - return .empty() + for result in results { + if case .failure(let error) = result { + return .error(error) + } } + return .empty() }) } } diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 212f603e..5a08e569 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -1,8 +1,5 @@ // swiftlint:disable function_body_length - -import os -import UIKit -import UserNotifications +// swiftlint:disable file_length import AuthFeature import AuthFeatureInterface @@ -17,32 +14,36 @@ import DictionaryFeature import DictionaryFeatureInterface import Domain import DomainInterface -import MyPageFeature -import MyPageFeatureInterface - import Firebase import KakaoSDKCommon +import MyPageFeature +import MyPageFeatureInterface +import UIKit +import UserNotifications +import os @main class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication - .LaunchOptionsKey: Any]?) -> Bool { + .LaunchOptionsKey: Any]? + ) -> Bool { // MARK: - UserNotification Set - FirebaseApp.configure() // Firebase Set - Messaging.messaging().delegate = self // 파이어베이스 Meesaging 설정 + FirebaseApp.configure() // Firebase Set + Messaging.messaging().delegate = self // 파이어베이스 Meesaging 설정 - UNUserNotificationCenter.current().delegate = self // NotificationCenter Delegate - let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정 + UNUserNotificationCenter.current().delegate = self // NotificationCenter Delegate + let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정 UNUserNotificationCenter.current().requestAuthorization( options: authOptions, - completionHandler: { _, _ in }) - application.registerForRemoteNotifications() // UNUserNotificationCenterDelegate를 구현한 메서드를 실행시킴 + completionHandler: { _, _ in } + ) + application.registerForRemoteNotifications() // UNUserNotificationCenterDelegate를 구현한 메서드를 실행시킴 // 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 = @@ -56,15 +57,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions) -> UISceneConfiguration { + options: UIScene.ConnectionOptions + ) -> UISceneConfiguration { return UISceneConfiguration( name: "Default Configuration", - sessionRole: connectingSceneSession.role) + sessionRole: connectingSceneSession.role + ) } func application( _ application: UIApplication, - didDiscardSceneSessions sceneSessions: Set) {} + didDiscardSceneSessions sceneSessions: Set + ) {} } // MARK: - Notification Delegate, MessagingDelegate @@ -72,24 +76,32 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, - withCompletionHandler completionHandler: @escaping ( - UNNotificationPresentationOptions - ) -> Void) { + withCompletionHandler completionHandler: + @escaping ( + UNNotificationPresentationOptions + ) -> Void + ) { completionHandler([.list, .banner]) } // 파이어베이스 MessagingDelegate 설정 func messaging( - _ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { + _ messaging: Messaging, + didReceiveRegistrationToken fcmToken: String? + ) { let dataDict: [String: String] = ["token": fcmToken ?? ""] NotificationCenter.default.post( name: Notification.Name("FCMToken"), object: nil, - userInfo: dataDict) + userInfo: dataDict + ) let tokenUseCase = DIContainer.resolve( - type: SaveTokenToLocalUseCase.self) + type: SaveTokenToLocalUseCase.self + ) let result = tokenUseCase.execute( - type: .fcmToken, value: fcmToken ?? "") + type: .fcmToken, + value: fcmToken ?? "" + ) switch result { case .success: @@ -101,8 +113,8 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { } // MARK: - registerDependencies -private extension AppDelegate { - func registerDependencies() { +extension AppDelegate { + fileprivate func registerDependencies() { registerProvider() registerRepository() registerUseCase() @@ -111,37 +123,51 @@ private extension AppDelegate { DIContainer.register(type: AppCoordinatorProtocol.self) { AppCoordinator( window: nil, - dictionaryMainViewFactory: DIContainer.resolve(type: DictionaryMainViewFactory.self), - bookmarkMainFactory: DIContainer.resolve(type: BookmarkMainFactory.self), - myPageMainFactory: DIContainer.resolve(type: MyPageMainFactory.self), - loginFactory: DIContainer.resolve(type: LoginFactory.self)) + dictionaryMainViewFactory: DIContainer.resolve( + type: DictionaryMainViewFactory.self + ), + bookmarkMainFactory: DIContainer.resolve( + type: BookmarkMainFactory.self + ), + myPageMainFactory: DIContainer.resolve( + type: MyPageMainFactory.self + ), + loginFactory: DIContainer.resolve(type: LoginFactory.self) + ) } } - func registerProvider() { + fileprivate func registerProvider() { DIContainer.register(type: NetworkProvider.self) { NetworkProviderImpl() } DIContainer.register( - type: SocialAuthenticatableProvider.self, name: "kakao") { + type: SocialAuthenticatableProvider.self, + name: "kakao" + ) { KakaoLoginProviderImpl() } DIContainer.register( - type: SocialAuthenticatableProvider.self, name: "apple") { + type: SocialAuthenticatableProvider.self, + name: "apple" + ) { AppleLoginProviderImpl() } DIContainer.register(type: Interceptor.self) { TokenInterceptor( fetchTokenUseCase: DIContainer.resolve( - type: FetchTokenFromLocalUseCase.self)) + type: FetchTokenFromLocalUseCase.self + ) + ) } } - func registerRepository() { + fileprivate func registerRepository() { DIContainer.register(type: AuthAPIRepository.self) { AuthAPIRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), - interceptor: DIContainer.resolve(type: Interceptor.self)) + interceptor: DIContainer.resolve(type: Interceptor.self) + ) } DIContainer.register(type: TokenRepository.self) { KeyChainRepositoryImpl() @@ -149,17 +175,20 @@ private extension AppDelegate { DIContainer.register(type: DictionaryDetailAPIRepository.self) { DictionaryDetailAPIRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), - tokenInterceptor: DIContainer.resolve(type: Interceptor.self)) + tokenInterceptor: DIContainer.resolve(type: Interceptor.self) + ) } DIContainer.register(type: DictionaryListAPIRepository.self) { DictionaryListAPIRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), - tokenInterceptor: DIContainer.resolve(type: Interceptor.self)) + tokenInterceptor: DIContainer.resolve(type: Interceptor.self) + ) } DIContainer.register(type: BookmarkRepository.self) { BookmarkRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), - interceptor: DIContainer.resolve(type: Interceptor.self)) + interceptor: DIContainer.resolve(type: Interceptor.self) + ) } DIContainer.register(type: UserDefaultsRepository.self) { UserDefaultsRepositoryImpl() @@ -167,26 +196,36 @@ private extension AppDelegate { DIContainer.register(type: AlarmAPIRepository.self) { AlarmAPIRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), - interceptor: DIContainer.resolve(type: Interceptor.self)) + interceptor: DIContainer.resolve(type: Interceptor.self) + ) } DIContainer.register(type: CollectionAPIRepository.self) { CollectionAPIRepositoryImpl( provider: DIContainer.resolve(type: NetworkProvider.self), - tokenInterceptor: DIContainer.resolve(type: Interceptor.self)) + tokenInterceptor: DIContainer.resolve(type: Interceptor.self) + ) } } - func registerUseCase() { + fileprivate func registerUseCase() { DIContainer.register( - type: FetchSocialCredentialUseCase.self, name: "kakao") { + type: FetchSocialCredentialUseCase.self, + name: "kakao" + ) { let provider = DIContainer.resolve( - type: SocialAuthenticatableProvider.self, name: "kakao") + type: SocialAuthenticatableProvider.self, + name: "kakao" + ) return SocialLoginUseCaseImpl(provider: provider) } DIContainer.register( - type: FetchSocialCredentialUseCase.self, name: "apple") { + type: FetchSocialCredentialUseCase.self, + name: "apple" + ) { let provider = DIContainer.resolve( - type: SocialAuthenticatableProvider.self, name: "apple") + type: SocialAuthenticatableProvider.self, + name: "apple" + ) return SocialLoginUseCaseImpl(provider: provider) } DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { @@ -197,63 +236,82 @@ private extension AppDelegate { } DIContainer.register(type: FetchJobListUseCase.self) { FetchJobListUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: LoginWithAppleUseCase.self) { LoginWithAppleUseCaseImpl( authRepository: DIContainer.resolve( - type: AuthAPIRepository.self), + type: AuthAPIRepository.self + ), tokenRepository: DIContainer.resolve( - type: TokenRepository.self), + type: TokenRepository.self + ), userDefaultsRepository: DIContainer.resolve( - type: UserDefaultsRepository.self)) + type: UserDefaultsRepository.self + ) + ) } DIContainer.register(type: LoginWithKakaoUseCase.self) { LoginWithKakaoUseCaseImpl( authRepository: DIContainer.resolve( - type: AuthAPIRepository.self), + type: AuthAPIRepository.self + ), tokenRepository: DIContainer.resolve( - type: TokenRepository.self), + type: TokenRepository.self + ), userDefaultsRepository: DIContainer.resolve( - type: UserDefaultsRepository.self)) + type: UserDefaultsRepository.self + ) + ) } DIContainer.register(type: SignUpWithAppleUseCase.self) { SignUpWithAppleUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: SignUpWithKakaoUseCase.self) { SignUpWithKakaoUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: UpdateUserInfoUseCase.self) { UpdateUserInfoUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: ReissueUseCase.self) { ReissueUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: PutFCMTokenUseCase.self) { PutFCMTokenUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: FetchTokenFromLocalUseCase.self) { FetchTokenFromLocalUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self)) + repository: DIContainer.resolve(type: TokenRepository.self) + ) } DIContainer.register(type: SaveTokenToLocalUseCase.self) { SaveTokenToLocalUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self)) + repository: DIContainer.resolve(type: TokenRepository.self) + ) } DIContainer.register(type: DeleteTokenFromLocalUseCase.self) { DeleteTokenFromLocalUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self)) + repository: DIContainer.resolve(type: TokenRepository.self) + ) } DIContainer.register(type: UpdateMarketingAgreementUseCase.self) { UpdateMarketingAgreementUseCaseImpl( authRepository: DIContainer.resolve( - type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self)) + type: AuthAPIRepository.self + ), + tokenRepository: DIContainer.resolve(type: TokenRepository.self) + ) } DIContainer.register(type: CheckNotificationPermissionUseCase.self) { CheckNotificationPermissionUseCaseImpl() @@ -264,228 +322,303 @@ private extension AppDelegate { DIContainer.register(type: UpdateNotificationAgreementUseCase.self) { UpdateNotificationAgreementUseCaseImpl( authRepository: DIContainer.resolve( - type: AuthAPIRepository.self)) + type: AuthAPIRepository.self + ) + ) } DIContainer.register(type: CheckLoginUseCase.self) { CheckLoginUseCaseImpl( authRepository: DIContainer.resolve( - type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self)) + type: AuthAPIRepository.self + ), + tokenRepository: DIContainer.resolve(type: TokenRepository.self) + ) } DIContainer.register(type: FetchDictionaryAllListUseCase.self) { FetchDictionaryAllListUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: SetBookmarkUseCase.self) { SetBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self)) + repository: DIContainer.resolve(type: BookmarkRepository.self) + ) } DIContainer.register(type: FetchPlatformUseCase.self) { FetchPlatformUseCaseImpl( repository: DIContainer.resolve( - type: UserDefaultsRepository.self)) + type: UserDefaultsRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryMapListUseCase.self) { FetchDictionaryMapListUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryItemListUseCase.self) { FetchDictionaryItemListUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryQuestListUseCase.self) { FetchDictionaryQuestListUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryNpcListUseCase.self) { FetchDictionaryNpcListUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryMonsterListUseCase.self) { FetchDictionaryMonsterListUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailMonsterUseCase.self) { FetchDictionaryDetailMonsterUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register( type: FetchDictionaryDetailMonsterItemsUseCase.self ) { FetchDictionaryDetailMonsterDropItemUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } - DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) { + DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) + { FetchDictionaryDetailMonsterMapUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailNpcUseCase.self) { FetchDictionaryDetailNpcUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailNpcQuestUseCase.self) { FetchDictionaryDetailNpcQuestUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailNpcMapUseCase.self) { FetchDictionaryDetailNpcMapUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailItemUseCase.self) { FetchDictionaryDetailItemUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register( type: FetchDictionaryDetailItemDropMonsterUseCase.self ) { FetchDictionaryDetailItemDropMonsterUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailQuestUseCase.self) { FetchDictionaryDetailQuestUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register( type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self ) { FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailMapUseCase.self) { FetchDictionaryDetailMapUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register( type: FetchDictionaryDetailMapSpawnMonsterUseCase.self ) { FetchDictionaryDetailMapSpawnMonsterUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryDetailMapNpcUseCase.self) { FetchDictionaryDetailMapNpcUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self)) + type: DictionaryDetailAPIRepository.self + ) + ) } DIContainer.register(type: RecentSearchRemoveUseCase.self) { RecentSearchRemoveUseCaseImpl( repository: DIContainer.resolve( - type: UserDefaultsRepository.self)) + type: UserDefaultsRepository.self + ) + ) } DIContainer.register(type: RecentSearchAddUseCase.self) { RecentSearchAddUseCaseImpl( repository: DIContainer.resolve( - type: UserDefaultsRepository.self)) + type: UserDefaultsRepository.self + ) + ) } DIContainer.register(type: FetchDictionaryListCountUseCase.self) { FetchDictionaryListCountUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: FetchDictionarySearchListUseCase.self) { FetchDictionarySearchListUseCaseImpl( repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self)) + type: DictionaryListAPIRepository.self + ) + ) } DIContainer.register(type: RecentSearchFetchUseCase.self) { RecentSearchFetchUseCaseImpl( repository: DIContainer.resolve( - type: UserDefaultsRepository.self)) + type: UserDefaultsRepository.self + ) + ) } DIContainer.register(type: FetchBookmarkUseCase.self) { FetchBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self)) + repository: DIContainer.resolve(type: BookmarkRepository.self) + ) } DIContainer.register(type: FetchMonsterBookmarkUseCase.self) { FetchMonsterBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self)) + repository: DIContainer.resolve(type: BookmarkRepository.self) + ) } DIContainer.register(type: FetchItemBookmarkUseCase.self) { FetchItemBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self)) + repository: DIContainer.resolve(type: BookmarkRepository.self) + ) } DIContainer.register(type: FetchNPCBookmarkUseCase.self) { FetchNPCBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self)) + repository: DIContainer.resolve(type: BookmarkRepository.self) + ) } DIContainer.register(type: FetchQuestBookmarkUseCase.self) { FetchQuestBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self)) + repository: DIContainer.resolve(type: BookmarkRepository.self) + ) } DIContainer.register(type: FetchMapBookmarkUseCase.self) { FetchMapBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self)) + repository: DIContainer.resolve(type: BookmarkRepository.self) + ) } DIContainer.register(type: UpdateProfileImageUseCase.self) { UpdateProfileImageUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: FetchJobUseCase.self) { FetchJobUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: FetchProfileUseCase.self) { FetchProfileUseCaseImpl( repository: DIContainer.resolve(type: AuthAPIRepository.self), - fetchJobUseCase: DIContainer.resolve(type: FetchJobUseCase.self)) + fetchJobUseCase: DIContainer.resolve(type: FetchJobUseCase.self) + ) } DIContainer.register(type: CheckNickNameUseCase.self) { CheckNickNameUseCaseImpl() } DIContainer.register(type: UpdateNickNameUseCase.self) { UpdateNickNameUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self)) + repository: DIContainer.resolve(type: AuthAPIRepository.self) + ) } DIContainer.register(type: LogoutUseCase.self) { LogoutUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self)) + repository: DIContainer.resolve(type: TokenRepository.self) + ) } DIContainer.register(type: WithdrawUseCase.self) { WithdrawUseCaseImpl( authRepository: DIContainer.resolve( - type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self)) + type: AuthAPIRepository.self + ), + tokenRepository: DIContainer.resolve(type: TokenRepository.self) + ) } DIContainer.register(type: FetchNoticesUseCase.self) { FetchNoticesUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self)) + repository: DIContainer.resolve(type: AlarmAPIRepository.self) + ) } DIContainer.register(type: FetchOngoingEventsUseCase.self) { FetchOngoingEventsUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self)) + repository: DIContainer.resolve(type: AlarmAPIRepository.self) + ) } DIContainer.register(type: FetchOutdatedEventsUseCase.self) { FetchOutdatedEventsUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self)) + repository: DIContainer.resolve(type: AlarmAPIRepository.self) + ) } DIContainer.register(type: FetchPatchNotesUseCase.self) { FetchPatchNotesUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self)) + repository: DIContainer.resolve(type: AlarmAPIRepository.self) + ) } DIContainer.register(type: SetReadUseCase.self) { SetReadUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self)) + repository: DIContainer.resolve(type: AlarmAPIRepository.self) + ) } DIContainer.register(type: FetchAllAlarmUseCase.self) { FetchAllAlarmUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self)) + repository: DIContainer.resolve(type: AlarmAPIRepository.self) + ) } DIContainer.register(type: ParseItemFilterResultUseCase.self) { ParseItemFilterResultUseCaseImpl() @@ -493,34 +626,54 @@ private extension AppDelegate { DIContainer.register(type: FetchCollectionListUseCase.self) { FetchCollectionListUseCaseImpl( repository: DIContainer.resolve( - type: CollectionAPIRepository.self)) + type: CollectionAPIRepository.self + ) + ) } DIContainer.register(type: CreateCollectionListUseCase.self) { CreateCollectionListUseCaseImpl( repository: DIContainer.resolve( - type: CollectionAPIRepository.self)) + type: CollectionAPIRepository.self + ) + ) } DIContainer.register(type: FetchCollectionUseCase.self) { - FetchCollectionUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + FetchCollectionUseCaseImpl( + repository: DIContainer.resolve( + type: CollectionAPIRepository.self + ) + ) } -// DIContainer.register(type: AddCollectionsToBookmarkUseCase.self) { -// AddCollectionsToBookmarkUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) -// } + // DIContainer.register(type: AddCollectionsToBookmarkUseCase.self) { + // AddCollectionsToBookmarkUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + // } DIContainer.register(type: SetCollectionUseCase.self) { - SetCollectionUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + SetCollectionUseCaseImpl( + repository: DIContainer.resolve( + type: CollectionAPIRepository.self + ) + ) } DIContainer.register(type: DeleteCollectionUseCase.self) { - DeleteCollectionUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + DeleteCollectionUseCaseImpl( + repository: DIContainer.resolve( + type: CollectionAPIRepository.self + ) + ) } -// DIContainer.register(type: AddBookmarksToCollectionUseCase.self) { -// AddBookmarksToCollectionUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) -// } + // DIContainer.register(type: AddBookmarksToCollectionUseCase.self) { + // AddBookmarksToCollectionUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + // } DIContainer.register(type: AddCollectionAndBookmarkUseCase.self) { - AddCollectionAndBookmarkUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + AddCollectionAndBookmarkUseCaseImpl( + repository: DIContainer.resolve( + type: CollectionAPIRepository.self + ) + ) } } - func registerFactory() { + fileprivate func registerFactory() { DIContainer.register(type: ItemFilterBottomSheetFactory.self) { ItemFilterBottomSheetFactoryImpl() } @@ -531,245 +684,338 @@ private extension AppDelegate { SortedBottomSheetFactoryImpl() } DIContainer.register(type: AddCollectionFactory.self) { - AddCollectionFactoryImpl(createCollectionListUseCase: DIContainer.resolve(type: CreateCollectionListUseCase.self), setCollectionUseCase: DIContainer.resolve(type: SetCollectionUseCase.self)) + AddCollectionFactoryImpl( + createCollectionListUseCase: DIContainer.resolve( + type: CreateCollectionListUseCase.self + ), + setCollectionUseCase: DIContainer.resolve( + type: SetCollectionUseCase.self + ) + ) } DIContainer.register(type: BookmarkModalFactory.self) { BookmarkModalFactoryImpl( addCollectionFactory: DIContainer.resolve( - type: AddCollectionFactory.self), fetchCollectionListUseCase: DIContainer.resolve(type: FetchCollectionListUseCase.self), - addCollectionAndBookmarkUseCase: DIContainer.resolve(type: AddCollectionAndBookmarkUseCase.self)) + type: AddCollectionFactory.self + ), + fetchCollectionListUseCase: DIContainer.resolve( + type: FetchCollectionListUseCase.self + ), + addCollectionAndBookmarkUseCase: DIContainer.resolve( + type: AddCollectionAndBookmarkUseCase.self + ) + ) } DIContainer.register(type: LoginFactory.self) { LoginFactoryImpl( termsAgreementsFactory: DIContainer.resolve( - type: TermsAgreementFactory.self), + type: TermsAgreementFactory.self + ), appleLoginUseCase: DIContainer.resolve( - type: FetchSocialCredentialUseCase.self, name: "apple"), + type: FetchSocialCredentialUseCase.self, + name: "apple" + ), kakaoLoginUseCase: DIContainer.resolve( - type: FetchSocialCredentialUseCase.self, name: "kakao"), + type: FetchSocialCredentialUseCase.self, + name: "kakao" + ), loginWithAppleUseCase: DIContainer.resolve( - type: LoginWithAppleUseCase.self), + type: LoginWithAppleUseCase.self + ), loginWithKakaoUseCase: DIContainer.resolve( - type: LoginWithKakaoUseCase.self), + type: LoginWithKakaoUseCase.self + ), fetchTokenUseCase: DIContainer.resolve( - type: FetchTokenFromLocalUseCase.self), + type: FetchTokenFromLocalUseCase.self + ), putFCMTokenUseCase: DIContainer.resolve( - type: PutFCMTokenUseCase.self), + type: PutFCMTokenUseCase.self + ), fetchPlatformUseCase: DIContainer.resolve( - type: FetchPlatformUseCase.self)) + type: FetchPlatformUseCase.self + ) + ) } DIContainer.register(type: DictionaryDetailFactory.self) { DictionaryDetailFactoryImpl( loginFactory: { DIContainer.resolve(type: LoginFactory.self) }, bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self), - dictionaryDetailFactory: { DIContainer - .resolve(type: DictionaryDetailFactory.self) }, + type: BookmarkModalFactory.self + ), + dictionaryDetailFactory: { + DIContainer + .resolve(type: DictionaryDetailFactory.self) + }, appCoordinator: { DIContainer.resolve(type: AppCoordinatorProtocol.self) }, dictionaryDetailMapUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMapUseCase.self), + type: FetchDictionaryDetailMapUseCase.self + ), dictionaryDetailMapSpawnMonsterUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMapSpawnMonsterUseCase.self), + type: FetchDictionaryDetailMapSpawnMonsterUseCase.self + ), dictionaryDetailMapNpcUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMapNpcUseCase.self), + type: FetchDictionaryDetailMapNpcUseCase.self + ), dictionaryDetailQuestLinkedQuestsUseCase: DIContainer.resolve( - type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self), + type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self + ), dictionaryDetailQuestUseCase: DIContainer.resolve( - type: FetchDictionaryDetailQuestUseCase.self), + type: FetchDictionaryDetailQuestUseCase.self + ), dictionaryDetailItemDropMonsterUseCase: DIContainer.resolve( - type: FetchDictionaryDetailItemDropMonsterUseCase.self), + type: FetchDictionaryDetailItemDropMonsterUseCase.self + ), dictionaryDetailItemUseCase: DIContainer.resolve( - type: FetchDictionaryDetailItemUseCase.self), + type: FetchDictionaryDetailItemUseCase.self + ), dictionaryDetailNpcUseCase: DIContainer.resolve( - type: FetchDictionaryDetailNpcUseCase.self), + type: FetchDictionaryDetailNpcUseCase.self + ), dictionaryDetailNpcQuestUseCase: DIContainer.resolve( - type: FetchDictionaryDetailNpcQuestUseCase.self), + type: FetchDictionaryDetailNpcQuestUseCase.self + ), dictionaryDetailNpcMapUseCase: DIContainer.resolve( - type: FetchDictionaryDetailNpcMapUseCase.self), + type: FetchDictionaryDetailNpcMapUseCase.self + ), dictionaryDetailMonsterUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMonsterUseCase.self), + type: FetchDictionaryDetailMonsterUseCase.self + ), dictionaryDetailMonsterDropItemUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMonsterItemsUseCase.self), + type: FetchDictionaryDetailMonsterItemsUseCase.self + ), dictionaryDetailMonsterMapUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMonsterMapUseCase.self), + type: FetchDictionaryDetailMonsterMapUseCase.self + ), checkLoginUseCase: DIContainer.resolve( - type: CheckLoginUseCase.self), + type: CheckLoginUseCase.self + ), setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self)) + type: SetBookmarkUseCase.self + ) + ) } DIContainer.register(type: DictionaryMainListFactory.self) { DictionaryListFactoryImpl( checkLoginUseCase: DIContainer.resolve( - type: CheckLoginUseCase.self), + type: CheckLoginUseCase.self + ), dictionaryAllListItemUseCase: DIContainer.resolve( - type: FetchDictionaryAllListUseCase.self), + type: FetchDictionaryAllListUseCase.self + ), dictionaryMapListItemUseCase: DIContainer.resolve( - type: FetchDictionaryMapListUseCase.self), + type: FetchDictionaryMapListUseCase.self + ), dictionaryItemListItemUseCase: DIContainer.resolve( - type: FetchDictionaryItemListUseCase.self), + type: FetchDictionaryItemListUseCase.self + ), dictionaryQuestListItemUseCase: DIContainer.resolve( - type: FetchDictionaryQuestListUseCase.self), + type: FetchDictionaryQuestListUseCase.self + ), dictionaryNpcListItemUseCase: - DIContainer + DIContainer .resolve(type: FetchDictionaryNpcListUseCase.self), dictionaryListItemUseCase: DIContainer.resolve( - type: FetchDictionaryMonsterListUseCase.self), + type: FetchDictionaryMonsterListUseCase.self + ), setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self), + type: SetBookmarkUseCase.self + ), parseItemFilterResultUseCase: DIContainer.resolve( - type: ParseItemFilterResultUseCase.self), + type: ParseItemFilterResultUseCase.self + ), itemFilterFactory: DIContainer.resolve( - type: ItemFilterBottomSheetFactory.self), + type: ItemFilterBottomSheetFactory.self + ), monsterFilterFactory: DIContainer.resolve( - type: MonsterFilterBottomSheetFactory.self), + type: MonsterFilterBottomSheetFactory.self + ), sortedFactory: DIContainer.resolve( - type: SortedBottomSheetFactory.self), + type: SortedBottomSheetFactory.self + ), bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self), + type: BookmarkModalFactory.self + ), detailFactory: DIContainer.resolve( - type: DictionaryDetailFactory.self), - loginFactory: { DIContainer.resolve(type: LoginFactory.self) }) + type: DictionaryDetailFactory.self + ), + loginFactory: { DIContainer.resolve(type: LoginFactory.self) } + ) } DIContainer.register(type: DictionarySearchResultFactory.self) { DictionarySearchResultFactoryImpl( dictionaryListCountUseCase: DIContainer.resolve( - type: FetchDictionaryListCountUseCase.self), + type: FetchDictionaryListCountUseCase.self + ), dictionaryMainListFactory: - DIContainer + DIContainer .resolve(type: DictionaryMainListFactory.self), dictionarySearchListUseCase: DIContainer.resolve( - type: FetchDictionarySearchListUseCase.self)) + type: FetchDictionarySearchListUseCase.self + ) + ) } DIContainer.register(type: DictionarySearchFactory.self) { DictionarySearchFactoryImpl( recentSearchRemoveUseCase: DIContainer.resolve( - type: RecentSearchRemoveUseCase.self), + type: RecentSearchRemoveUseCase.self + ), recentSearchAddUseCase: DIContainer.resolve( - type: RecentSearchAddUseCase.self), + type: RecentSearchAddUseCase.self + ), searchResultFactory: - DIContainer + DIContainer .resolve(type: DictionarySearchResultFactory.self), recentSearchFetchUseCase: DIContainer.resolve( - type: RecentSearchFetchUseCase.self)) + type: RecentSearchFetchUseCase.self + ) + ) } DIContainer.register(type: NotificationSettingFactory.self) { NotificationSettingFactoryImpl( checkNotificationPermissionUseCase: DIContainer.resolve( - type: CheckNotificationPermissionUseCase.self), + type: CheckNotificationPermissionUseCase.self + ), updateNotificationAgreementUseCase: DIContainer.resolve( - type: UpdateNotificationAgreementUseCase.self)) + type: UpdateNotificationAgreementUseCase.self + ) + ) } DIContainer.register(type: DictionaryNotificationFactory.self) { DictionaryNotificationFactoryImpl( notificationSettingFactory: DIContainer.resolve( - type: NotificationSettingFactory.self), + type: NotificationSettingFactory.self + ), fetchAllAlarmUseCase: DIContainer.resolve( - type: FetchAllAlarmUseCase.self), + type: FetchAllAlarmUseCase.self + ), fetchProfileUseCase: DIContainer.resolve( - type: FetchProfileUseCase.self)) + type: FetchProfileUseCase.self + ) + ) } DIContainer.register(type: DictionaryMainViewFactory.self) { DictionaryMainViewFactoryImpl( dictionaryMainListFactory: - DIContainer + DIContainer .resolve(type: DictionaryMainListFactory.self), searchFactory: DIContainer.resolve( - type: DictionarySearchFactory.self), + type: DictionarySearchFactory.self + ), notificationFactory: - DIContainer + DIContainer .resolve(type: DictionaryNotificationFactory.self), checkLoginUseCase: DIContainer.resolve( - type: CheckLoginUseCase.self)) + type: CheckLoginUseCase.self + ) + ) } 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), - dictionaryMainViewFactory: DIContainer.resolve( - type: DictionaryMainViewFactory.self)) + type: UpdateUserInfoUseCase.self + ), + appCoordinator: { + DIContainer.resolve( + type: AppCoordinatorProtocol.self + ) + } + ) } DIContainer.register(type: OnBoardingInputFactory.self) { OnBoardingInputFactoryImpl( checkEmptyUseCase: DIContainer.resolve( - type: CheckEmptyLevelAndRoleUseCase.self), + type: CheckEmptyLevelAndRoleUseCase.self + ), checkValidLevelUseCase: DIContainer.resolve( - type: CheckValidLevelUseCase.self), + type: CheckValidLevelUseCase.self + ), fetchJobListUseCase: DIContainer.resolve( - type: FetchJobListUseCase.self), + type: FetchJobListUseCase.self + ), updateUserInfoUseCase: DIContainer.resolve( - type: UpdateUserInfoUseCase.self), + type: UpdateUserInfoUseCase.self + ), onBoardingNotificationFactory: DIContainer.resolve( - type: OnBoardingNotificationFactory.self), - dictionaryMainViewFactory: DIContainer.resolve( - type: DictionaryMainViewFactory.self + type: OnBoardingNotificationFactory.self ), appCoordinator: { DIContainer.resolve(type: AppCoordinatorProtocol.self) - }) + } + ) } DIContainer.register(type: OnBoardingQuestionFactory.self) { OnBoardingQuestionFactoryImpl( onBoardingInputFactory: DIContainer.resolve( - type: OnBoardingInputFactory.self) + type: OnBoardingInputFactory.self + ) ) } DIContainer.register(type: TermsAgreementFactory.self) { TermsAgreementFactoryImpl( onBoardingQuestionFactory: DIContainer.resolve( - type: OnBoardingQuestionFactory.self), + type: OnBoardingQuestionFactory.self + ), signUpWithKakaoUseCase: DIContainer.resolve( - type: SignUpWithKakaoUseCase.self), + type: SignUpWithKakaoUseCase.self + ), signUpWithAppleUseCase: DIContainer.resolve( - type: SignUpWithAppleUseCase.self), + type: SignUpWithAppleUseCase.self + ), saveTokenUseCase: DIContainer.resolve( - type: SaveTokenToLocalUseCase.self), + type: SaveTokenToLocalUseCase.self + ), fetchTokenUseCase: DIContainer.resolve( - type: FetchTokenFromLocalUseCase.self), + type: FetchTokenFromLocalUseCase.self + ), updateMarketingAgreementUseCase: DIContainer.resolve( - type: UpdateMarketingAgreementUseCase.self)) + type: UpdateMarketingAgreementUseCase.self + ) + ) } DIContainer.register(type: OnBoardingNotificationFactory.self) { OnBoardingNotificationFactoryImpl( onBoardingNotificationSheetFactory: DIContainer.resolve( - type: OnBoardingNotificationSheetFactory.self), - dictionaryMainViewFactory: DIContainer.resolve( - type: DictionaryMainViewFactory.self + type: OnBoardingNotificationSheetFactory.self ), - appCoordinator: { DIContainer.resolve( - type: AppCoordinatorProtocol.self - ) }) + appCoordinator: { + DIContainer.resolve( + type: AppCoordinatorProtocol.self + ) + } + ) } DIContainer.register(type: BookmarkMainFactory.self) { BookmarkMainFactoryImpl( setBookmarkUseCase: - DIContainer + DIContainer .resolve(type: SetBookmarkUseCase.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 - )) + ) + ) } DIContainer.register(type: BookmarkOnBoardingFactory.self) { BookmarkOnBoardingFactoryImpl() @@ -777,72 +1023,99 @@ private extension AppDelegate { DIContainer.register(type: BookmarkListFactory.self) { BookmarkListFactoryImpl( itemFilterFactory: DIContainer.resolve( - type: ItemFilterBottomSheetFactory.self), + type: ItemFilterBottomSheetFactory.self + ), monsterFilterFactory: DIContainer.resolve( - type: MonsterFilterBottomSheetFactory.self), + type: MonsterFilterBottomSheetFactory.self + ), sortedFactory: DIContainer.resolve( - type: SortedBottomSheetFactory.self), + type: SortedBottomSheetFactory.self + ), bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self), + type: BookmarkModalFactory.self + ), loginFactory: DIContainer.resolve(type: LoginFactory.self), dictionaryDetailFactory: DIContainer.resolve( - type: DictionaryDetailFactory.self), + type: DictionaryDetailFactory.self + ), collectionEditFactory: DIContainer.resolve( - type: CollectionEditFactory.self), + type: CollectionEditFactory.self + ), setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self), + type: SetBookmarkUseCase.self + ), checkLoginUseCase: DIContainer.resolve( - type: CheckLoginUseCase.self), + type: CheckLoginUseCase.self + ), fetchBookmarkUseCase: DIContainer.resolve( - type: FetchBookmarkUseCase.self), + type: FetchBookmarkUseCase.self + ), fetchMonsterBookmarkUseCase: DIContainer.resolve( - type: FetchMonsterBookmarkUseCase.self), + type: FetchMonsterBookmarkUseCase.self + ), fetchItemBookmarkUseCase: DIContainer.resolve( - type: FetchItemBookmarkUseCase.self), + type: FetchItemBookmarkUseCase.self + ), fetchNPCBookmarkUseCase: DIContainer.resolve( - type: FetchNPCBookmarkUseCase.self), + type: FetchNPCBookmarkUseCase.self + ), fetchQuestBookmarkUseCase: DIContainer.resolve( - type: FetchQuestBookmarkUseCase.self), + type: FetchQuestBookmarkUseCase.self + ), fetchMapBookmarkUseCase: DIContainer.resolve( - type: FetchMapBookmarkUseCase.self), - parseItemFilterResultUseCase: DIContainer.resolve(type: ParseItemFilterResultUseCase.self)) + type: FetchMapBookmarkUseCase.self + ), + parseItemFilterResultUseCase: DIContainer.resolve( + type: ParseItemFilterResultUseCase.self + ) + ) } DIContainer.register(type: CollectionListFactory.self) { CollectionListFactoryImpl( fetchCollectionListUseCase: DIContainer.resolve( - type: FetchCollectionListUseCase.self), + type: FetchCollectionListUseCase.self + ), addCollectionFactory: DIContainer.resolve( - type: AddCollectionFactory.self), + type: AddCollectionFactory.self + ), bookmarkDetailFactory: DIContainer.resolve( - type: CollectionDetailFactory.self), - sortedBottomSheetFactory: DIContainer - .resolve(type: SortedBottomSheetFactory.self)) + type: CollectionDetailFactory.self + ), + sortedBottomSheetFactory: + 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 + type: FetchCollectionUseCase.self + ), + deleteCollectionUseCase: + DIContainer .resolve(type: DeleteCollectionUseCase.self), - addCollectionAndBookmarkUseCase: DIContainer.resolve(type: AddCollectionAndBookmarkUseCase.self)) + addCollectionAndBookmarkUseCase: DIContainer.resolve( + type: AddCollectionAndBookmarkUseCase.self + ) + ) } DIContainer.register(type: CollectionSettingFactory.self) { CollectionSettingFactoryImpl() @@ -850,73 +1123,92 @@ private extension AppDelegate { DIContainer.register(type: CollectionEditFactory.self) { CollectionEditFactoryImpl( setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self), + type: SetBookmarkUseCase.self + ), bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self)) + type: BookmarkModalFactory.self + ) + ) } DIContainer.register(type: MyPageMainFactory.self) { 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)) + type: FetchProfileUseCase.self + ) + ) } DIContainer.register(type: CustomerSupportFactory.self) { CustomerSupportBaseViewFactoryImpl( fetchNoticesUseCase: DIContainer.resolve( - type: FetchNoticesUseCase.self), + type: FetchNoticesUseCase.self + ), fetchOngoingEventsUseCase: DIContainer.resolve( - type: FetchOngoingEventsUseCase.self), + type: FetchOngoingEventsUseCase.self + ), fetchOutdatedEventsUseCase: DIContainer.resolve( - type: FetchOutdatedEventsUseCase.self), + type: FetchOutdatedEventsUseCase.self + ), fetchPatchNotesUseCase: DIContainer.resolve( - type: FetchPatchNotesUseCase.self), - setReadUseCase: DIContainer.resolve(type: SetReadUseCase.self)) + type: FetchPatchNotesUseCase.self + ), + setReadUseCase: DIContainer.resolve(type: SetReadUseCase.self) + ) } DIContainer.register(type: SetProfileFactory.self) { SetProfileFactoryImpl( selectImageFactory: DIContainer.resolve( - type: SelectImageFactory.self), + type: SelectImageFactory.self + ), checkNickNameUseCase: DIContainer.resolve( - type: CheckNickNameUseCase.self), + type: CheckNickNameUseCase.self + ), updateNickNameUseCase: DIContainer.resolve( - type: UpdateNickNameUseCase.self), + type: UpdateNickNameUseCase.self + ), logoutUseCase: DIContainer.resolve(type: LogoutUseCase.self), withdrawUseCase: DIContainer.resolve( - type: WithdrawUseCase.self), + type: WithdrawUseCase.self + ), fetchProfileUseCase: DIContainer.resolve( - type: FetchProfileUseCase.self)) + type: FetchProfileUseCase.self + ) + ) } 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 - .resolve(type: UpdateUserInfoUseCase.self)) + DIContainer + .resolve(type: UpdateUserInfoUseCase.self) + ) } DIContainer.register(type: SelectImageFactory.self) { SelectImageFactoryImpl( updateProfileImageUseCase: DIContainer.resolve( - type: UpdateProfileImageUseCase.self)) + type: UpdateProfileImageUseCase.self + ) + ) } } } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift index c03d3a01..dcba72ae 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift @@ -4,17 +4,15 @@ import DictionaryFeatureInterface public struct OnBoardingNotificationFactoryImpl: OnBoardingNotificationFactory { private let onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory - private let dictionaryMainViewFactory: DictionaryMainViewFactory private let appCoordinator: () -> AppCoordinatorProtocol - public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, dictionaryMainViewFactory: DictionaryMainViewFactory, appCoordinator: @escaping () -> AppCoordinatorProtocol) { + public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, appCoordinator: @escaping () -> AppCoordinatorProtocol) { self.onBoardingNotificationSheetFactory = onBoardingNotificationSheetFactory - self.dictionaryMainViewFactory = dictionaryMainViewFactory self.appCoordinator = appCoordinator } public func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController { - let viewController = OnBoardingNotificationViewController(onBoardingNotificationSheetFactory: onBoardingNotificationSheetFactory, dictionaryMainViewFactory: dictionaryMainViewFactory, appCoordinator: appCoordinator()) + let viewController = OnBoardingNotificationViewController(onBoardingNotificationSheetFactory: onBoardingNotificationSheetFactory, appCoordinator: appCoordinator()) viewController.isBottomTabbarHidden = true viewController.reactor = OnBoardingNotificationReactor(selectedLevel: selectedLevel, selectedJobID: selectedJobID) return viewController diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift index 270e5292..62aec0ad 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift @@ -17,16 +17,14 @@ public class OnBoardingNotificationViewController: BaseViewController, View { public var disposeBag = DisposeBag() private let onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory - private let dictionaryMainViewFactory: DictionaryMainViewFactory private let appCoordinator: AppCoordinatorProtocol // MARK: - Components private var mainView = OnBoardingNotificationView() - public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, dictionaryMainViewFactory: DictionaryMainViewFactory, appCoordinator: AppCoordinatorProtocol) { + public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, appCoordinator: AppCoordinatorProtocol) { self.onBoardingNotificationSheetFactory = onBoardingNotificationSheetFactory - self.dictionaryMainViewFactory = dictionaryMainViewFactory self.appCoordinator = appCoordinator super.init() } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift index bc5b47f6..19243aeb 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift @@ -9,7 +9,6 @@ public struct OnBoardingInputFactoryImpl: OnBoardingInputFactory { private let fetchJobListUseCase: FetchJobListUseCase private let updateUserInfoUseCase: UpdateUserInfoUseCase private let onBoardingNotificationFactory: OnBoardingNotificationFactory - private let dictionaryMainViewFactory: DictionaryMainViewFactory private let appCoordinator: () -> AppCoordinatorProtocol public init( @@ -18,7 +17,6 @@ public struct OnBoardingInputFactoryImpl: OnBoardingInputFactory { fetchJobListUseCase: FetchJobListUseCase, updateUserInfoUseCase: UpdateUserInfoUseCase, onBoardingNotificationFactory: OnBoardingNotificationFactory, - dictionaryMainViewFactory: DictionaryMainViewFactory, appCoordinator: @escaping () -> AppCoordinatorProtocol ) { self.checkEmptyUseCase = checkEmptyUseCase @@ -26,12 +24,11 @@ public struct OnBoardingInputFactoryImpl: OnBoardingInputFactory { self.fetchJobListUseCase = fetchJobListUseCase self.updateUserInfoUseCase = updateUserInfoUseCase self.onBoardingNotificationFactory = onBoardingNotificationFactory - self.dictionaryMainViewFactory = dictionaryMainViewFactory self.appCoordinator = appCoordinator } public func make() -> BaseViewController { - let viewController = OnBoardingInputViewController(onBoardingNotificationFactory: onBoardingNotificationFactory, dictionaryMainViewFactory: dictionaryMainViewFactory, appCoordinator: appCoordinator()) + let viewController = OnBoardingInputViewController(onBoardingNotificationFactory: onBoardingNotificationFactory, appCoordinator: appCoordinator()) viewController.isBottomTabbarHidden = true viewController.reactor = OnBoardingInputReactor( checkEmptyUseCase: checkEmptyUseCase, diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift index 4d467fc1..1da435e4 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift @@ -18,16 +18,14 @@ public class OnBoardingInputViewController: BaseViewController, View { public var disposeBag = DisposeBag() private let onBoardingNotificationFactory: OnBoardingNotificationFactory - private let dictionaryMainViewFactory: DictionaryMainViewFactory private let appCoordinator: AppCoordinatorProtocol // MARK: - Components private var mainView = OnBoardingInputView() - init(onBoardingNotificationFactory: OnBoardingNotificationFactory, dictionaryMainViewFactory: DictionaryMainViewFactory, appCoordinator: AppCoordinatorProtocol) { + init(onBoardingNotificationFactory: OnBoardingNotificationFactory, appCoordinator: AppCoordinatorProtocol) { self.onBoardingNotificationFactory = onBoardingNotificationFactory - self.dictionaryMainViewFactory = dictionaryMainViewFactory self.appCoordinator = appCoordinator super.init() } diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift index b2ab803f..97613d4e 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift @@ -8,24 +8,24 @@ public struct OnBoardingNotificationSheetFactoryImpl: OnBoardingNotificationShee private let openNotificationSettingUseCase: OpenNotificationSettingUseCase private let updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase private let updateUserInfoUseCase: UpdateUserInfoUseCase - private let dictionaryMainViewFactory: DictionaryMainViewFactory + private let appCoordinator: () -> AppCoordinatorProtocol public init( checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, openNotificationSettingUseCase: OpenNotificationSettingUseCase, updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase, updateUserInfoUseCase: UpdateUserInfoUseCase, - dictionaryMainViewFactory: DictionaryMainViewFactory + appCoordinator: @escaping () -> AppCoordinatorProtocol ) { self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase self.openNotificationSettingUseCase = openNotificationSettingUseCase self.updateNotificationAgreementUseCase = updateNotificationAgreementUseCase self.updateUserInfoUseCase = updateUserInfoUseCase - self.dictionaryMainViewFactory = dictionaryMainViewFactory + self.appCoordinator = appCoordinator } public func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController & ModalPresentable { - let viewController = OnBoardingNotificationSheetViewController(dictionaryMainViewFactory: dictionaryMainViewFactory) + let viewController = OnBoardingNotificationSheetViewController(appCoordinator: appCoordinator()) viewController.isBottomTabbarHidden = true viewController.reactor = OnBoardingNotificationSheetReactor( selectedLevel: selectedLevel, diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift index dce5deee..2c2ed762 100644 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift +++ b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift @@ -18,13 +18,13 @@ public final class OnBoardingNotificationSheetViewController: BaseViewController // MARK: - Properties - private let dictionaryMainViewFactory: DictionaryMainViewFactory + private let appCoordinator: AppCoordinatorProtocol // MARK: - Components private var mainView = OnBoardingNotificationSheetView() - init(dictionaryMainViewFactory: DictionaryMainViewFactory) { - self.dictionaryMainViewFactory = dictionaryMainViewFactory + init(appCoordinator: AppCoordinatorProtocol) { + self.appCoordinator = appCoordinator super.init() } } @@ -112,10 +112,7 @@ extension OnBoardingNotificationSheetViewController { case .dismiss: owner.dismissCurrentModal() case .home: - let viewController = owner.dictionaryMainViewFactory.make() - viewController.isBottomTabbarHidden = false - let navigationController = UINavigationController(rootViewController: viewController) - AppRouter.setRoot(navigationController) + owner.appCoordinator.showMainTab() case .setting: guard let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) else { return } From 3fe7bda52e5c568ece749e8d46d776a035bd38f4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Nov 2025 16:09:44 +0000 Subject: [PATCH 7/7] style/#273: Apply SwiftLint autocorrect --- MLS/MLS/Application/AppDelegate.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index 5a08e569..01d3a82b 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -18,9 +18,9 @@ import Firebase import KakaoSDKCommon import MyPageFeature import MyPageFeatureInterface +import os import UIKit import UserNotifications -import os @main class AppDelegate: UIResponder, UIApplicationDelegate { @@ -404,8 +404,7 @@ extension AppDelegate { ) ) } - DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) - { + DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) { FetchDictionaryDetailMonsterMapUseCaseImpl( repository: DIContainer.resolve( type: DictionaryDetailAPIRepository.self