diff --git a/Atcha-iOS.xcodeproj/project.pbxproj b/Atcha-iOS.xcodeproj/project.pbxproj index 06606a69..5f03f507 100644 --- a/Atcha-iOS.xcodeproj/project.pbxproj +++ b/Atcha-iOS.xcodeproj/project.pbxproj @@ -2516,7 +2516,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 23SCTLK482; FRAMEWORK_SEARCH_PATHS = ( @@ -2539,7 +2539,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.9.2; + MARKETING_VERSION = 1.9.5; PRODUCT_BUNDLE_IDENTIFIER = com.atcha.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2563,7 +2563,7 @@ CODE_SIGN_ENTITLEMENTS = "Atcha-iOS/Atcha-iOS.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 23SCTLK482; EXCLUDED_ARCHS = ""; FRAMEWORK_SEARCH_PATHS = ( @@ -2586,7 +2586,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.9.2; + MARKETING_VERSION = 1.9.5; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.atcha.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2611,7 +2611,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 23SCTLK482; FRAMEWORK_SEARCH_PATHS = ( @@ -2634,7 +2634,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.9.2; + MARKETING_VERSION = 1.9.5; PRODUCT_BUNDLE_IDENTIFIER = com.atcha.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Atcha-iOS.xcodeproj/xcshareddata/xcschemes/Atcha-Live.xcscheme b/Atcha-iOS.xcodeproj/xcshareddata/xcschemes/Atcha-Live.xcscheme index e3c07a7f..859af9a4 100644 --- a/Atcha-iOS.xcodeproj/xcshareddata/xcschemes/Atcha-Live.xcscheme +++ b/Atcha-iOS.xcodeproj/xcshareddata/xcschemes/Atcha-Live.xcscheme @@ -40,7 +40,7 @@ shouldAutocreateTestPlan = "YES"> { containerView.snp.makeConstraints { $0.leading.trailing.equalToSuperview() $0.bottom.equalToSuperview() - $0.height.equalTo(195) + $0.height.equalTo(182) } labelStackView.snp.makeConstraints { diff --git a/Atcha-iOS/Core/Network/API/APIServiceImpl.swift b/Atcha-iOS/Core/Network/API/APIServiceImpl.swift index 44d10056..ea45324c 100644 --- a/Atcha-iOS/Core/Network/API/APIServiceImpl.swift +++ b/Atcha-iOS/Core/Network/API/APIServiceImpl.swift @@ -124,6 +124,7 @@ extension APIServiceImpl { } DiscordWebhookManager.shared.sendErrorLog( + baseURL: NetworkConstant.baseURL, statusCode: statusCode, method: method, path: serverPath, @@ -136,7 +137,7 @@ extension APIServiceImpl { let apiError = APIError.serverError(statusCode: statusCode, responseCode: responseCode) - NotificationCenter.default.post(name: .apiErrorOccurred, object: apiError) +// NotificationCenter.default.post(name: .apiErrorOccurred, object: apiError) continuation.resume(throwing: apiError) } } diff --git a/Atcha-iOS/Core/Network/Token/TokenInterceptor.swift b/Atcha-iOS/Core/Network/Token/TokenInterceptor.swift index 4bdab1b3..97361f57 100644 --- a/Atcha-iOS/Core/Network/Token/TokenInterceptor.swift +++ b/Atcha-iOS/Core/Network/Token/TokenInterceptor.swift @@ -38,9 +38,9 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable { ] if publicPaths.contains(where: { path.hasSuffix($0) }) { - completion(.success(request)) - return - } + completion(.success(request)) + return + } if path.contains("/auth/logout") { if let refreshToken = tokenStorage.refreshToken { @@ -65,7 +65,6 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable { return } - let path = request.request?.url?.path ?? "unknown" if path.contains("/auth/reissue") { @@ -78,6 +77,8 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable { return } + let actualHeaders = request.request?.allHTTPHeaderFields ?? [:] + guard let refreshToken = tokenStorage.refreshToken else { SessionController.shared.expireAndRouteToLogin() completion(.doNotRetry) @@ -109,12 +110,29 @@ final class TokenInterceptor: RequestInterceptor, @unchecked Sendable { return } + let successBody = [ + "newAccessToken": p.accessToken, + "newRefreshToken": p.refreshToken + ] + + DiscordWebhookManager.shared.sendErrorLog( + baseURL: NetworkConstant.baseURL, + statusCode: 200, + method: "GET", + path: "/auth/reissue", + responseCode: "REISSUE_SUCCESS", + message: "토큰 재발급에 성공하여 새로운 토큰을 수신했습니다.", + requestHeaders: actualHeaders, + requestBody: successBody, // 여기서 받은 토큰 정보를 보냅니다. + requestParameters: nil + ) + self.tokenStorage.accessToken = p.accessToken self.tokenStorage.refreshToken = p.refreshToken waiters.forEach { $0(.retry) } - case .failure(let error): + case .failure(_): SessionController.shared.expireAndRouteToLogin() waiters.forEach { $0(.doNotRetry) } } diff --git a/Atcha-iOS/Data/Repository/CourseRepositoryImpl.swift b/Atcha-iOS/Data/Repository/CourseRepositoryImpl.swift index 78df090e..8fc0550f 100644 --- a/Atcha-iOS/Data/Repository/CourseRepositoryImpl.swift +++ b/Atcha-iOS/Data/Repository/CourseRepositoryImpl.swift @@ -72,21 +72,8 @@ final class CourseRepositoryImpl: CourseRepository { throw URLError(.badServerResponse) } - // 401 외의 코드도 명확히 분기 - if http.statusCode == 401 { - if let tokens = await refreshToken() { - tokenStorage.accessToken = tokens.accessToken - if let rt = tokens.refreshToken { tokenStorage.refreshToken = rt } - print("재발급 성공 → 스트림 재연결") - await startStream(request, continuation: continuation) - return - } else { - continuation.finish(throwing: NSError(domain: "CourseRepository", code: 401, userInfo: [NSLocalizedDescriptionKey: "토큰 재발급 실패"])) - return - } - } else if http.statusCode != 200 { - // 서버가 JSON 에러 바디를 줄 수 있으니 한번 읽어봄 - // bytes(for:)는 스트림이므로 바디를 통째로 읽기 어렵다 → 상태만으로 에러 처리 + // HTTP 401 체크는 제거 (서버가 200으로 주기 때문) + if http.statusCode != 200 { continuation.finish(throwing: NSError(domain: "CourseRepository", code: http.statusCode, userInfo: [NSLocalizedDescriptionKey: "SSE 연결 실패 (\(http.statusCode))"])) return } @@ -100,23 +87,41 @@ final class CourseRepositoryImpl: CourseRepository { let events = parser.feed(Data([byte])) for event in events { guard !event.data.isEmpty, let payload = event.data.data(using: .utf8) else { continue } + + // 1. 데이터 내부의 에러 코드 확인 (TOK_001) + if let errorCheck = try? JSONDecoder().decode(SSEErrorPayload.self, from: payload), + errorCheck.responseCode == "TOK_001" { + + if let tokens = await refreshToken() { + tokenStorage.accessToken = tokens.accessToken + if let rt = tokens.refreshToken { tokenStorage.refreshToken = rt } + print("재발급 성공 → 스트림 재연결") + // 현재 스트림을 종료하지 않고 새 연결 시도 + await startStream(request, continuation: continuation) + return + } else { + continuation.finish(throwing: NSError(domain: "CourseRepository", code: 401, userInfo: [NSLocalizedDescriptionKey: "토큰 재발급 실패"])) + return + } + } + + // 2. 정상 데이터 디코딩 do { let decoded = try JSONDecoder().decode(CourseSearchResponse.self, from: payload) + print("데이터 수신: \(decoded)") continuation.yield(decoded) } catch { - // 서버가 keep-alive ping 이나 텍스트를 보낼 수 있으므로 디코드 실패는 경고만 - print("SSE decode 실패:", error, "raw:", event.data) + // 단순 텍스트나 핑 데이터인 경우 무시 + print("SSE decode 실패 (데이터 무시):", error, "raw:", event.data) } } } } catch { - // 실제 네트워크 오류(연결 끊김 등) print("SSE stream read error:", error) continuation.finish(throwing: error) return } - // 서버가 조용히 닫은 케이스 if !receivedAny { continuation.finish(throwing: NSError(domain: "CourseRepository", code: -1, userInfo: [NSLocalizedDescriptionKey: "SSE에서 응답이 없습니다."])) return @@ -182,6 +187,9 @@ final class CourseRepositoryImpl: CourseRepository { return nil } } - } +struct SSEErrorPayload: Decodable { + let responseCode: String? + let message: String? +} diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/Contents.json b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/Contents.json new file mode 100644 index 00000000..1c128afb --- /dev/null +++ b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "bus-chevron-right.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "bus-chevron-right@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "bus-chevron-right@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right.png new file mode 100644 index 00000000..08073d2d Binary files /dev/null and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right@2x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right@2x.png new file mode 100644 index 00000000..3f45f4ab Binary files /dev/null and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right@2x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right@3x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right@3x.png new file mode 100644 index 00000000..2830bdf4 Binary files /dev/null and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/bus-chevron-right.imageset/bus-chevron-right@3x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/Contents.json b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/Contents.json new file mode 100644 index 00000000..8d64233b --- /dev/null +++ b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "station-checron_down.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "station-checron_down@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "station-checron_down@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down.png new file mode 100644 index 00000000..ea342a2c Binary files /dev/null and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down@2x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down@2x.png new file mode 100644 index 00000000..c1682e72 Binary files /dev/null and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down@2x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down@3x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down@3x.png new file mode 100644 index 00000000..bdf291e7 Binary files /dev/null and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Normal/Chevron/station-checron_down.imageset/station-checron_down@3x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1.png index 128acd29..5adcc394 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@2x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@2x.png index ec4db33d..a959169e 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@2x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@2x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@3x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@3x.png index 738786a1..380b2d62 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@3x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step1.imageset/step1@3x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2.png index 11e7b267..2966637f 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@2x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@2x.png index ccd44a0c..dabea2cc 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@2x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@2x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@3x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@3x.png index 06714fb4..3d6c77c8 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@3x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step2.imageset/step2@3x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3.png index 284a6012..e7688fff 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@2x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@2x.png index dbbc4e9b..9af6bbdf 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@2x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@2x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@3x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@3x.png index 078bf0f4..6c7353bf 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@3x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step3.imageset/step3@3x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4.png index 9c9ad0f2..2c891710 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@2x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@2x.png index 22543ca5..317a59d4 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@2x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@2x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@3x.png b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@3x.png index 60da199f..e983bcbb 100644 Binary files a/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@3x.png and b/Atcha-iOS/DesignSource/AtchaImage/Icon.xcassets/Splash/step4.imageset/step4@3x.png differ diff --git a/Atcha-iOS/DesignSource/AtchaLottie/RefreshView.swift b/Atcha-iOS/DesignSource/AtchaLottie/RefreshView.swift index acecd55f..d20f1894 100644 --- a/Atcha-iOS/DesignSource/AtchaLottie/RefreshView.swift +++ b/Atcha-iOS/DesignSource/AtchaLottie/RefreshView.swift @@ -50,7 +50,7 @@ final class RefreshView: UIView { } animationView.snp.makeConstraints { make in make.center.equalTo(refreshImageView) - make.size.equalTo(24) + make.size.equalTo(36) } } diff --git a/Atcha-iOS/Presentation/BusDetail/BusDetailViewController.swift b/Atcha-iOS/Presentation/BusDetail/BusDetailViewController.swift index 99d3b03a..d38f45e6 100644 --- a/Atcha-iOS/Presentation/BusDetail/BusDetailViewController.swift +++ b/Atcha-iOS/Presentation/BusDetail/BusDetailViewController.swift @@ -138,7 +138,7 @@ class BusDetailViewController: BaseViewController { } refreshButton.snp.makeConstraints { make in - make.size.equalTo(48) + make.size.equalTo(52) make.trailing.equalToSuperview().inset(16) make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).inset(16) } diff --git a/Atcha-iOS/Presentation/BusDetail/BusInfo/BusInfoViewController.swift b/Atcha-iOS/Presentation/BusDetail/BusInfo/BusInfoViewController.swift index dadcc42d..3b5e7984 100644 --- a/Atcha-iOS/Presentation/BusDetail/BusInfo/BusInfoViewController.swift +++ b/Atcha-iOS/Presentation/BusDetail/BusInfo/BusInfoViewController.swift @@ -205,7 +205,7 @@ class BusInfoViewController: BaseViewController { } refreshButton.snp.makeConstraints { make in - make.size.equalTo(48) + make.size.equalTo(52) make.trailing.equalToSuperview().inset(16) make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).inset(16) } diff --git a/Atcha-iOS/Presentation/Common/BaseViewController.swift b/Atcha-iOS/Presentation/Common/BaseViewController.swift index b4120853..6109f78d 100644 --- a/Atcha-iOS/Presentation/Common/BaseViewController.swift +++ b/Atcha-iOS/Presentation/Common/BaseViewController.swift @@ -49,7 +49,7 @@ class BaseViewController: UIViewController { setupBindings() setupKeyboardDismiss() observeNetwork() - setupErrorObserver() +// setupErrorObserver() } override func viewDidAppear(_ animated: Bool) { @@ -216,54 +216,54 @@ class BaseViewController: UIViewController { reconnectView = nil } - private func setupErrorObserver() { - NotificationCenter.default.addObserver( - self, - selector: #selector(handleServerError(_:)), - name: .apiErrorOccurred, - object: nil - ) - } +// private func setupErrorObserver() { +// NotificationCenter.default.addObserver( +// self, +// selector: #selector(handleServerError(_:)), +// name: .apiErrorOccurred, +// object: nil +// ) +// } - @objc private func handleServerError(_ notification: Notification) { - // 1. 전달된 오브젝트가 APIError인지 확인 - guard let apiError = notification.object as? APIError else { return } - - // 2. 에러 케이스와 상태 코드 추출 (APIError가 statusCode를 가지고 있다고 가정) - if case .serverError(let statusCode, _) = apiError { - - // 3. 500번대 에러인 경우에만 팝업 노출 - if (500...599).contains(statusCode) && !ErrorState.isShowing500Error { - guard self.presentedViewController == nil else { return } - - DispatchQueue.main.async { [weak self] in - self?.showAtchaErrorPopup() - } - } else { - // 400번대 등 기타 에러는 팝업을 띄우지 않고 로그만 남기거나 별도 처리 - print("UI 팝업 제외 대상 에러: \(statusCode)") - } - } - } +// @objc private func handleServerError(_ notification: Notification) { +// // 1. 전달된 오브젝트가 APIError인지 확인 +// guard let apiError = notification.object as? APIError else { return } +// +// // 2. 에러 케이스와 상태 코드 추출 (APIError가 statusCode를 가지고 있다고 가정) +// if case .serverError(let statusCode, _) = apiError { +// +// // 3. 500번대 에러인 경우에만 팝업 노출 +// if (500...599).contains(statusCode) && !ErrorState.isShowing500Error { +// guard self.presentedViewController == nil else { return } +// +// DispatchQueue.main.async { [weak self] in +// self?.showAtchaErrorPopup() +// } +// } else { +// // 400번대 등 기타 에러는 팝업을 띄우지 않고 로그만 남기거나 별도 처리 +// print("UI 팝업 제외 대상 에러: \(statusCode)") +// } +// } +// } - private func showAtchaErrorPopup() { - ErrorState.isShowing500Error = true - - // 이전에 만드신 앗차팝업 호출 (에러 케이스용) - let popupVM = AtchaPopupViewModel(info: .serverError) // Enum에 .serverError 추가 필요 - let popupVC = AtchaPopupViewController(viewModel: popupVM) - - popupVC.confirmButton.addAction(UIAction { [weak popupVC] _ in - ErrorState.isShowing500Error = false - popupVC?.dismiss(animated: false) - }, for: .touchUpInside) - - popupVC.modalPresentationStyle = .overFullScreen - self.present(popupVC, animated: false) - } +// private func showAtchaErrorPopup() { +// ErrorState.isShowing500Error = true +// +// // 이전에 만드신 앗차팝업 호출 (에러 케이스용) +// let popupVM = AtchaPopupViewModel(info: .serverError) // Enum에 .serverError 추가 필요 +// let popupVC = AtchaPopupViewController(viewModel: popupVM) +// +// popupVC.confirmButton.addAction(UIAction { [weak popupVC] _ in +// ErrorState.isShowing500Error = false +// popupVC?.dismiss(animated: false) +// }, for: .touchUpInside) +// +// popupVC.modalPresentationStyle = .overFullScreen +// self.present(popupVC, animated: false) +// } deinit { - NotificationCenter.default.removeObserver(self, name: .apiErrorOccurred, object: nil) +// NotificationCenter.default.removeObserver(self, name: .apiErrorOccurred, object: nil) } } diff --git a/Atcha-iOS/Presentation/Course/CourseSearch/CourseCell.swift b/Atcha-iOS/Presentation/Course/CourseSearch/CourseCell.swift index 5edfe4a4..1ead56ac 100644 --- a/Atcha-iOS/Presentation/Course/CourseSearch/CourseCell.swift +++ b/Atcha-iOS/Presentation/Course/CourseSearch/CourseCell.swift @@ -130,7 +130,7 @@ final class CourseCell: UICollectionViewCell { departureTimeLabel.layer.borderColor = AtchaColor.gray500.cgColor } - departureLabel.attributedText = AtchaFont.R_13("에 자리에서 출발", color: AtchaColor.gray200) + departureLabel.attributedText = AtchaFont.R_13("내 자리에서 출발", color: AtchaColor.gray200) progressView.configure(infos: course.toLegTrafficInfos()) courseStepsStackView.configure(legs: course.legs) diff --git a/Atcha-iOS/Presentation/Intro/IntroCell.swift b/Atcha-iOS/Presentation/Intro/IntroCell.swift index 180926a3..c871ef03 100644 --- a/Atcha-iOS/Presentation/Intro/IntroCell.swift +++ b/Atcha-iOS/Presentation/Intro/IntroCell.swift @@ -39,10 +39,10 @@ final class IntroCell: UICollectionViewCell { private func setupAutoLayout() { imageView.snp.makeConstraints { make in - make.top.equalToSuperview().offset(125.34) + make.top.equalToSuperview().offset(125.23) make.centerX.equalToSuperview() make.horizontalEdges.equalToSuperview() - make.height.equalTo(imageView.snp.width).multipliedBy(415.32 / 392.0) + make.height.equalTo(imageView.snp.width).multipliedBy(415.55 / 392.0) } titleLabel.snp.makeConstraints { make in diff --git a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteBusCell.swift b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteBusCell.swift index df69983c..57e394be 100644 --- a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteBusCell.swift +++ b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteBusCell.swift @@ -307,14 +307,14 @@ final class DetailRouteBusCell: UICollectionViewCell { let startCombinedLabel = NSMutableAttributedString() startCombinedLabel.append(AtchaFont.B3_M_15("\(firstStation.stationName ?? "")", - color: .gray100)) - startCombinedLabel.append(AtchaFont.B3_M_15(" 승차", color: .gray500)) + color: .white)) + startCombinedLabel.append(AtchaFont.B3_M_15(" 승차", color: .gray200)) startLabel.attributedText = startCombinedLabel let endCombinedLabel = NSMutableAttributedString() endCombinedLabel.append(AtchaFont.B3_M_15("\(lastStation.stationName ?? "")", - color: .gray100)) - endCombinedLabel.append(AtchaFont.B3_M_15(" 하차", color: .gray500)) + color: .white)) + endCombinedLabel.append(AtchaFont.B3_M_15(" 하차", color: .gray200)) endLabel.attributedText = endCombinedLabel self.busTimerStackView.isHidden = !isAlarmFired diff --git a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteSubwayCell.swift b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteSubwayCell.swift index f0b2dbe4..f6e2a6c1 100644 --- a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteSubwayCell.swift +++ b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/Cell/DetailRouteSubwayCell.swift @@ -306,14 +306,14 @@ final class DetailRouteSubwayCell: UICollectionViewCell { let startCombinedLabel = NSMutableAttributedString() startCombinedLabel.append(AtchaFont.B3_M_15("\(firstStation.stationName ?? "")역", - color: .gray100)) - startCombinedLabel.append(AtchaFont.B3_M_15(" 승차", color: .gray500)) + color: .white)) + startCombinedLabel.append(AtchaFont.B3_M_15(" 승차", color: .gray200)) startLabel.attributedText = startCombinedLabel let endCombinedLabel = NSMutableAttributedString() endCombinedLabel.append(AtchaFont.B3_M_15("\(lastStation.stationName ?? "")역", - color: .gray100)) - endCombinedLabel.append(AtchaFont.B3_M_15(" 하차", color: .gray500)) + color: .white)) + endCombinedLabel.append(AtchaFont.B3_M_15(" 하차", color: .gray200)) endLabel.attributedText = endCombinedLabel // if isCurrentTimeBetween(startTime: info.startTime, endTime: info.endTime) { diff --git a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteBusLabel.swift b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteBusLabel.swift index d4e9fc51..7ed590e7 100644 --- a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteBusLabel.swift +++ b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteBusLabel.swift @@ -32,7 +32,7 @@ final class BusBadgeView: UIView { numberLabel.font = .systemFont(ofSize: 20, weight: .bold) numberLabel.textColor = .white - arrowImageView.image = UIImage(systemName: "chevron.right") + arrowImageView.image = UIImage.busChevronRight arrowImageView.contentMode = .scaleAspectFit arrowImageView.tintColor = UIColor.white.withAlphaComponent(0.7) diff --git a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteSummaryView.swift b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteSummaryView.swift index c6ba43ef..b3f4cdd1 100644 --- a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteSummaryView.swift +++ b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteSummaryView.swift @@ -28,7 +28,7 @@ final class DetailRouteSummaryView: UIView { summaryLabel.font = .systemFont(ofSize: 14, weight: .regular) summaryLabel.textColor = .white - arrowImageView.image = UIImage(systemName: "chevron.down") + arrowImageView.image = UIImage.stationChecronDown arrowImageView.contentMode = .scaleAspectFit arrowImageView.tintColor = .gray200 @@ -50,7 +50,7 @@ final class DetailRouteSummaryView: UIView { } func configure(duration: String, stops: Int) { - summaryLabel.attributedText = AtchaFont.B7_M_13("\(duration), \(stops - 1)개 정류장 이동", color: .white) + summaryLabel.attributedText = AtchaFont.B6_R_14("\(duration), \(stops - 1)개 정류장 이동", color: .white) arrowImageView.isHidden = false } } diff --git a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteTimeLabel.swift b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteTimeLabel.swift index e73ffabb..5d6da2d6 100644 --- a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteTimeLabel.swift +++ b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteInfo/DetailRouteTimeLabel.swift @@ -25,7 +25,7 @@ final class TimeBadgeLabel: UIView { } func setText(_ text: String?) { - label.attributedText = AtchaFont.M_11(text ?? "", color: .gray200) + label.attributedText = AtchaFont.M_11(text ?? "", color: .gray200, alignment: .center) } private func setupUI() { diff --git a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewController.swift b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewController.swift index ce84370a..7823c62c 100644 --- a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewController.swift +++ b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewController.swift @@ -183,7 +183,7 @@ final class DetailRouteViewController: BaseViewController, make.width.height.equalTo(40) } refreshButton.snp.makeConstraints { make in - make.size.equalTo(48) + make.size.equalTo(52) make.trailing.equalToSuperview().inset(16) make.bottom.equalTo(view.snp.bottom).inset(40) } diff --git a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewModel.swift b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewModel.swift index 6f538716..68c3d312 100644 --- a/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewModel.swift +++ b/Atcha-iOS/Presentation/Location/DetailRoute/DetailRouteViewModel.swift @@ -186,6 +186,12 @@ final class DetailRouteViewModel: BaseViewModel { } private func startPolling() { + let isFired = UserDefaultsWrapper.shared.bool(forKey: UserDefaultsWrapper.Key.departureAlarmDidFire.rawValue) ?? false + guard isFired else { + print("알람이 등록되지 않은 상태이므로 폴링을 시작하지 않습니다.") + return + } + stopPolling() pollingTask = Task { [weak self] in @@ -364,6 +370,7 @@ final class DetailRouteViewModel: BaseViewModel { } catch { // 실패 시 기존 값 유지 print("실시간 버스 조회 실패: \(route), \(error)") + if checkAndStopPolling(error: error) { break } } } @@ -385,6 +392,7 @@ final class DetailRouteViewModel: BaseViewModel { } catch { // 실패 시 기존 유지 print("실시간 지하철 조회 실패: \(route), \(error)") + if checkAndStopPolling(error: error) { break } } } } @@ -494,7 +502,7 @@ extension DetailRouteViewModel { private func checkAndStopPolling(error: Error) -> Bool { if let apiError = error as? APIError { if case .serverError(_, let code) = apiError { - let stopCodes = ["URT_001", "LRT_001", "LRT_003"] + let stopCodes = ["URT_001", "LRT_001", "LRT_003", "REQ_004"] if let code = code, stopCodes.contains(code) { self.stopPolling() diff --git a/Atcha-iOS/Presentation/Location/MainViewController.swift b/Atcha-iOS/Presentation/Location/MainViewController.swift index c39c7e07..87ceab62 100644 --- a/Atcha-iOS/Presentation/Location/MainViewController.swift +++ b/Atcha-iOS/Presentation/Location/MainViewController.swift @@ -69,21 +69,16 @@ final class MainViewController: BaseViewController, var shouldShowWelcomeToast: Bool = false private var hasShownAlarmRegisteredToast = false - private lazy var shouldShowTopLineInSearch: Bool = { - let isRevisit = UserDefaultsWrapper.shared.bool(forKey: UserDefaultsWrapper.Key.reVisit.rawValue) ?? false - if !isRevisit { - // 처음 방문 시 기기에는 '방문함'으로 저장해두되, - // 현재 앱이 켜져있는 이 세션 동안은 계속 true(첫 방문 취급)를 반환하도록 함 - UserDefaultsWrapper.shared.set(true, forKey: UserDefaultsWrapper.Key.reVisit.rawValue) - return true - } - return false - }() private var isFirstVisit: Bool = false private var isShowingToast = false private var balloonHideWorkItem: DispatchWorkItem? + private var shouldShowMapGuide: Bool { + if viewModel.isGuest { return false } + return viewModel.isGuideActiveInSession + } + // MARK: - Life Cycle override func viewDidLoad() { @@ -175,17 +170,18 @@ final class MainViewController: BaseViewController, self?.ensureLocationPermissionOrShowToast() } } - - // 즉시 말풍선 업데이트 (1줄짜리로 자연스럽게 나타남) - if self.viewModel.bottomType == .search || self.viewModel.bottomType == nil { - self.showOrUpdatePersistentBalloon( - isFirstVisit: self.isFirstVisit, - isServiceRegion: self.latestIsServiceRegion, - fareStr: self.latestFareString - ) - } } + // 즉시 말풍선 업데이트 (1줄짜리로 자연스럽게 나타남) + if self.viewModel.bottomType == .search || self.viewModel.bottomType == nil { + self.showOrUpdatePersistentBalloon( + isFirstVisit: self.isFirstVisit, + isServiceRegion: self.latestIsServiceRegion, + fareStr: self.latestFareString + ) + } + + self.viewModel.refreshCurrentMapCenterData() let isGuest = UserDefaultsWrapper.shared.bool( @@ -693,7 +689,6 @@ extension MainViewController { switch type { case .departure: - self.shouldShowTopLineInSearch = false lastTrainDepartView.isHidden = false viewModel.startAlarmTimer() mapContainerView.afterUserMarker() @@ -1070,6 +1065,25 @@ extension MainViewController: UIGestureRecognizerDelegate { shouldCenterToCurrentLocationOnce = false viewModel.stopHeading() } + + let isRevisit = UserDefaultsWrapper.shared.bool(forKey: UserDefaultsWrapper.Key.reVisit.rawValue) ?? false + + // 세션 가이드가 켜져 있거나, 혹은 앱 재시작 등으로 인해 아직 reVisit이 기록되지 않은 상태라면 + if viewModel.isGuideActiveInSession || !isRevisit { + + // 1. 모든 플래그를 종료 상태로 변경 + viewModel.isGuideActiveInSession = false + UserDefaultsWrapper.shared.set(true, forKey: UserDefaultsWrapper.Key.reVisit.rawValue) + + // 2. 말풍선 즉시 갱신 (가이드 문구가 사라진 버전으로) + showOrUpdatePersistentBalloon( + isFirstVisit: false, + isServiceRegion: latestIsServiceRegion, + fareStr: latestFareString + ) + + print("DEBUG: 가이드 종료 및 reVisit 기록 완료") + } } } @@ -1219,35 +1233,32 @@ extension MainViewController { private func showOrUpdatePersistentBalloon(isFirstVisit: Bool, isServiceRegion: Bool?, fareStr: String?) { guard !isShowingToast else { return } - let topText = "지도를 움직여 출발지를 설정해요" + // [수정] 우리가 정의한 로그인 기반 가이드 로직 적용 + let showGuideLine = shouldShowMapGuide + let topText: String? = showGuideLine ? "지도를 움직여 출발지를 설정해요" : nil if isServiceRegion == false { - // 1. 확실하게 서비스 지역이 아닐 때 - ballonView.setupTitle(topMessage: isFirstVisit ? topText : nil, bottomMessage: "서울, 경기, 인천 내에서만 사용할 수 있어요") - + ballonView.setupTitle(topMessage: topText, bottomMessage: "서울, 경기, 인천 내에서만 사용할 수 있어요") } else { - // 2. 서비스 지역이거나 로딩 중일 때 if viewModel.isGuest { - // 비회원: ???원 유지 (색상 분리) - ballonView.separationTitle(grayMessage: "여기서 막차 놓치면 택시비 ", whiteMessage: "약 ???원", showTopLine: isFirstVisit) + // 비로그인: 가이드 없이 ???원만 노출 + ballonView.separationTitle(grayMessage: "여기서 막차 놓치면 택시비 ", whiteMessage: "약 ???원", showTopLine: false) } else { - // 회원 + // 로그인 상태 if let fare = fareStr { - // 요금 조회가 완료되었을 때 (색상 분리) - ballonView.separationTitle(grayMessage: "여기서 막차 놓치면 택시비 ", whiteMessage: "약 \(fare)원", showTopLine: isFirstVisit) + ballonView.separationTitle(grayMessage: "여기서 막차 놓치면 택시비 ", whiteMessage: "약 \(fare)원", showTopLine: showGuideLine) } else { - // 요금 조회 중일 때 (단일 색상으로 '계산중...' 표시) - ballonView.separationTitle(grayMessage: "여기서 막차 놓치면 택시비 계산중...", whiteMessage: "", showTopLine: isFirstVisit) + ballonView.separationTitle(grayMessage: "여기서 막차 놓치면 택시비 계산중...", whiteMessage: "", showTopLine: showGuideLine) } } } + // 애니메이션 처리 if ballonView.isHidden || ballonView.alpha == 0 { - safeStartJump() // 무조건 점프! + safeStartJump() ballonView.isHidden = false ballonView.alpha = 1 - - let delay: TimeInterval = isFirstVisit ? 0.8 : 0.0 + let delay: TimeInterval = showGuideLine ? 0.8 : 0.0 ballonView.animateStaggered(secondaryDelay: delay, fade: 0.3) } else { ballonView.revealImmediately() diff --git a/Atcha-iOS/Presentation/Location/MainViewModel.swift b/Atcha-iOS/Presentation/Location/MainViewModel.swift index 66f628cc..22979709 100644 --- a/Atcha-iOS/Presentation/Location/MainViewModel.swift +++ b/Atcha-iOS/Presentation/Location/MainViewModel.swift @@ -66,6 +66,7 @@ final class MainViewModel: BaseViewModel{ return formatter }() private var cachedPathCoordinates: [CLLocationCoordinate2D] = [] + var isGuideActiveInSession: Bool = false init(authorizationUseCase: RequestLocationAuthorizationUseCase, streamUseCase: ObserveLocationStreamUseCase, @@ -230,6 +231,7 @@ final class MainViewModel: BaseViewModel{ wrapper.remove(forKey: UserDefaultsWrapper.Key.departureTime.rawValue) wrapper.remove(forKey: UserDefaultsWrapper.Key.arrivalTime.rawValue) wrapper.remove(forKey: UserDefaultsWrapper.Key.alarmRegister.rawValue) + self.cachedPathCoordinates.removeAll() } func requestPermissionAndStartTracking() { @@ -364,6 +366,8 @@ final class MainViewModel: BaseViewModel{ let wrapper = UserDefaultsWrapper.shared let routeId = wrapper.string(forKey: UserDefaultsWrapper.Key.lastRouteId.rawValue) ?? "" + self.cachedPathCoordinates.removeAll() + Task { do { let info = try await courseUseCase.courseSearch(routeId) @@ -389,6 +393,8 @@ final class MainViewModel: BaseViewModel{ AlarmManager.shared.cancelArrivalTimeout() + self.cachedPathCoordinates.removeAll() + let wrapper = UserDefaultsWrapper.shared let savedLastRouteId: String? = wrapper.string( forKey: UserDefaultsWrapper.Key.lastRouteId.rawValue) diff --git a/Atcha-iOS/Presentation/Location/View/HomeRegisterBottomView.swift b/Atcha-iOS/Presentation/Location/View/HomeRegisterBottomView.swift index f4962f3d..1812eff0 100644 --- a/Atcha-iOS/Presentation/Location/View/HomeRegisterBottomView.swift +++ b/Atcha-iOS/Presentation/Location/View/HomeRegisterBottomView.swift @@ -20,7 +20,7 @@ final class HomeRegisterBottomView: UIView { private var currentAddress: String? private let nameLabel: UILabel = UILabel() private let addressLabel: UILabel = UILabel() - private let button: AtchaButton = AtchaButton(text: "우리집 등록", + private let button: AtchaButton = AtchaButton(text: "우리집 설정", size: .h52, style: .filled(.primary)) private lazy var titleStackView: UIStackView = { diff --git a/Atcha-iOS/Presentation/Main/MainCoordinator.swift b/Atcha-iOS/Presentation/Main/MainCoordinator.swift index 56e99caa..8c5e379d 100644 --- a/Atcha-iOS/Presentation/Main/MainCoordinator.swift +++ b/Atcha-iOS/Presentation/Main/MainCoordinator.swift @@ -353,19 +353,22 @@ final class MainCoordinator: NSObject { DispatchQueue.main.async { guard let self = self else { return } - UserDefaultsWrapper.shared.set(false, forKey: UserDefaultsWrapper.Key.isGuest.rawValue) - self.mainViewModel?.isGuest = false + self.mainViewModel?.isGuideActiveInSession = true - self.navigationController.dismiss(animated: true) { + if isExist { + UserDefaultsWrapper.shared.set(false, forKey: UserDefaultsWrapper.Key.isGuest.rawValue) + self.mainViewModel?.isGuest = false - if isExist { + self.navigationController.dismiss(animated: true) { self.mainViewModel?.refreshCurrentMapCenterData() - } else { - self.routeToOnboarding?() + self.loginCoordinator = nil } - // 로그인 코디네이터 메모리 해제 - self.loginCoordinator = nil + } else { + self.navigationController.dismiss(animated: true) { + self.routeToOnboarding?() + self.loginCoordinator = nil + } } } } diff --git a/Atcha-iOS/Presentation/Onboarding/RegisterLocation/RegisterLocationViewController.swift b/Atcha-iOS/Presentation/Onboarding/RegisterLocation/RegisterLocationViewController.swift index 6ed4f6dc..0e084442 100644 --- a/Atcha-iOS/Presentation/Onboarding/RegisterLocation/RegisterLocationViewController.swift +++ b/Atcha-iOS/Presentation/Onboarding/RegisterLocation/RegisterLocationViewController.swift @@ -17,7 +17,7 @@ class RegisterLocationViewController: BaseViewController