diff --git a/walkmong/walkmong/Application/SceneDelegate.swift b/walkmong/walkmong/Application/SceneDelegate.swift index 68b179d6..cb599bab 100644 --- a/walkmong/walkmong/Application/SceneDelegate.swift +++ b/walkmong/walkmong/Application/SceneDelegate.swift @@ -28,9 +28,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window?.rootViewController = navigationController } - let splashViewController = MatchingApplyWalkRequestViewController() - window?.rootViewController = splashViewController - window?.overrideUserInterfaceStyle = .light window?.makeKeyAndVisible() } diff --git a/walkmong/walkmong/Global/Components/CountingTextView.swift b/walkmong/walkmong/Global/Components/CountingTextView.swift new file mode 100644 index 00000000..14bebf32 --- /dev/null +++ b/walkmong/walkmong/Global/Components/CountingTextView.swift @@ -0,0 +1,88 @@ +// +// CountingTextView.swift +// walkmong +// +// Created by 황채웅 on 1/11/25. +// + +import Foundation +import UIKit + +final class CountingTextView: UITextView { + + private let maxCharacter: Int + private let countingLabel = MainParagraphLabel(text: "(0/250)") + private var placeHolderText: String + + init(placeHolderText: String, maxCharacter: Int) { + self.placeHolderText = placeHolderText + self.maxCharacter = maxCharacter + super.init(frame: .zero, textContainer: nil) + self.textContainer.lineBreakMode = .byWordWrapping + self.textContainerInset = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12) + self.textColor = .gray400 + self.backgroundColor = .gray100 + self.layer.cornerRadius = 5 + self.text = placeHolderText + self.textAlignment = .left + self.font = UIFont(name: "Pretendard-Regular", size: 16) + self.showsVerticalScrollIndicator = false + self.delegate = self + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + addSubview() + setConstraints() + updateCountingLabel() + } + + private func addSubview() { + self.addSubview(countingLabel) + } + + private func setConstraints() { + countingLabel.textAlignment = .right + countingLabel.snp.makeConstraints { make in + make.trailing.equalToSuperview().inset(12) + make.bottom.equalToSuperview().inset(12) + } + } + + private func updateCountingLabel() { + let currentCount = self.text == placeHolderText ? 0 : self.text.count + countingLabel.text = "(\(currentCount)/\(maxCharacter))" + countingLabel.textColor = currentCount == 0 ? .gray400 : .mainBlue + } + + private func isPlaceholderActive() -> Bool { + return self.text == placeHolderText + } +} + +extension CountingTextView: UITextViewDelegate { + func textViewDidChange(_ textView: UITextView) { + if textView.text.count > maxCharacter { + textView.text = String(textView.text.prefix(maxCharacter)) + } + updateCountingLabel() + } + + func textViewDidBeginEditing(_ textView: UITextView) { + if isPlaceholderActive() { + textView.text = "" + textView.textColor = .gray500 + } + } + + func textViewDidEndEditing(_ textView: UITextView) { + if textView.text.isEmpty { + textView.text = placeHolderText + textView.textColor = .gray400 + } + updateCountingLabel() + } +} diff --git a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/ViewController/MatchingApplyFirstIntroductionViewController.swift b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/ViewController/MatchingApplyFirstIntroductionViewController.swift index 5fb759a1..d583b74a 100644 --- a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/ViewController/MatchingApplyFirstIntroductionViewController.swift +++ b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/ViewController/MatchingApplyFirstIntroductionViewController.swift @@ -9,9 +9,36 @@ import UIKit final class MatchingApplyFirstIntroductionViewController: UIViewController { + private let matchingApplyFirstIntroductionView = MatchingApplyFirstIntroductionView() + override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = .white + setUI() + } + private func addSubview() { + view.addSubview(matchingApplyFirstIntroductionView) + } + + private func setConstraints() { + matchingApplyFirstIntroductionView.snp.makeConstraints { make in + make.horizontalEdges.bottom.equalToSuperview() + make.top.equalToSuperview().offset(156) + } } + + private func setUI() { + addSubview() + setConstraints() + addCustomNavigationBar(titleText: "", showLeftBackButton: true, showLeftCloseButton: false, showRightCloseButton: false, showRightRefreshButton: false) + addProgressBar(currentStep: 3, totalSteps: 7) + matchingApplyFirstIntroductionView.delegate = self + dismissKeyboardOnTap() + } +} +extension MatchingApplyFirstIntroductionViewController: MatchingApplyFirstIntroductionViewDelegate { + func didTapNextButton(_ message: String) { + //TODO: 산책 추가 정보 등록 API 호출 + } } diff --git a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/Views/MatchingApplyFirstApplyIntroductionView.swift b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/Views/MatchingApplyFirstApplyIntroductionView.swift index 3a968a44..9ca0d065 100644 --- a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/Views/MatchingApplyFirstApplyIntroductionView.swift +++ b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/Introduction/Views/MatchingApplyFirstApplyIntroductionView.swift @@ -7,15 +7,71 @@ import UIKit +protocol MatchingApplyFirstIntroductionViewDelegate: AnyObject { + func didTapNextButton(_ message: String) +} + final class MatchingApplyFirstIntroductionView: UIView { + + private let titleLabel = MiddleTitleLabel(text: "본인을 소개하는 글을 작성해주세요.") + + private let textView = CountingTextView(placeHolderText: "본인의 성향, 반려동물을 사랑하는 마음 등을 간단히 적어주세요. 상대방이 신뢰할 수 있는 소개가 좋아요! (최소 20자 이상)", maxCharacter: 250) + + private let nextButton = NextButton(text: "저장하기") + + weak var delegate: MatchingApplyFirstIntroductionViewDelegate? override init(frame: CGRect) { super.init(frame: frame) + addSubview() + setConstraints() + setButtonAction() } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + private func addSubview() { + addSubviews(titleLabel, textView, nextButton) + } + + private func setConstraints() { + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(15) + make.horizontalEdges.equalToSuperview().inset(18) + } + textView.snp.makeConstraints { make in + make.horizontalEdges.equalToSuperview().inset(16) + make.top.equalTo(titleLabel.snp.bottom).offset(20) + make.height.equalTo(169) + } + nextButton.snp.makeConstraints { make in + make.height.equalTo(54) + make.horizontalEdges.equalToSuperview().inset(20) + make.bottom.equalToSuperview().inset(58) + } + } + + private func setButtonAction() { + nextButton.setButtonState(isEnabled: true) + nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside) + } + + @objc private func nextButtonTapped() { + if textView.text.count >= 20 { + delegate?.didTapNextButton(textView.text) + }else { + if let vc = self.getViewController() { + CustomAlertViewController.CustomAlertBuilder(viewController: vc) + .setButtonState(.singleButton) + .setTitleState(.useTitleOnly) + .setSingleButtonTitle("돌아가기") + .setTitleText("20자 이상 입력해주세요") + .showAlertView() + } + } + } + } diff --git a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/ViewController/MatchingApplyPetExperienceViewController.swift b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/ViewController/MatchingApplyPetExperienceViewController.swift index 9e96fc2a..059e36fd 100644 --- a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/ViewController/MatchingApplyPetExperienceViewController.swift +++ b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/ViewController/MatchingApplyPetExperienceViewController.swift @@ -8,10 +8,37 @@ import UIKit final class MatchingApplyPetExperienceViewController: UIViewController { - + + private let matchingApplyPetExperienceView = MatchingApplyPetExperienceView() + override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = .white + setUI() + } + private func addSubview() { + view.addSubview(matchingApplyPetExperienceView) + } + + private func setConstraints() { + matchingApplyPetExperienceView.snp.makeConstraints { make in + make.horizontalEdges.bottom.equalToSuperview() + make.top.equalToSuperview().offset(156) + } } + + private func setUI() { + addSubview() + setConstraints() + addCustomNavigationBar(titleText: "", showLeftBackButton: true, showLeftCloseButton: false, showRightCloseButton: false, showRightRefreshButton: false) + addProgressBar(currentStep: 1, totalSteps: 7) + matchingApplyPetExperienceView.delegate = self + } +} +extension MatchingApplyPetExperienceViewController: MatchingApplyPetExperienceViewDelegate { + func didSelectExperience(_ experienceYn: String) { + let nextVC = MatchingApplyPetWalkExperienceViewController() + navigationController?.pushViewController(nextVC, animated: true) + } } diff --git a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/Views/MatchingApplyPetExperienceView.swift b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/Views/MatchingApplyPetExperienceView.swift index 4fda0e17..48da45bd 100644 --- a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/Views/MatchingApplyPetExperienceView.swift +++ b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetExperience/Views/MatchingApplyPetExperienceView.swift @@ -7,13 +7,100 @@ import UIKit +protocol MatchingApplyPetExperienceViewDelegate: AnyObject { + func didSelectExperience(_ experienceYn: String) +} + final class MatchingApplyPetExperienceView: UIView { + + private let titleLabel = MiddleTitleLabel(text: "반려견을 키운 경험이 있나요?") + private let stackView: UIStackView = { + let stackView = UIStackView() + stackView.alignment = .fill + stackView.distribution = .fillEqually + stackView.axis = .vertical + stackView.spacing = 12 + return stackView + }() + private let tenYearsButton = UIButton.createStyledButton(type: .largeSelection, style: .light, title: "10년 이상") + private let fiveYearsButton = UIButton.createStyledButton(type: .largeSelection, style: .light, title: "5년 이상") + private let threeYearsOverButton = UIButton.createStyledButton(type: .largeSelection, style: .light, title: "3년 이상") + private let threeYearsUnderButton = UIButton.createStyledButton(type: .largeSelection, style: .light, title: "3년 미만") + private let zeroButton = UIButton.createStyledButton(type: .largeSelection, style: .light, title: "반려동물을 키운 경험이 없어요") + private let nextButton = NextButton(text: "다음으로") + + weak var delegate: MatchingApplyPetExperienceViewDelegate? + + private var selectedButton: UIButton? override init(frame: CGRect) { super.init(frame: frame) + addSubview() + setConstraints() + setButtonAction() } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + private func addSubview() { + addSubviews(titleLabel, stackView, nextButton) + stackView.addArrangedSubview(tenYearsButton) + stackView.addArrangedSubview(fiveYearsButton) + stackView.addArrangedSubview(threeYearsOverButton) + stackView.addArrangedSubview(threeYearsUnderButton) + stackView.addArrangedSubview(zeroButton) + } + + private func setConstraints() { + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(15) + make.horizontalEdges.equalToSuperview().inset(18) + } + stackView.snp.makeConstraints { make in + make.height.equalTo(278) + make.horizontalEdges.equalToSuperview().inset(16) + make.bottom.equalTo(nextButton.snp.top).offset(-37) + } + nextButton.snp.makeConstraints { make in + make.height.equalTo(54) + make.horizontalEdges.equalToSuperview().inset(20) + make.bottom.equalToSuperview().inset(58) + } + } + + private func setButtonAction() { + tenYearsButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) + fiveYearsButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) + threeYearsOverButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) + threeYearsUnderButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) + zeroButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) + nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside) + } + + @objc private func buttonTapped(_ sender: UIButton) { + nextButton.setButtonState(isEnabled: true) + if selectedButton != sender { + if let previousButton = selectedButton { + previousButton.isSelected = false + previousButton.backgroundColor = .gray100 + previousButton.setTitleColor(.gray500, for: .normal) + } + self.selectedButton = sender + if let currentButton = self.selectedButton { + currentButton.isSelected = true + currentButton.backgroundColor = .mainBlue + currentButton.setTitleColor(.gray100, for: .selected) + } + } + } + + private func getExperienceYn() -> String { + return selectedButton == zeroButton ? "N" : "Y" + } + + @objc private func nextButtonTapped() { + delegate?.didSelectExperience(getExperienceYn()) + } } diff --git a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/ViewController/MatchingApplyPetWalkExperienceViewController.swift b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/ViewController/MatchingApplyPetWalkExperienceViewController.swift index a1482108..a75081b8 100644 --- a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/ViewController/MatchingApplyPetWalkExperienceViewController.swift +++ b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/ViewController/MatchingApplyPetWalkExperienceViewController.swift @@ -8,10 +8,37 @@ import UIKit final class MatchingApplyPetWalkExperienceViewController: UIViewController { + + private let matchingApplyPetWalkExperienceView = MatchingApplyPetWalkExperienceView() override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = .white + setUI() + } + private func addSubview() { + view.addSubview(matchingApplyPetWalkExperienceView) + } + + private func setConstraints() { + matchingApplyPetWalkExperienceView.snp.makeConstraints { make in + make.horizontalEdges.bottom.equalToSuperview() + make.top.equalToSuperview().offset(156) + } } + private func setUI() { + addSubview() + setConstraints() + addCustomNavigationBar(titleText: "", showLeftBackButton: true, showLeftCloseButton: false, showRightCloseButton: false, showRightRefreshButton: false) + addProgressBar(currentStep: 2, totalSteps: 7) + matchingApplyPetWalkExperienceView.delegate = self + } +} + +extension MatchingApplyPetWalkExperienceViewController: MatchingApplyPetWalkExperienceViewDelegate { + func didTapNextButton(_ experience: Bool, _ breed: String) { + let nextVC = MatchingApplyFirstIntroductionViewController() + self.navigationController?.pushViewController(nextVC, animated: true) + } } diff --git a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/Views/MatchingApplyPetWalkExperienceView.swift b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/Views/MatchingApplyPetWalkExperienceView.swift index 3f781cc9..9c5dd483 100644 --- a/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/Views/MatchingApplyPetWalkExperienceView.swift +++ b/walkmong/walkmong/Presentation/MatchingApply/FirstApply/PetWalkExperience/Views/MatchingApplyPetWalkExperienceView.swift @@ -7,14 +7,151 @@ import UIKit +protocol MatchingApplyPetWalkExperienceViewDelegate: AnyObject { + func didTapNextButton(_ experience: Bool, _ breed: String) +} + final class MatchingApplyPetWalkExperienceView: UIView { + + private let titleLabel = MiddleTitleLabel(text: "반려견 산책과 관련된 질문입니다.") + + private let experienceLabel = SmallTitleLabel(text: "반려견을 산책시킨 경험이 있나요?") + private let experienceMainLabel = MainParagraphLabel(text: "반려견을 산책시킨 경험이") + private let experienceNoButton = UIButton.createStyledButton(type: .smallSelection, style: .light, title: "없어요") + private let experienceYesButton = UIButton.createStyledButton(type: .smallSelection, style: .light, title: "있어요") + + private let breedLabel = SmallTitleLabel(text: "반려견을 산책시킨 경험이 있나요?") + private let breedMainLabel = MainParagraphLabel(text: "산책이 가능한 견종을 모두 선택해주세요") + private let smallBreedButton = UIButton.createStyledButton(type: .smallSelection, style: .light, title: "소형견") + private let mediumBreedButton = UIButton.createStyledButton(type: .smallSelection, style: .light, title: "중형견") + private let bigBreedButton = UIButton.createStyledButton(type: .smallSelection, style: .light, title: "대형견") + + private let nextButton = NextButton(text: "다음으로") + + private var selectedExperienceButton: UIButton? + private var selectedBreedButton: UIButton? + + weak var delegate: MatchingApplyPetWalkExperienceViewDelegate? override init(frame: CGRect) { super.init(frame: frame) + addSubview() + setConstraints() + setButtonAction() } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + private func addSubview() { + addSubviews(titleLabel, experienceLabel, experienceMainLabel, experienceNoButton, experienceYesButton, breedLabel, breedMainLabel, smallBreedButton, mediumBreedButton, bigBreedButton, nextButton) + } + + private func setConstraints() { + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(15) + make.horizontalEdges.equalToSuperview().inset(18) + } + experienceLabel.snp.makeConstraints { make in + make.horizontalEdges.equalToSuperview().inset(16) + make.top.equalTo(titleLabel.snp.bottom).offset(44) + } + experienceMainLabel.snp.makeConstraints { make in + make.horizontalEdges.equalToSuperview().inset(16) + make.top.equalTo(experienceLabel.snp.bottom).offset(24) + } + experienceYesButton.snp.makeConstraints { make in + make.trailing.equalToSuperview().offset(-16) + make.centerY.equalTo(experienceMainLabel) + } + experienceNoButton.snp.makeConstraints { make in + make.trailing.equalTo(experienceYesButton.snp.leading).offset(-12) + make.centerY.equalTo(experienceMainLabel) + } + breedLabel.snp.makeConstraints { make in + make.top.equalTo(experienceMainLabel.snp.bottom).offset(72) + make.horizontalEdges.equalToSuperview().inset(16) + } + breedMainLabel.snp.makeConstraints { make in + make.horizontalEdges.equalToSuperview().inset(16) + make.top.equalTo(breedLabel.snp.bottom).offset(20) + } + smallBreedButton.snp.makeConstraints { make in + make.top.equalTo(breedMainLabel.snp.bottom).offset(16) + make.leading.equalToSuperview().offset(16) + } + mediumBreedButton.snp.makeConstraints { make in + make.centerY.equalTo(smallBreedButton.snp.centerY) + make.leading.equalTo(smallBreedButton.snp.trailing).offset(12) + } + bigBreedButton.snp.makeConstraints { make in + make.centerY.equalTo(smallBreedButton.snp.centerY) + make.leading.equalTo(mediumBreedButton.snp.trailing).offset(12) + } + nextButton.snp.makeConstraints { make in + make.height.equalTo(54) + make.horizontalEdges.equalToSuperview().inset(20) + make.bottom.equalToSuperview().inset(58) + } + } + + private func setButtonAction() { + experienceNoButton.addTarget(self, action: #selector(experienceButtonTapped), for: .touchUpInside) + experienceYesButton.addTarget(self, action: #selector(experienceButtonTapped), for: .touchUpInside) + smallBreedButton.addTarget(self, action: #selector(breedButtonTapped), for: .touchUpInside) + mediumBreedButton.addTarget(self, action: #selector(breedButtonTapped), for: .touchUpInside) + bigBreedButton.addTarget(self, action: #selector(breedButtonTapped), for: .touchUpInside) + nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside) + } + + @objc private func breedButtonTapped(_ sender: UIButton) { + if selectedBreedButton != sender { + if let previousButton = selectedBreedButton { + previousButton.isSelected = false + previousButton.backgroundColor = .gray100 + previousButton.setTitleColor(.gray500, for: .normal) + } + self.selectedBreedButton = sender + if let currentButton = self.selectedBreedButton { + currentButton.isSelected = true + currentButton.backgroundColor = .mainBlue + currentButton.setTitleColor(.gray100, for: .selected) + } + } + if let _ = selectedBreedButton, let _ = selectedExperienceButton { + nextButton.setButtonState(isEnabled: true) + } + } + + @objc private func experienceButtonTapped(_ sender: UIButton) { + if selectedExperienceButton != sender { + if let previousButton = selectedExperienceButton { + previousButton.isSelected = false + previousButton.backgroundColor = .gray100 + previousButton.setTitleColor(.gray500, for: .normal) + } + self.selectedExperienceButton = sender + if let currentButton = self.selectedExperienceButton { + currentButton.isSelected = true + currentButton.backgroundColor = .mainBlue + currentButton.setTitleColor(.gray100, for: .selected) + } + } + if let _ = selectedBreedButton, let _ = selectedExperienceButton { + nextButton.setButtonState(isEnabled: true) + } + } + + @objc private func nextButtonTapped() { + let selectedBreed = switch selectedBreedButton { + case smallBreedButton: + "SMALL" + case mediumBreedButton: + "MEDIUM" + default: + "BIG" + } + delegate?.didTapNextButton(selectedExperienceButton == experienceYesButton, selectedBreed) + } }