From 77e793befd4bd945279d25368450de39644b2e08 Mon Sep 17 00:00:00 2001 From: kim-seonwoo Date: Sun, 24 Nov 2024 20:00:08 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[Feat/#114]=20=EC=98=A8=EB=B3=B4=EB=94=A9?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Refactor/OnboardingState.swift | 60 +++++ .../Sources/Refactor/OnboardingUseCase.swift | 61 +++++ .../OnboardingViewModel_Refactor.swift | 251 ++++++++++++++++++ 3 files changed, 372 insertions(+) create mode 100644 HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingState.swift create mode 100644 HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift create mode 100644 HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingState.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingState.swift new file mode 100644 index 00000000..047a985c --- /dev/null +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingState.swift @@ -0,0 +1,60 @@ +// +// OnboardingState.swift +// OnboardingFeature +// +// Created by Seonwoo Kim on 11/23/24. +// Copyright © 2024 HMH-iOS. All rights reserved. +// + +import Foundation +import DSKit + +enum OnboardingState: Int { + case timeSurveySelect = 0 + case problemSurveySelect + case challangePeriodSelect + case goalTimeSelect + case permissionSelect +} + +extension OnboardingState { + var mainTitle: String { + switch self { + case .timeSurveySelect: + return StringLiteral.OnboardigMain.timeSurveySelect + case .problemSurveySelect: + return StringLiteral.OnboardigMain.problemSurveySelect + case .challangePeriodSelect: + return StringLiteral.OnboardigMain.periodSelect + case .permissionSelect: + return StringLiteral.OnboardigMain.permissionSelect + case .goalTimeSelect: + return StringLiteral.OnboardigMain.appGoalTimeSelect + } + } + + var subTitle: String { + switch self { + case .timeSurveySelect: + return "" + case .problemSurveySelect: + return StringLiteral.OnboardigSub.problemSurveySelect + case .challangePeriodSelect: + return StringLiteral.OnboardigSub.periodSelect + case .permissionSelect: + return StringLiteral.OnboardigSub.permissionSelect + case .goalTimeSelect: + return StringLiteral.OnboardigSub.appGoalTimeSelect + } + } + + var nextButtonTitle: String { + switch self { + case .timeSurveySelect, .problemSurveySelect, .challangePeriodSelect, .goalTimeSelect: + return StringLiteral.OnboardingButton.next + case .permissionSelect: + return StringLiteral.OnboardingButton.permission + } + } +} + diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift new file mode 100644 index 00000000..2cfa0edc --- /dev/null +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift @@ -0,0 +1,61 @@ +// +// OnboardingUseCase.swift +// OnboardingFeatureInterface +// +// Created by Seonwoo Kim on 11/18/24. +// Copyright © 2024 HMH-iOS. All rights reserved. +// + +import Foundation +import Combine + +import Domain +import Core + +public protocol OnboardingUseCaseType { + func postSignUpData( + socialPlatform: String, + userName: String, + averageUseTime: String, + problems: [String], + period: Int + ) -> AnyPublisher +} + +public final class OnboardingUseCase: OnboardingUseCaseType { + + private let repository: AuthRepositoryType + + public init(repository: AuthRepositoryType) { + self.repository = repository + } + + public func postSignUpData( + socialPlatform: String, + userName: String, + averageUseTime: String, + problems: [String], + period: Int + ) -> AnyPublisher { + let challengeInfo = ChallengeInfo(period: period, goalTime: 0, apps: []) + + return repository.signUp( + socialPlatform: socialPlatform, + name: userName, + averageUseTime: averageUseTime, + problem: problems, + challengeInfo: challengeInfo + ) + .map { auth -> Void in +// UserManager.shared.accessToken = auth.accessToken +// UserManager.shared.refreshToken = auth.refreshToken + print("Sign-up successful with user: \(auth)") + } + .mapError { error -> Error in + print("Sign-up failed with error: \(error)") + return error + } + .eraseToAnyPublisher() + } +} + diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift new file mode 100644 index 00000000..b3767c3a --- /dev/null +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift @@ -0,0 +1,251 @@ +// +// OnboardingViewModel_Refactor.swift +// OnboardingFeatureInterface +// +// Created by Seonwoo Kim on 11/18/24. +// Copyright © 2024 HMH-iOS. All rights reserved. +// + +import Foundation +import Combine + +import Core +import Domain +import DSKit + +public final class OnboardingViewModel_Refactor : ObservableObject { + + private let useCase: OnboardingUseCaseType + private var cancelBag = CancelBag() + + @Published private(set) var state = State(onboardingState: .timeSurveySelect, surveyButtonItems: [[]], isNextAvailable: false) + var userName: String + var averageUseTime: String + var problems: [String] + var period: Int + + public init(useCase: OnboardingUseCaseType) { + self.useCase = useCase + self.state = State( + onboardingState: .timeSurveySelect, + surveyButtonItems: initializeSurveyButtonItems(), + isNextAvailable: false + ) + self.userName = "" + self.averageUseTime = "" + self.problems = [] + self.period = 0 + } + + // MARK: Action + + enum Action { + case nextButtonTap + case arrowButtonTap + case surveyButtonTap(index: Int) + } + + // MARK: State + + struct State { + var onboardingState: OnboardingState + var surveyButtonItems: [[SurveyButtonInfo]] + var isNextAvailable: Bool + } + + func send(action: Action) { + switch action { + case .nextButtonTap: + handleNextButtonTap() + case .arrowButtonTap: + handleBackButtonTap() + case .surveyButtonTap(index: let index): + surveyButtonTap(index: index) + } + } + + func surveyButtonTap(index: Int) { + guard state.onboardingState.rawValue < state.surveyButtonItems.count else { return } + + // 현재 상태에 해당하는 버튼 리스트 가져오기 + let currentSurveyItems = state.surveyButtonItems[state.onboardingState.rawValue] + + // index 유효성 검증 + guard index >= 0 && index < currentSurveyItems.count else { return } + + // 상태에 따라 다른 선택 로직 적용 + switch state.onboardingState { + case .timeSurveySelect, .challangePeriodSelect, .goalTimeSelect: + // 단일 선택 상태 + for i in 0.. [[SurveyButtonInfo]] { + return [ + [ + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.firstSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.secondSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.thirdSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.fourthSelect, isSelected: false), + ], + [ + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.firstSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.secondSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.thirdSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.fourthSelect, isSelected: false), + ], + [ + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.firstSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.secondSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.thirdSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.fourthSelect, isSelected: false), + ] + ] + } + + private func resetSelections(for state: OnboardingState) { + guard state.rawValue < self.state.surveyButtonItems.count else { return } + for i in 0.. Int? { + guard !string.isEmpty else { + return nil + } + + let modifiedString = String(string.dropLast()) + + return Int(modifiedString) + } + + private func handleBackButtonTap() { + switch state.onboardingState { + case .timeSurveySelect: + UserManager.shared.appStateString = "login" + offIsCompleted() + case .problemSurveySelect, .challangePeriodSelect, .goalTimeSelect: + guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } + state.onboardingState = previousState + offIsCompleted() + case .appSelect: + guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } + state.onboardingState = previousState + offIsCompleted() + default: + guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } + state.onboardingState = previousState + onIsCompleted() + } + } + + + private func offIsCompleted() { + state.isNextAvailable = false + } + + private func onIsCompleted() { + state.isNextAvailable = true + } + + private func completOnboarding() { + useCase.postSignUpData(socialPlatform: <#T##String#>, userName: <#T##String#>, averageUseTime: <#T##String#>, problems: <#T##[String]#>, period: <#T##Int#>) + .sink(receiveCompletion: { _ in }) { + } + .store(in: cancelBag) + } + + +} + From 7b53075b5413c746804d4fdae2c81dd0b6b23bca Mon Sep 17 00:00:00 2001 From: kim-seonwoo Date: Mon, 25 Nov 2024 11:40:50 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[refactor/#114]=20=EB=B7=B0=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=97=B0=EA=B2=B0=20=EB=A6=AC=ED=8E=99=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LoginFeature/Sources/LoginUseCase 2.swift | 62 ++ .../Sources/Views/LoginUseCase.swift | 62 ++ .../Sources/Models/OnboardingModel.swift | 25 + .../Sources/Refactor/OnboardingUseCase.swift | 3 +- .../OnboardingViewModel_Refactor.swift | 95 +-- .../ViewModels/OnboardingViewModel.swift | 774 +++++++++--------- .../Sources/Views/AppGoalTimeView.swift | 4 +- .../Sources/Views/Common/PickerView.swift | 9 +- .../Sources/Views/NextButtonView.swift | 10 +- .../Sources/Views/OnboardingContentView.swift | 104 +-- .../Sources/Views/SurveyButton.swift | 10 +- 11 files changed, 644 insertions(+), 514 deletions(-) create mode 100644 HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift create mode 100644 HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginUseCase.swift diff --git a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift new file mode 100644 index 00000000..272c858e --- /dev/null +++ b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift @@ -0,0 +1,62 @@ +// +// LoginUseCase.swift +// LoginFeature +// +// Created by Seonwoo Kim on 11/8/24. +// Copyright © 2024 HMH-iOS. All rights reserved. +// + +import Foundation +import Combine + +import Domain +import Core + +public enum LoginResponseType { + case loginSuccess + case loginFailure + case onboardingNeeded +} + +public protocol LoginUseCaseType { + func login(provider: OAuthProviderType) -> AnyPublisher +} + +public final class LoginUseCase: LoginUseCaseType { + + private let repository: AuthRepositoryType + + public init(repository: AuthRepositoryType) { + self.repository = repository + } + + public func login(provider: OAuthProviderType) -> AnyPublisher { + repository.authorize(provider) + .handleEvents(receiveOutput: { socialToken in + UserManager.shared.socialToken = socialToken + }) + .flatMap { [weak self] _ -> AnyPublisher in + guard let self = self else { + return Fail(error: AuthError.appleAuthrizeError).eraseToAnyPublisher() + } + + return self.repository.socialLogin(socialPlatform: provider.rawValue) + .map { _ in LoginResponseType.loginSuccess } + .catch { error -> AnyPublisher in + switch error { + case .unregisteredUser: + return Just(.onboardingNeeded) + .setFailureType(to: AuthError.self) + .eraseToAnyPublisher() + default: + return Just(.loginFailure) + .setFailureType(to: AuthError.self) + .eraseToAnyPublisher() + } + } + .eraseToAnyPublisher() + } + .eraseToAnyPublisher() + } +} + diff --git a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginUseCase.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginUseCase.swift new file mode 100644 index 00000000..272c858e --- /dev/null +++ b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginUseCase.swift @@ -0,0 +1,62 @@ +// +// LoginUseCase.swift +// LoginFeature +// +// Created by Seonwoo Kim on 11/8/24. +// Copyright © 2024 HMH-iOS. All rights reserved. +// + +import Foundation +import Combine + +import Domain +import Core + +public enum LoginResponseType { + case loginSuccess + case loginFailure + case onboardingNeeded +} + +public protocol LoginUseCaseType { + func login(provider: OAuthProviderType) -> AnyPublisher +} + +public final class LoginUseCase: LoginUseCaseType { + + private let repository: AuthRepositoryType + + public init(repository: AuthRepositoryType) { + self.repository = repository + } + + public func login(provider: OAuthProviderType) -> AnyPublisher { + repository.authorize(provider) + .handleEvents(receiveOutput: { socialToken in + UserManager.shared.socialToken = socialToken + }) + .flatMap { [weak self] _ -> AnyPublisher in + guard let self = self else { + return Fail(error: AuthError.appleAuthrizeError).eraseToAnyPublisher() + } + + return self.repository.socialLogin(socialPlatform: provider.rawValue) + .map { _ in LoginResponseType.loginSuccess } + .catch { error -> AnyPublisher in + switch error { + case .unregisteredUser: + return Just(.onboardingNeeded) + .setFailureType(to: AuthError.self) + .eraseToAnyPublisher() + default: + return Just(.loginFailure) + .setFailureType(to: AuthError.self) + .eraseToAnyPublisher() + } + } + .eraseToAnyPublisher() + } + .eraseToAnyPublisher() + } +} + diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Models/OnboardingModel.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Models/OnboardingModel.swift index 2dc16a24..246d55ed 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Models/OnboardingModel.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Models/OnboardingModel.swift @@ -6,6 +6,7 @@ // import Foundation +import DSKit struct SurveyButtonInfo: Identifiable { let id = UUID() @@ -13,4 +14,28 @@ struct SurveyButtonInfo: Identifiable { var isSelected: Bool } +extension SurveyButtonInfo { + static func initializeSurveyButtonItems() -> [[SurveyButtonInfo]] { + return [ + [ + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.firstSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.secondSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.thirdSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.fourthSelect, isSelected: false), + ], + [ + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.firstSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.secondSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.thirdSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.fourthSelect, isSelected: false), + ], + [ + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.firstSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.secondSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.thirdSelect, isSelected: false), + SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.fourthSelect, isSelected: false), + ] + ] + } +} diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift index 2cfa0edc..52879bd2 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift @@ -49,10 +49,9 @@ public final class OnboardingUseCase: OnboardingUseCaseType { .map { auth -> Void in // UserManager.shared.accessToken = auth.accessToken // UserManager.shared.refreshToken = auth.refreshToken - print("Sign-up successful with user: \(auth)") } .mapError { error -> Error in - print("Sign-up failed with error: \(error)") + return error } .eraseToAnyPublisher() diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift index b3767c3a..d94391d6 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift @@ -13,28 +13,38 @@ import Core import Domain import DSKit -public final class OnboardingViewModel_Refactor : ObservableObject { +public final class OnboardingViewModel : ObservableObject { private let useCase: OnboardingUseCaseType private var cancelBag = CancelBag() - @Published private(set) var state = State(onboardingState: .timeSurveySelect, surveyButtonItems: [[]], isNextAvailable: false) + @Published private(set) var state = State(onboardingState: .timeSurveySelect, surveyButtonItems: [[]], isNextAvailable: false, surveyState: 0) + @Published + var selectedAppHour: String + @Published + var selectedAppMinute: String + var userName: String var averageUseTime: String var problems: [String] var period: Int + var appGoalTime: Int public init(useCase: OnboardingUseCaseType) { self.useCase = useCase self.state = State( onboardingState: .timeSurveySelect, - surveyButtonItems: initializeSurveyButtonItems(), - isNextAvailable: false + surveyButtonItems: SurveyButtonInfo.initializeSurveyButtonItems(), + isNextAvailable: false, + surveyState: 0 ) self.userName = "" self.averageUseTime = "" self.problems = [] self.period = 0 + self.selectedAppHour = "" + self.selectedAppMinute = "" + self.appGoalTime = 0 } // MARK: Action @@ -51,6 +61,7 @@ public final class OnboardingViewModel_Refactor : ObservableObject { var onboardingState: OnboardingState var surveyButtonItems: [[SurveyButtonInfo]] var isNextAvailable: Bool + var surveyState: Int } func send(action: Action) { @@ -67,65 +78,32 @@ public final class OnboardingViewModel_Refactor : ObservableObject { func surveyButtonTap(index: Int) { guard state.onboardingState.rawValue < state.surveyButtonItems.count else { return } - // 현재 상태에 해당하는 버튼 리스트 가져오기 let currentSurveyItems = state.surveyButtonItems[state.onboardingState.rawValue] - // index 유효성 검증 - guard index >= 0 && index < currentSurveyItems.count else { return } - - // 상태에 따라 다른 선택 로직 적용 switch state.onboardingState { case .timeSurveySelect, .challangePeriodSelect, .goalTimeSelect: - // 단일 선택 상태 for i in 0.. [[SurveyButtonInfo]] { - return [ - [ - SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.firstSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.secondSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.thirdSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.TimeSurveySelect.fourthSelect, isSelected: false), - ], - [ - SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.firstSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.secondSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.thirdSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.ProblemSurveySelect.fourthSelect, isSelected: false), - ], - [ - SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.firstSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.secondSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.thirdSelect, isSelected: false), - SurveyButtonInfo(buttonTitle: StringLiteral.PeriodSelect.fourthSelect, isSelected: false), - ] - ] - } - + private func resetSelections(for state: OnboardingState) { guard state.rawValue < self.state.surveyButtonItems.count else { return } for i in 0.. Int { + let hourInt = Int(hour ?? "") ?? 0 + let minuteInt = Int(minute ?? "") ?? 0 + + let totalMinutes = hourInt * 60 + minuteInt + let totalMilliseconds = totalMinutes * 60 * 1000 + return totalMilliseconds } private func addOnboardingState() { - state.onboardingState.rawValue += 1 + guard let nextState = OnboardingState(rawValue: state.onboardingState.rawValue + 1) else { return } + state.onboardingState = nextState + if nextState.rawValue <= 2 { + state.surveyState = nextState.rawValue + } } + private func removeLastCharacterAndConvertToInt(from string: String) -> Int? { guard !string.isEmpty else { return nil @@ -218,16 +205,16 @@ public final class OnboardingViewModel_Refactor : ObservableObject { case .problemSurveySelect, .challangePeriodSelect, .goalTimeSelect: guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } state.onboardingState = previousState - offIsCompleted() - case .appSelect: - guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } - state.onboardingState = previousState + state.surveyState = previousState.rawValue + resetSelections(for: previousState) offIsCompleted() default: guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } state.onboardingState = previousState onIsCompleted() } + + print(state.onboardingState.rawValue) } @@ -240,12 +227,10 @@ public final class OnboardingViewModel_Refactor : ObservableObject { } private func completOnboarding() { - useCase.postSignUpData(socialPlatform: <#T##String#>, userName: <#T##String#>, averageUseTime: <#T##String#>, problems: <#T##[String]#>, period: <#T##Int#>) + useCase.postSignUpData(socialPlatform: "KAKAO", userName: "", averageUseTime: averageUseTime, problems: problems, period: period) .sink(receiveCompletion: { _ in }) { } .store(in: cancelBag) } - } - diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift index 1d3c21f0..8c5027ce 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift @@ -1,398 +1,398 @@ +//// +//// OnboardingViewModel.swift +//// HMH_iOS +//// +//// Created by Seonwoo Kim on 3/24/24. +//// // -// OnboardingViewModel.swift -// HMH_iOS +//import SwiftUI +//import FamilyControls +//import Foundation // -// Created by Seonwoo Kim on 3/24/24. +//import Core +//import DSKit +//import Domain // - -import SwiftUI -import FamilyControls -import Foundation - -import Core -import DSKit -import Domain - - -public class OnboardingViewModel: ObservableObject { - - //TODO: 말썽꾸러기 스크린뷰모델 -// var screenViewModel: ScreenTimeViewModel - - @Published - var surveyButtonItems: [[SurveyButtonInfo]] - - var problems: [String] - - @Published - var onboardingState: Int - - @Published - public var isCompleted: Bool - - @Published - var isPickerPresented: Bool = false - - @Published - var isOnboardingError : Bool = false - - @Published - var isCompletePresented: Bool = false - - @Published - var selectedGoalTime: String - - @Published - var selectedAppHour: String - - @Published - var selectedAppMinute: String - - var averageUseTime: String - - var period: Int - - var isChallengeMode: Bool - - var goalTime: Int - - var appGoalTime: Int - - @AppStorage("socialPlatform") private var socialPlatform = "" - @AppStorage("userName") private var userName = "" - - @MainActor func saveOnboardingData() { - print(onboardingState) - switch onboardingState { - case 0: - for index in 0..<4{ - if surveyButtonItems[onboardingState][index].isSelected { - self.averageUseTime = surveyButtonItems[onboardingState][index].buttonTitle - } - } - addOnboardingState() - offIsCompleted() - case 1: - for index in 0..<4{ - if surveyButtonItems[onboardingState][index].isSelected { - self.problems.append(surveyButtonItems[onboardingState][index].buttonTitle) - } - } - addOnboardingState() - offIsCompleted() - case 2: - for index in 0..<4{ - if surveyButtonItems[onboardingState] [index].isSelected { - self.period = removeLastCharacterAndConvertToInt(from: surveyButtonItems[onboardingState] [index].buttonTitle) ?? 0 - - print(surveyButtonItems[onboardingState] [index].buttonTitle) - - } - } - if isChallengeMode { - onboardingState = 6 - } else { - addOnboardingState() - } - case 3: - break - //TODO: 말썽꾸러기 스크린뷰모델 -// screenViewModel.requestAuthorization() -// if screenViewModel.authorizationCenter.authorizationStatus == .approved { -// onboardingState += 1 +// +//public class OnboardingViewModel_refactor: ObservableObject { +// +// //TODO: 말썽꾸러기 스크린뷰모델 +//// var screenViewModel: ScreenTimeViewModel +// +// @Published +// var surveyButtonItems: [[SurveyButtonInfo]] +// +// var problems: [String] +// +// @Published +// var onboardingState: Int +// +// @Published +// public var isCompleted: Bool +// +// @Published +// var isPickerPresented: Bool = false +// +// @Published +// var isOnboardingError : Bool = false +// +// @Published +// var isCompletePresented: Bool = false +// +// @Published +// var selectedGoalTime: String +// +// @Published +// var selectedAppHour: String +// +// @Published +// var selectedAppMinute: String +// +// var averageUseTime: String +// +// var period: Int +// +// var isChallengeMode: Bool +// +// var goalTime: Int +// +// var appGoalTime: Int +// +// @AppStorage("socialPlatform") private var socialPlatform = "" +// @AppStorage("userName") private var userName = "" +// +// @MainActor func saveOnboardingData() { +// print(onboardingState) +// switch onboardingState { +// case 0: +// for index in 0..<4{ +// if surveyButtonItems[onboardingState][index].isSelected { +// self.averageUseTime = surveyButtonItems[onboardingState][index].buttonTitle +// } // } - case 4: - isPickerPresented = true - case 5: - self.appGoalTime = convertToTotalMilliseconds(hour: selectedAppHour, minute: selectedAppMinute) - if isChallengeMode { - //TODO: 말썽꾸러기 스크린뷰모델 -// screenViewModel.handleStartDeviceActivityMonitoring(interval: appGoalTime) - addOnboardingState() - } else { - addOnboardingState() - } - offIsCompleted() - case 6: - self.goalTime = convertToTotalMilliseconds(hour: selectedGoalTime, minute: "0") - //TODO: 말썽꾸러기 스크린뷰모델 -// screenViewModel.handleTotalDeviceActivityMonitoring(interval: goalTime) - if isChallengeMode { - postCreateChallengeData() - isCompletePresented = true - } else { - postSignUpLoginData() - } - offIsCompleted() - default: - break - } - } - - func alertAction() { - postCreateChallengeData() - addOnboardingState() - isCompletePresented = false - } - - func addOnboardingState() { - onboardingState += 1 - } - - func backButtonTapped() { - switch onboardingState { - case 0: - UserManager.shared.appStateString = "login" - offIsCompleted() - case 1, 2, 3 : - onboardingState -= 1 - offIsCompleted() - resetAllSelections() - case 6: - onboardingState -= 1 - offIsCompleted() - default: - onIsCompleted() - onboardingState -= 1 - } - } - - func onIsCompleted() { - isCompleted = true - } - - func offIsCompleted() { - isCompleted = false - } - - func resetOnboardingState() { - onboardingState = 0 - } - - public func getSurveyState() -> Int { - return onboardingState <= 2 ? onboardingState : 0 - } - - func pushToComplete() { - // if onboardingState == 6 { - // NavigationLink(PermissionView) - // } - } - - func removeLastCharacterAndConvertToInt(from string: String) -> Int? { - guard !string.isEmpty else { - return nil - } - - let modifiedString = String(string.dropLast()) - - return Int(modifiedString) - } - - - @MainActor func postSignUpLoginData() { - //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -// let appValues = [ Apps( -// appCode: "app goalTime", -// goalTime: appGoalTime -// ) -// ] -// let request = SignUpRequestDTO( -// socialPlatform: socialPlatform, -// name: userName, -// onboarding: Onboarding( -// averageUseTime: self.averageUseTime, -// problem: self.problems -// ), -// challenge: Challenge( -// period: self.period, -// goalTime: self.goalTime, -// apps: appValues -// ) -// ) -// -// let provider = Providers.AuthProvider -// provider.request(target: .signUp(data: request), instance: BaseResponse.self) { data in -// print(data.status) -// if data.status == 201 { -// UserManager.shared.appStateString = "onboardingComplete" -// UserManager.shared.accessToken = data.data?.token.accessToken ?? "" -// UserManager.shared.refreshToken = data.data?.token.refreshToken ?? "" -// } else if data.message == "이미 회원가입된 유저입니다." { -// self.isOnboardingError = true +// addOnboardingState() +// offIsCompleted() +// case 1: +// for index in 0..<4{ +// if surveyButtonItems[onboardingState][index].isSelected { +// self.problems.append(surveyButtonItems[onboardingState][index].buttonTitle) +// } +// } +// addOnboardingState() +// offIsCompleted() +// case 2: +// for index in 0..<4{ +// if surveyButtonItems[onboardingState] [index].isSelected { +// self.period = removeLastCharacterAndConvertToInt(from: surveyButtonItems[onboardingState] [index].buttonTitle) ?? 0 +// +// print(surveyButtonItems[onboardingState] [index].buttonTitle) +// +// } +// } +// if isChallengeMode { +// onboardingState = 6 // } else { -// self.isOnboardingError = true +// addOnboardingState() // } +// case 3: +// break +// //TODO: 말썽꾸러기 스크린뷰모델 +//// screenViewModel.requestAuthorization() +//// if screenViewModel.authorizationCenter.authorizationStatus == .approved { +//// onboardingState += 1 +//// } +// case 4: +// isPickerPresented = true +// case 5: +// self.appGoalTime = convertToTotalMilliseconds(hour: selectedAppHour, minute: selectedAppMinute) +// if isChallengeMode { +// //TODO: 말썽꾸러기 스크린뷰모델 +//// screenViewModel.handleStartDeviceActivityMonitoring(interval: appGoalTime) +// addOnboardingState() +// } else { +// addOnboardingState() +// } +// offIsCompleted() +// case 6: +// self.goalTime = convertToTotalMilliseconds(hour: selectedGoalTime, minute: "0") +// //TODO: 말썽꾸러기 스크린뷰모델 +//// screenViewModel.handleTotalDeviceActivityMonitoring(interval: goalTime) +// if isChallengeMode { +// postCreateChallengeData() +// isCompletePresented = true +// } else { +// postSignUpLoginData() +// } +// offIsCompleted() +// default: +// break +// } +// } +// +// func alertAction() { +// postCreateChallengeData() +// addOnboardingState() +// isCompletePresented = false +// } +// +// func addOnboardingState() { +// onboardingState += 1 +// } +// +// func backButtonTapped() { +// switch onboardingState { +// case 0: +// UserManager.shared.appStateString = "login" +// offIsCompleted() +// case 1, 2, 3 : +// onboardingState -= 1 +// offIsCompleted() +// resetAllSelections() +// case 6: +// onboardingState -= 1 +// offIsCompleted() +// default: +// onIsCompleted() +// onboardingState -= 1 +// } +// } +// +// func onIsCompleted() { +// isCompleted = true +// } +// +// func offIsCompleted() { +// isCompleted = false +// } +// +// func resetOnboardingState() { +// onboardingState = 0 +// } +// +// public func getSurveyState() -> Int { +// return onboardingState <= 2 ? onboardingState : 0 +// } +// +// func pushToComplete() { +// // if onboardingState == 6 { +// // NavigationLink(PermissionView) +// // } +// } +// +// func removeLastCharacterAndConvertToInt(from string: String) -> Int? { +// guard !string.isEmpty else { +// return nil // } - } - - func postCreateChallengeData() { - //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -// let request = CreateChallengeRequestDTO(period: self.period, goalTime: self.goalTime) // -// let provider = Providers.challengeProvider -// provider.request(target: .createChallenge(data: request), instance: BaseResponse.self) { data in -// print(data.status) +// let modifiedString = String(string.dropLast()) +// +// return Int(modifiedString) +// } +// +// +// @MainActor func postSignUpLoginData() { +// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 +//// let appValues = [ Apps( +//// appCode: "app goalTime", +//// goalTime: appGoalTime +//// ) +//// ] +//// let request = SignUpRequestDTO( +//// socialPlatform: socialPlatform, +//// name: userName, +//// onboarding: Onboarding( +//// averageUseTime: self.averageUseTime, +//// problem: self.problems +//// ), +//// challenge: Challenge( +//// period: self.period, +//// goalTime: self.goalTime, +//// apps: appValues +//// ) +//// ) +//// +//// let provider = Providers.AuthProvider +//// provider.request(target: .signUp(data: request), instance: BaseResponse.self) { data in +//// print(data.status) +//// if data.status == 201 { +//// UserManager.shared.appStateString = "onboardingComplete" +//// UserManager.shared.accessToken = data.data?.token.accessToken ?? "" +//// UserManager.shared.refreshToken = data.data?.token.refreshToken ?? "" +//// } else if data.message == "이미 회원가입된 유저입니다." { +//// self.isOnboardingError = true +//// } else { +//// self.isOnboardingError = true +//// } +//// } +// } +// +// func postCreateChallengeData() { +// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 +//// let request = CreateChallengeRequestDTO(period: self.period, goalTime: self.goalTime) +//// +//// let provider = Providers.challengeProvider +//// provider.request(target: .createChallenge(data: request), instance: BaseResponse.self) { data in +//// print(data.status) +//// } +// } +// +// func patchApp(appGoalTime: Int) { +// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 +//// let applist = [ +//// Apps( +//// appCode: "#temp", +//// goalTime: appGoalTime +//// ) +//// ] +//// let requestDTO = AddAppRequestDTO(apps: applist) +//// Providers.challengeProvider.request(target: .addApp(data: requestDTO), +//// instance: BaseResponse.self) { result in +//// print("result: \(result)") +//// } +// } +// +// @MainActor func createAppChallengeData(appGoalTime: Int) { +// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 +//// var applist: [Apps] = [] +//// // screenViewModel.hashVaule +//// applist = [Apps(appCode: "#24333", goalTime: appGoalTime)] +//// Providers.challengeProvider.request(target: .addApp(data: AddAppRequestDTO(apps: applist)), instance: BaseResponse.self) { [weak self] result in +//// UserManager.shared.appStateString = "home" +//// self?.screenViewModel.handleStartDeviceActivityMonitoring(includeUsageThreshold: true, interval: self?.appGoalTime ?? 0) +//// } +// } +// +// func changeSurveyButtonStatus(num: Int) { +// if onboardingState == 1 { +// let selectedCount = surveyButtonItems[onboardingState].filter { $0.isSelected }.count +// if surveyButtonItems[onboardingState][num].isSelected { +// surveyButtonItems[onboardingState][num].isSelected.toggle() +// } else if selectedCount < 2 { +// surveyButtonItems[onboardingState][num].isSelected = true +// } +// } else { +// for index in 0..<4 { +// surveyButtonItems[onboardingState][index].isSelected = (index == num) +// } // } - } - - func patchApp(appGoalTime: Int) { - //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -// let applist = [ -// Apps( -// appCode: "#temp", -// goalTime: appGoalTime -// ) -// ] -// let requestDTO = AddAppRequestDTO(apps: applist) -// Providers.challengeProvider.request(target: .addApp(data: requestDTO), -// instance: BaseResponse.self) { result in -// print("result: \(result)") +// } +// +// +// func convertToTotalMilliseconds(hour: String?, minute: String?) -> Int { +// let hourInt = Int(hour ?? "") ?? 0 +// let minuteInt = Int(minute ?? "") ?? 0 +// +// let totalMinutes = hourInt * 60 + minuteInt +// let totalMilliseconds = totalMinutes * 60 * 1000 +// return totalMilliseconds +// } +// +// +// func getOnboardigMain() -> String { +// switch onboardingState { +// case 0: +// StringLiteral.OnboardigMain.timeSurveySelect +// case 1: +// StringLiteral.OnboardigMain.problemSurveySelect +// case 2: +// StringLiteral.OnboardigMain.periodSelect +// case 3: +// StringLiteral.OnboardigMain.permissionSelect +// case 4: +// StringLiteral.OnboardigMain.appSelect +// case 5: +// StringLiteral.OnboardigMain.appGoalTimeSelect +// case 6: +// StringLiteral.OnboardigMain.goalTimeSelect +// default: +// "" // } - } - - @MainActor func createAppChallengeData(appGoalTime: Int) { - //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -// var applist: [Apps] = [] -// // screenViewModel.hashVaule -// applist = [Apps(appCode: "#24333", goalTime: appGoalTime)] -// Providers.challengeProvider.request(target: .addApp(data: AddAppRequestDTO(apps: applist)), instance: BaseResponse.self) { [weak self] result in -// UserManager.shared.appStateString = "home" -// self?.screenViewModel.handleStartDeviceActivityMonitoring(includeUsageThreshold: true, interval: self?.appGoalTime ?? 0) +// } +// +// func getOnboardigSub() -> String { +// switch onboardingState { +// case 0: +// "" +// case 1: +// StringLiteral.OnboardigSub.problemSurveySelect +// case 2: +// StringLiteral.OnboardigSub.periodSelect +// case 3: +// StringLiteral.OnboardigSub.permissionSelect +// case 4: +// StringLiteral.OnboardigSub.appSelect +// case 5: +// StringLiteral.OnboardigSub.appGoalTimeSelect +// case 6: +// StringLiteral.OnboardigSub.goalTimeSelect +// default: +// "" // } - } - - func changeSurveyButtonStatus(num: Int) { - if onboardingState == 1 { - let selectedCount = surveyButtonItems[onboardingState].filter { $0.isSelected }.count - if surveyButtonItems[onboardingState][num].isSelected { - surveyButtonItems[onboardingState][num].isSelected.toggle() - } else if selectedCount < 2 { - surveyButtonItems[onboardingState][num].isSelected = true - } - } else { - for index in 0..<4 { - surveyButtonItems[onboardingState][index].isSelected = (index == num) - } - } - } - - - func convertToTotalMilliseconds(hour: String?, minute: String?) -> Int { - let hourInt = Int(hour ?? "") ?? 0 - let minuteInt = Int(minute ?? "") ?? 0 - - let totalMinutes = hourInt * 60 + minuteInt - let totalMilliseconds = totalMinutes * 60 * 1000 - return totalMilliseconds - } - - - func getOnboardigMain() -> String { - switch onboardingState { - case 0: - StringLiteral.OnboardigMain.timeSurveySelect - case 1: - StringLiteral.OnboardigMain.problemSurveySelect - case 2: - StringLiteral.OnboardigMain.periodSelect - case 3: - StringLiteral.OnboardigMain.permissionSelect - case 4: - StringLiteral.OnboardigMain.appSelect - case 5: - StringLiteral.OnboardigMain.appGoalTimeSelect - case 6: - StringLiteral.OnboardigMain.goalTimeSelect - default: - "" - } - } - - func getOnboardigSub() -> String { - switch onboardingState { - case 0: - "" - case 1: - StringLiteral.OnboardigSub.problemSurveySelect - case 2: - StringLiteral.OnboardigSub.periodSelect - case 3: - StringLiteral.OnboardigSub.permissionSelect - case 4: - StringLiteral.OnboardigSub.appSelect - case 5: - StringLiteral.OnboardigSub.appGoalTimeSelect - case 6: - StringLiteral.OnboardigSub.goalTimeSelect - default: - "" - } - } - - func getNextButton() -> String { - switch onboardingState { - case 0, 1, 2, 5: - StringLiteral.OnboardingButton.next - case 3: - StringLiteral.OnboardingButton.permission - case 4: - StringLiteral.OnboardingButton.appSelect - case 6: - StringLiteral.OnboardingButton.complete - default: - "" - } - } - - func handleOnAppear() { - if onboardingState == 3 && isChallengeMode { - isPickerPresented = true - } - } - - func resetAllSelections() { - for i in 0.. String { +// switch onboardingState { +// case 0, 1, 2, 5: +// StringLiteral.OnboardingButton.next +// case 3: +// StringLiteral.OnboardingButton.permission +// case 4: +// StringLiteral.OnboardingButton.appSelect +// case 6: +// StringLiteral.OnboardingButton.complete +// default: +// "" +// } +// } +// +// func handleOnAppear() { +// if onboardingState == 3 && isChallengeMode { +// isPickerPresented = true +// } +// } +// +// func resetAllSelections() { +// for i in 0.. UIPickerView { let pickerView = UIPickerView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) @@ -30,19 +29,17 @@ struct PickerView: UIViewRepresentable { } func makeCoordinator() -> PickerCoordinator { - return PickerCoordinator(times: times, selectedTime: $selectedTimes, viewModel: viewModel) + return PickerCoordinator(times: times, selectedTime: $selectedTimes) } } class PickerCoordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource { - @ObservedObject var viewModel: OnboardingViewModel var times: [String] var selectedTime: Binding - init(times: [String], selectedTime: Binding, viewModel: OnboardingViewModel) { + init(times: [String], selectedTime: Binding) { self.times = times self.selectedTime = selectedTime - self.viewModel = viewModel } func numberOfComponents(in pickerView: UIPickerView) -> Int { @@ -72,7 +69,7 @@ class PickerCoordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { selectedTime.wrappedValue = times[row] - viewModel.isCompleted = true +// viewModel.state.isNextAvailable = true } func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/NextButtonView.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/NextButtonView.swift index eaa656ed..3bfff8fe 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/NextButtonView.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/NextButtonView.swift @@ -16,19 +16,19 @@ struct NextButtonView: View { var body: some View { VStack { Button { - viewModel.saveOnboardingData() + viewModel.send(action: .nextButtonTap) } label: { - Text(viewModel.getNextButton()) + Text(viewModel.state.onboardingState.nextButtonTitle) .font(.text4_semibold_16) .frame(minWidth: 100, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .center) } .frame(maxWidth: .infinity) .frame(height: 52) .foregroundColor( - viewModel.isCompleted ? DSKitAsset.whiteBtn.swiftUIColor : DSKitAsset.gray2.swiftUIColor) - .background(viewModel.isCompleted ? DSKitAsset.bluePurpleButton.swiftUIColor : DSKitAsset.gray5.swiftUIColor) + viewModel.state.isNextAvailable ? DSKitAsset.whiteBtn.swiftUIColor : DSKitAsset.gray2.swiftUIColor) + .background(viewModel.state.isNextAvailable ? DSKitAsset.bluePurpleButton.swiftUIColor : DSKitAsset.gray5.swiftUIColor) .clipShape(RoundedRectangle(cornerRadius: 4)) - .disabled(!viewModel.isCompleted) + .disabled(!viewModel.state.isNextAvailable) } } } diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift index 0eb46164..dbe3efbe 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift @@ -10,13 +10,15 @@ import FamilyControls import DSKit import Core +import Data +import Networks public struct OnboardingContentView: View { //TODO: 말썽꾸러기 스크린뷰모델 // @StateObject var screenViewModel = ScreenTimeViewModel() @StateObject - var onboardingViewModel: OnboardingViewModel + var onboardingViewModel = OnboardingViewModel(useCase: OnboardingUseCase(repository: AuthRepository(authService: AuthService(), oauthServiceFactory: OAuthServiceFactory()))) @State private var selection = FamilyActivitySelection() var isChallengeMode: Bool @@ -27,7 +29,7 @@ public struct OnboardingContentView: View { // let screenTimeViewModel = ScreenTimeViewModel() // _screenViewModel = StateObject(wrappedValue: screenTimeViewModel) // _onboardingViewModel = StateObject(wrappedValue: OnboardingViewModel(viewModel: screenTimeViewModel, onboardingState: onboardingState, isChallengeMode: isChallengeMode)) - _onboardingViewModel = StateObject(wrappedValue: OnboardingViewModel(onboardingState: onboardingState, isChallengeMode: isChallengeMode)) +// _onboardingViewModel = StateObject(wrappedValue: OnboardingViewModel(onboardingState: onboardingState, isChallengeMode: isChallengeMode)) self.isChallengeMode = isChallengeMode } @@ -56,54 +58,54 @@ public struct OnboardingContentView: View { .padding(.bottom, 20) .background(DSKitAsset.blackground.swiftUIColor) .navigationBarHidden(true) - .onChange(of: onboardingViewModel.onboardingState) { newState in - if isChallengeMode && (newState == 1 || newState == 3 || newState == 7 ) { - self.presentationMode.wrappedValue.dismiss() - onboardingViewModel.resetOnboardingState() - } - } - .familyActivityPicker(isPresented: $onboardingViewModel.isPickerPresented, - selection: $selection) +// .onChange(of: onboardingViewModel.onboardingState) { newState in +// if isChallengeMode && (newState == 1 || newState == 3 || newState == 7 ) { +// self.presentationMode.wrappedValue.dismiss() +// onboardingViewModel.resetOnboardingState() +// } +// } +// .familyActivityPicker(isPresented: $onboardingViewModel.isPickerPresented, +// selection: $selection) .onChange(of: selection) { newSelection in //TODO: 말썽꾸러기 스크린뷰모델 // screenViewModel.updateSelectedApp(newSelection: newSelection) - } - .onChange(of: onboardingViewModel.isPickerPresented) { isPresented in - if !isPresented { - onboardingViewModel.addOnboardingState() - onboardingViewModel.offIsCompleted() - } +// } +// .onChange(of: onboardingViewModel.isPickerPresented) { isPresented in +// if !isPresented { +// onboardingViewModel.addOnboardingState() +// onboardingViewModel.offIsCompleted() +// } } .onAppear() { //TODO: 말썽꾸러기 스크린뷰모델 // selection = screenViewModel.selectedApp - onboardingViewModel.handleOnAppear() +// onboardingViewModel.handleOnAppear() } - .showToast(toastType: .onboardingWarn, isPresented: $onboardingViewModel.isOnboardingError) - .customAlert( - isPresented: $onboardingViewModel.isCompletePresented, - customAlert: { - CustomAlertView( - alertType: .challengeCreationComplete, - confirmBtn: CustomAlertButtonView( - buttonType: .Confirm, - alertType: .challengeCreationComplete, - isPresented: $onboardingViewModel.isCompletePresented, - action: { - onboardingViewModel.alertAction() - } - ), - cancelBtn: CustomAlertButtonView( - buttonType: .Cancel, - alertType: .challengeCreationComplete, - isPresented: $onboardingViewModel.isCompletePresented, - action: { - onboardingViewModel.alertAction() - } - ), currentPoint: 0, usagePoint: 0 - ) - } - ) +// .showToast(toastType: .onboardingWarn, isPresented: $onboardingViewModel.isOnboardingError) +// .customAlert( +// isPresented: $onboardingViewModel.isCompletePresented, +// customAlert: { +// CustomAlertView( +// alertType: .challengeCreationComplete, +// confirmBtn: CustomAlertButtonView( +// buttonType: .Confirm, +// alertType: .challengeCreationComplete, +// isPresented: $onboardingViewModel.isCompletePresented, +// action: { +// onboardingViewModel.alertAction() +// } +// ), +// cancelBtn: CustomAlertButtonView( +// buttonType: .Cancel, +// alertType: .challengeCreationComplete, +// isPresented: $onboardingViewModel.isCompletePresented, +// action: { +// onboardingViewModel.alertAction() +// } +// ), currentPoint: 0, usagePoint: 0 +// ) +// } +// ) } } @@ -111,7 +113,7 @@ extension OnboardingContentView { private func OnboardingNavigationView() -> some View { HStack { Button(action: { - onboardingViewModel.backButtonTapped() + onboardingViewModel.send(action: .arrowButtonTap) }, label: { Image(uiImage: DSKitAsset.chevronLeft.image) .frame(width: 24, height: 24) @@ -131,20 +133,20 @@ extension OnboardingContentView { .cornerRadius(1.0) Rectangle() .foregroundColor(DSKitAsset.bluePurpleLine.swiftUIColor) - .frame(width: CGFloat(onboardingViewModel.onboardingState) / CGFloat(6) * 334, height: 4) + .frame(width: CGFloat(onboardingViewModel.state.onboardingState.rawValue) / CGFloat(6) * 334, height: 4) .cornerRadius(10.0) - .animation(Animation.spring(duration: 0.5), value: onboardingViewModel.onboardingState) + .animation(Animation.spring(duration: 0.5), value: onboardingViewModel.state.onboardingState) } } } private func OnboardingTitleView() -> some View { VStack(alignment: .leading, spacing: 8) { - Text(onboardingViewModel.getOnboardigMain()) + Text(onboardingViewModel.state.onboardingState.mainTitle) .font(.title3_semibold_22) .lineSpacing(1.5) .foregroundStyle(DSKitAsset.whiteText.swiftUIColor) - Text(onboardingViewModel.getOnboardigSub()) + Text(onboardingViewModel.state.onboardingState.subTitle) .font(.detail1_regular_14) .lineSpacing(1.5) .foregroundStyle(DSKitAsset.gray2.swiftUIColor) @@ -153,13 +155,11 @@ extension OnboardingContentView { private func SurveyContainerView() -> some View { VStack { - switch onboardingViewModel.onboardingState { - case 0, 1, 2: + switch onboardingViewModel.state.onboardingState { + case .timeSurveySelect, .problemSurveySelect, .challangePeriodSelect: SurveyView(viewModel: onboardingViewModel) - case 5: + case .goalTimeSelect: AppGoalTimeView(viewModel: onboardingViewModel) - case 6: - GoalTimeView(viewModel: onboardingViewModel) default: EmptyView() } diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift index f1bef383..5d95c8b0 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift @@ -17,18 +17,18 @@ struct SurveyButton: View { var body: some View { Button { - viewModel.changeSurveyButtonStatus(num: numberOfRow) - viewModel.onIsCompleted() + viewModel.send(action: .surveyButtonTap(index: numberOfRow)) +// viewModel.onIsCompleted() } label: { - Text(viewModel.surveyButtonItems[viewModel.getSurveyState()][numberOfRow].buttonTitle) + Text(viewModel.state.surveyButtonItems[viewModel.state.surveyState][numberOfRow].buttonTitle) .font(.text4_semibold_16) .frame(minWidth: 100, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .center) } .frame(maxWidth: .infinity) .frame(height: 62) .foregroundColor(DSKitAsset.whiteBtn.swiftUIColor) - .background(viewModel.surveyButtonItems[viewModel.getSurveyState()][numberOfRow].isSelected ? DSKitAsset.bluePurpleOpacity22.swiftUIColor : DSKitAsset.gray7.swiftUIColor) - .border(viewModel.surveyButtonItems[viewModel.getSurveyState()][numberOfRow].isSelected ? DSKitAsset.bluePurpleLine.swiftUIColor : DSKitAsset.gray7.swiftUIColor, width: /*@START_MENU_TOKEN@*/1/*@END_MENU_TOKEN@*/) + .background(viewModel.state.surveyButtonItems[viewModel.state.surveyState][numberOfRow].isSelected ? DSKitAsset.bluePurpleOpacity22.swiftUIColor : DSKitAsset.gray7.swiftUIColor) + .border(viewModel.state.surveyButtonItems[viewModel.state.surveyState][numberOfRow].isSelected ? DSKitAsset.bluePurpleLine.swiftUIColor : DSKitAsset.gray7.swiftUIColor, width: /*@START_MENU_TOKEN@*/1/*@END_MENU_TOKEN@*/) .clipShape(RoundedRectangle(cornerRadius: 4)) } } From 7544a8cab24393ed9d00077e00a5b0b5b00ff886 Mon Sep 17 00:00:00 2001 From: kim-seonwoo Date: Mon, 25 Nov 2024 11:50:30 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[Fix/#114]=20=ED=94=BC=EC=BB=A4=EB=B7=B0=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Refactor/OnboardingViewModel_Refactor.swift | 1 + .../OnboardingFeature/Sources/Views/Common/PickerView.swift | 2 +- .../OnboardingFeature/Sources/Views/OnboardingContentView.swift | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift index d94391d6..2df2948d 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift @@ -181,6 +181,7 @@ public final class OnboardingViewModel : ObservableObject { private func addOnboardingState() { guard let nextState = OnboardingState(rawValue: state.onboardingState.rawValue + 1) else { return } state.onboardingState = nextState + if nextState.rawValue <= 2 { state.surveyState = nextState.rawValue } diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/Common/PickerView.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/Common/PickerView.swift index 0bc83b3e..21831359 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/Common/PickerView.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/Common/PickerView.swift @@ -56,7 +56,7 @@ class PickerCoordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { let time = UIColor(DSKitAsset.whiteText.swiftUIColor) - let font = UIFont(name: "Pretendard-Medium", size: 22) + let font = DSKitFontFamily.Pretendard.medium.font(size: 22) let attributes: [NSAttributedString.Key: Any] = [ diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift index dbe3efbe..fc657f2c 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/OnboardingContentView.swift @@ -133,7 +133,7 @@ extension OnboardingContentView { .cornerRadius(1.0) Rectangle() .foregroundColor(DSKitAsset.bluePurpleLine.swiftUIColor) - .frame(width: CGFloat(onboardingViewModel.state.onboardingState.rawValue) / CGFloat(6) * 334, height: 4) + .frame(width: CGFloat(onboardingViewModel.state.onboardingState.rawValue) / CGFloat(5) * 334, height: 4) .cornerRadius(10.0) .animation(Animation.spring(duration: 0.5), value: onboardingViewModel.state.onboardingState) } From 6758b332e6b4e15b7f777f530319af6c960601c5 Mon Sep 17 00:00:00 2001 From: kim-seonwoo Date: Mon, 25 Nov 2024 18:59:01 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[Fix/#114]=20DsKit=20Font=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Common/Custom/PickerView.swift | 2 +- .../Sources/Refactor/OnboardingUseCase.swift | 31 +- .../OnboardingViewModel_Refactor.swift | 237 ------- .../ViewModels/OnboardingViewModel.swift | 608 ++++++------------ .../Sources/Views/AppGoalTimeView.swift | 4 +- .../Sources/Views/GoalTimeView.swift | 2 +- .../Sources/Views/NextButtonView.swift | 2 +- .../Views/OnboardingCompleteView.swift | 6 +- .../Sources/Views/OnboardingContentView.swift | 92 +-- .../Sources/Views/StoryContentView.swift | 2 +- .../Sources/Views/SurveyButton.swift | 2 +- 11 files changed, 267 insertions(+), 721 deletions(-) delete mode 100644 HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift diff --git a/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/PickerView.swift b/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/PickerView.swift index 3bd83e89..c750a5d3 100644 --- a/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/PickerView.swift +++ b/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/PickerView.swift @@ -73,7 +73,7 @@ class PickerCoordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { selectedTime.wrappedValue = times[row] - viewModel.isCompleted = true +// viewModel.isCompleted = true } func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift index 52879bd2..0648be64 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingUseCase.swift @@ -18,12 +18,15 @@ public protocol OnboardingUseCaseType { userName: String, averageUseTime: String, problems: [String], - period: Int + period: Int, + goalTime: Int ) -> AnyPublisher + func calculateGoalTime(hour: String, minute: String) -> Int + func removeLastCharacterAndConvertToInt(from string: String) -> Int? } public final class OnboardingUseCase: OnboardingUseCaseType { - + private let repository: AuthRepositoryType public init(repository: AuthRepositoryType) { @@ -35,9 +38,10 @@ public final class OnboardingUseCase: OnboardingUseCaseType { userName: String, averageUseTime: String, problems: [String], - period: Int + period: Int, + goalTime: Int ) -> AnyPublisher { - let challengeInfo = ChallengeInfo(period: period, goalTime: 0, apps: []) + let challengeInfo = ChallengeInfo(period: period, goalTime: goalTime, apps: []) return repository.signUp( socialPlatform: socialPlatform, @@ -56,5 +60,24 @@ public final class OnboardingUseCase: OnboardingUseCaseType { } .eraseToAnyPublisher() } + + public func calculateGoalTime(hour: String, minute: String) -> Int { + let hourInt = Int(hour) ?? 0 + let minuteInt = Int(minute) ?? 0 + + let totalMinutes = hourInt * 60 + minuteInt + let totalMilliseconds = totalMinutes * 60 * 1000 + return totalMilliseconds + } + + public func removeLastCharacterAndConvertToInt(from string: String) -> Int? { + guard !string.isEmpty else { + return nil + } + + let modifiedString = String(string.dropLast()) + + return Int(modifiedString) + } } diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift deleted file mode 100644 index 2df2948d..00000000 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Refactor/OnboardingViewModel_Refactor.swift +++ /dev/null @@ -1,237 +0,0 @@ -// -// OnboardingViewModel_Refactor.swift -// OnboardingFeatureInterface -// -// Created by Seonwoo Kim on 11/18/24. -// Copyright © 2024 HMH-iOS. All rights reserved. -// - -import Foundation -import Combine - -import Core -import Domain -import DSKit - -public final class OnboardingViewModel : ObservableObject { - - private let useCase: OnboardingUseCaseType - private var cancelBag = CancelBag() - - @Published private(set) var state = State(onboardingState: .timeSurveySelect, surveyButtonItems: [[]], isNextAvailable: false, surveyState: 0) - @Published - var selectedAppHour: String - @Published - var selectedAppMinute: String - - var userName: String - var averageUseTime: String - var problems: [String] - var period: Int - var appGoalTime: Int - - public init(useCase: OnboardingUseCaseType) { - self.useCase = useCase - self.state = State( - onboardingState: .timeSurveySelect, - surveyButtonItems: SurveyButtonInfo.initializeSurveyButtonItems(), - isNextAvailable: false, - surveyState: 0 - ) - self.userName = "" - self.averageUseTime = "" - self.problems = [] - self.period = 0 - self.selectedAppHour = "" - self.selectedAppMinute = "" - self.appGoalTime = 0 - } - - // MARK: Action - - enum Action { - case nextButtonTap - case arrowButtonTap - case surveyButtonTap(index: Int) - } - - // MARK: State - - struct State { - var onboardingState: OnboardingState - var surveyButtonItems: [[SurveyButtonInfo]] - var isNextAvailable: Bool - var surveyState: Int - } - - func send(action: Action) { - switch action { - case .nextButtonTap: - handleNextButtonTap() - case .arrowButtonTap: - handleBackButtonTap() - case .surveyButtonTap(index: let index): - surveyButtonTap(index: index) - } - } - - func surveyButtonTap(index: Int) { - guard state.onboardingState.rawValue < state.surveyButtonItems.count else { return } - - let currentSurveyItems = state.surveyButtonItems[state.onboardingState.rawValue] - - switch state.onboardingState { - case .timeSurveySelect, .challangePeriodSelect, .goalTimeSelect: - for i in 0.. Int { - let hourInt = Int(hour ?? "") ?? 0 - let minuteInt = Int(minute ?? "") ?? 0 - - let totalMinutes = hourInt * 60 + minuteInt - let totalMilliseconds = totalMinutes * 60 * 1000 - return totalMilliseconds - } - - private func addOnboardingState() { - guard let nextState = OnboardingState(rawValue: state.onboardingState.rawValue + 1) else { return } - state.onboardingState = nextState - - if nextState.rawValue <= 2 { - state.surveyState = nextState.rawValue - } - } - - - private func removeLastCharacterAndConvertToInt(from string: String) -> Int? { - guard !string.isEmpty else { - return nil - } - - let modifiedString = String(string.dropLast()) - - return Int(modifiedString) - } - - private func handleBackButtonTap() { - switch state.onboardingState { - case .timeSurveySelect: - UserManager.shared.appStateString = "login" - offIsCompleted() - case .problemSurveySelect, .challangePeriodSelect, .goalTimeSelect: - guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } - state.onboardingState = previousState - state.surveyState = previousState.rawValue - resetSelections(for: previousState) - offIsCompleted() - default: - guard let previousState = OnboardingState(rawValue: state.onboardingState.rawValue - 1) else { return } - state.onboardingState = previousState - onIsCompleted() - } - - print(state.onboardingState.rawValue) - } - - - private func offIsCompleted() { - state.isNextAvailable = false - } - - private func onIsCompleted() { - state.isNextAvailable = true - } - - private func completOnboarding() { - useCase.postSignUpData(socialPlatform: "KAKAO", userName: "", averageUseTime: averageUseTime, problems: problems, period: period) - .sink(receiveCompletion: { _ in }) { - } - .store(in: cancelBag) - } - -} diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift index 8c5027ce..933431db 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift @@ -1,398 +1,216 @@ -//// -//// OnboardingViewModel.swift -//// HMH_iOS -//// -//// Created by Seonwoo Kim on 3/24/24. -//// // -//import SwiftUI -//import FamilyControls -//import Foundation +// OnboardingViewModel.swift +// OnboardingFeatureInterface // -//import Core -//import DSKit -//import Domain +// Created by Seonwoo Kim on 11/18/24. +// Copyright © 2024 HMH-iOS. All rights reserved. // -// -//public class OnboardingViewModel_refactor: ObservableObject { -// -// //TODO: 말썽꾸러기 스크린뷰모델 -//// var screenViewModel: ScreenTimeViewModel -// -// @Published -// var surveyButtonItems: [[SurveyButtonInfo]] -// -// var problems: [String] -// -// @Published -// var onboardingState: Int -// -// @Published -// public var isCompleted: Bool -// -// @Published -// var isPickerPresented: Bool = false -// -// @Published -// var isOnboardingError : Bool = false -// -// @Published -// var isCompletePresented: Bool = false -// -// @Published -// var selectedGoalTime: String -// -// @Published -// var selectedAppHour: String -// -// @Published -// var selectedAppMinute: String -// -// var averageUseTime: String -// -// var period: Int -// -// var isChallengeMode: Bool -// -// var goalTime: Int -// -// var appGoalTime: Int -// -// @AppStorage("socialPlatform") private var socialPlatform = "" -// @AppStorage("userName") private var userName = "" -// -// @MainActor func saveOnboardingData() { -// print(onboardingState) -// switch onboardingState { -// case 0: -// for index in 0..<4{ -// if surveyButtonItems[onboardingState][index].isSelected { -// self.averageUseTime = surveyButtonItems[onboardingState][index].buttonTitle -// } -// } -// addOnboardingState() -// offIsCompleted() -// case 1: -// for index in 0..<4{ -// if surveyButtonItems[onboardingState][index].isSelected { -// self.problems.append(surveyButtonItems[onboardingState][index].buttonTitle) -// } -// } -// addOnboardingState() -// offIsCompleted() -// case 2: -// for index in 0..<4{ -// if surveyButtonItems[onboardingState] [index].isSelected { -// self.period = removeLastCharacterAndConvertToInt(from: surveyButtonItems[onboardingState] [index].buttonTitle) ?? 0 -// -// print(surveyButtonItems[onboardingState] [index].buttonTitle) -// -// } -// } -// if isChallengeMode { -// onboardingState = 6 -// } else { -// addOnboardingState() -// } -// case 3: -// break -// //TODO: 말썽꾸러기 스크린뷰모델 -//// screenViewModel.requestAuthorization() -//// if screenViewModel.authorizationCenter.authorizationStatus == .approved { -//// onboardingState += 1 -//// } -// case 4: -// isPickerPresented = true -// case 5: -// self.appGoalTime = convertToTotalMilliseconds(hour: selectedAppHour, minute: selectedAppMinute) -// if isChallengeMode { -// //TODO: 말썽꾸러기 스크린뷰모델 -//// screenViewModel.handleStartDeviceActivityMonitoring(interval: appGoalTime) -// addOnboardingState() -// } else { -// addOnboardingState() -// } -// offIsCompleted() -// case 6: -// self.goalTime = convertToTotalMilliseconds(hour: selectedGoalTime, minute: "0") -// //TODO: 말썽꾸러기 스크린뷰모델 -//// screenViewModel.handleTotalDeviceActivityMonitoring(interval: goalTime) -// if isChallengeMode { -// postCreateChallengeData() -// isCompletePresented = true -// } else { -// postSignUpLoginData() -// } -// offIsCompleted() -// default: -// break -// } -// } -// -// func alertAction() { -// postCreateChallengeData() -// addOnboardingState() -// isCompletePresented = false -// } -// -// func addOnboardingState() { -// onboardingState += 1 -// } -// -// func backButtonTapped() { -// switch onboardingState { -// case 0: -// UserManager.shared.appStateString = "login" -// offIsCompleted() -// case 1, 2, 3 : -// onboardingState -= 1 -// offIsCompleted() -// resetAllSelections() -// case 6: -// onboardingState -= 1 -// offIsCompleted() -// default: -// onIsCompleted() -// onboardingState -= 1 -// } -// } -// -// func onIsCompleted() { -// isCompleted = true -// } -// -// func offIsCompleted() { -// isCompleted = false -// } -// -// func resetOnboardingState() { -// onboardingState = 0 -// } -// -// public func getSurveyState() -> Int { -// return onboardingState <= 2 ? onboardingState : 0 -// } -// -// func pushToComplete() { -// // if onboardingState == 6 { -// // NavigationLink(PermissionView) -// // } -// } -// -// func removeLastCharacterAndConvertToInt(from string: String) -> Int? { -// guard !string.isEmpty else { -// return nil -// } -// -// let modifiedString = String(string.dropLast()) -// -// return Int(modifiedString) -// } -// -// -// @MainActor func postSignUpLoginData() { -// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -//// let appValues = [ Apps( -//// appCode: "app goalTime", -//// goalTime: appGoalTime -//// ) -//// ] -//// let request = SignUpRequestDTO( -//// socialPlatform: socialPlatform, -//// name: userName, -//// onboarding: Onboarding( -//// averageUseTime: self.averageUseTime, -//// problem: self.problems -//// ), -//// challenge: Challenge( -//// period: self.period, -//// goalTime: self.goalTime, -//// apps: appValues -//// ) -//// ) -//// -//// let provider = Providers.AuthProvider -//// provider.request(target: .signUp(data: request), instance: BaseResponse.self) { data in -//// print(data.status) -//// if data.status == 201 { -//// UserManager.shared.appStateString = "onboardingComplete" -//// UserManager.shared.accessToken = data.data?.token.accessToken ?? "" -//// UserManager.shared.refreshToken = data.data?.token.refreshToken ?? "" -//// } else if data.message == "이미 회원가입된 유저입니다." { -//// self.isOnboardingError = true -//// } else { -//// self.isOnboardingError = true -//// } -//// } -// } -// -// func postCreateChallengeData() { -// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -//// let request = CreateChallengeRequestDTO(period: self.period, goalTime: self.goalTime) -//// -//// let provider = Providers.challengeProvider -//// provider.request(target: .createChallenge(data: request), instance: BaseResponse.self) { data in -//// print(data.status) -//// } -// } -// -// func patchApp(appGoalTime: Int) { -// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -//// let applist = [ -//// Apps( -//// appCode: "#temp", -//// goalTime: appGoalTime -//// ) -//// ] -//// let requestDTO = AddAppRequestDTO(apps: applist) -//// Providers.challengeProvider.request(target: .addApp(data: requestDTO), -//// instance: BaseResponse.self) { result in -//// print("result: \(result)") -//// } -// } -// -// @MainActor func createAppChallengeData(appGoalTime: Int) { -// //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다 -//// var applist: [Apps] = [] -//// // screenViewModel.hashVaule -//// applist = [Apps(appCode: "#24333", goalTime: appGoalTime)] -//// Providers.challengeProvider.request(target: .addApp(data: AddAppRequestDTO(apps: applist)), instance: BaseResponse.self) { [weak self] result in -//// UserManager.shared.appStateString = "home" -//// self?.screenViewModel.handleStartDeviceActivityMonitoring(includeUsageThreshold: true, interval: self?.appGoalTime ?? 0) -//// } -// } -// -// func changeSurveyButtonStatus(num: Int) { -// if onboardingState == 1 { -// let selectedCount = surveyButtonItems[onboardingState].filter { $0.isSelected }.count -// if surveyButtonItems[onboardingState][num].isSelected { -// surveyButtonItems[onboardingState][num].isSelected.toggle() -// } else if selectedCount < 2 { -// surveyButtonItems[onboardingState][num].isSelected = true -// } -// } else { -// for index in 0..<4 { -// surveyButtonItems[onboardingState][index].isSelected = (index == num) -// } -// } -// } -// -// -// func convertToTotalMilliseconds(hour: String?, minute: String?) -> Int { -// let hourInt = Int(hour ?? "") ?? 0 -// let minuteInt = Int(minute ?? "") ?? 0 -// -// let totalMinutes = hourInt * 60 + minuteInt -// let totalMilliseconds = totalMinutes * 60 * 1000 -// return totalMilliseconds -// } -// -// -// func getOnboardigMain() -> String { -// switch onboardingState { -// case 0: -// StringLiteral.OnboardigMain.timeSurveySelect -// case 1: -// StringLiteral.OnboardigMain.problemSurveySelect -// case 2: -// StringLiteral.OnboardigMain.periodSelect -// case 3: -// StringLiteral.OnboardigMain.permissionSelect -// case 4: -// StringLiteral.OnboardigMain.appSelect -// case 5: -// StringLiteral.OnboardigMain.appGoalTimeSelect -// case 6: -// StringLiteral.OnboardigMain.goalTimeSelect -// default: -// "" -// } -// } -// -// func getOnboardigSub() -> String { -// switch onboardingState { -// case 0: -// "" -// case 1: -// StringLiteral.OnboardigSub.problemSurveySelect -// case 2: -// StringLiteral.OnboardigSub.periodSelect -// case 3: -// StringLiteral.OnboardigSub.permissionSelect -// case 4: -// StringLiteral.OnboardigSub.appSelect -// case 5: -// StringLiteral.OnboardigSub.appGoalTimeSelect -// case 6: -// StringLiteral.OnboardigSub.goalTimeSelect -// default: -// "" -// } -// } -// -// func getNextButton() -> String { -// switch onboardingState { -// case 0, 1, 2, 5: -// StringLiteral.OnboardingButton.next -// case 3: -// StringLiteral.OnboardingButton.permission -// case 4: -// StringLiteral.OnboardingButton.appSelect -// case 6: -// StringLiteral.OnboardingButton.complete -// default: -// "" -// } -// } -// -// func handleOnAppear() { -// if onboardingState == 3 && isChallengeMode { -// isPickerPresented = true -// } -// } -// -// func resetAllSelections() { -// for i in 0.. some View { HStack { Button(action: { - onboardingViewModel.send(action: .arrowButtonTap) + viewModel.send(action: .arrowButtonTap) }, label: { Image(uiImage: DSKitAsset.chevronLeft.image) .frame(width: 24, height: 24) @@ -133,21 +75,21 @@ extension OnboardingContentView { .cornerRadius(1.0) Rectangle() .foregroundColor(DSKitAsset.bluePurpleLine.swiftUIColor) - .frame(width: CGFloat(onboardingViewModel.state.onboardingState.rawValue) / CGFloat(5) * 334, height: 4) + .frame(width: CGFloat(viewModel.state.onboardingState.rawValue) / CGFloat(5) * 334, height: 4) .cornerRadius(10.0) - .animation(Animation.spring(duration: 0.5), value: onboardingViewModel.state.onboardingState) + .animation(Animation.spring(duration: 0.5), value: viewModel.state.onboardingState) } } } private func OnboardingTitleView() -> some View { VStack(alignment: .leading, spacing: 8) { - Text(onboardingViewModel.state.onboardingState.mainTitle) - .font(.title3_semibold_22) + Text(viewModel.state.onboardingState.mainTitle) + .font(DSKitFontFamily.Pretendard.semiBold.swiftUIFont(size: 22)) .lineSpacing(1.5) .foregroundStyle(DSKitAsset.whiteText.swiftUIColor) - Text(onboardingViewModel.state.onboardingState.subTitle) - .font(.detail1_regular_14) + Text(viewModel.state.onboardingState.subTitle) + .font(DSKitFontFamily.Pretendard.regular.swiftUIFont(size: 14)) .lineSpacing(1.5) .foregroundStyle(DSKitAsset.gray2.swiftUIColor) } @@ -155,11 +97,11 @@ extension OnboardingContentView { private func SurveyContainerView() -> some View { VStack { - switch onboardingViewModel.state.onboardingState { + switch viewModel.state.onboardingState { case .timeSurveySelect, .problemSurveySelect, .challangePeriodSelect: - SurveyView(viewModel: onboardingViewModel) + SurveyView(viewModel: viewModel) case .goalTimeSelect: - AppGoalTimeView(viewModel: onboardingViewModel) + AppGoalTimeView(viewModel: viewModel) default: EmptyView() } diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/StoryContentView.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/StoryContentView.swift index 51231f99..25e23241 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/StoryContentView.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/StoryContentView.swift @@ -22,7 +22,7 @@ struct StoryContentView: View { Spacer() .frame(height: 40) Text("아무데나 눌러서 이동") - .font(.text5_medium_16) + .font(DSKitFontFamily.Pretendard.medium.swiftUIFont(size: 16)) .foregroundColor(DSKitAsset.gray1.swiftUIColor) } diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift index 5d95c8b0..d1a844cd 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/Views/SurveyButton.swift @@ -21,7 +21,7 @@ struct SurveyButton: View { // viewModel.onIsCompleted() } label: { Text(viewModel.state.surveyButtonItems[viewModel.state.surveyState][numberOfRow].buttonTitle) - .font(.text4_semibold_16) + .font(DSKitFontFamily.Pretendard.semiBold.swiftUIFont(size: 16)) .frame(minWidth: 100, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .center) } .frame(maxWidth: .infinity) From 358e9367b760c705f59719ae8bc6f94432c6ae3a Mon Sep 17 00:00:00 2001 From: kim-seonwoo Date: Mon, 25 Nov 2024 19:08:24 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[Del/#114]=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LoginFeature/Sources/LoginUseCase 2.swift | 62 ------------------- .../ViewModels/OnboardingViewModel.swift | 1 - 2 files changed, 63 deletions(-) delete mode 100644 HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift diff --git a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift deleted file mode 100644 index 272c858e..00000000 --- a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase 2.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// LoginUseCase.swift -// LoginFeature -// -// Created by Seonwoo Kim on 11/8/24. -// Copyright © 2024 HMH-iOS. All rights reserved. -// - -import Foundation -import Combine - -import Domain -import Core - -public enum LoginResponseType { - case loginSuccess - case loginFailure - case onboardingNeeded -} - -public protocol LoginUseCaseType { - func login(provider: OAuthProviderType) -> AnyPublisher -} - -public final class LoginUseCase: LoginUseCaseType { - - private let repository: AuthRepositoryType - - public init(repository: AuthRepositoryType) { - self.repository = repository - } - - public func login(provider: OAuthProviderType) -> AnyPublisher { - repository.authorize(provider) - .handleEvents(receiveOutput: { socialToken in - UserManager.shared.socialToken = socialToken - }) - .flatMap { [weak self] _ -> AnyPublisher in - guard let self = self else { - return Fail(error: AuthError.appleAuthrizeError).eraseToAnyPublisher() - } - - return self.repository.socialLogin(socialPlatform: provider.rawValue) - .map { _ in LoginResponseType.loginSuccess } - .catch { error -> AnyPublisher in - switch error { - case .unregisteredUser: - return Just(.onboardingNeeded) - .setFailureType(to: AuthError.self) - .eraseToAnyPublisher() - default: - return Just(.loginFailure) - .setFailureType(to: AuthError.self) - .eraseToAnyPublisher() - } - } - .eraseToAnyPublisher() - } - .eraseToAnyPublisher() - } -} - diff --git a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift index 933431db..0846d842 100644 --- a/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift +++ b/HMH_Tuist_iOS/Projects/Features/OnboardingFeature/Sources/ViewModels/OnboardingViewModel.swift @@ -212,5 +212,4 @@ public final class OnboardingViewModel : ObservableObject { } .store(in: cancelBag) } - }