Skip to content

Commit

Permalink
Merge branch 'develop' into feat/#118
Browse files Browse the repository at this point in the history
  • Loading branch information
HELLOHIDI committed Nov 25, 2024
2 parents a317727 + 73dfa9a commit 36acdc5
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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()
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation

public enum OAuthProviderType {
case kakao
case apple
public enum OAuthProviderType: String {
case kakao = "KAKAO"
case apple = "APPLE"
}
Original file line number Diff line number Diff line change
@@ -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<LoginResponseType, AuthError>
}

public final class LoginUseCase: LoginUseCaseType {

private let repository: AuthRepositoryType

public init(repository: AuthRepositoryType) {
self.repository = repository
}

public func login(provider: OAuthProviderType) -> AnyPublisher<LoginResponseType, Domain.AuthError> {
repository.authorize(provider)
.handleEvents(receiveOutput: { socialToken in
UserManager.shared.socialToken = socialToken
})
.flatMap { [weak self] _ -> AnyPublisher<LoginResponseType, AuthError> 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<LoginResponseType, AuthError> in
switch error {
case .unregisteredUser:
return Just(.onboardingNeeded)
.setFailureType(to: AuthError.self)
.eraseToAnyPublisher()
default:
return Just(.loginFailure)
.setFailureType(to: AuthError.self)
.eraseToAnyPublisher()
}
}
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
//

import SwiftUI
import AuthenticationServices

import DSKit
import Domain

public struct LoginView: View {
@ObservedObject var viewModel: LoginViewModel
Expand All @@ -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)
}
}


Original file line number Diff line number Diff line change
@@ -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<SocialLogineResponseDTO>.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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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..<imageNames.count, id: \.self) { index in
Image(imageNames[index])
TabView(selection: Binding(
get: { viewModel.state.swipeImageIndex },
set: { index in
viewModel.send(action: .swipeButtonDidTap(index: index))
}
)) {
ForEach(0..<swipeImages.count, id: \.self) { index in
swipeImages[index]
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: .infinity, maxHeight: .infinity)
Expand All @@ -28,22 +30,17 @@ struct SwipeView: View {
}
.padding(.bottom, 30)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))

HStack {
ForEach(0..<imageNames.count, id: \.self) { index in
ForEach(0..<swipeImages.count, id: \.self) { index in
Rectangle()
.fill(selectedImageIndex == index ? Color(.white) : Color(DSKitAsset.gray2.swiftUIColor))
.fill(viewModel.state.swipeImageIndex == index ? Color(.white) : Color(DSKitAsset.gray2.swiftUIColor))
.frame(width: 8, height: 8)
.onTapGesture {
selectedImageIndex = index
.onTapGesture { viewModel.send(action: .swipeButtonDidTap(index: index))
}
}
}
}
.frame(maxWidth: .infinity)
.onReceive(timer) { _ in
withAnimation(.default) {
selectedImageIndex = (selectedImageIndex + 1) % imageNames.count
}
}
}
}

0 comments on commit 36acdc5

Please sign in to comment.