Skip to content

Commit 08e37dc

Browse files
authored
Feat: 온보딩 여부 저장 및 분기 처리
* Feat: 온보딩 여부 저장 및 불러오기, 삭제 로직 구현 - 온보딩 여부 저장, 불러오기, 삭제 로직 구현 - 필요없는 profileImageUrl 저장, 불러오기, 삭제 로직 제거 * Feat: 온보딩 여부에 따른 진입 뷰 분기 처리 - 온보딩 여부에 따른 진입 뷰 분기 처리 - 그에 따른 ViewController, ViewModel 접근제어자 변경 (internal -> public) * Feat: 온보딩 네비게이션 Background 색상 변경 * Refactor: 코드 리뷰 반영 - 중복된 네비게이션 바 Appearance 설정 제거 - OnboardingView viewDidLoad 제거 * Refactor: 온보딩 첫 화면에서 백버튼 제거
1 parent 7726a5a commit 08e37dc

15 files changed

Lines changed: 113 additions & 52 deletions

File tree

Projects/App/Sources/SceneDelegate.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,22 @@ extension SceneDelegate: SplashViewDelegate {
5454
guard let userDataRepository = DIContainer.shared.resolve(type: UserDataRepositoryProtocol.self)
5555
else { fatalError("userDataRepository 의존성이 등록되지 않았습니다.") }
5656

57+
guard let onboardingRepository = DIContainer.shared.resolve(type: OnboardingRepositoryProtocol.self)
58+
else { fatalError("onboardingRepository 의존성이 등록되지 않았습니다.") }
59+
5760
Task { @MainActor in
5861
let isLogined = await userDataRepository.reissueToken()
5962
if isLogined {
60-
window?.rootViewController = TabBarView()
63+
if onboardingRepository.isOnboardingDone() {
64+
window?.rootViewController = TabBarView()
65+
} else {
66+
guard let onboardingViewModel = DIContainer.shared.resolve(type: OnboardingViewModel.self) else {
67+
fatalError("onboardingViewModel 의존성이 등록되지 않았습니다.")
68+
}
69+
let onboardingView = OnboardingView(viewModel: onboardingViewModel, onboarding: .time)
70+
let navigationController = UINavigationController(rootViewController: onboardingView)
71+
window?.rootViewController = navigationController
72+
}
6173
} else {
6274
let introView = IntroView()
6375
let navigationController = UINavigationController(rootViewController: introView)

Projects/DataSource/Sources/Common/Enum/UserDefaultsKey.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
enum UserDefaultsKey: String {
99
case nickname
1010
case socialLoginType
11-
case profileImageUrl
11+
case onboarding
1212
}

Projects/DataSource/Sources/Common/Error/UserError.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ enum UserError: Error, CustomStringConvertible {
1212
case socialLoginTypeSaveFailed
1313
case socialLoginTypeLoadFailed
1414
case socialLoginTypeRemoveFailed
15-
case profileImageUrlSaveFailed
16-
case profileImageUrlLoadFailed
17-
case profileImageUrlRemoveFailed
15+
case onboardingSaveFailed
16+
case onboardingLoadFailed
17+
case onboardingRemoveFailed
1818
case unknown(error: Error)
1919

2020
var description: String {
@@ -31,12 +31,12 @@ enum UserError: Error, CustomStringConvertible {
3131
return "소셜 로그인 타입 불러오기에 실패했습니다."
3232
case .socialLoginTypeRemoveFailed:
3333
return "소셜 로그인 타입 삭제 실패했습니다."
34-
case .profileImageUrlSaveFailed:
35-
return "유저 프로필 저장 실패했습니다."
36-
case .profileImageUrlLoadFailed:
37-
return "유저 프로필 불러오기에 실패했습니다."
38-
case .profileImageUrlRemoveFailed:
39-
return "유저 프로필 삭제 실패했습니다."
34+
case .onboardingSaveFailed:
35+
return "온보딩 여부 저장 실패했습니다."
36+
case .onboardingLoadFailed:
37+
return "온보딩 여부 불러오기에 실패했습니다."
38+
case .onboardingRemoveFailed:
39+
return "온보딩 여부를 삭제하는데 실패했습니다."
4040
case .unknown(let error):
4141
return "알 수 없는 에러가 발생했습니다. \(error.localizedDescription)"
4242
}

Projects/DataSource/Sources/Repository/AuthRepository.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,6 @@ final class AuthRepository: AuthRepositoryProtocol {
138138
}
139139
}
140140

141-
// UserDefaults에 프로필 이미지를 저장합니다.
142-
private func saveUserProfileImageUrl(profileImageUrl: URL) throws {
143-
guard userDefaultsStorage.save(profileImageUrl.absoluteString, forKey: UserDefaultsKey.profileImageUrl.rawValue) else {
144-
throw UserError.profileImageUrlSaveFailed
145-
}
146-
}
147-
148141
// UserDefaults에 저장된 유저 정보(닉네임, 소셜 로그인 타입, 프로필 이미지)를 삭제합니다.
149142
private func removeUserInfo() throws {
150143
guard userDefaultsStorage.remove(forKey: UserDefaultsKey.nickname.rawValue) else {
@@ -155,8 +148,9 @@ final class AuthRepository: AuthRepositoryProtocol {
155148
throw UserError.socialLoginTypeRemoveFailed
156149
}
157150

158-
guard userDefaultsStorage.remove(forKey: UserDefaultsKey.profileImageUrl.rawValue) else {
159-
throw UserError.profileImageUrlRemoveFailed
151+
guard userDefaultsStorage.remove(forKey: UserDefaultsKey.onboarding.rawValue) else {
152+
throw UserError.onboardingRemoveFailed
160153
}
154+
161155
}
162156
}

Projects/DataSource/Sources/Repository/OnboardingRepository.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,27 @@ import Domain
99

1010
final class OnboardingRepository: OnboardingRepositoryProtocol {
1111
private let networkService = NetworkService.shared
12+
private let userDefaultsStorage = UserDefaultsStorage.shared
1213

1314
func registerOnboarding(onboardingChoices: [String : String]) async throws -> [RecommendedRoutineEntity] {
1415
let endpoint = OnboardingEndpoint.registerOnboarding(choices: onboardingChoices)
1516
guard let response = try await networkService.request(endpoint: endpoint, type: RecommendedRoutineListResponseDTO.self)
1617
else { return [] }
1718

19+
guard userDefaultsStorage.save(true, forKey: UserDefaultsKey.onboarding.rawValue)
20+
else { throw UserError.onboardingSaveFailed }
21+
1822
let recommendedRoutineEntity = response.recommendedRoutines.compactMap({ $0.toRecommendedRoutineEntity() })
1923
return recommendedRoutineEntity
2024
}
2125

26+
func isOnboardingDone() -> Bool {
27+
guard let isOnboardingDone: Bool = userDefaultsStorage.load(forKey: UserDefaultsKey.onboarding.rawValue)
28+
else { return false }
29+
30+
return isOnboardingDone
31+
}
32+
2233
func registerRecommendedRoutines(selectedRoutines: [Int]) async throws {
2334
let endpoint = OnboardingEndpoint.registerRecommendedRoutine(selectedRoutines: selectedRoutines)
2435
_ = try await networkService.request(endpoint: endpoint, type: EmptyResponseDTO.self)

Projects/Domain/Sources/Protocol/Repository/OnboardingRepositoryProtocol.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ public protocol OnboardingRepositoryProtocol {
1414
/// 선택한 추천 루틴을 등록합니다.
1515
/// - Parameter selectedRoutines: 선택한 추천 루틴 ID 목록
1616
func registerRecommendedRoutines(selectedRoutines: [Int]) async throws
17+
18+
/// 온보딩 여부를 반환합니다.
19+
/// - Returns: 온보딩 여부
20+
func isOnboardingDone() -> Bool
1721
}

Projects/Presentation/Sources/Common/Extension/UIViewController+.swift

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@ import UIKit
1010
extension UIViewController {
1111
// MARK: - NavigationBar
1212
func configureNavigationBar(navigationStyle: NavigationBarStyle) {
13-
let appearance = UINavigationBarAppearance()
14-
appearance.backgroundEffect = .none
15-
appearance.configureWithOpaqueBackground()
16-
appearance.shadowColor = .clear
17-
navigationController?.navigationBar.standardAppearance = appearance
18-
navigationController?.navigationBar.scrollEdgeAppearance = appearance
19-
2013
switch navigationStyle {
2114
case .hidden:
2215
navigationController?.setNavigationBarHidden(true, animated: false)
@@ -35,6 +28,11 @@ extension UIViewController {
3528
navigationController?.setNavigationBarHidden(false, animated: false)
3629
configureCustomBackButton()
3730
configureProgressNavigationBar(step: step, stepCount: stepCount)
31+
32+
case .withPrograssBarWithoutBackButton(let step, let stepCount):
33+
navigationController?.setNavigationBarHidden(false, animated: false)
34+
navigationController?.navigationItem.setHidesBackButton(true, animated: false)
35+
configureProgressNavigationBar(step: step, stepCount: stepCount)
3836
}
3937
}
4038

@@ -46,6 +44,7 @@ extension UIViewController {
4644
action: #selector(popViewController))
4745
backButton.tintColor = .black
4846
navigationItem.leftBarButtonItem = backButton
47+
changeNavigationBackground(color: .white)
4948
}
5049

5150
private func configureCustomBackButton() {
@@ -56,12 +55,14 @@ extension UIViewController {
5655
action: #selector(popTwoViewControllers))
5756
backButton.tintColor = .black
5857
navigationItem.leftBarButtonItem = backButton
58+
changeNavigationBackground(color: .white)
5959
}
6060

6161
private func configureProgressNavigationBar(step: Int, stepCount: Int) {
6262
self.title = ""
6363
let progressView = ProgressBarView(step: step, stepCount: stepCount)
6464
navigationItem.titleView = progressView
65+
changeNavigationBackground(color: BitnagilColor.gray99)
6566
}
6667

6768
@objc private func popViewController() {
@@ -82,6 +83,17 @@ extension UIViewController {
8283
navigationController.popToViewController(targetViewController, animated: true)
8384
}
8485

86+
private func changeNavigationBackground(color: UIColor?) {
87+
let appearance = UINavigationBarAppearance()
88+
appearance.configureWithOpaqueBackground()
89+
appearance.backgroundColor = color
90+
appearance.shadowColor = .clear
91+
92+
navigationController?.navigationBar.standardAppearance = appearance
93+
navigationController?.navigationBar.scrollEdgeAppearance = appearance
94+
navigationController?.navigationBar.compactAppearance = appearance
95+
}
96+
8597
// MARK: - BottomSheet
8698
func presentCustomBottomSheet(contentViewController: UIViewController, maxHeight: CGFloat) {
8799
let bottomSheet = CustomBottomSheet(contentViewController: contentViewController, maxHeight: maxHeight)
@@ -94,4 +106,5 @@ enum NavigationBarStyle {
94106
case withBackButton(title: String)
95107
case withPrograssBar(step: Int, stepCount: Int)
96108
case withPrograssBarWithCustomBackButton(step: Int, stepCount: Int)
109+
case withPrograssBarWithoutBackButton(step: Int, stepCount: Int)
97110
}

Projects/Presentation/Sources/Common/Protocol/BaseViewController.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import UIKit
99

10-
class BaseViewController<T: ViewModel>: UIViewController {
10+
public class BaseViewController<T: ViewModel>: UIViewController {
1111
let viewModel: T
1212

1313
init(viewModel: T) {
@@ -19,7 +19,7 @@ class BaseViewController<T: ViewModel>: UIViewController {
1919
fatalError("init(coder:) has not been implemented")
2020
}
2121

22-
override func viewDidLoad() {
22+
public override func viewDidLoad() {
2323
super.viewDidLoad()
2424

2525
configureAttribute()

Projects/Presentation/Sources/Common/Protocol/ViewModel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Created by 최정인 on 6/26/25.
66
//
77

8-
protocol ViewModel {
8+
public protocol ViewModel {
99
associatedtype Input
1010
associatedtype Output
1111

Projects/Presentation/Sources/Home/View/HomeView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ final class HomeView: BaseViewController<HomeViewModel> {
102102

103103
override func viewWillAppear(_ animated: Bool) {
104104
super.viewWillAppear(animated)
105+
configureNavigationBar(navigationStyle: .hidden)
105106
viewModel.action(input: .fetchEmotion)
106107
}
107108

0 commit comments

Comments
 (0)