From 0c06cd71f87b8a1837dc88a07d9bf7b480e77a5f Mon Sep 17 00:00:00 2001 From: Melt Date: Fri, 28 Apr 2023 04:47:13 +0900 Subject: [PATCH] =?UTF-8?q?[Refactor]=20MVVM=20=ED=8C=A8=ED=84=B4=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=ED=98=95=EC=8B=9D,?= =?UTF-8?q?=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=ED=95=A0=EB=95=8C=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=EB=B2=84=ED=8A=BC=20=ED=99=9C=EC=84=B1=ED=99=94=20#10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthScene/View/AuthTextField.swift | 11 ++-- .../ViewContoller/OnboardingVC.swift | 2 +- .../AuthScene/ViewContoller/SignInVC.swift | 36 ++++++------ .../AuthScene/ViewModel/SignInViewModel.swift | 55 +++++++++++++++++++ .../Builder/AuthTextFieldBuilder.swift | 2 +- .../SOPTving/Utility/Extension/String+.swift | 8 +++ 6 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 SOPTving/SOPTving/Presentation/AuthScene/ViewModel/SignInViewModel.swift diff --git a/SOPTving/SOPTving/Presentation/AuthScene/View/AuthTextField.swift b/SOPTving/SOPTving/Presentation/AuthScene/View/AuthTextField.swift index 0c0936d..c914e06 100644 --- a/SOPTving/SOPTving/Presentation/AuthScene/View/AuthTextField.swift +++ b/SOPTving/SOPTving/Presentation/AuthScene/View/AuthTextField.swift @@ -14,16 +14,16 @@ final class AuthTextField : UITextField { //MARK: - Properties - typealias handler = (() -> Void) + typealias handler = ((String) -> Void) private var updateHandler: handler? enum TextFieldType { - case id + case email case password var isSecureTextEntry: Bool { switch self { - case .id: return false + case .email: return false case .password: return true } } @@ -71,7 +71,7 @@ final class AuthTextField : UITextField { //MARK: - Life Cycle - init(viewType: TextFieldType = .id) { + init(viewType: TextFieldType = .email) { self.textFieldType = viewType super.init(frame: .zero) @@ -164,7 +164,8 @@ extension AuthTextField: UITextFieldDelegate { func textFieldDidChangeSelection(_ textField: UITextField) { updateClearButtonUI() - updateHandler?() + guard let text = textField.text else { return} + updateHandler?(text) } } diff --git a/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/OnboardingVC.swift b/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/OnboardingVC.swift index 2eb85dd..1a298ab 100644 --- a/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/OnboardingVC.swift +++ b/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/OnboardingVC.swift @@ -55,7 +55,7 @@ extension OnboardingVC { @objc private func startButtonDidTap() { - let signInVC = SignInVC(viewModel: DefaultSignInViewModel()) + let signInVC = SignInVC(viewModel: DefaultSignInViewModel(email: "", password: "")) present(signInVC, animated: true) } } diff --git a/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/SignInVC.swift b/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/SignInVC.swift index e3a5740..7a2728f 100644 --- a/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/SignInVC.swift +++ b/SOPTving/SOPTving/Presentation/AuthScene/ViewContoller/SignInVC.swift @@ -37,7 +37,7 @@ final class SignInVC: UIViewController { // 그냥 TextField에 프로퍼티 줄어든 버전이랄까 // 기본 프로퍼티만 추가할땐 그닥 효율성 못느낌. // addRightButton 과 같은 함수 추가할땐 좋은 패턴인듯. - private let idTextField = AuthTextFieldBuilder(viewType: .id) + private let emailTextField = AuthTextFieldBuilder(viewType: .email) .setText(color: .white, font: .tvingSemiBold(ofSize: 16)) .setPlaceholder(text: "아이디", color: .tvingLightGray) .setLeftPaddingAmount(22) @@ -73,7 +73,6 @@ final class SignInVC: UIViewController { style() hierarchy() layout() - updateSignInButtonUI() } required init?(coder: NSCoder) { @@ -86,26 +85,31 @@ final class SignInVC: UIViewController { extension SignInVC { private func target() { - idTextField.setUpdateHandler { [weak self] in + emailTextField.setUpdateHandler { [weak self] text in guard let self else { return } - self.updateSignInButtonUI() + self.viewModel.idTextFieldDidChangeEvent(text) } - passwordTextField.setUpdateHandler { [weak self] in + passwordTextField.setUpdateHandler { [weak self] text in guard let self else { return } - self.updateSignInButtonUI() + self.viewModel.passwordTextFieldDidChangeEvent(text) } } private func binding() { - + viewModel.isValidEmail.observe(on: self) { bool in + + } + viewModel.isValidPassword + viewModel.ableToLogin.observe(on: self) { isEnabled in + print("🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏") + self.updateSignInButtonUI(isEnabled) + } } // 이부분을 뷰모델이 했으면 좋겠다 - private func updateSignInButtonUI() { - let isEnabled = idTextField.hasText && passwordTextField.hasText - - + private func updateSignInButtonUI(_ isEnabled: Bool) { + let backgroundColor: UIColor = isEnabled ? .tvingRed : .black let borderColor: UIColor = isEnabled ? .tvingRed : .tvingLightGray @@ -139,7 +143,7 @@ extension SignInVC { private func hierarchy() { view.addSubviews(backButton, titleLabel, - idTextField, + emailTextField, passwordTextField, signInButton) } @@ -157,16 +161,16 @@ extension SignInVC { $0.top.equalToSuperview().offset(50) } - idTextField.snp.makeConstraints { + emailTextField.snp.makeConstraints { $0.top.equalTo(titleLabel.snp.bottom).offset(31) $0.leading.trailing.equalToSuperview().inset(20) $0.height.equalTo(52) } passwordTextField.snp.makeConstraints { - $0.top.equalTo(idTextField.snp.bottom).offset(10) - $0.leading.trailing.equalTo(idTextField) - $0.height.equalTo(idTextField) + $0.top.equalTo(emailTextField.snp.bottom).offset(10) + $0.leading.trailing.equalTo(emailTextField) + $0.height.equalTo(emailTextField) } signInButton.snp.makeConstraints { diff --git a/SOPTving/SOPTving/Presentation/AuthScene/ViewModel/SignInViewModel.swift b/SOPTving/SOPTving/Presentation/AuthScene/ViewModel/SignInViewModel.swift new file mode 100644 index 0000000..18545ca --- /dev/null +++ b/SOPTving/SOPTving/Presentation/AuthScene/ViewModel/SignInViewModel.swift @@ -0,0 +1,55 @@ +// +// SignInViewModel.swift +// SOPTving +// +// Created by 장석우 on 2023/04/28. +// + +import Foundation + +protocol SignInViewModelInput { + func idTextFieldDidChangeEvent(_ text: String) + func passwordTextFieldDidChangeEvent(_ text: String) +} + +protocol SignInViewModelOutput { + var isValidEmail: Observable { get } + var isValidPassword: Observable { get } + var ableToLogin: Observable { get } +} + +protocol SignInViewModel: SignInViewModelInput, SignInViewModelOutput { } + +final class DefaultSignInViewModel: SignInViewModel { + + private var email: String + private var password: String + + //MARK: - Output + + var isValidEmail: Observable = Observable(false) + var isValidPassword: Observable = Observable(false) + var ableToLogin: Observable = Observable(false) + + //MARK: - Init + + init(email: String, password: String) { + self.email = email + self.password = password + } + +} + +extension DefaultSignInViewModel { + + func idTextFieldDidChangeEvent(_ text: String) { + self.isValidEmail.value = text.isEmailFormat && text.isMoreThan(8) + self.ableToLogin.value = isValidEmail.value && isValidPassword.value + } + + func passwordTextFieldDidChangeEvent(_ text: String) { + self.isValidPassword.value = text.isMoreThan(8) + self.ableToLogin.value = isValidEmail.value && isValidPassword.value + } + +} diff --git a/SOPTving/SOPTving/Utility/Builder/AuthTextFieldBuilder.swift b/SOPTving/SOPTving/Utility/Builder/AuthTextFieldBuilder.swift index 54c183f..e38ab60 100644 --- a/SOPTving/SOPTving/Utility/Builder/AuthTextFieldBuilder.swift +++ b/SOPTving/SOPTving/Utility/Builder/AuthTextFieldBuilder.swift @@ -87,7 +87,7 @@ final class AuthTextFieldDirector { func buildIDTextField() -> AuthTextField { - builder = AuthTextFieldBuilder(viewType: .id) + builder = AuthTextFieldBuilder(viewType: .email) .setLeftPaddingAmount(20) .setText(color: .white, font: .tvingMedium(ofSize: 16)) .setPlaceholder(text: "아이디", color: .tvingLightGray) diff --git a/SOPTving/SOPTving/Utility/Extension/String+.swift b/SOPTving/SOPTving/Utility/Extension/String+.swift index 16d5e4b..1555c76 100644 --- a/SOPTving/SOPTving/Utility/Extension/String+.swift +++ b/SOPTving/SOPTving/Utility/Extension/String+.swift @@ -13,4 +13,12 @@ extension String { let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}" return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: self) } + + var hasText: Bool { + return !isEmpty + } + + func isMoreThan(_ length: Int) -> Bool { + return self.count > length + } }