Skip to content

Commit

Permalink
[Merge] MVVM 리팩토링 (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
seuriseuljjeok authored Jun 28, 2024
2 parents dd60da8 + 0237df0 commit 9fdd74b
Show file tree
Hide file tree
Showing 34 changed files with 842 additions and 292 deletions.
68 changes: 52 additions & 16 deletions Tving_CloneProject/Tving_CloneProject.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import UIKit

import Then

class TabBarViewController: UITabBarController {
final class TabBarViewController: UITabBarController {

// MARK: - UI Components

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// String+.swift
// Tving_CloneProject
//
// Created by 윤희슬 on 5/31/24.
//

import Foundation

extension String {

static func calculateDate() -> String {
let today = Date()
let calendar = Calendar.current
var dateComponents = DateComponents()
dateComponents.day = -1

if let oneDayAgo = calendar.date(byAdding: dateComponents, to: today) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd"

let oneDayAgoString = dateFormatter.string(from: oneDayAgo)
return oneDayAgoString
} else {
return ""
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// ObservablePattern.swift
// Tving_CloneProject
//
// Created by 윤희슬 on 5/30/24.
//

import Foundation

final class ObservablePattern<T> { // --- a

var value: T? { // --- b
didSet {
self.listener?(value)
}
}

init(_ value: T?) {
self.value = value
}

private var listener: ((T?) -> Void)? // --- c

func bind(_ listener: @escaping (T?) -> Void) {
listener(value) // 생략 가능, 여기선 시작되는 순간부터 초기값을 갖고 동작하기 위해 사용
self.listener = listener
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ protocol LoginViewDelegate: AnyObject {
func pushToWelcomeVC(id: String)
}

class LoginView: UIView {
final class LoginView: UIView {

// MARK: - UI Properties

Expand All @@ -38,6 +38,8 @@ class LoginView: UIView {

weak var delegate: LoginViewDelegate?

private let loginViewModel: LoginViewModel = LoginViewModel()


// MARK: - Life Cycles

Expand All @@ -61,12 +63,10 @@ class LoginView: UIView {
private extension LoginView {

func setHierarchy() {

self.addSubviews(idTextField, pwTextField, loginButton)
}

func setLayout() {

idTextField.snp.makeConstraints {
$0.top.centerX.width.equalToSuperview()
$0.height.equalTo(52)
Expand All @@ -87,7 +87,6 @@ private extension LoginView {
}

func setStyle() {

self.backgroundColor = UIColor(resource: .black)

idTextField.do {
Expand Down Expand Up @@ -203,17 +202,10 @@ private extension LoginView {

@objc
func textFieldChange() {
let id = self.idTextField.text ?? ""
let pw = self.pwTextField.text ?? ""

if !id.isEmpty {
idClearButton.isHidden = false
} else {
pwClearButton.isHidden = false
maskButton.isHidden = false
}
let id = self.idTextField.text
let pw = self.pwTextField.text

setLoginButton(isEnabled: !id.isEmpty && !pw.isEmpty)
setLoginButton(isEnabled: loginViewModel.checkValid(id: id, pw: pw))
}

@objc
Expand All @@ -224,9 +216,9 @@ private extension LoginView {
@objc
func clearButtonTapped(_ sender: UIButton) {
if sender.tag == 0 {
self.idTextField.text = ""
self.loginViewModel.clearText(textfield: self.idTextField)
} else {
self.pwTextField.text = ""
self.loginViewModel.clearText(textfield: self.pwTextField)
}
setLoginButton(isEnabled: false)
}
Expand All @@ -246,23 +238,11 @@ private extension LoginView {
extension LoginView: UITextFieldDelegate {

func textFieldDidBeginEditing (_ textField: UITextField) {

if textField.placeholder == "아이디" {
self.idTextField.layer.borderWidth = 1
self.idTextField.layer.borderColor = UIColor(resource: .grey2).cgColor
} else {
self.pwTextField.layer.borderWidth = 1
self.pwTextField.layer.borderColor = UIColor(resource: .grey2).cgColor
}

textField.layer.borderWidth = 1
textField.layer.borderColor = UIColor(resource: .grey2).cgColor
}

func textFieldDidEndEditing(_ textField: UITextField) {

if textField.placeholder == "아이디" {
self.idTextField.layer.borderWidth = 0
} else {
self.pwTextField.layer.borderWidth = 0
}
textField.layer.borderWidth = 0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ protocol CreateNicknameVCDelegate: AnyObject {
func saveUserNickname(nickname: String)
}

class CreateNicknameViewController: UIViewController {
final class CreateNicknameViewController: UIViewController {

// MARK: - UI Properties

Expand All @@ -34,6 +34,8 @@ class CreateNicknameViewController: UIViewController {

weak var delegate: CreateNicknameVCDelegate?

private let loginViewModel: LoginViewModel = LoginViewModel()


// MARK: - Life Cycles

Expand Down Expand Up @@ -131,7 +133,6 @@ private extension CreateNicknameViewController {
}

warningLabel.do {
$0.text = "닉네임은 \"한글\"만 사용 가능해요!"
$0.font = UIFont.pretendard(.subhead5)
$0.textColor = UIColor(resource: .red)
$0.isHidden = true
Expand Down Expand Up @@ -167,8 +168,7 @@ private extension CreateNicknameViewController {

@objc
func textFieldChange() {
let nickname = self.nicknameTextField.text ?? ""
setSaveButton(isEnabled: !nickname.isEmpty)
setSaveButton(isEnabled: loginViewModel.checkValidNickname(nickname: self.nicknameTextField.text))
}

@objc
Expand All @@ -192,15 +192,14 @@ private extension CreateNicknameViewController {
extension CreateNicknameViewController: UITextFieldDelegate {

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// 정규식 패턴
let pattern = "^[ㄱ-ㅎㅏ-ㅣ가-힣]*$"

// 입력된 문자열이 패턴과 일치하는지 확인
if let _ = string.range(of: pattern, options: .regularExpression) {
if loginViewModel.checkValidNickname(nickname: textField.text) {
self.warningLabel.isHidden = true
return true
} else {
self.warningLabel.isHidden = false
self.warningLabel.text = loginViewModel.fetchErrMessage()
setSaveButton(isEnabled: false)
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import UIKit
import SnapKit
import Then

class LoginViewController: UIViewController {
final class LoginViewController: UIViewController {

// MARK: - UI Properties

Expand All @@ -33,7 +33,9 @@ class LoginViewController: UIViewController {

var isActivate: Bool = false

var nickname: String = ""
var nickname: String? = nil

private let loginViewModel: LoginViewModel = LoginViewModel()


// MARK: - Life Cycles
Expand Down Expand Up @@ -79,7 +81,6 @@ private extension LoginViewController {
findIdLabel.snp.makeConstraints {
$0.top.equalTo(loginView.snp.bottom).offset(30)
$0.leading.equalToSuperview().inset(85)
// $0.trailing.equalToSuperview().inset(225)
}

divider.snp.makeConstraints {
Expand All @@ -92,7 +93,6 @@ private extension LoginViewController {
findPwLabel.snp.makeConstraints {
$0.top.equalTo(loginView.snp.bottom).offset(30)
$0.leading.equalTo(divider.snp.trailing).offset(35)
// $0.width.equalTo(ScreenUtils.getWidth(75))
}

messageLabel.snp.makeConstraints {
Expand Down Expand Up @@ -180,7 +180,7 @@ extension LoginViewController: LoginViewDelegate {

func pushToWelcomeVC(id: String) {
let welcomeVC = WelcomeViewController()
welcomeVC.userInfo = nickname.isEmpty ? id : nickname
welcomeVC.userInfo = loginViewModel.checkValidNickname(nickname: self.nickname) ? nickname : id
self.navigationController?.pushViewController(welcomeVC, animated: true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// LoginViewModel.swift
// Tving_CloneProject
//
// Created by 윤희슬 on 5/28/24.
//

import UIKit

final class LoginViewModel {

// MARK: - Properties

var id: ObservablePattern<String> = ObservablePattern<String>.init(nil)

var pw: ObservablePattern<String> = ObservablePattern<String>.init(nil)

var nickname: ObservablePattern<String> = ObservablePattern<String>.init(nil)

var errMessage: ObservablePattern<String> = ObservablePattern<String>.init(nil)

}

extension LoginViewModel {

func checkEmptyNickname(nickname: String?) -> Bool {
guard let nickname else {
errMessage.value = "닉네임을 입력해주세요"
return false
}

self.nickname.value = nickname
return true
}

func checkValidNickname(nickname: String?) -> Bool {
guard let nickname else {
errMessage.value = "닉네임을 입력해주세요"
return false
}

// 정규식 패턴
let pattern = "^[ㄱ-ㅎㅏ-ㅣ가-힣]*$"
guard let _ = nickname.range(of: pattern, options: .regularExpression) else {
errMessage.value = "닉네임은 \"한글\"만 사용 가능해요!"
return false
}

self.nickname.value = nickname
return true
}

func checkValid(id: String?, pw: String?) -> Bool {
guard let id else {
errMessage.value = "아이디를 입력해주세요"
return false
}
self.id.value = id

guard let pw else {
errMessage.value = "비밀번호를 입력해주세요"
return false
}
self.pw.value = pw

return true
}

func clearText(textfield: UITextField) {
textfield.text = ""
}

func fetchErrMessage() -> String? {
return self.errMessage.value
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Observable.swift
// Tving_CloneProject
//
// Created by 윤희슬 on 5/27/24.
//

import Foundation

class ObservablePattern<T> {

var value: T? {
didSet {
self.listener?(value)
}
}

init(_ value: T?) {
self.value = value
}

private var listener: ((T?) -> Void)? // --- c

func bind(_ listener: @escaping (T?) -> Void) {
listener(value)
self.listener = listener
}
}
Loading

0 comments on commit 9fdd74b

Please sign in to comment.