diff --git a/Projects/Core/Sources/Base/BaseViewController.swift b/Projects/Core/Sources/Base/BaseViewController.swift index 7655f9ab..11a87963 100644 --- a/Projects/Core/Sources/Base/BaseViewController.swift +++ b/Projects/Core/Sources/Base/BaseViewController.swift @@ -28,6 +28,7 @@ open class BaseViewController: UIViewController { open override func viewDidLoad() { super.viewDidLoad() bindViewModel() + bindActions() layout() setupKeyboardHandling() attribute() diff --git a/Projects/Data/Sources/Repository/AuthRepository.swift b/Projects/Data/Sources/Repository/AuthRepository.swift index ee32e741..f182daed 100644 --- a/Projects/Data/Sources/Repository/AuthRepository.swift +++ b/Projects/Data/Sources/Repository/AuthRepository.swift @@ -1,4 +1,5 @@ import UIKit +import MGNetworks import RxSwift import RxCocoa @@ -7,32 +8,45 @@ import Moya import RxMoya import Domain -import MGNetworks +import KakaoSDKAuth public class AuthRepository: AuthRepositoryInterface { + private let networkService: AuthService - public init(networkService: AuthService) { - self.networkService = networkService + public func oauthSignup(nickname: String, accessToken: String, oauth: OauthType) -> Single { + return networkService.oauthSingup(nickname: nickname, accessToken: accessToken, oauth: oauth) } - public func kakaoToken() -> Single { - networkService.kakaoTokenState() + public func oauthLogin(accessToken: String, oauth: OauthType) -> Single { + return networkService.oauthLogin(accessToken: accessToken, oauth: oauth) } - public func getCSRFToken() -> Single { - return networkService.getCSRFToken() + public func oauthRecovery(accessToken: String, oauth: OauthType) -> Single { + return networkService.oauthRecovery(accessToken: accessToken, oauth: oauth) } + public func nicknameCheck(nickname: String) -> Single { + return networkService.nicknameCheck(nickname: nickname) + } + public func getIntroData() -> Single { return networkService.requestIntroData() } - public func appleSignup() -> RxSwift.Single { - return networkService.appleSignup() + public func appleButtonTap() -> Single { + return networkService.appleButtonTap() + } + + public func kakaoButtonTap() -> Single { + return networkService.kakaoButtonTap() } - public func appleSingup(nickname: String, accessToken: String) -> Single { - return networkService.appleSignup(nickname: nickname, accessToken: accessToken) + public init(networkService: AuthService) { + self.networkService = networkService } + +// public func appleSingup(nickname: String, accessToken: String) -> Single { +// return networkService.appleSignup(nickname: nickname, accessToken: accessToken) +// } } diff --git a/Projects/Domain/Sources/RepositoryInterface/AuthRepositoryInterface.swift b/Projects/Domain/Sources/RepositoryInterface/AuthRepositoryInterface.swift index eafcc0ad..e096e0e8 100644 --- a/Projects/Domain/Sources/RepositoryInterface/AuthRepositoryInterface.swift +++ b/Projects/Domain/Sources/RepositoryInterface/AuthRepositoryInterface.swift @@ -2,11 +2,22 @@ import UIKit import RxSwift import RxCocoa +import Moya + +import KakaoSDKAuth + +public enum OauthType { + case google + case kakao + case apple +} public protocol AuthRepositoryInterface { - func kakaoToken() -> Single - func getCSRFToken() -> Single + func kakaoButtonTap() -> Single + func appleButtonTap() -> Single + func oauthSignup(nickname: String, accessToken: String, oauth: OauthType) -> Single + func oauthLogin(accessToken: String, oauth: OauthType) -> Single + func oauthRecovery(accessToken: String, oauth: OauthType) -> Single + func nicknameCheck(nickname: String) -> Single func getIntroData() -> Single - func appleSignup() -> Single - func appleSingup(nickname: String, accessToken: String) -> Single } diff --git a/Projects/Domain/Sources/Response/LoginDTO.swift b/Projects/Domain/Sources/Response/LoginDTO.swift new file mode 100644 index 00000000..9382ff21 --- /dev/null +++ b/Projects/Domain/Sources/Response/LoginDTO.swift @@ -0,0 +1,20 @@ +import Foundation + +public struct LoginResponseDTO: Decodable { + public let status: Int + public let accessToken: String + public let refreshToken: String +} + +public struct SignupResponseDTO: Decodable { + public let status: Int +} + +public struct RecoveryResponseDTO: Decodable { + public let status: Int +} + +enum AuthErrorType: Error { + case notFound400 + case notInt +} diff --git a/Projects/Domain/Sources/Response/dummy4.swift b/Projects/Domain/Sources/Response/dummy4.swift deleted file mode 100644 index fecc4ab4..00000000 --- a/Projects/Domain/Sources/Response/dummy4.swift +++ /dev/null @@ -1 +0,0 @@ -import Foundation diff --git a/Projects/Domain/Sources/UseCase/AuthUseCase.swift b/Projects/Domain/Sources/UseCase/AuthUseCase.swift index a86a8915..8b8eb063 100644 --- a/Projects/Domain/Sources/UseCase/AuthUseCase.swift +++ b/Projects/Domain/Sources/UseCase/AuthUseCase.swift @@ -6,15 +6,16 @@ import RxCocoa import Core import Moya +import MGLogger import TokenManager import AuthenticationServices public protocol AuthUseCase { func kakaoButtonTap() - func getCSRFToken() -> Single func getIntroData() - func appleButtonTap() -> Single -// func appleNickNameButtonTap() -> Single + func appleButtonTap() + func changeNickname(nickname: String) + func nextButtonTap() var appleSignupResult: PublishSubject { get } var introData: PublishSubject { get } } @@ -23,60 +24,235 @@ public class DefaultAuthUseCase { private let authRepository: AuthRepositoryInterface private let disposeBag = DisposeBag() + open var oauthType: OauthType = .kakao + public var nicknameText: String = "" + public let introData = PublishSubject() public let appleSignupResult = PublishSubject() public let appleNicknameSignupResult = PublishSubject() - public init(authRepository: AuthRepositoryInterface) { self.authRepository = authRepository } } extension DefaultAuthUseCase: AuthUseCase { + + public func changeNickname(nickname: String) { + self.nicknameText = nickname + } - - public func appleButtonTap() -> Single { - authRepository.appleSignup() - .subscribe( - onSuccess: { [weak self] token in - self?.appleSignupResult.onNext(token) - }, - onFailure: { [weak self] error in - self?.appleSignupResult.onError(error) + public func kakaoButtonTap() { + oauthType = .kakao + authRepository.kakaoButtonTap().subscribe(onSuccess: { [self] token in + let oauthToken = token!.accessToken + MGLogger.debug("kakaoButtonTap token ✅ \(oauthToken)") + TokenManagerImpl().save(token: oauthToken, with: .authorizationToken) + authRepository.oauthLogin(accessToken: oauthToken, oauth: .kakao) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } } - ) - .disposed(by: disposeBag) - - return appleSignupResult.take(1).asSingle() + .subscribe(onSuccess: { element in + MGLogger.debug("appleButtonTap login ✅ \(String(describing: element.response))") + if let headers = element.response?.headers { + let accessToken = headers.value(for: "Authorization")?.replacingOccurrences(of: "Bearer ", with: "") + let refreshToken = headers["Set-Cookie"]?.components(separatedBy: ";").first(where: { $0.contains("RF-TOKEN") })?.replacingOccurrences(of: "RF-TOKEN=", with: "") + if let accessToken = accessToken { + TokenManagerImpl().save(token: accessToken, with: .authorizationToken) + } + if let refreshToken = refreshToken { + TokenManagerImpl().save(token: refreshToken, with: .refreshToken) + } + } + AuthStepper.shared.steps.accept(MGStep.initialization) + }, onFailure: { [self] error in + MGLogger.debug("appleButtonTap login ❌ \(error)") + authRepository.oauthRecovery(accessToken: oauthToken, oauth: .kakao) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { [self] element in + MGLogger.debug("appleButtonTap recovery ✅ \(element)") + authRepository.oauthLogin(accessToken: oauthToken, oauth: .kakao) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { element in + MGLogger.debug("appleButtonTap login ✅ \(String(describing: element.response))") + if let headers = element.response?.headers { + let accessToken = headers.value(for: "Authorization")?.replacingOccurrences(of: "Bearer ", with: "") + let refreshToken = headers["Set-Cookie"]?.components(separatedBy: ";").first(where: { $0.contains("RF-TOKEN") })?.replacingOccurrences(of: "RF-TOKEN=", with: "") + if let accessToken = accessToken { + TokenManagerImpl().save(token: accessToken, with: .authorizationToken) + } + if let refreshToken = refreshToken { + TokenManagerImpl().save(token: refreshToken, with: .refreshToken) + } + } + }, onFailure: { error in + MGLogger.debug("appleButtonTap login(여기서 절대 에러가 나면 안됩니다...) ❌ \(error)") + }).disposed(by: disposeBag) + }, onFailure: { error in + MGLogger.debug("appleButtonTap recovery ❌ \(error)") + AuthStepper.shared.steps.accept(MGStep.authAgreeIsRequired) + }).disposed(by: disposeBag) + }).disposed(by: disposeBag) + }, onFailure: { error in + MGLogger.debug("kakaoButtonTap token error ❌ \(error)") + }).disposed(by: disposeBag) } - + + public func appleButtonTap() { + oauthType = .apple + authRepository.appleButtonTap() + .subscribe(onSuccess: { [self] token in + MGLogger.debug("appleButtonTap token ✅ \(token)") + TokenManagerImpl().save(token: token, with: KeychainType.authorizationToken) + authRepository.oauthLogin(accessToken: token, oauth: .apple) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { element in + MGLogger.debug("appleButtonTap login ✅ \(String(describing: element.response))") + if let headers = element.response?.headers { + let accessToken = headers.value(for: "Authorization")?.replacingOccurrences(of: "Bearer ", with: "") + let refreshToken = headers["Set-Cookie"]?.components(separatedBy: ";").first(where: { $0.contains("RF-TOKEN") })?.replacingOccurrences(of: "RF-TOKEN=", with: "") + if let accessToken = accessToken { + TokenManagerImpl().save(token: accessToken, with: .authorizationToken) + } + if let refreshToken = refreshToken { + TokenManagerImpl().save(token: refreshToken, with: .refreshToken) + } + } + AuthStepper.shared.steps.accept(MGStep.initialization) + }, onFailure: { [self] error in + MGLogger.debug("appleButtonTap login ❌ \(error)") + authRepository.oauthRecovery(accessToken: token, oauth: .apple) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { [self] element in + MGLogger.debug("appleButtonTap recovery ✅ \(element)") + authRepository.oauthLogin(accessToken: token, oauth: .apple) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { element in + MGLogger.debug("appleButtonTap login ✅ \(String(describing: element.response))") + if let headers = element.response?.headers { + let accessToken = headers.value(for: "Authorization")?.replacingOccurrences(of: "Bearer ", with: "") + let refreshToken = headers["Set-Cookie"]?.components(separatedBy: ";").first(where: { $0.contains("RF-TOKEN") })?.replacingOccurrences(of: "RF-TOKEN=", with: "") + if let accessToken = accessToken { + TokenManagerImpl().save(token: accessToken, with: .authorizationToken) + } + if let refreshToken = refreshToken { + TokenManagerImpl().save(token: refreshToken, with: .refreshToken) + } + } + }, onFailure: { error in + MGLogger.debug("appleButtonTap login(여기서 절대 에러가 나면 안됩니다...) ❌ \(error)") + }).disposed(by: disposeBag) + }, onFailure: { error in + MGLogger.debug("appleButtonTap recovery ❌ \(error)") + AuthStepper.shared.steps.accept(MGStep.authAgreeIsRequired) + }).disposed(by: disposeBag) + }).disposed(by: disposeBag) + }, onFailure: { error in + MGLogger.debug("appleButtonTap token error ❌ \(error)") + }).disposed(by: disposeBag) + } + + public func nextButtonTap() { + let accessToken = TokenManagerImpl().get(key: KeychainType.authorizationToken)! + authRepository.nicknameCheck(nickname: nicknameText) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { [self] element in + MGLogger.debug("nicknameButtonTap nickname ✅ \(element)") + MGLogger.debug("nicknameButtonTap nickname ✅ \(nicknameText)") + + authRepository.oauthSignup(nickname: nicknameText, + accessToken: accessToken, + oauth: .kakao) + .flatMap { response -> Single in + MGLogger.debug(response) + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { [self] element in + MGLogger.debug("nicknameButtonTap Signup ✅ \(element)") + authRepository.oauthLogin(accessToken: accessToken, oauth: .kakao) + .flatMap { response -> Single in + if response.statusCode >= 400 { + return Single.error(AuthErrorType.notFound400) + } else { + return Single.just(response) + } + } + .subscribe(onSuccess: { element in + MGLogger.debug("nicknameButtonTap Login ✅ \(element)") + if let headers = element.response?.headers { + let accessToken = headers.value(for: "Authorization") + let refreshToken = headers["Set-Cookie"]?.components(separatedBy: ";").first(where: { $0.contains("RF-TOKEN") })?.replacingOccurrences(of: "RF-TOKEN=", with: "") + if let accessToken = accessToken { + TokenManagerImpl().save(token: accessToken, with: .authorizationToken) + } + if let refreshToken = refreshToken { + TokenManagerImpl().save(token: refreshToken, with: .refreshToken) + } + } + AuthStepper.shared.steps.accept(MGStep.authCompleteIsRequired) + }, onFailure: { error in + MGLogger.debug("nicknameButtonTap Login(여기선 절대 에러가 나면 안됩니다...) ❌ \(error)") + }).disposed(by: disposeBag) + }, onFailure: { error in + MGLogger.debug("nicknameButtonTap Signup(여기선 절대 에러가 나면 안됩니다...) ❌ \(error)") + }).disposed(by: disposeBag) + }, onFailure: { error in + MGLogger.debug("nicknameButtonTap nickname 중복 ❌ \(error)") + }).disposed(by: disposeBag) + } + public func getIntroData() { return authRepository.getIntroData() .subscribe(onSuccess: { [weak self] introModel in self?.introData.onNext(introModel) }, - onFailure: { error in + onFailure: { error in print("AuthUseCase getIntroData error occurred: \(error)") }) .disposed(by: disposeBag) } - - public func getCSRFToken() -> Single { - return authRepository.getCSRFToken() - } - - public func kakaoButtonTap() { - return authRepository.kakaoToken() - .subscribe(onSuccess: { _ in - print("토큰 저장 성공") - }, onFailure: { error in - print("AuthUseCase getIntroData error occurred: \(error)") - }) - .disposed(by: self.disposeBag) - } - -// public func appleNickNameButtonTap(nickname: String) -> Single { -// return authRepository.appleSingup(nickname: nickname, accessToken: TokenManagerImpl().get(key: .authorizationToken)).mapString -// } } diff --git a/Projects/Features/AuthFeature/Sources/IntroScene/VC/IntroViewController.swift b/Projects/Features/AuthFeature/Sources/IntroScene/VC/IntroViewController.swift index 663d05b6..d6e6e236 100644 --- a/Projects/Features/AuthFeature/Sources/IntroScene/VC/IntroViewController.swift +++ b/Projects/Features/AuthFeature/Sources/IntroScene/VC/IntroViewController.swift @@ -1,8 +1,8 @@ import UIKit -import RxFlow -import RxCocoa import RxSwift +import RxCocoa +import RxFlow import SnapKit import Then @@ -19,9 +19,6 @@ import BaseFeatureDependency import AuthenticationServices public class IntroViewController: BaseViewController, Stepper { - -// let config = GIDConfiguration(clientID: "9435200486-2epc0q27qhose5v9gkjr5vfa7o97md9u.apps.googleusercontent.com") - public var steps = PublishRelay() @@ -38,157 +35,99 @@ public class IntroViewController: BaseViewController, Stepper { font: UIFont.Pretendard.titleMedium, isCenter: true ) - + private var subTitle = MGLabel( font: UIFont.Pretendard.bodyMedium, textColor: DSKitAsset.Colors.gray600.color, numberOfLineCount: 2 ) - + private var stackView = UIStackView().then { $0.axis = .vertical $0.alignment = .center $0.distribution = .equalSpacing $0.spacing = 16.0 } - + private var googleButton = MGAuthButton(type: .google) private var kakaoButton = MGAuthButton(type: .kakao) private var appleButton = MGAuthButton(type: .apple) - + public override func layout() { super.layout() - + let width = view.frame.width / 430.0 let height = view.frame.height / 932.0 - + view.addSubviews([introImageView, mainTitle, subTitle, stackView]) - + stackView.addArrangedSubviews(googleButton, kakaoButton, appleButton) - + introImageView.snp.makeConstraints { $0.centerX.equalToSuperview() - $0.top.equalTo(view.safeAreaLayoutGuide).offset(105.0 * height) + $0.top.equalToSuperview().offset(158.0) } - + mainTitle.snp.makeConstraints { $0.centerX.equalToSuperview() $0.top.equalTo(introImageView.snp.bottom).offset(30.0 * height) } - + subTitle.snp.makeConstraints { $0.centerX.equalToSuperview() $0.top.equalTo(mainTitle.snp.bottom).offset(10.0 * height) } - + googleButton.snp.makeConstraints { $0.centerX.equalToSuperview() $0.width.equalTo(390.0 * width) $0.height.equalTo(60.0 * height) } - + kakaoButton.snp.makeConstraints { $0.centerX.equalToSuperview() $0.width.equalTo(390.0 * width) $0.height.equalTo(60.0 * height) } - + appleButton.snp.makeConstraints { $0.centerX.equalToSuperview() $0.width.equalTo(390.0 * width) $0.height.equalTo(60.0 * height) } - + stackView.snp.makeConstraints { $0.centerX.equalToSuperview() - $0.top.equalTo(subTitle.snp.bottom).offset(20.0 * height) + $0.top.equalTo(subTitle.snp.bottom).offset(68.0) } } - + public override func bindViewModel() { - super.bindViewModel() - + super.bindViewModel() + let useCase = DefaultAuthUseCase(authRepository: AuthRepository(networkService: AuthService())) - viewModel = IntroViewModel(authUseCase: useCase) - - let input = IntroViewModel.Input( - goolgeButtonTapped: googleButton.rx.tap.asDriver(), - appleButtonTapped: appleButton.rx.tap.asDriver(), - kakaoButtonTapped: kakaoButton.rx.tap.asDriver(), - getIntroData: Observable.just(()).asDriver(onErrorDriveWith: .never()) - ) - + viewModel = IntroViewModel(authUseCase: useCase) + + let input = IntroViewModel.Input( + goolgeButtonTapped: googleButton.rx.tap.asDriver(), + appleButtonTapped: appleButton.rx.tap.asDriver(), + kakaoButtonTapped: kakaoButton.rx.tap.asDriver(), + getIntroData: Observable.just(()).asDriver(onErrorDriveWith: .never()) + ) + let ouput = viewModel.transform(input, action: { output in output.introDatas - .subscribe(onNext: { introData in - self.introModel = introData - self.mainTitle.text = self.introModel?.mainTitle - self.subTitle.text = self.introModel?.subTitle + .subscribe(onNext: { [weak self] introData in + self?.introModel = introData + self?.mainTitle.changeText(text: self?.introModel?.mainTitle) + self?.subTitle.changeText(text: self?.introModel?.subTitle) }) .disposed(by: disposeBag) }) - - appleButton.rx.tap - .bind { - let appleProvider = ASAuthorizationAppleIDProvider() - let request = appleProvider.createRequest() - request.requestedScopes = [.fullName, .email] -// - let controller = ASAuthorizationController(authorizationRequests: [request]) - controller.delegate = self - controller.performRequests() - } - .disposed(by: disposeBag) - } -} - -extension IntroViewController: ASAuthorizationControllerDelegate, - ASAuthorizationControllerPresentationContextProviding { - public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { - return self.view.window! - } - - public func authorizationController(controller: ASAuthorizationController, - didCompleteWithAuthorization authorization: ASAuthorization - ) { - switch authorization.credential { - case let appleIDCredential as ASAuthorizationAppleIDCredential: - let userIdentifier = appleIDCredential.user - let fullName = appleIDCredential.fullName - let email = appleIDCredential.email - - if let authorizationCode = appleIDCredential.authorizationCode, - let identityToken = appleIDCredential.identityToken, - let authCodeString = String(data: authorizationCode, encoding: .utf8), - let identifyTokenString = String(data: identityToken, encoding: .utf8) { - print("authorizationCode: \(authorizationCode)") - print("identityToken: \(identityToken)") - print("authCodeString: \(authCodeString)") - print("identifyTokenString: \(identifyTokenString)") - } - - print("useridentifier: \(userIdentifier)") - print("fullName: \(String(describing: fullName))") - print("email: \(String(describing: email))") - - case let passwordCredential as ASPasswordCredential: - let username = passwordCredential.user - let password = passwordCredential.password - - print("username: \(username)") - print("password: \(password)") - - default: - break - } - } - - public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { - print("login failed - \(error.localizedDescription)") } } diff --git a/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/IntroViewModel.swift b/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/IntroViewModel.swift index d75c451e..de6ba162 100644 --- a/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/IntroViewModel.swift +++ b/Projects/Features/AuthFeature/Sources/IntroScene/ViewModel/IntroViewModel.swift @@ -39,10 +39,6 @@ public class IntroViewModel: AuthViewModelType { var introDatas: Observable } -// public var goolgeButtonTap: (() -> Void)? -// public var appleButtonTap: (() -> Void)? -// public var kakaoButtonTap: (() -> Bool)? - private let introModelSubject = PublishSubject() public init(authUseCase: AuthUseCase) { @@ -58,20 +54,8 @@ public class IntroViewModel: AuthViewModelType { bindOutput(output: output) - useCase.getCSRFToken() - .subscribe(onSuccess: { token in - if TokenManagerImpl().save(token: token, with: self.keychainCSRF) { - print("토큰 저장 성공") - } else { - print("토큰 저장 실패") - } - }, onFailure: { error in - print("Error: \(error)") - }) - .disposed(by: disposeBag) - input.goolgeButtonTapped - .drive(onNext: { [weak self] _ in + .drive(onNext: { _ in print("goolgeButtonTapped") AuthStepper.shared.steps.accept(MGStep.authAgreeIsRequired) }) diff --git a/Projects/Features/AuthFeature/Sources/SignupScene/VC/AgreeViewController.swift b/Projects/Features/AuthFeature/Sources/SignupScene/VC/AgreeViewController.swift index e06b7702..4a75d70b 100644 --- a/Projects/Features/AuthFeature/Sources/SignupScene/VC/AgreeViewController.swift +++ b/Projects/Features/AuthFeature/Sources/SignupScene/VC/AgreeViewController.swift @@ -15,12 +15,14 @@ import Domain import MGLogger import MGNetworks -public class AgreeViewController: BaseViewController, UIGestureRecognizerDelegate, Stepper { +public class AgreeViewController: BaseViewController, Stepper, UIGestureRecognizerDelegate { public var steps = PublishRelay() private var naviBar = AuthNavigationBarBar() + private let containerView = BaseView() + private let agreeLabel = MGLabel( text: "약관동의", font: UIFont.Pretendard.titleLarge @@ -32,12 +34,22 @@ public class AgreeViewController: BaseViewController, UIGestureR textColor: DSKitAsset.Colors.gray600.color ) - private let agreeTermsView = MGAgreeView( - firstAgreeText: .privacyAgreeText, - secondAgreeText: .termsAgreeText, - thirdAgreeText: .ageAgreeText, - fourthAgreeText: .marketingAgreeText - ) + private let decorateLine1 = MGLine() + private let allAgreeButton = MGAgreeButton(type: .allAgreeText) + private let decorateLine2 = MGLine() + + private let firstAgreeButton = MGAgreeButton(type: .privacyAgreeText) + private let secondAgreeButton = MGAgreeButton(type: .termsAgreeText) + private let thirdAgreeButton = MGAgreeButton(type: .ageAgreeText) + private let fourthAgreeButton = MGAgreeButton(type: .marketingAgreeText, chooseType: true) + + // private let readMore = MGButton( + // titleText: "자세히 보기", + // font: UIFont.Pretendard.labelSmall, + // textColor: DSKitAsset.Colors.gray300.color + // ).then { + // $0.isHidden = false + // } private var checkButton = MGCheckButton(text: "확인") @@ -53,7 +65,7 @@ public class AgreeViewController: BaseViewController, UIGestureR } public override func layout() { - view.addSubviews([naviBar, agreeLabel, textInformation, agreeTermsView, checkButton]) + view.addSubviews([naviBar, agreeLabel, textInformation, containerView, checkButton]) naviBar.snp.makeConstraints { $0.leading.top.trailing.equalTo(view.safeAreaLayoutGuide) @@ -71,9 +83,10 @@ public class AgreeViewController: BaseViewController, UIGestureR $0.width.equalTo(287.0) } - agreeTermsView.snp.makeConstraints { + containerView.snp.makeConstraints { $0.top.equalTo(textInformation.snp.bottom).offset(40.0) - $0.leading.equalToSuperview().offset(20.0) + $0.height.equalTo(284.0) + $0.leading.trailing.equalToSuperview().inset(20.0) } checkButton.snp.makeConstraints { @@ -82,6 +95,54 @@ public class AgreeViewController: BaseViewController, UIGestureR $0.trailing.equalToSuperview().offset(-20.0) $0.height.equalTo(58.0) } + + containerView.addSubviews([decorateLine1, + allAgreeButton, + decorateLine2, + firstAgreeButton, + secondAgreeButton, + thirdAgreeButton, + fourthAgreeButton]) + + decorateLine1.snp.makeConstraints { + $0.top.equalToSuperview() + $0.centerX.equalToSuperview() + } + + allAgreeButton.snp.makeConstraints { + $0.top.equalTo(decorateLine1.snp.bottom).offset(12.0) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(44.0) + } + + decorateLine2.snp.makeConstraints { + $0.top.equalTo(allAgreeButton.snp.bottom).offset(12.0) + $0.centerX.equalToSuperview() + } + + firstAgreeButton.snp.makeConstraints { + $0.top.equalTo(decorateLine2.snp.bottom).offset(8.0) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(44.0) + } + + secondAgreeButton.snp.makeConstraints { + $0.top.equalTo(firstAgreeButton.snp.bottom).offset(8.0) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(44.0) + } + + thirdAgreeButton.snp.makeConstraints { + $0.top.equalTo(secondAgreeButton.snp.bottom).offset(8.0) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(44.0) + } + + fourthAgreeButton.snp.makeConstraints { + $0.top.equalTo(thirdAgreeButton.snp.bottom).offset(8.0) + $0.leading.trailing.equalToSuperview() + $0.height.equalTo(44.0) + } } public override func bindViewModel() { @@ -94,11 +155,11 @@ public class AgreeViewController: BaseViewController, UIGestureR let input = AgreeViewModel.Input( navButtonTapped: navButtonTapped, - allAgreeButtonTap: agreeTermsView.allAgreeButton.rx.tap.asSignal(), - firstAgreeButtonTap: agreeTermsView.firstAgreeButton.rx.tap.asSignal(), - secondAgreeButtonTap: agreeTermsView.secondAgreeButton.rx.tap.asSignal(), - thirdAgreeButtonTap: agreeTermsView.thirdAgreeButton.rx.tap.asSignal(), - fourthAgreeButtonTap: agreeTermsView.fourthAgreeButton.rx.tap.asSignal(), + allAgreeButtonTap: allAgreeButton.rx.tap.asSignal(), + firstAgreeButtonTap: firstAgreeButton.rx.tap.asSignal(), + secondAgreeButtonTap: secondAgreeButton.rx.tap.asSignal(), + thirdAgreeButtonTap: thirdAgreeButton.rx.tap.asSignal(), + fourthAgreeButtonTap: fourthAgreeButton.rx.tap.asSignal(), nextButtonTap: checkButton.rx.tap.asSignal() ) @@ -106,7 +167,7 @@ public class AgreeViewController: BaseViewController, UIGestureR output.allAgreeButtonClickedMessage .drive(onNext: { [weak self] message in print(message) - self?.agreeTermsView.setAllAgreeButtonState(!(self?.agreeTermsView.allAgreeButtonState ?? false)) + self?.setAllAgreeButtonState(!(self?.allAgreeButtonState ?? false)) }) .disposed(by: disposeBag) @@ -120,7 +181,7 @@ public class AgreeViewController: BaseViewController, UIGestureR agreeButtons.forEach { buttonOutput in buttonOutput .drive(onNext: { [weak self] message in - self?.agreeTermsView.updateAllAgreeButtonState() + self?.updateAllAgreeButtonState() MGLogger.verbose(message) }) .disposed(by: disposeBag) @@ -128,24 +189,24 @@ public class AgreeViewController: BaseViewController, UIGestureR output.firstAgreeButtonClickedMessage .drive(onNext: { message in - self.agreeTermsView.updateAllAgreeButtonState() - _ = self.agreeTermsView.buttonActivationChecked(button: self.checkButton) + self.updateAllAgreeButtonState() + _ = self.buttonActivationChecked(button: self.checkButton) MGLogger.verbose(message) }) .disposed(by: disposeBag) output.secondAgreeButtonClickedMessage .drive(onNext: { message in - self.agreeTermsView.updateAllAgreeButtonState() - _ = self.agreeTermsView.buttonActivationChecked(button: self.checkButton) + self.updateAllAgreeButtonState() + _ = self.buttonActivationChecked(button: self.checkButton) MGLogger.verbose(message) }) .disposed(by: disposeBag) output.thirdAgreeButtonClickedMessage .drive(onNext: { message in - self.agreeTermsView.updateAllAgreeButtonState() - _ = self.agreeTermsView.buttonActivationChecked(button: self.checkButton) + self.updateAllAgreeButtonState() + _ = self.buttonActivationChecked(button: self.checkButton) MGLogger.verbose(message) }) .disposed(by: disposeBag) @@ -164,4 +225,48 @@ public class AgreeViewController: BaseViewController, UIGestureR .disposed(by: disposeBag) }) } + + public var allAgreeButtonState: Bool { + return firstAgreeButton.checked && + secondAgreeButton.checked && + thirdAgreeButton.checked && + fourthAgreeButton.checked + } + + public func setAllAgreeButtonState(_ isEnabled: Bool) { + allAgreeButton.checked = isEnabled + if isEnabled { + firstAgreeButton.buttonYesChecked() + secondAgreeButton.buttonYesChecked() + thirdAgreeButton.buttonYesChecked() + fourthAgreeButton.buttonYesChecked() + updateAllAgreeButtonState() + } else { + firstAgreeButton.buttonNoChecked() + secondAgreeButton.buttonNoChecked() + thirdAgreeButton.buttonNoChecked() + fourthAgreeButton.buttonNoChecked() + updateAllAgreeButtonState() + } + } + + public func updateAllAgreeButtonState() { + if allAgreeButtonState == true { + allAgreeButton.buttonYesChecked() + } else { + allAgreeButton.buttonNoChecked() + } + } + + public func buttonActivationChecked(button: MGCheckButton) -> Bool { + let shouldActivateButton = firstAgreeButton.checked && + secondAgreeButton.checked && + thirdAgreeButton.checked && + !fourthAgreeButton.checked + button.isEnabled = shouldActivateButton + button.backgroundColor = shouldActivateButton ? AuthResourcesService.Colors.blue500 : AuthResourcesService.Colors.gray400 + button.textLabel.textColor = shouldActivateButton ? .white : AuthResourcesService.Colors.gray200 + + return shouldActivateButton + } } diff --git a/Projects/Features/AuthFeature/Sources/SignupScene/VC/NicknameViewController.swift b/Projects/Features/AuthFeature/Sources/SignupScene/VC/NicknameViewController.swift index d6f9529b..a3edaab3 100644 --- a/Projects/Features/AuthFeature/Sources/SignupScene/VC/NicknameViewController.swift +++ b/Projects/Features/AuthFeature/Sources/SignupScene/VC/NicknameViewController.swift @@ -114,21 +114,41 @@ public class NicknameViewController: BaseViewController, Step } public override func bindViewModel() { -// let navButtonTapped = naviBar.leftButtonTap.asDriver(onErrorDriveWith: .never()) -// let useCase = DefaultAuthUseCase(authRepository: AuthRepository(networkService: AuthService())) -// -// viewModel = NicknameViewModel(useCase: useCase) -// -// let input = NicknameViewModel.Input(navButtonTapped: navButtonTapped, nextButtonTap: checkButton.rx.tap.asSignal()) -// -// let output = viewModel.transform(input, action: { -// ouput in -// ouput.nextButtonClicked -// .drive(onNext: { message in -// AuthStepper.shared.steps.accept(MGStep.authCompleteIsRequired) -// MGLogger.verbose(message) -// }).disposed(by: disposeBag) -// }) + let useCase = DefaultAuthUseCase(authRepository: AuthRepository(networkService: AuthService())) + viewModel = NicknameViewModel(useCase: useCase) + + let navButtonTapped = naviBar.leftButtonTap.asDriver(onErrorDriveWith: .never()) + let nextButtonTapped = checkButton.rx.tap.asDriver(onErrorDriveWith: .never()) + + let input = NicknameViewModel.Input(navButtonTap: navButtonTapped, nextButtonTap: nextButtonTapped) + + let output = viewModel.transform(input, action: { output in + output.nextButtonTap.drive(onNext: { _ in + useCase.changeNickname(nickname: self.nicknameTF.text ?? "") + useCase.nextButtonTap() + }).disposed(by: disposeBag) + + output.navButtonTap.drive(onNext: { _ in + AuthStepper.shared.steps.accept(MGStep.authBack) + }).disposed(by: disposeBag) + }) + } + + public override func bindActions() { + nicknameTF.rx.text + .map { ($0?.count ?? 0) >= 2 && ($0?.count ?? 0) <= 10 ? true : false } + .subscribe( + onNext: { [weak self] state in + MGLogger.debug(state) + switch state { + case true: + self?.checkButton.isEnabled = state + self?.checkButton.backgroundColor = AuthResourcesService.Colors.blue500 + case false: + self?.checkButton.isEnabled = state + self?.checkButton.backgroundColor = AuthResourcesService.Colors.gray400 + } + }).disposed(by: disposeBag) } func animateButtonWithKeyboard(notification: NSNotification, show: Bool) { diff --git a/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/AgreeViewModel.swift b/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/AgreeViewModel.swift index 8ef4c348..d39e6cc2 100644 --- a/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/AgreeViewModel.swift +++ b/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/AgreeViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import RxFlow -import RxCocoa import RxSwift +import RxCocoa +import RxFlow import Core import Domain @@ -40,8 +40,6 @@ public class AgreeViewModel: BaseViewModel { self.useCase = useCase } - public var onNextButtonTap: (() -> Void)? - public func transform(_ input: Input, action: (Output) -> Void) -> Output { let allAgreeClickedMessage = input.allAgreeButtonTap.map { "전체 클릭" }.asDriver(onErrorJustReturn: "") diff --git a/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/NicknameViewModel.swift b/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/NicknameViewModel.swift index f67a6b57..8ee412d0 100644 --- a/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/NicknameViewModel.swift +++ b/Projects/Features/AuthFeature/Sources/SignupScene/ViewModel/NicknameViewModel.swift @@ -1,57 +1,3 @@ -//import Foundation -// -//import RxFlow -//import RxCocoa -//import RxSwift -// -//import Core -//import Domain -//import MGNetworks -// -//public class NicknameViewModel: BaseViewModel { -// -// public typealias ViewModel = NicknameViewModel -// -// private let useCase: AuthUseCase -// -// public var disposeBag: DisposeBag = DisposeBag() -// -// public struct Input { -// let navButtonTapped: Driver -// let nextButtonTap: Driver -// } -// -// public struct Output { -// let navButtonTapped: Driver -// let nextButtonClicked: Driver -// } -// -// public init(useCase: AuthUseCase) { -// self.useCase = useCase -// } -// -// public func transform(_ input: Input, action: (Output) -> Void) -> Output { -// -//// let nextButtonClicked = input.nextButtonTap.map { true }.asDriver(onErrorJustReturn: false) -// -// let output = Output(navButtonTapped: input.navButtonTapped.asDriver(), nextButtonClicked: input.nextButtonTap.asDriver()) -// -// action(output) -// -// input.nextButtonTap -// .drive(onNext: { _ in -// useCase.appleNickNameButtonTap() -// }).disposed(by: disposeBag) -// -// input.navButtonTapped -// .drive(onNext: { _ in -// AuthStepper.shared.steps.accept(MGStep.authBack) -// }).disposed(by: disposeBag) -// -// return output -// } -//} - import Foundation import RxFlow @@ -59,26 +5,38 @@ import RxCocoa import RxSwift import Core +import Domain +import MGLogger + +import MGNetworks public class NicknameViewModel: BaseViewModel { public typealias ViewModel = NicknameViewModel - public func transform(_ input: Input, action: (Output) -> Void) -> Output { - return Output() - } + private let useCase: AuthUseCase - public struct Input { + public var disposeBag: DisposeBag = DisposeBag() + public struct Input { + let navButtonTap: Driver + let nextButtonTap: Driver } public struct Output { + let navButtonTap: Driver + let nextButtonTap: Driver + } + public init(useCase: AuthUseCase) { + self.useCase = useCase } - public init() { + public func transform(_ input: Input, action: (Output) -> Void) -> Output { + + let output = Output(navButtonTap: input.navButtonTap.asDriver(), nextButtonTap: input.nextButtonTap.asDriver()) + action(output) + return output } } - - diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/Contents.json b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/Contents.json new file mode 100644 index 00000000..f89881a7 --- /dev/null +++ b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "IntroIcon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "IntroIcon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "IntroIcon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon.png b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon.png new file mode 100644 index 00000000..72002370 Binary files /dev/null and b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon.png differ diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon@2x.png b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon@2x.png new file mode 100644 index 00000000..da07fe77 Binary files /dev/null and b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon@2x.png differ diff --git a/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon@3x.png b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon@3x.png new file mode 100644 index 00000000..8644478e Binary files /dev/null and b/Projects/Modules/DSKit/Resources/Assets.xcassets/Icons/IntroIcon.imageset/IntroIcon@3x.png differ diff --git a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/AgreeButtonType.swift b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/AgreeButtonType.swift index 355e58cd..3eb0ed39 100644 --- a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/AgreeButtonType.swift +++ b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/AgreeButtonType.swift @@ -1,3 +1,4 @@ +import UIKit import Foundation public enum agreeButtonTextType { @@ -21,4 +22,19 @@ public enum agreeButtonTextType { return "모두 동의해요" } } + + var font: UIFont { + switch self { + case .privacyAgreeText: + return UIFont.Pretendard.bodyMedium + case .termsAgreeText: + return UIFont.Pretendard.bodyMedium + case .ageAgreeText: + return UIFont.Pretendard.bodyMedium + case .marketingAgreeText: + return UIFont.Pretendard.bodyMedium + case .allAgreeText: + return UIFont.Pretendard.labelLarge + } + } } diff --git a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/MG+AgreeButton.swift b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/MG+AgreeButton.swift index f4cc6fdc..fb2a21c1 100644 --- a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/MG+AgreeButton.swift +++ b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymButton/Agree/MG+AgreeButton.swift @@ -9,15 +9,15 @@ import SnapKit import Core open class MGAgreeButton: BaseButton { - - public var checked: Bool = false - public var iconImageView = UIImageView().then { + public var checked: Bool = false + + private var iconImageView = UIImageView().then { $0.image = DSKitAsset.Assets.noCheckActIcon.image } private var textLabel = MGLabel(numberOfLineCount: 1) - + private let chooseLabel = MGLabel(text: "(선택)", font: UIFont.Pretendard.bodyMedium, textColor: DSKitAsset.Colors.gray400.color, @@ -26,136 +26,69 @@ open class MGAgreeButton: BaseButton { ).then { $0.isHidden = true } - - private let readMore = MGButton( - titleText: "자세히 보기", - font: UIFont.Pretendard.labelSmall, - textColor: DSKitAsset.Colors.gray300.color - ).then { - $0.isHidden = false - } - - private let readMoreLine = MGLine(lineColor: DSKitAsset.Colors.gray300.color, - lineWidth: 64.0, - lineHeight: 1.0 - ) public init ( - text: agreeButtonTextType, - font: UIFont? = UIFont.Pretendard.bodyMedium, - type: Int? = 1, - readMoreType: Bool? = false, + type: agreeButtonTextType, chooseType: Bool? = false ) { super.init(frame: .zero) - - setupUI(textType: text, - font: font, - type: type, - readMoreType: readMoreType, - chooseType: chooseType) + + setup(textType: type, chooseType: chooseType) } - + required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + public override func layout() { super.layout() - - self.addSubviews([iconImageView, textLabel, chooseLabel, readMoreLine, readMore]) - - self.snp.makeConstraints { - $0.width.equalTo(390.0) - $0.height.equalTo(44.0) - } - + + self.addSubviews([iconImageView, textLabel, chooseLabel]) + iconImageView.snp.makeConstraints { $0.width.height.equalTo(28.0) - $0.leading.equalToSuperview().offset(0.0) + $0.leading.equalToSuperview() $0.centerY.equalToSuperview() } - + textLabel.snp.makeConstraints { $0.leading.equalTo(iconImageView.snp.trailing).offset(12.0) $0.centerY.equalToSuperview() $0.height.equalTo(20.0) } - + chooseLabel.snp.makeConstraints { $0.height.equalTo(20.0) $0.centerY.equalToSuperview() $0.leading.equalTo(textLabel.snp.trailing).offset(5.0) } - - readMoreLine.snp.makeConstraints { - $0.trailing.equalToSuperview().offset(0.0) - $0.bottom.equalToSuperview().offset(-13.0) - } - - readMore.snp.makeConstraints { - $0.width.equalTo(64.0) - $0.height.equalToSuperview() - $0.trailing.equalToSuperview().offset(0.0) - $0.top.equalToSuperview().offset(0.0) - } - } - - open override func buttonAction() { - super.buttonAction() - buttonTapped() } - + public func buttonYesChecked() { checked = true iconImageView.image = DSKitAsset.Assets.yesCheckActIcon.image } - + public func buttonNoChecked() { checked = false iconImageView.image = DSKitAsset.Assets.noCheckActIcon.image } - public func editButtonType(text: String, readMoreType: Bool? = false) { - self.textLabel.text = text - - readMore.isHidden = !(readMoreType ?? true) - readMoreLine.isHidden = !(readMoreType ?? true) + public override func buttonAction() { + self.rx.tap.subscribe(onNext: { [self] in + checked ? buttonNoChecked() : buttonYesChecked() + }).disposed(by: disposeBag) } } private extension MGAgreeButton { - func setupUI(textType: agreeButtonTextType, - font: UIFont?, - type: Int?, - readMoreType: Bool?, - chooseType: Bool? + func setup(textType: agreeButtonTextType, + chooseType: Bool? = false ) { - self.textLabel.text = textType.message - self.textLabel.font = font - - setOptionalViewVisibility(shouldShow: chooseType ?? true) - - if (type != nil) != false { + textLabel.changeText(text: textType.message) + textLabel.changeFont(font: textType.font) + if chooseType == true { chooseLabel.isHidden = false } } - - func buttonTapped() { - rx.tap - .subscribe(onNext: { [self] in - checked ? buttonNoChecked() : buttonYesChecked() - }).disposed(by: disposeBag) - - readMore.rx.tap - .subscribe(onNext: { - print("자세히 보기 클릭 됨") - }).disposed(by: disposeBag) - } - - func setOptionalViewVisibility(shouldShow: Bool) { - chooseLabel.isHidden = !shouldShow - readMore.isHidden = !shouldShow - readMoreLine.isHidden = !shouldShow - } } diff --git a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymLabel /MG+Label.swift b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymLabel /MG+Label.swift index edced561..de0d4712 100644 --- a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymLabel /MG+Label.swift +++ b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymLabel /MG+Label.swift @@ -51,6 +51,10 @@ open class MGLabel: BaseLabel { public func changeText(text: String?) { textLabel.text = text } + + public func changeFont(font: UIFont?) { + textLabel.font = font + } public override func layout() { super.layout() diff --git a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymProfile/MG+ProfileType.swift b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymProfile/MG+ProfileType.swift index 6e9dafb0..4388958c 100644 --- a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymProfile/MG+ProfileType.swift +++ b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymProfile/MG+ProfileType.swift @@ -61,7 +61,7 @@ public struct MGProfileImage { switch type { case .custom: guard let customImage = customImage else { - return DSKitAsset.Assets.blueHomeTapBar.image + return DSKitAsset.Assets.introIcon.image } return customImage diff --git a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymTextField/MG+TextField.swift b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymTextField/MG+TextField.swift index 958e2b49..905ed555 100644 --- a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymTextField/MG+TextField.swift +++ b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymTextField/MG+TextField.swift @@ -1,6 +1,8 @@ import UIKit -import Then + import SnapKit +import Then + import Core import RxSwift import RxCocoa @@ -37,7 +39,7 @@ open class MGTextField: UITextField { errorLabel.text = errorMessage } } - + public var nameErrorType: TextFieldErrorType.Name? { didSet { if let errorType = nameErrorType { @@ -46,17 +48,17 @@ open class MGTextField: UITextField { } } } - + public override var placeholder: String? { didSet { placeholderLabel.text = placeholder super.placeholder = "" } } - + public convenience init(placeholder: String) { self.init(frame: .zero) - + placeholderLabel.text = placeholder } @@ -64,25 +66,24 @@ open class MGTextField: UITextField { super.init(frame: frame) setupUI() } - + required public init?(coder: NSCoder) { super.init(coder: coder) setupUI() } - + private func setupUI() { configure() - - delegate = self + bind() self.tintColor = .black } - + private func configure() { - addSubview(placeholderLabel) - addSubview(underlineView) - addSubview(errorLabel) - + addSubviews([placeholderLabel, + underlineView, + errorLabel]) + placeholderLabel.snp.makeConstraints { $0.leading.trailing.equalToSuperview() $0.bottom.equalTo(underlineView.snp.top).offset(-8.0) @@ -95,45 +96,40 @@ open class MGTextField: UITextField { $0.bottom.equalToSuperview() $0.height.equalTo(1) } - + errorLabel.snp.makeConstraints { $0.leading.trailing.equalToSuperview() $0.top.equalTo(underlineView.snp.bottom).offset(8.0) } - } -} -extension MGTextField: UITextFieldDelegate { - public func textFieldDidBeginEditing(_ textField: UITextField) { - UIView.animate(withDuration: 0.3) { - - self.underlineView.backgroundColor = DSKitAsset.Colors.blue500.color - self.placeholderLabel.font = UIFont.Pretendard.bodySmall - self.placeholderLabel.snp.updateConstraints { - $0.bottom.equalTo(self.underlineView.snp.top).offset(-(self.placeholderLabel.frame.size.height + 4)) - } - self.layoutIfNeeded() - } - } - - public func textFieldDidEndEditing(_ textField: UITextField) { - if textField.text == "" { - UIView.animate(withDuration: 0.3) { - self.underlineView.backgroundColor = DSKitAsset.Colors.gray400.color - self.placeholderLabel.font = UIFont.Pretendard.bodyLarge - self.placeholderLabel.snp.updateConstraints { - $0.bottom.equalTo(self.underlineView.snp.top).offset(-4) + private func bind() { + self.rx.controlEvent(.editingDidBegin) + .asObservable() + .subscribe(onNext: { [weak self] _ in + UIView.animate(withDuration: 0.3) { + self?.underlineView.backgroundColor = DSKitAsset.Colors.blue500.color + self?.placeholderLabel.font = UIFont.Pretendard.bodySmall + self?.placeholderLabel.snp.updateConstraints { + $0.bottom.equalTo(self!.underlineView.snp.top).offset(-(self!.placeholderLabel.frame.size.height + 4)) + } + self?.layoutIfNeeded() } - self.layoutIfNeeded() - } - } - } - - public override func touchesBegan(_ touches: Set, with event: UIEvent?) { - super.touchesBegan(touches, with: event) - if let touch = touches.first { - _ = touch.location(in: self) - } + }).disposed(by: disposeBag) + + self.rx.controlEvent(.editingDidEnd) + .asObservable() + .subscribe(onNext: { [weak self] _ in + if self?.text == "" { + UIView.animate(withDuration: 0.3) { + self?.underlineView.backgroundColor = DSKitAsset.Colors.gray400.color + self?.placeholderLabel.font = UIFont.Pretendard.bodyLarge + self?.placeholderLabel.snp.updateConstraints { + $0.bottom.equalTo(self!.underlineView.snp.top).offset(-4) + } + self?.layoutIfNeeded() + } + } + }).disposed(by: disposeBag) } } diff --git a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymVIew/MG+AgreeView.swift b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymVIew/MG+AgreeView.swift index cfbe6e08..dbd60ace 100644 --- a/Projects/Modules/DSKit/Sources/Components/MaeumGaGymVIew/MG+AgreeView.swift +++ b/Projects/Modules/DSKit/Sources/Components/MaeumGaGymVIew/MG+AgreeView.swift @@ -1,145 +1,145 @@ -import UIKit -import SnapKit -import Then -import RxSwift -import RxCocoa - -open class MGAgreeView: UIView { - - let disposeBag = DisposeBag() - - private let decorateLine1 = MGLine() - public let allAgreeButton = MGAgreeButton(text: .allAgreeText, font: UIFont.Pretendard.labelLarge) - private let decorateLine2 = MGLine() - - public let firstAgreeButton = MGAgreeButton(text: .privacyAgreeText, readMoreType: true) - public let secondAgreeButton = MGAgreeButton(text: .termsAgreeText, readMoreType: true) - public let thirdAgreeButton = MGAgreeButton(text: .ageAgreeText) - public let fourthAgreeButton = MGAgreeButton(text: .marketingAgreeText, chooseType: true) - - private var blueColor = DSKitAsset.Colors.blue500.color - private var grayColor = DSKitAsset.Colors.gray400.color - - public init () { - super.init(frame: .zero) - setupUI() - } - - public init(firstAgreeText: agreeButtonTextType, - firstReadMoreType: Bool? = false, - secondAgreeText: agreeButtonTextType, - secondReadMoreType: Bool? = false, - thirdAgreeText: agreeButtonTextType, - thirdReadMoreType: Bool? = false, - fourthAgreeText: agreeButtonTextType, - fourthReadMoreType: Bool? = false - ) { - super.init(frame: .zero) - - firstAgreeButton.editButtonType(text: firstAgreeText.message, readMoreType: firstReadMoreType) - secondAgreeButton.editButtonType(text: secondAgreeText.message, readMoreType: secondReadMoreType) - thirdAgreeButton.editButtonType(text: thirdAgreeText.message, readMoreType: thirdReadMoreType) - fourthAgreeButton.editButtonType(text: fourthAgreeText.message, readMoreType: fourthReadMoreType) - - setupUI() - } - - required public init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupUI() { - self.snp.makeConstraints { - $0.width.equalTo(390.0) - $0.height.equalTo(284.0) - } - - addSubviews([decorateLine1, - allAgreeButton, - decorateLine2, - firstAgreeButton, - secondAgreeButton, - thirdAgreeButton, - fourthAgreeButton]) - - decorateLine1.snp.makeConstraints { - $0.top.equalToSuperview() - $0.centerX.equalToSuperview() - } - - allAgreeButton.snp.makeConstraints { - $0.top.equalTo(decorateLine1.snp.bottom).offset(12.0) - $0.centerX.equalToSuperview() - } - - decorateLine2.snp.makeConstraints { - $0.top.equalTo(allAgreeButton.snp.bottom).offset(12.0) - $0.centerX.equalToSuperview() - } - - firstAgreeButton.snp.makeConstraints { - $0.top.equalTo(decorateLine2.snp.bottom).offset(8.0) - $0.centerX.equalToSuperview() - } - - secondAgreeButton.snp.makeConstraints { - $0.top.equalTo(firstAgreeButton.snp.bottom).offset(8.0) - $0.centerX.equalToSuperview() - } - - thirdAgreeButton.snp.makeConstraints { - $0.top.equalTo(secondAgreeButton.snp.bottom).offset(8.0) - $0.centerX.equalToSuperview() - } - - fourthAgreeButton.snp.makeConstraints { - $0.top.equalTo(thirdAgreeButton.snp.bottom).offset(8.0) - $0.centerX.equalToSuperview() - } - } - - public var allAgreeButtonState: Bool { - return firstAgreeButton.checked && - secondAgreeButton.checked && - thirdAgreeButton.checked && - fourthAgreeButton.checked - } - - public func setAllAgreeButtonState(_ isEnabled: Bool) { - allAgreeButton.checked = isEnabled - if isEnabled { - firstAgreeButton.buttonYesChecked() - secondAgreeButton.buttonYesChecked() - thirdAgreeButton.buttonYesChecked() - fourthAgreeButton.buttonYesChecked() - updateAllAgreeButtonState() - } else { - firstAgreeButton.buttonNoChecked() - secondAgreeButton.buttonNoChecked() - thirdAgreeButton.buttonNoChecked() - fourthAgreeButton.buttonNoChecked() - updateAllAgreeButtonState() - } - } - - public func updateAllAgreeButtonState() { - if allAgreeButtonState == true { - allAgreeButton.buttonYesChecked() - } else { - allAgreeButton.buttonNoChecked() - } - } - - public func buttonActivationChecked(button: MGCheckButton) -> Bool { - let shouldActivateButton = firstAgreeButton.checked && - secondAgreeButton.checked && - thirdAgreeButton.checked && - !fourthAgreeButton.checked - - button.isEnabled = shouldActivateButton - button.backgroundColor = shouldActivateButton ? blueColor : grayColor - button.textLabel.textColor = shouldActivateButton ? .white : DSKitAsset.Colors.gray200.color - - return shouldActivateButton - } -} +//import UIKit +//import SnapKit +//import Then +//import RxSwift +//import RxCocoa +// +//open class MGAgreeView: UIView { +// +// let disposeBag = DisposeBag() +// +// private let decorateLine1 = MGLine() +// public let allAgreeButton = MGAgreeButton(text: .allAgreeText, font: UIFont.Pretendard.labelLarge) +// private let decorateLine2 = MGLine() +// +// public let firstAgreeButton = MGAgreeButton(text: .privacyAgreeText, readMoreType: true) +// public let secondAgreeButton = MGAgreeButton(text: .termsAgreeText, readMoreType: true) +// public let thirdAgreeButton = MGAgreeButton(text: .ageAgreeText) +// public let fourthAgreeButton = MGAgreeButton(text: .marketingAgreeText, chooseType: true) +// +// private var blueColor = DSKitAsset.Colors.blue500.color +// private var grayColor = DSKitAsset.Colors.gray400.color +// +// public init () { +// super.init(frame: .zero) +// setupUI() +// } +// +// public init(firstAgreeText: agreeButtonTextType, +// firstReadMoreType: Bool? = false, +// secondAgreeText: agreeButtonTextType, +// secondReadMoreType: Bool? = false, +// thirdAgreeText: agreeButtonTextType, +// thirdReadMoreType: Bool? = false, +// fourthAgreeText: agreeButtonTextType, +// fourthReadMoreType: Bool? = false +// ) { +// super.init(frame: .zero) +// +// firstAgreeButton.editButtonType(text: firstAgreeText.message, readMoreType: firstReadMoreType) +// secondAgreeButton.editButtonType(text: secondAgreeText.message, readMoreType: secondReadMoreType) +// thirdAgreeButton.editButtonType(text: thirdAgreeText.message, readMoreType: thirdReadMoreType) +// fourthAgreeButton.editButtonType(text: fourthAgreeText.message, readMoreType: fourthReadMoreType) +// +// setupUI() +// } +// +// required public init?(coder: NSCoder) { +// fatalError("init(coder:) has not been implemented") +// } +// +// private func setupUI() { +// self.snp.makeConstraints { +// $0.width.equalTo(390.0) +// $0.height.equalTo(284.0) +// } +// +// addSubviews([decorateLine1, +// allAgreeButton, +// decorateLine2, +// firstAgreeButton, +// secondAgreeButton, +// thirdAgreeButton, +// fourthAgreeButton]) +// +// decorateLine1.snp.makeConstraints { +// $0.top.equalToSuperview() +// $0.centerX.equalToSuperview() +// } +// +// allAgreeButton.snp.makeConstraints { +// $0.top.equalTo(decorateLine1.snp.bottom).offset(12.0) +// $0.centerX.equalToSuperview() +// } +// +// decorateLine2.snp.makeConstraints { +// $0.top.equalTo(allAgreeButton.snp.bottom).offset(12.0) +// $0.centerX.equalToSuperview() +// } +// +// firstAgreeButton.snp.makeConstraints { +// $0.top.equalTo(decorateLine2.snp.bottom).offset(8.0) +// $0.centerX.equalToSuperview() +// } +// +// secondAgreeButton.snp.makeConstraints { +// $0.top.equalTo(firstAgreeButton.snp.bottom).offset(8.0) +// $0.centerX.equalToSuperview() +// } +// +// thirdAgreeButton.snp.makeConstraints { +// $0.top.equalTo(secondAgreeButton.snp.bottom).offset(8.0) +// $0.centerX.equalToSuperview() +// } +// +// fourthAgreeButton.snp.makeConstraints { +// $0.top.equalTo(thirdAgreeButton.snp.bottom).offset(8.0) +// $0.centerX.equalToSuperview() +// } +// } +// +// public var allAgreeButtonState: Bool { +// return firstAgreeButton.checked && +// secondAgreeButton.checked && +// thirdAgreeButton.checked && +// fourthAgreeButton.checked +// } +// +// public func setAllAgreeButtonState(_ isEnabled: Bool) { +// allAgreeButton.checked = isEnabled +// if isEnabled { +// firstAgreeButton.buttonYesChecked() +// secondAgreeButton.buttonYesChecked() +// thirdAgreeButton.buttonYesChecked() +// fourthAgreeButton.buttonYesChecked() +// updateAllAgreeButtonState() +// } else { +// firstAgreeButton.buttonNoChecked() +// secondAgreeButton.buttonNoChecked() +// thirdAgreeButton.buttonNoChecked() +// fourthAgreeButton.buttonNoChecked() +// updateAllAgreeButtonState() +// } +// } +// +// public func updateAllAgreeButtonState() { +// if allAgreeButtonState == true { +// allAgreeButton.buttonYesChecked() +// } else { +// allAgreeButton.buttonNoChecked() +// } +// } +// +// public func buttonActivationChecked(button: MGCheckButton) -> Bool { +// let shouldActivateButton = firstAgreeButton.checked && +// secondAgreeButton.checked && +// thirdAgreeButton.checked && +// !fourthAgreeButton.checked +// +// button.isEnabled = shouldActivateButton +// button.backgroundColor = shouldActivateButton ? blueColor : grayColor +// button.textLabel.textColor = shouldActivateButton ? .white : DSKitAsset.Colors.gray200.color +// +// return shouldActivateButton +// } +//} diff --git a/Projects/Modules/MGNetworks/Sources/API/Auth/AppleAPI.swift b/Projects/Modules/MGNetworks/Sources/API/Auth/AppleAPI.swift index 4aa2c63b..757470eb 100644 --- a/Projects/Modules/MGNetworks/Sources/API/Auth/AppleAPI.swift +++ b/Projects/Modules/MGNetworks/Sources/API/Auth/AppleAPI.swift @@ -1,27 +1,25 @@ import Foundation -import Alamofire import Moya import Core - -import TokenManager +import Alamofire public enum AppleAPI { - case appleLogin case appleSignup(nickname: String, accessToken: String) - case appleRecovery + case appleLogin(accessToken: String) + case appleRecovery(accessToken: String) } extension AppleAPI: BaseAPI { - + public static var apiType: APIType = .apple public var path: String { switch self { - case .appleLogin: - return "/login" case .appleSignup: return "/signup" + case .appleLogin: + return "/login" case .appleRecovery: return "/recovery" } @@ -29,10 +27,10 @@ extension AppleAPI: BaseAPI { public var method: Moya.Method { switch self { - case .appleLogin: - return .get case .appleSignup: return .post + case .appleLogin: + return .get case .appleRecovery: return .put } @@ -41,13 +39,23 @@ extension AppleAPI: BaseAPI { public var task: Moya.Task { switch self { case let .appleSignup(nickname, accessToken): + let bodyParameters: [String: Any] = [ + "nickname": nickname + ] + let urlParameters: [String: Any] = [ + "access_token": accessToken + ] + return .requestCompositeParameters(bodyParameters: bodyParameters, bodyEncoding: JSONEncoding.default, urlParameters: urlParameters) + case let .appleLogin(accessToken): + let parameters: [String: Any] = [ + "access_token": accessToken + ] + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) + case let .appleRecovery(accessToken): let parameters: [String: Any] = [ - "nickname": nickname, "access_token": accessToken ] - return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) - case .appleLogin, .appleRecovery: - return .requestPlain + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) } } diff --git a/Projects/Modules/MGNetworks/Sources/API/Auth/AuthAPI.swift b/Projects/Modules/MGNetworks/Sources/API/Auth/AuthAPI.swift new file mode 100644 index 00000000..4a5b38f4 --- /dev/null +++ b/Projects/Modules/MGNetworks/Sources/API/Auth/AuthAPI.swift @@ -0,0 +1,59 @@ +import Foundation + +import Moya +import Core +import Alamofire + +public enum AuthAPI { + case delete(accessToken: String) + case reissuanceToken(refreshToken: String) + case nickname(nickname: String) +} + +extension AuthAPI: BaseAPI { + + public static var apiType: APIType = .auth + + public var path: String { + switch self { + case .delete: + return "" + case .reissuanceToken: + return "/re-issue" + case let .nickname(nickname): + return "/nickname/\(nickname)" + } + } + + public var method: Moya.Method { + switch self { + case .delete: + return .delete + case .reissuanceToken: + return .get + case .nickname: + return .get + } + } + + public var task: Moya.Task { + switch self { + case .delete, .nickname: + return .requestPlain + case let .reissuanceToken(refreshToken): + let parameters: [String: Any] = [ + "refresh_token": refreshToken + ] + return .requestParameters(parameters: parameters, encoding: URLEncoding.default) + } + } + + public var headers: [String : String]? { + switch self { + case let .delete(accessToken): + return ["Authorization": "\(accessToken)"] + default: + return nil + } + } +} diff --git a/Projects/Modules/MGNetworks/Sources/API/Auth/CsrfAPI.swift b/Projects/Modules/MGNetworks/Sources/API/Auth/CsrfAPI.swift deleted file mode 100644 index 8ef9ab27..00000000 --- a/Projects/Modules/MGNetworks/Sources/API/Auth/CsrfAPI.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Foundation - -import Alamofire -import Moya - -import Core - -public enum CsrfAPI { - case getCSRFToken -} - -extension CsrfAPI: BaseAPI { - - public static var apiType: APIType = .CSRFToken - - public var path: String { - switch self { - case .getCSRFToken: - return "/csrf" - } - } - - public var method: Moya.Method { - return .get - } - - public var task: Task { - return .requestPlain - } - - public var headers: [String : String]? { - return nil - } -} diff --git a/Projects/Modules/MGNetworks/Sources/API/Auth/GoogleAPI.swift b/Projects/Modules/MGNetworks/Sources/API/Auth/GoogleAPI.swift index cdb1103e..fb168047 100644 --- a/Projects/Modules/MGNetworks/Sources/API/Auth/GoogleAPI.swift +++ b/Projects/Modules/MGNetworks/Sources/API/Auth/GoogleAPI.swift @@ -1,15 +1,13 @@ import Foundation -import Alamofire import Moya import Core - -import TokenManager +import Alamofire public enum GoogleAPI { - case googleLogin case googleSignup(nickname: String, accessToken: String) - case googleRecovery + case googleLogin(accessToken: String) + case googleRecovery(accessToken: String) } extension GoogleAPI: BaseAPI { @@ -18,10 +16,10 @@ extension GoogleAPI: BaseAPI { public var path: String { switch self { - case .googleLogin: - return "/login" case .googleSignup: return "/signup" + case .googleLogin: + return "/login" case .googleRecovery: return "/recovery" } @@ -29,10 +27,10 @@ extension GoogleAPI: BaseAPI { public var method: Moya.Method { switch self { - case .googleLogin: - return .get case .googleSignup: return .post + case .googleLogin: + return .get case .googleRecovery: return .put } @@ -41,13 +39,23 @@ extension GoogleAPI: BaseAPI { public var task: Moya.Task { switch self { case let .googleSignup(nickname, accessToken): + let bodyParameters: [String: Any] = [ + "nickname": nickname + ] + let urlParameters: [String: Any] = [ + "access_token": accessToken + ] + return .requestCompositeParameters(bodyParameters: bodyParameters, bodyEncoding: JSONEncoding.default, urlParameters: urlParameters) + case let .googleLogin(accessToken): + let parameters: [String: Any] = [ + "access_token": accessToken + ] + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) + case let .googleRecovery(accessToken): let parameters: [String: Any] = [ - "nickname": nickname, "access_token": accessToken ] - return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) - case .googleLogin, .googleRecovery: - return .requestPlain + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) } } diff --git a/Projects/Modules/MGNetworks/Sources/API/Auth/KakaoAPI.swift b/Projects/Modules/MGNetworks/Sources/API/Auth/KakaoAPI.swift index 0287c819..ca73cb90 100644 --- a/Projects/Modules/MGNetworks/Sources/API/Auth/KakaoAPI.swift +++ b/Projects/Modules/MGNetworks/Sources/API/Auth/KakaoAPI.swift @@ -1,69 +1,65 @@ import Foundation -import Alamofire import Moya import Core - -import TokenManager +import Alamofire public enum KakaoAPI { - case kakaoLogin case kakaoSignup(nickname: String, accessToken: String) - case kakaoRecovery + case kakaoLogin(accessToken: String) + case kakaoRecovery(accessToken: String) } extension KakaoAPI: BaseAPI { - + public static var apiType: APIType = .kakao public var path: String { switch self { - case .kakaoLogin: - return "/login" case .kakaoSignup: return "/signup" + case .kakaoLogin: + return "/login" case .kakaoRecovery: return "/recovery" } } - + public var method: Moya.Method { switch self { - case .kakaoLogin: - return .get case .kakaoSignup: return .post + case .kakaoLogin: + return .get case .kakaoRecovery: return .put } } - + public var task: Moya.Task { switch self { case let .kakaoSignup(nickname, accessToken): + let bodyParameters: [String: Any] = [ + "nickname": nickname + ] + let urlParameters: [String: Any] = [ + "access_token": accessToken + ] + return .requestCompositeParameters(bodyParameters: bodyParameters, bodyEncoding: JSONEncoding.default, urlParameters: urlParameters) + case let .kakaoLogin(accessToken): + let parameters: [String: Any] = [ + "access_token": accessToken + ] + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) + case let .kakaoRecovery(accessToken): let parameters: [String: Any] = [ - "nickname": nickname, "access_token": accessToken ] - return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) - case .kakaoLogin, .kakaoRecovery: - return .requestPlain + return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString) } } - + public var headers: [String : String]? { - switch self { - case .kakaoSignup: - if let csrfToken = TokenManagerImpl().get(key: .CSRFToken) { - return [ - "X-XSRF-TOKEN": csrfToken - ] - } else { - return nil - } - case .kakaoLogin, .kakaoRecovery: - return nil - } + return nil } - } diff --git a/Projects/Modules/MGNetworks/Sources/Foundation/Base/APIType.swift b/Projects/Modules/MGNetworks/Sources/Foundation/Base/APIType.swift index 77bea87d..9dde3637 100644 --- a/Projects/Modules/MGNetworks/Sources/Foundation/Base/APIType.swift +++ b/Projects/Modules/MGNetworks/Sources/Foundation/Base/APIType.swift @@ -3,7 +3,8 @@ import RxMoya import Core public enum APIType { - + + case auth case CSRFToken // Oauth diff --git a/Projects/Modules/MGNetworks/Sources/Foundation/Base/BaseAPI.swift b/Projects/Modules/MGNetworks/Sources/Foundation/Base/BaseAPI.swift index 7acfdc0d..5c03e9dd 100644 --- a/Projects/Modules/MGNetworks/Sources/Foundation/Base/BaseAPI.swift +++ b/Projects/Modules/MGNetworks/Sources/Foundation/Base/BaseAPI.swift @@ -13,7 +13,7 @@ public protocol BaseAPI: TargetType { extension BaseAPI { public var baseURL: URL { - var appURL = Config.setConfigTypeAndGetBaseURL(.application) + var appURL = Config.setConfigTypeAndGetBaseURL(.devTest) // var devURL = Config.setConfigTypeAndGetBaseURL(.devTest) switch Self.apiType { @@ -25,6 +25,8 @@ extension BaseAPI { appURL += "/google" case .apple: appURL += "/apple" + case .auth: + appURL += "/auth" } guard let url = URL(string: appURL) else { diff --git a/Projects/Modules/MGNetworks/Sources/ResourcesService/AuthResourcesService.swift b/Projects/Modules/MGNetworks/Sources/ResourcesService/AuthResourcesService.swift index 85610fd8..3530b68b 100644 --- a/Projects/Modules/MGNetworks/Sources/ResourcesService/AuthResourcesService.swift +++ b/Projects/Modules/MGNetworks/Sources/ResourcesService/AuthResourcesService.swift @@ -12,6 +12,7 @@ public enum AuthResourcesService { public static let cancel = DSKitAsset.Assets.circleCancel.image public static let mainLogo = DSKitAsset.Assets.mainLogo.image public static let leftArrow = DSKitAsset.Assets.blackLeftBarArrow.image + public static let introIcon = DSKitAsset.Assets.introIcon.image } public enum Colors { diff --git a/Projects/Modules/MGNetworks/Sources/Service/AuthService.swift b/Projects/Modules/MGNetworks/Sources/Service/AuthService.swift index 2a58f671..5b44cf3c 100644 --- a/Projects/Modules/MGNetworks/Sources/Service/AuthService.swift +++ b/Projects/Modules/MGNetworks/Sources/Service/AuthService.swift @@ -1,5 +1,4 @@ import UIKit -import AuthenticationServices import RxSwift import RxCocoa @@ -7,132 +6,115 @@ import RxCocoa import RxMoya import Moya -import Domain import DSKit import TokenManager +import Domain +import MGLogger import KakaoSDKUser +import KakaoSDKAuth + +import AuthenticationServices public class AuthService: NSObject { - let provider = MoyaProvider() let kakaoProvider = MoyaProvider() let googleProvider = MoyaProvider() let appleProvider = MoyaProvider() - - public func googleSignup(nickname: String, accessToken: String) -> Single { - return googleProvider.rx.request(.googleSignup(nickname: nickname, accessToken: accessToken)) - .mapString() - } - - public func googleLogin() -> Single { - return googleProvider.rx.request(.googleLogin) - .mapString() - } - -// public func googleTokenState() -> Single { -// return Single.create { [weak self] single in - -// } -// } - + let authProvider = MoyaProvider() + private let keychainAuthorization = KeychainType.authorizationToken private let appleSignupSubject = PublishSubject() - public func requestToken() -> Single { - return Single.just(true) + public func nicknameCheck(nickname: String) -> Single { + return authProvider.rx.request(.nickname(nickname: nickname)) + .filterSuccessfulStatusCodes() } - - public func kakaoLogin() -> Single { - return kakaoProvider.rx.request(.kakaoLogin) - .mapString() + + public func oauthSingup(nickname: String, accessToken: String, oauth: OauthType) -> Single { + switch oauth { + case .google: + return googleSignup(nickname: nickname, accessToken: accessToken) + case .kakao: + return kakaoSignup(nickname: nickname, accessToken: accessToken) + case .apple: + return appleSignup(nickname: nickname, accessToken: accessToken) + } } + +// public func oauthLogin(accessToken: String, oauth: OauthType) -> Observable { +// switch oauth { +// case .google: +// return googleLogin(accessToken: accessToken) +// case .kakao: +// return kakaoLogin(accessToken: accessToken) +// case .apple: +// return appleLogin(accessToken: accessToken) +// } +// } - public func kakaoSignup(nickname: String, accessToken: String) -> Single { - return kakaoProvider.rx.request(.kakaoSignup(nickname: nickname, accessToken: accessToken)) - .mapString() + public func oauthLogin(accessToken: String, oauth: OauthType) -> Single { + switch oauth { + case .google: + return googleLogin(accessToken: accessToken) + case .kakao: + return kakaoLogin(accessToken: accessToken) + case .apple: + return appleLogin(accessToken: accessToken) + } } - - public func kakaoRecovery() -> Single { - return kakaoProvider.rx.request(.kakaoRecovery) - .mapString() + + public func oauthRecovery(accessToken: String, oauth: OauthType) -> Single { + switch oauth { + case .google: + return googleRecovery(accessToken: accessToken) + case .kakao: + return kakaoRecovery(accessToken: accessToken) + case .apple: + return appleRecovery(accessToken: accessToken) + } } - - public func kakaoTokenState() -> Single { - return Single.create { [weak self] single in + + public func kakaoButtonTap() -> Single { + return Single.create { single in if UserApi.isKakaoTalkLoginAvailable() { UserApi.shared.loginWithKakaoTalk { (oauthToken, error) in - if let error = error { - single(.success(false)) + if let oauthToken = oauthToken { + single(.success(oauthToken)) } else { - guard let self = self, let accessToken = oauthToken?.accessToken else { - single(.success(false)) - return - } - if TokenManagerImpl().save(token: accessToken, with: self.keychainAuthorization) { - single(.success(true)) - } else { - single(.success(false)) - } + single(.success(nil)) } } } else { - single(.success(false)) + single(.success(nil)) } return Disposables.create() } } - - public func getCSRFToken() -> Single { - return provider.rx.request(.getCSRFToken) - .flatMap { response -> Single in - if let setCookieHeader = response.response?.allHeaderFields["Set-Cookie"] as? String { - let cookies = setCookieHeader.components(separatedBy: ", ") - for cookie in cookies { - if cookie.hasPrefix("XSRF-TOKEN") { - let token = cookie.components(separatedBy: "=")[1].components(separatedBy: ";")[0] - return Single.just(token) - } - } - } - return Single.error(AuthError.tokenNotFound) - } + + public func requestToken() -> Single { + return Single.just(true) } - + public func requestIntroData() -> Single { return Single.just(IntroModel(image: DSKitAsset.Assets.airSqt.image, mainTitle: "이제 헬창이 되어보세요!", subTitle: "저희의 좋은 서비스를 통해 즐거운 생활을\n즐겨보세요!")) } - - public func appleLogin() -> Single { - return appleProvider.rx.request(.appleLogin) - .mapString() - } - - public func appleSignup(nickname: String, accessToken: String) -> Single { - return appleProvider.rx.request(.appleSignup(nickname: nickname, accessToken: accessToken)) - .mapString() - } - - public func appleRecovery() -> Single { - return appleProvider.rx.request(.appleRecovery) - .mapString() - } - - public func appleSignup() -> Single { + + public func appleButtonTap() -> Single { let appleProvider = ASAuthorizationAppleIDProvider() let request = appleProvider.createRequest() request.requestedScopes = [.fullName, .email] - + let controller = ASAuthorizationController(authorizationRequests: [request]) controller.performRequests() - + controller.delegate = self - + return appleSignupSubject.take(1).asSingle() } - + public override init() { - + } } @@ -146,7 +128,6 @@ extension AuthService: ASAuthorizationControllerDelegate { let tokenString = String(data: identityToken, encoding: .utf8) { appleSignupSubject.onNext(tokenString) appleSignupSubject.onCompleted() - TokenManagerImpl().save(token: tokenString, with: keychainAuthorization) } default: break @@ -157,3 +138,47 @@ extension AuthService: ASAuthorizationControllerDelegate { appleSignupSubject.onError(error) } } + +private extension AuthService { + func googleSignup(nickname: String, accessToken: String) -> Single { + return googleProvider.rx.request(.googleSignup(nickname: nickname, accessToken: accessToken)) + } + + func googleLogin(accessToken: String) -> Single { + return googleProvider.rx.request(.googleLogin(accessToken: accessToken)) + } + + func googleRecovery(accessToken: String) -> Single { + return googleProvider.rx.request(.googleRecovery(accessToken: accessToken)) + } + + func kakaoSignup(nickname: String, accessToken: String) -> Single { + return kakaoProvider.rx.request(.kakaoSignup(nickname: nickname, accessToken: accessToken)) + } + + func kakaoLogin(accessToken: String) -> Single { + return kakaoProvider.rx.request(.kakaoLogin(accessToken: accessToken)) + } + + func kakaoRecovery(accessToken: String) -> Single { + return kakaoProvider.rx.request(.kakaoRecovery(accessToken: accessToken)) + } + + func appleSignup(nickname: String, accessToken: String) -> Single { + return appleProvider.rx.request(.appleSignup(nickname: nickname, accessToken: accessToken)) + } + + func appleLogin(accessToken: String) -> Single { + return appleProvider.rx.request(.appleLogin(accessToken: accessToken)) + } + + func appleRecovery(accessToken: String) -> Single { + return appleProvider.rx.request(.appleRecovery(accessToken: accessToken)) + } + + // public func appleTokenState() -> Single { + // return Single.create { [weak self] single in + + // } + // } +} diff --git a/Projects/Modules/TokenManager/Sources/KeychainType.swift b/Projects/Modules/TokenManager/Sources/KeychainType.swift index eccf99ff..a05d3baa 100644 --- a/Projects/Modules/TokenManager/Sources/KeychainType.swift +++ b/Projects/Modules/TokenManager/Sources/KeychainType.swift @@ -2,6 +2,7 @@ import Foundation public enum KeychainType: String { case authorizationToken + case refreshToken case CSRFToken case test }