Skip to content

Commit

Permalink
[Merge] RxSwift 적용 (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
seuriseuljjeok authored Jul 10, 2024
2 parents 1e97aea + 5f897a6 commit fbac103
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 135 deletions.
41 changes: 41 additions & 0 deletions Tving_CloneProject/Tving_CloneProject.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
CA3D0C9C2C10D5D500735097 /* ButtonStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3D0C9B2C10D5D500735097 /* ButtonStatus.swift */; };
CA3D0C9E2C10DB6C00735097 /* UIButton+.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3D0C9D2C10DB6C00735097 /* UIButton+.swift */; };
CA3D0CA22C11969100735097 /* CompositionalLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3D0CA12C11969100735097 /* CompositionalLayout.swift */; };
CA3D0CA42C12174A00735097 /* ViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3D0CA32C12174A00735097 /* ViewModelType.swift */; };
CA3D0CA72C12181F00735097 /* RxBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = CA3D0CA62C12181F00735097 /* RxBlocking */; };
CA3D0CA92C12181F00735097 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = CA3D0CA82C12181F00735097 /* RxCocoa */; };
CA3D0CAB2C12181F00735097 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = CA3D0CAA2C12181F00735097 /* RxRelay */; };
CA3D0CAD2C12F27700735097 /* TextfieldStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3D0CAC2C12F27700735097 /* TextfieldStatus.swift */; };
CA803D982C05B977006B8C35 /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA803D972C05B977006B8C35 /* LoginViewModel.swift */; };
CA803D9A2C0866BA006B8C35 /* ObservablePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA803D992C0866BA006B8C35 /* ObservablePattern.swift */; };
CA803D9C2C09C784006B8C35 /* MovieViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA803D9B2C09C784006B8C35 /* MovieViewModel.swift */; };
Expand Down Expand Up @@ -122,6 +127,8 @@
CA3D0C9B2C10D5D500735097 /* ButtonStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonStatus.swift; sourceTree = "<group>"; };
CA3D0C9D2C10DB6C00735097 /* UIButton+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+.swift"; sourceTree = "<group>"; };
CA3D0CA12C11969100735097 /* CompositionalLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionalLayout.swift; sourceTree = "<group>"; };
CA3D0CA32C12174A00735097 /* ViewModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModelType.swift; sourceTree = "<group>"; };
CA3D0CAC2C12F27700735097 /* TextfieldStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextfieldStatus.swift; sourceTree = "<group>"; };
CA803D972C05B977006B8C35 /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
CA803D992C0866BA006B8C35 /* ObservablePattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservablePattern.swift; sourceTree = "<group>"; };
CA803D9B2C09C784006B8C35 /* MovieViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -156,10 +163,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CA3D0CA92C12181F00735097 /* RxCocoa in Frameworks */,
CA3953052BC4527D00B15E91 /* SnapKit in Frameworks */,
CA3D0CAB2C12181F00735097 /* RxRelay in Frameworks */,
CA3953152BC45CA700B15E91 /* Then in Frameworks */,
CA8496E22BE7E36D0064E0CC /* Moya in Frameworks */,
CA3953072BC4527D00B15E91 /* SnapKit-Dynamic in Frameworks */,
CA3D0CA72C12181F00735097 /* RxBlocking in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -506,6 +516,8 @@
children = (
CA3D0C9B2C10D5D500735097 /* ButtonStatus.swift */,
CA3D0CA12C11969100735097 /* CompositionalLayout.swift */,
CA3D0CA32C12174A00735097 /* ViewModelType.swift */,
CA3D0CAC2C12F27700735097 /* TextfieldStatus.swift */,
);
path = Protocols;
sourceTree = "<group>";
Expand Down Expand Up @@ -630,6 +642,9 @@
CA3953062BC4527D00B15E91 /* SnapKit-Dynamic */,
CA3953142BC45CA700B15E91 /* Then */,
CA8496E12BE7E36D0064E0CC /* Moya */,
CA3D0CA62C12181F00735097 /* RxBlocking */,
CA3D0CA82C12181F00735097 /* RxCocoa */,
CA3D0CAA2C12181F00735097 /* RxRelay */,
);
productName = Tving_CloneProject;
productReference = CA3952E22BC31F9900B15E91 /* Tving_CloneProject.app */;
Expand Down Expand Up @@ -663,6 +678,7 @@
CA3953032BC4527D00B15E91 /* XCRemoteSwiftPackageReference "SnapKit" */,
CA3953132BC45CA700B15E91 /* XCRemoteSwiftPackageReference "Then" */,
CA8496E02BE7E36D0064E0CC /* XCRemoteSwiftPackageReference "Moya" */,
CA3D0CA52C12181F00735097 /* XCRemoteSwiftPackageReference "RxSwift" */,
);
productRefGroup = CA3952E32BC31F9900B15E91 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -702,7 +718,9 @@
CA3953002BC44B9900B15E91 /* UIView+.swift in Sources */,
CA1F68F02BD5691D00439E33 /* HomeViewController.swift in Sources */,
CA8496F22BE8A6700064E0CC /* NetworkResult.swift in Sources */,
CA3D0CAD2C12F27700735097 /* TextfieldStatus.swift in Sources */,
CA3D0C702C0D9D4500735097 /* MainView.swift in Sources */,
CA3D0CA42C12174A00735097 /* ViewModelType.swift in Sources */,
CA902EBC2BD6F9F900560D26 /* ImageWithTitleCell.swift in Sources */,
CA3953222BC6FA9F00B15E91 /* Constant.swift in Sources */,
CA902EF52BDE9E4800560D26 /* ToBeReleasedViewController.swift in Sources */,
Expand Down Expand Up @@ -988,6 +1006,14 @@
minimumVersion = 3.0.0;
};
};
CA3D0CA52C12181F00735097 /* XCRemoteSwiftPackageReference "RxSwift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ReactiveX/RxSwift";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 6.7.1;
};
};
CA8496E02BE7E36D0064E0CC /* XCRemoteSwiftPackageReference "Moya" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Moya/Moya";
Expand All @@ -1014,6 +1040,21 @@
package = CA3953132BC45CA700B15E91 /* XCRemoteSwiftPackageReference "Then" */;
productName = Then;
};
CA3D0CA62C12181F00735097 /* RxBlocking */ = {
isa = XCSwiftPackageProductDependency;
package = CA3D0CA52C12181F00735097 /* XCRemoteSwiftPackageReference "RxSwift" */;
productName = RxBlocking;
};
CA3D0CA82C12181F00735097 /* RxCocoa */ = {
isa = XCSwiftPackageProductDependency;
package = CA3D0CA52C12181F00735097 /* XCRemoteSwiftPackageReference "RxSwift" */;
productName = RxCocoa;
};
CA3D0CAA2C12181F00735097 /* RxRelay */ = {
isa = XCSwiftPackageProductDependency;
package = CA3D0CA52C12181F00735097 /* XCRemoteSwiftPackageReference "RxSwift" */;
productName = RxRelay;
};
CA8496E12BE7E36D0064E0CC /* Moya */ = {
isa = XCSwiftPackageProductDependency;
package = CA8496E02BE7E36D0064E0CC /* XCRemoteSwiftPackageReference "Moya" */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ extension UITextField {
}

//TextField 기본 속성 커스텀
func setTextField(forBackgroundColor: UIColor, forBorderColor: UIColor, forBorderWidth: CGFloat, forCornerRadius: CGFloat = 0) {
func setTextField(textfieldStatus: TextfieldStatus) {
self.clipsToBounds = true
self.layer.borderColor = forBorderColor.cgColor
self.layer.borderWidth = forBorderWidth
self.backgroundColor = forBackgroundColor
self.layer.cornerRadius = forCornerRadius
self.layer.borderColor = textfieldStatus.borderColor.cgColor
self.layer.borderWidth = textfieldStatus.borderWidth
self.backgroundColor = textfieldStatus.bgColor
self.layer.cornerRadius = textfieldStatus.borderRadius
}

//TextField placeholder 커스텀
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// TextfieldStatus.swift
// Tving_CloneProject
//
// Created by 윤희슬 on 6/7/24.
//

import UIKit

protocol TextfieldStatus {

var bgColor: UIColor { get }

var borderColor: UIColor { get }

var borderWidth: CGFloat { get }

var borderRadius: CGFloat { get }

}

extension TextfieldStatus {

var borderWidth: CGFloat { return 0 }

var borderRadius: CGFloat { return 3 }
}

struct UnselectedTextfield: TextfieldStatus {

var bgColor: UIColor = UIColor(resource: .grey4)

var borderColor: UIColor = UIColor(resource: .grey4)

}

struct SelectedTextfield: TextfieldStatus {

var bgColor: UIColor = UIColor(resource: .grey4)

var borderColor: UIColor = UIColor(resource: .grey2)

var borderWidth: CGFloat = 1

}

struct CreateNicknameTextfield: TextfieldStatus {

var bgColor: UIColor = UIColor(resource: .grey2)

var borderColor: UIColor = UIColor(resource: .grey2)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// ViewModelType.swift
// Tving_CloneProject
//
// Created by 윤희슬 on 6/7/24.
//

import RxSwift

protocol ViewModelType {
associatedtype Input
associatedtype Output

func transform(from input: Input, disposeBag: RxSwift.DisposeBag) -> Output
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ final class CreateNicknameView: UIView {

private let disabledButtonStatus = DisabledSaveButton()

private let textfieldStatus: TextfieldStatus = CreateNicknameTextfield()


// MARK: - Life Cycles

Expand Down Expand Up @@ -123,10 +125,7 @@ private extension CreateNicknameView {
}

nicknameTextField.do {
$0.setTextField(forBackgroundColor: UIColor(resource: .grey2),
forBorderColor: UIColor(resource: .grey2),
forBorderWidth: 0,
forCornerRadius: 3)
$0.setTextField(textfieldStatus: textfieldStatus)
$0.textColor = UIColor(resource: .grey4)
$0.setLeftPadding(amount: 23)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

import UIKit

import SnapKit
import Then
import RxSwift
import RxCocoa

protocol CreateNicknameVCDelegate: AnyObject {
func saveUserNickname(nickname: String)
}
Expand All @@ -20,12 +25,19 @@ final class CreateNicknameViewController: UIViewController {

// MARK: - Properties

var isActivate: Bool = false
var isActivate: Bool = false {
didSet {
self.createNicknameView.warningLabel.isHidden = isActivate
self.createNicknameView.setSaveButton(isEnabled: isActivate)
}
}

weak var delegate: CreateNicknameVCDelegate?

private let createNicknameViewModel = CreateNicknameViewModel()

private let disposeBag = DisposeBag()


// MARK: - Life Cycles

Expand All @@ -39,6 +51,7 @@ final class CreateNicknameViewController: UIViewController {
setStyle()
setCreateNicknameView()
setViewModel()
didTapSaveButton()
}

}
Expand All @@ -59,40 +72,33 @@ private extension CreateNicknameViewController {
let gesture = UITapGestureRecognizer(target: self, action: #selector(didTapDimmedView))
$0.dimmedView.isUserInteractionEnabled = true
$0.dimmedView.addGestureRecognizer(gesture)
$0.nicknameTextField.addTarget(self, action: #selector(textFieldChange), for: .editingChanged)
$0.saveButton.addTarget(self, action: #selector(popToLoginVC), for: .touchUpInside)
}
}

func setViewModel() {
createNicknameViewModel.isValid.bind { [weak self] isValid in
guard let isValid else { return }
if isValid {
self?.createNicknameView.warningLabel.isHidden = true
self?.isActivate = true
self?.createNicknameView.setSaveButton(isEnabled: true)
} else {
self?.createNicknameView.warningLabel.isHidden = false
self?.createNicknameView.warningLabel.text = self?.createNicknameViewModel.fetchErrMessage()
self?.isActivate = false
self?.createNicknameView.setSaveButton(isEnabled: false)
}
}
}

@objc
func textFieldChange() {
createNicknameViewModel.checkValidNickname(
nicknameModel: CreateNicknameModel(nickname: self.createNicknameView.nicknameTextField.text))
let input = CreateNicknameViewModel.Input(
nicknameTextfieldDidChangeEvent: createNicknameView.nicknameTextField.rx.text.asObservable()
)

let output = createNicknameViewModel.transform(from: input, disposeBag: disposeBag)

output.isValid.subscribe(onNext: { [weak self] isValid in
self?.isActivate = isValid ? true : false
}).disposed(by: disposeBag)

output.errMessage.subscribe(onNext: { [weak self] errMessage in
self?.createNicknameView.warningLabel.text = errMessage
}).disposed(by: disposeBag)
}

@objc
func popToLoginVC() {
if isActivate {
let nickname = self.createNicknameView.nicknameTextField.text ?? ""
self.delegate?.saveUserNickname(nickname: nickname)
self.dismiss(animated: true)
}

func didTapSaveButton() {
createNicknameView.saveButton.rx.tap.subscribe(onNext: { _ in
if self.isActivate {
guard let nickname = self.createNicknameView.nicknameTextField.text else { return }
self.delegate?.saveUserNickname(nickname: nickname)
self.dismiss(animated: true)
}
}).disposed(by: disposeBag)
}

@objc
Expand Down
Loading

0 comments on commit fbac103

Please sign in to comment.