diff --git a/SOPT-Stamp-iOS/Projects/Core/Sources/Literals/StringLiterals.swift b/SOPT-Stamp-iOS/Projects/Core/Sources/Literals/StringLiterals.swift index ab64fc5a7..ddb7748bb 100644 --- a/SOPT-Stamp-iOS/Projects/Core/Sources/Literals/StringLiterals.swift +++ b/SOPT-Stamp-iOS/Projects/Core/Sources/Literals/StringLiterals.swift @@ -20,6 +20,39 @@ public struct I18N { public static let verify = "확인" } + public struct Navi { + public static let post = "공지" + } + + public struct Search { + public static let placeholder = "검색어 입력" + public static let cancel = "취소" + public static let countUnit = " 건" + public static let enterSearch = "검색어를 입력해 주세요." + public static let noSearchData = "등록된 게시물이 없습니다" + } + + public struct Onboarding { + public static let title1 = "A부터 Z까지 SOPT 즐기기" + public static let caption1 = "동아리 활동을 더욱 재미있게\n즐기는 방법을 알려드려요!" + public static let title2 = "랭킹으로 다같이 참여하기" + public static let caption2 = "미션을 달성하고 랭킹이 올라가는\n재미를 느껴보세요!" + public static let title3 = "완료된 미션으로 추억 감상하기" + public static let caption3 = "완료된 미션을 확인하며\n추억을 감상할 수 있어요" + public static let start = "시작하기" + } + + public struct SignIn { + public static let id = "ID" + public static let enterID = "이메일을 입력해주세요." + public static let password = "Password" + public static let enterPW = "비밀번호를 입력해주세요." + public static let checkAccount = "정보를 다시 확인해 주세요." + public static let findAccount = "계정 찾기" + public static let signIn = "로그인" + public static let signUp = "회원가입" + } + public struct SignUp { public static let signUp = "회원가입" public static let nickname = "닉네임" @@ -47,6 +80,8 @@ public struct I18N { public static let mission = "미션" public static let missionComplete = "미션 완료" public static let editComplte = "수정 완료" + public static let deleteTitle = "달성한 미션을 삭제하시겠습니까?" + } } diff --git a/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/SignInRepository.swift b/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/SignInRepository.swift new file mode 100644 index 000000000..2e0a4f6b0 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/SignInRepository.swift @@ -0,0 +1,26 @@ +// +// SignInRepository.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Combine + +import Domain +import Network + +public class SignInRepository { + + private let networkService: AuthService + private let cancelBag = Set() + + public init(service: AuthService) { + self.networkService = service + } +} + +extension SignInRepository: SignInRepositoryInterface { + +} diff --git a/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/SignInTransform.swift b/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/SignInTransform.swift new file mode 100644 index 000000000..dadd4e75d --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/SignInTransform.swift @@ -0,0 +1,19 @@ +// +// SignInTransform.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Foundation + +import Domain +import Network + +extension SignInEntity { + + public func toDomain() -> SignInModel { + return SignInModel.init() + } +} diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/OnboardingDataModel.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/OnboardingDataModel.swift new file mode 100644 index 000000000..d2c3763f8 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/OnboardingDataModel.swift @@ -0,0 +1,20 @@ +// +// OnboardingDataModel.swift +// Domain +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import UIKit + +public struct OnboardingDataModel { + public var image: UIImage + public var title, caption: String + + public init(image: UIImage, title: String, caption: String) { + self.image = image + self.title = title + self.caption = caption + } +} diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/SignInModel.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/SignInModel.swift new file mode 100644 index 000000000..164fad282 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/SignInModel.swift @@ -0,0 +1,16 @@ +// +// SignInModel.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Foundation + +public struct SignInModel { + + public init() { + + } +} diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/SignInRepositoryInterface.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/SignInRepositoryInterface.swift new file mode 100644 index 000000000..02bd828e1 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/SignInRepositoryInterface.swift @@ -0,0 +1,13 @@ +// +// SignInRepositoryInterface.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Combine + +public protocol SignInRepositoryInterface { + +} diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/SignInUseCase.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/SignInUseCase.swift new file mode 100644 index 000000000..ac68f117d --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/SignInUseCase.swift @@ -0,0 +1,27 @@ +// +// SignInUseCase.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Combine + +public protocol SignInUseCase { + +} + +public class DefaultSignInUseCase { + + private let repository: SignInRepositoryInterface + private var cancelBag = Set() + + public init(repository: SignInRepositoryInterface) { + self.repository = repository + } +} + +extension DefaultSignInUseCase: SignInUseCase { + +} diff --git a/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomTextFieldView.swift b/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomTextFieldView.swift index e80981c3e..2769fc70f 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomTextFieldView.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomTextFieldView.swift @@ -320,6 +320,7 @@ extension CustomTextFieldView { textField.backgroundColor = .clear textField.textColor = .black textField.font = UIFont.caption1 + textField.returnKeyType = .done alertlabel.font = UIFont.caption3 alertlabel.textColor = SoptampColor.error300.color @@ -477,6 +478,11 @@ extension CustomTextFieldView: UITextFieldDelegate { self.setTextFieldViewState(.editing) } } + + public func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return true + } } // MARK: - CustomTextFieldViewAlertDelegate diff --git a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Entity/SignInEntity.swift b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Entity/SignInEntity.swift new file mode 100644 index 000000000..706461fa7 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Entity/SignInEntity.swift @@ -0,0 +1,13 @@ +// +// SignInEntity.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Foundation + +public struct SignInEntity { + +} diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/ModuleFactoryInterface.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/ModuleFactoryInterface.swift index 4670ea254..88acf3dd4 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/ModuleFactoryInterface.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/ModuleFactoryInterface.swift @@ -13,6 +13,7 @@ import Core public protocol ModuleFactoryInterface { func makeSplashVC() -> SplashVC func makeOnboardingVC() -> OnboardingVC + func makeSignInVC() -> SignInVC func makeSignUpVC() -> SignUpVC func makeSignUpCompleteVC() -> SignUpCompleteVC func makeMissionListVC(sceneType: MissionListSceneType) -> MissionListVC diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/OnboardingScene/VC/OnboardingVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/OnboardingScene/VC/OnboardingVC.swift index 9eee78623..b430cbb9f 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/OnboardingScene/VC/OnboardingVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/OnboardingScene/VC/OnboardingVC.swift @@ -10,6 +10,10 @@ import UIKit import DSKit +import Domain + +import Core + import SnapKit import Then @@ -17,16 +21,56 @@ public class OnboardingVC: UIViewController { // MARK: - Properties + private var onboardingData: [OnboardingDataModel] = [] + + private var currentPage: Int = 0 { + didSet { + pageControl.currentPage = currentPage + startButton.setEnabled(currentPage == 2) + } + } + public var factory: ModuleFactoryInterface! // MARK: - UI Components + private lazy var onboardingCollectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.isScrollEnabled = true + collectionView.isPagingEnabled = true + collectionView.showsHorizontalScrollIndicator = false + return collectionView + }() + + private lazy var pageControl = UIPageControl().then { + $0.pageIndicatorTintColor = DSKitAsset.Colors.purple200.color + $0.currentPageIndicatorTintColor = DSKitAsset.Colors.purple300.color + $0.numberOfPages = 3 + $0.isUserInteractionEnabled = false + } + + private lazy var startButton = CustomButton(title: I18N.Onboarding.start).setEnabled(false).then { + $0.addTarget(self, action: #selector(startButtonDidTap), for: .touchUpInside) + } + // MARK: - View Life Cycle public override func viewDidLoad() { super.viewDidLoad() self.setUI() self.setLayout() + self.setCollectionViewCell() + self.setOnboardingData() + } + + // MARK: - @objc Function + + @objc + private func startButtonDidTap() { + let vc = self.factory.makeSignInVC() + self.navigationController?.pushViewController(vc, animated: true) } } @@ -39,8 +83,87 @@ extension OnboardingVC { } private func setLayout() { + view.addSubviews(onboardingCollectionView, pageControl, startButton) + + onboardingCollectionView.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(40.adjustedH) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.height.equalTo(450.adjusted) + } + pageControl.snp.makeConstraints { make in + make.top.equalTo(onboardingCollectionView.snp.bottom).offset(14.adjustedH) + make.centerX.equalToSuperview() + } + + startButton.snp.makeConstraints { make in + make.top.equalTo(pageControl.snp.bottom).offset(50.adjustedH) + make.leading.trailing.equalTo(view.safeAreaInsets).inset(20) + make.height.equalTo(56) + } } } // MARK: - Methods + +extension OnboardingVC { + + private func setCollectionViewCell() { + onboardingCollectionView.delegate = self + onboardingCollectionView.dataSource = self + + onboardingCollectionView.register(OnboardingCVC.self, forCellWithReuseIdentifier: OnboardingCVC.className) + } + + private func setOnboardingData() { + onboardingData.append(contentsOf: [ + OnboardingDataModel(image: DSKitAsset.Assets.splashImg1.image, + title: I18N.Onboarding.title1, + caption: I18N.Onboarding.caption1), + OnboardingDataModel(image: DSKitAsset.Assets.splashImg2.image, + title: I18N.Onboarding.title2, + caption: I18N.Onboarding.caption2), + OnboardingDataModel(image: DSKitAsset.Assets.splashImg3.image, + title: I18N.Onboarding.title3, + caption: I18N.Onboarding.caption3) + ]) + } +} + +// MARK: - CollectionView Delegate, DataSource + +extension OnboardingVC: UICollectionViewDelegate, UICollectionViewDataSource { + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return onboardingData.count + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = onboardingCollectionView.dequeueReusableCell(withReuseIdentifier: OnboardingCVC.className, for: indexPath) as? OnboardingCVC else { return UICollectionViewCell() } + cell.setOnboardingSlides(onboardingData[indexPath.row]) + return cell + } + + public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { + let page = Int(targetContentOffset.pointee.x / self.view.frame.width) + self.currentPage = page + } +} + +// MARK: - CollectionView DelegateFlowLayout + +extension OnboardingVC: UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let length = self.view.frame.size.width + return CGSize(width: length, height: 450.adjustedH) + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return 0 + } +} diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/OnboardingScene/Views/CVC/OnboardingCVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/OnboardingScene/Views/CVC/OnboardingCVC.swift new file mode 100644 index 000000000..c6d318fcf --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/OnboardingScene/Views/CVC/OnboardingCVC.swift @@ -0,0 +1,91 @@ +// +// OnboardingCVC.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import UIKit + +import DSKit + +import Domain + +import SnapKit +import Then + +public class OnboardingCVC: UICollectionViewCell { + + // MARK: - UI Components + + private let imageView = UIImageView().then { + $0.contentMode = .scaleAspectFit + $0.layer.masksToBounds = true + } + + private let titleLabel = UILabel().then { + $0.setTypoStyle(.h1) + $0.textColor = DSKitAsset.Colors.gray900.color + } + + private let captionLabel = UILabel().then { + $0.textAlignment = .center + $0.textColor = DSKitAsset.Colors.gray500.color + $0.text = " " + $0.numberOfLines = 2 + $0.setTypoStyle(.subtitle2) + $0.setLineSpacing(lineSpacing: 8) + $0.textAlignment = .center + } + + // MARK: - Initialization + override init(frame: CGRect) { + super.init(frame: frame) + setUI() + setLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - UI & Layout + +extension OnboardingCVC { + + private func setUI() { + self.backgroundColor = DSKitAsset.Colors.white.color + } + + private func setLayout() { + addSubviews(imageView, titleLabel, captionLabel) + + imageView.snp.makeConstraints { make in + make.top.centerX.equalToSuperview() + make.width.height.equalTo(contentView.snp.width).multipliedBy(0.8) + } + + titleLabel.snp.makeConstraints { make in + make.top.equalTo(imageView.snp.bottom).offset(30.adjustedH) + make.centerX.equalToSuperview() + } + + captionLabel.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(12) + make.centerX.equalToSuperview() + } + } +} + +// MARK: - Methods + +extension OnboardingCVC { + + func setOnboardingSlides(_ slides: OnboardingDataModel) { + imageView.image = slides.image + titleLabel.text = slides.title + captionLabel.text = slides.caption + } +} diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/SampleScene/Views/.gitkeep b/SOPT-Stamp-iOS/Projects/Presentation/Sources/SampleScene/Views/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/SignInModel.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/SignInModel.swift new file mode 100644 index 000000000..164fad282 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/SignInModel.swift @@ -0,0 +1,16 @@ +// +// SignInModel.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Foundation + +public struct SignInModel { + + public init() { + + } +} diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/VC/SignInVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/VC/SignInVC.swift new file mode 100644 index 000000000..013632a3d --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/VC/SignInVC.swift @@ -0,0 +1,191 @@ +// +// SignInVC.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import UIKit + +import DSKit + +import Core + +import Combine +import SnapKit +import Then + +public class SignInVC: UIViewController { + + // MARK: - Properties + + public var factory: ModuleFactoryInterface! + public var viewModel: SignInViewModel! + private var cancelBag = CancelBag() + + // MARK: - UI Components + + private let logoImageView = UIImageView().then { + $0.image = DSKitAsset.Assets.logo.image + $0.contentMode = .scaleAspectFit + $0.layer.masksToBounds = true + } + + private lazy var emailTextField = CustomTextFieldView(type: .subTitle) + .setTextFieldType(.email) + .setSubTitle(I18N.SignIn.id) + .setPlaceholder(I18N.SignIn.enterID) + + private lazy var passwordTextField = CustomTextFieldView(type: .subTitle) + .setTextFieldType(.password) + .setSubTitle(I18N.SignIn.password) + .setPlaceholder(I18N.SignIn.enterPW) + + private lazy var findAccountButton = UIButton(type: .system).then { + $0.setTitle(I18N.SignIn.findAccount, for: .normal) + $0.setTitleColor(DSKitAsset.Colors.gray500.color, for: .normal) + $0.titleLabel!.setTypoStyle(.caption2) + $0.addTarget(self, action: #selector(findAccountButtonDidTap), for: .touchUpInside) + } + + private lazy var signInButton = CustomButton(title: I18N.SignIn.signIn).setEnabled(false).then { + $0.addTarget(self, action: #selector(signInButtonDidTap), for: .touchUpInside) + } + + private lazy var signUpButton = UIButton(type: .system).then { + $0.setTitle(I18N.SignIn.signUp, for: .normal) + $0.setTitleColor(DSKitAsset.Colors.gray900.color, for: .normal) + $0.titleLabel!.setTypoStyle(.caption1) + $0.addTarget(self, action: #selector(signUpButtonDidTap), for: .touchUpInside) + } + + // MARK: - View Life Cycle + + public override func viewDidLoad() { + super.viewDidLoad() + self.bindViewModels() + self.setUI() + self.setLayout() + self.setTapGesture() + } + + public override func viewWillAppear(_ animated: Bool) { + self.addKeyboardObserver() + } + + deinit { + self.removeKeyboardObserver() + } + + // MARK: - @objc Function + + @objc + private func findAccountButtonDidTap() { + print("find account btn did tap") + } + + @objc + private func signInButtonDidTap() { + print("sign in btn did tap") + } + + @objc + private func signUpButtonDidTap() { + print("sign up btn did tap") + } + +} + +// MARK: - UI & Layout + +extension SignInVC { + + private func setUI() { + self.view.backgroundColor = DSKitAsset.Colors.white.color + self.findAccountButton.setUnderline() + self.signUpButton.setUnderline() + } + + private func setLayout() { + self.view.addSubviews(logoImageView, emailTextField, passwordTextField, findAccountButton, signInButton, signUpButton) + + logoImageView.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(100.adjustedH) + make.centerX.equalToSuperview() + make.width.equalToSuperview().multipliedBy(0.7) + } + + emailTextField.snp.makeConstraints { make in + make.top.equalTo(logoImageView.snp.bottom).offset(90.adjustedH) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) + } + + passwordTextField.snp.makeConstraints { make in + make.top.equalTo(emailTextField.snp.bottom).offset(12.adjustedH) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) + } + + findAccountButton.snp.makeConstraints { make in + make.top.equalTo(passwordTextField.snp.bottom).offset(12.adjustedH) + make.trailing.equalTo(view.safeAreaLayoutGuide).inset(22) + } + + signInButton.snp.makeConstraints { make in + make.top.equalTo(findAccountButton.snp.bottom).offset(55.adjustedH) + make.leading.trailing.equalToSuperview().inset(20) + make.height.equalTo(56) + } + + signUpButton.snp.makeConstraints { make in + make.top.equalTo(signInButton.snp.bottom).offset(15.adjustedH) + make.centerX.equalToSuperview() + make.width.equalTo(100) + make.height.equalTo(20) + } + } +} + +// MARK: - Methods + +extension SignInVC { + + private func bindViewModels() { +// let input = SignInViewModel.Input() +// let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag) + } + + private func setTapGesture() { + let tap = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing)) + tap.cancelsTouchesInView = false + view.addGestureRecognizer(tap) + } + + private func addKeyboardObserver() { + NotificationCenter.default.addObserver(self, selector: #selector(keyboardUp), name: UIResponder.keyboardWillShowNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardDown), name: UIResponder.keyboardWillHideNotification, object: nil) + } + + private func removeKeyboardObserver() { + NotificationCenter.default.removeObserver(self) + } + + @objc func keyboardUp(notification: NSNotification) { + if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { + let keyboardRectangle = keyboardFrame.cgRectValue +// let safeHeight = self.view.safeAreaInsets.bottom + + UIView.animate( + withDuration: 0.3, + animations: { + self.view.transform = + CGAffineTransform(translationX: 0, y: -(keyboardRectangle.height)) + } + ) + } + } + + @objc func keyboardDown() { + self.view.transform = .identity + } +} diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/ViewModel/SignInViewModel.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/ViewModel/SignInViewModel.swift new file mode 100644 index 000000000..8a25e956e --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/SignInScene/ViewModel/SignInViewModel.swift @@ -0,0 +1,50 @@ +// +// SignInViewModel.swift +// Presentation +// +// Created by devxsby on 2022/12/01. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Combine + +import Core +import Domain + +public class SignInViewModel: ViewModelType { + + private let useCase: SignInUseCase + private var cancelBag = CancelBag() + + // MARK: - Inputs + + public struct Input { + + } + + // MARK: - Outputs + + public struct Output { + + } + + // MARK: - init + + public init(useCase: SignInUseCase) { + self.useCase = useCase + } +} + +extension SignInViewModel { + public func transform(from input: Input, cancelBag: CancelBag) -> Output { + let output = Output() + self.bindOutput(output: output, cancelBag: cancelBag) + // input,output 상관관계 작성 + + return output + } + + private func bindOutput(output: Output, cancelBag: CancelBag) { + + } +} diff --git a/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/ModuleFactory/ModuleFactory.swift b/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/ModuleFactory/ModuleFactory.swift index 06f197496..9dd9f033d 100644 --- a/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/ModuleFactory/ModuleFactory.swift +++ b/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/ModuleFactory/ModuleFactory.swift @@ -38,6 +38,16 @@ extension ModuleFactory: ModuleFactoryInterface { return onboardingVC } + public func makeSignInVC() -> Presentation.SignInVC { + let repository = SignInRepository(service: authService) + let useCase = DefaultSignInUseCase(repository: repository) + let viewModel = SignInViewModel(useCase: useCase) + let signinVC = SignInVC() + signinVC.factory = self + signinVC.viewModel = viewModel + return signinVC + } + public func makeSignUpVC() -> Presentation.SignUpVC { let repository = SignUpRepository(service: authService) let useCase = DefaultSignUpUseCase(repository: repository) @@ -98,4 +108,5 @@ extension ModuleFactory: ModuleFactoryInterface { rankingVC.viewModel = viewModel return rankingVC } + }