diff --git a/HMH_Tuist_iOS/Projects/App/Derived/InfoPlists/HMH-iOS-Info.plist b/HMH_Tuist_iOS/Projects/App/Derived/InfoPlists/HMH-iOS-Info.plist
index a3d5de43..a58e1a02 100644
--- a/HMH_Tuist_iOS/Projects/App/Derived/InfoPlists/HMH-iOS-Info.plist
+++ b/HMH_Tuist_iOS/Projects/App/Derived/InfoPlists/HMH-iOS-Info.plist
@@ -2,75 +2,87 @@
- BASE_URL
- $(BASE_URL)
- BGTaskSchedulerPermittedIdentifiers
-
- com.HMH.dailyTask
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 1.0
- CFBundleURLTypes
-
-
- CFBundleTypeRole
- Editor
- CFBundleURLSchemes
-
- kakao$(KAKAO_API_KEY)
-
-
-
- CFBundleVersion
- 1
- KAKAO_API_KEY
- $(KAKAO_API_KEY)
- LSApplicationQueriesSchemes
-
- kakaokompassauth
- kakaolink
-
- LSRequiresIPhoneOS
-
- NSAppTransportSecurity
-
- NSAllowsArbitraryLoads
-
-
- UIAppFonts
-
- Pretendard-Regular.otf
- Pretendard-SemiBold.otf
- Pretendard-Medium.otf
-
- UIApplicationSceneManifest
-
- UIApplicationSupportsMultipleScenes
-
- UISceneConfigurations
-
-
- UIRequiredDeviceCapabilities
-
- armv7
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
+ BASE_URL
+ $(BASE_URL)
+ BGTaskSchedulerPermittedIdentifiers
+
+ com.HMH.dailyTask
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLSchemes
+
+ kakao$(KAKAO_API_KEY)
+
+
+
+ CFBundleVersion
+ 1
+ KAKAO_API_KEY
+ $(KAKAO_API_KEY)
+ LSApplicationQueriesSchemes
+
+ kakaokompassauth
+ kakaolink
+
+ LSRequiresIPhoneOS
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ UIAppFonts
+
+ Pretendard-Regular.otf
+ Pretendard-SemiBold.otf
+ Pretendard-Medium.otf
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneConfigurationName
+ Default Configuration
+ UISceneDelegateClassName
+ $(PRODUCT_MODULE_NAME).SceneDelegate
+
+
+
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
diff --git a/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/SplashView.swift b/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/SplashView.swift
index 8acf9880..f2ae4aaa 100644
--- a/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/SplashView.swift
+++ b/HMH_Tuist_iOS/Projects/App/Sources/Common/Custom/SplashView.swift
@@ -30,7 +30,7 @@ struct SplashView: View {
.background(DSKitAsset.blackground.swiftUIColor, ignoresSafeAreaEdges: .all)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.5, execute: {
- viewModel.handleSplashScreen()
+// viewModel.handleSplashScreen()
})
}
}
diff --git a/HMH_Tuist_iOS/Projects/Domain/Sources/Entity/Auth/OAuthProviderType.swift b/HMH_Tuist_iOS/Projects/Domain/Sources/Entity/Auth/OAuthProviderType.swift
index 243724c5..449b6e43 100644
--- a/HMH_Tuist_iOS/Projects/Domain/Sources/Entity/Auth/OAuthProviderType.swift
+++ b/HMH_Tuist_iOS/Projects/Domain/Sources/Entity/Auth/OAuthProviderType.swift
@@ -8,7 +8,7 @@
import Foundation
-public enum OAuthProviderType {
- case kakao
- case apple
+public enum OAuthProviderType: String {
+ case kakao = "KAKAO"
+ case apple = "APPLE"
}
diff --git a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginUseCase.swift
new file mode 100644
index 00000000..272c858e
--- /dev/null
+++ b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/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/LoginFeature/Sources/LoginView.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginView.swift
index ea6245b4..00e7f9b2 100644
--- a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginView.swift
+++ b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/LoginView.swift
@@ -6,9 +6,9 @@
//
import SwiftUI
-import AuthenticationServices
import DSKit
+import Domain
public struct LoginView: View {
@ObservedObject var viewModel: LoginViewModel
@@ -23,15 +23,13 @@ public struct LoginView: View {
.ignoresSafeArea()
VStack(spacing: 10) {
//TODO: 이미지 타입 문제거 같은데 지금 해결하기엔 싱싱미역
-// SwipeView(imageNames: [.onboardingFirst, .onboardingSecond, .onboardingThird])
-// .padding(.bottom, 75)
- LoginButton(loginProvider: .kakao, viewModel: viewModel)
- LoginButton(loginProvider: .apple, viewModel: viewModel)
+ SwipeView(swipeImages: [DSKitAsset.onboardingFirst.swiftUIImage, DSKitAsset.onboardingSecond.swiftUIImage, DSKitAsset.onboardingThird.swiftUIImage], viewModel: viewModel)
+ .padding(.bottom, 75)
+ LoginButton(loginProvider: OAuthProviderType.kakao, viewModel: viewModel)
+ LoginButton(loginProvider: OAuthProviderType.apple, viewModel: viewModel)
}
}
.frame(maxHeight: .infinity)
.padding(.vertical, 22)
}
}
-
-
diff --git a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/ViewModels/LoginViewModel.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/ViewModels/LoginViewModel.swift
index 69304827..43f44a40 100644
--- a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/ViewModels/LoginViewModel.swift
+++ b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/ViewModels/LoginViewModel.swift
@@ -1,106 +1,65 @@
-import SwiftUI
-import AuthenticationServices
+//
+// LoginViewModel.swift
+// LoginFeature
+//
+// Created by Seonwoo Kim on 11/8/24.
+// Copyright © 2024 HMH-iOS. All rights reserved.
+//
-import KakaoSDKUser
+import Foundation
+import Combine
import Core
+import Domain
import DSKit
-public class LoginViewModel: NSObject, ObservableObject {
+public final class LoginViewModel: ObservableObject {
- @Published public var isLoading: Bool = true
- @Published var isPresented: Bool = false
- @Published var alertType: CustomAlertType = .unlock
+ private let loginUseCase: LoginUseCaseType
+ private var cancelBag = CancelBag()
- public func handleSplashScreen() {
- self.isLoading = false
- }
+ // 화면 이동 로직과 스와이프 인덱스 포함
+ @Published private(set) var state = State(loginStatus: .loginFailure, swipeImageIndex: 0)
- func handleAppleLogin() {
- let request = ASAuthorizationAppleIDProvider().createRequest()
- request.requestedScopes = [.fullName, .email]
-
- let authorizationController = ASAuthorizationController(authorizationRequests: [request])
- authorizationController.delegate = self
- authorizationController.performRequests()
+ public init(loginUseCase: LoginUseCaseType) {
+ self.loginUseCase = loginUseCase
+ startImageTimer()
}
- func handleKakaoLogin() {
- if (UserApi.isKakaoTalkLoginAvailable()) {
- UserApi.shared.loginWithKakaoTalk {(oauthToken, error) in
- if let error = error {
- print(error)
- }
- if let oauthToken = oauthToken{
- let idToken = oauthToken.accessToken
- UserManager.shared.socialPlatform = "KAKAO"
- UserManager.shared.socialToken = "Bearer " + idToken
- self.postSocialLoginData()
- }
- }
- } else {
- UserApi.shared.loginWithKakaoAccount {(oauthToken, error) in
- if let error = error {
- print("🍀",error)
- }
- if let oauthToken = oauthToken{
- print("kakao success")
- UserManager.shared.socialPlatform = "KAKAO"
- let idToken = oauthToken.accessToken
- UserManager.shared.socialToken = "Bearer " + idToken
- self.postSocialLoginData()
- }
- }
- }
+ // MARK: Action
+
+ enum Action {
+ case loginButtonDidTap(provider: OAuthProviderType)
+ case swipeButtonDidTap(index: Int)
}
- //TODO: 네트워크 부분은 의존성 정리한 뒤에 다시 연결해봅시다
- func postSocialLoginData() {
-// let provider = Providers.AuthProvider
-// let request = SocialLoginRequestDTO(socialPlatform: UserManager.shared.socialPlatform ?? "")
-//
-// provider.request(target: .socialLogin(data: request), instance: BaseResponse.self) { data in
-// if data.status == 403 {
-// UserManager.shared.appStateString = "onboarding"
-// } else if data.status == 200 {
-// guard let data = data.data else { return }
-// UserManager.shared.refreshToken = data.token.refreshToken
-// UserManager.shared.accessToken = data.token.accessToken
-// UserManager.shared.appStateString = "home"
-// }
-// }
+ // MARK: State
+
+ struct State {
+ var loginStatus: LoginResponseType
+ var swipeImageIndex: Int
}
-}
-
-extension LoginViewModel: ASAuthorizationControllerDelegate {
- public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
- switch authorization.credential {
- case let appleIDCredential as ASAuthorizationAppleIDCredential:
- let userIdentifier = appleIDCredential.user
- let fullName = appleIDCredential.fullName
-
- if let identityToken = appleIDCredential.identityToken,
- let identifyTokenString = String(data: identityToken, encoding: .utf8) {
- UserManager.shared.socialToken = identifyTokenString
- UserManager.shared.socialPlatform = "APPLE"
- self.postSocialLoginData()
- } else {
- print("Identity token is nil or failed to convert to string.")
- }
- default:
- break
+ func send(action: Action) {
+ switch action {
+ case .loginButtonDidTap(let provider):
+ loginUseCase.login(provider: provider)
+ .sink(receiveCompletion: { _ in }) { [weak self] response in
+ self?.state.loginStatus = response
+ }
+ .store(in: cancelBag)
+ case .swipeButtonDidTap(let index):
+ self.state.swipeImageIndex = index
}
}
- func handleAppleIDCredential(_ credential: ASAuthorizationAppleIDCredential) {
- let fullName = credential.fullName
- let name = (fullName?.familyName ?? "") + (fullName?.givenName ?? "")
- UserManager.shared.userName = name
- guard let idToken = String(data: credential.identityToken ?? Data(), encoding: .utf8) else { return print("no idToken!!") }
+ private func startImageTimer() {
+ Timer.publish(every: 3.0, on: .main, in: .common)
+ .autoconnect()
+ .sink { [weak self] _ in
+ self?.state.swipeImageIndex = ((self?.state.swipeImageIndex ?? 0) + 1) % 3
+ }
+ .store(in: cancelBag)
}
- public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
- print(error.localizedDescription)
- }
}
diff --git a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginButton.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginButton.swift
index 1765749d..c2d65a55 100644
--- a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginButton.swift
+++ b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/LoginButton.swift
@@ -6,42 +6,25 @@
//
import SwiftUI
-import AuthenticationServices
import DSKit
-
-enum SignInProvider {
- case apple
- case kakao
-
- var signInLogoImage: String {
- switch self {
- case .apple:
- return "appleLogo"
- case .kakao:
- return "kakaoLogo"
- }
- }
-}
+import Domain
struct LoginButton: View {
- let loginProvider: SignInProvider
+ var loginProvider: OAuthProviderType = .apple
@ObservedObject var viewModel: LoginViewModel
+ var signInLogoImage = DSKitAsset.appleLogo.swiftUIImage
var body: some View {
Button(action: {
- if loginProvider == .apple {
- viewModel.handleAppleLogin()
- } else if loginProvider == .kakao {
- viewModel.handleKakaoLogin()
- }
+ viewModel.send(action: .loginButtonDidTap(provider: loginProvider))
}) {
RoundedRectangle(cornerRadius: 6.3)
.frame(width:336, height: 51)
.foregroundColor(loginProvider == .apple ? DSKitAsset.whiteBtn.swiftUIColor : DSKitAsset.yelloBtn.swiftUIColor)
.overlay(
HStack {
- Image(loginProvider.signInLogoImage)
+ Image(uiImage: loginProvider == .apple ? DSKitAsset.appleLogo.image : DSKitAsset.kakaoLogo.image)
.resizable()
.frame(width: 24, height: 24)
.padding(.leading, 14)
diff --git a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/SwipeView.swift b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/SwipeView.swift
index 8e4f56c6..918125a9 100644
--- a/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/SwipeView.swift
+++ b/HMH_Tuist_iOS/Projects/Features/LoginFeature/Sources/Views/SwipeView.swift
@@ -6,20 +6,22 @@
//
import SwiftUI
-
import DSKit
struct SwipeView: View {
- var imageNames: [ImageResource]
- private let timer = Timer.publish(every: 3.0, on: .main, in: .common).autoconnect()
-
- @State private var selectedImageIndex: Int = 0
+ var swipeImages: [Image]
+ @ObservedObject var viewModel: LoginViewModel
var body: some View {
VStack {
- TabView(selection: $selectedImageIndex) {
- ForEach(0..