Skip to content

Commit 343d755

Browse files
committed
[#234] Add MyInfoView & ViewController Initial codes
1 parent f040ce8 commit 343d755

File tree

2 files changed

+363
-0
lines changed

2 files changed

+363
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//
2+
// MyInfoView.swift
3+
// EATSSU
4+
//
5+
// Created by Jiwoong CHOI on 01/31/25.
6+
//
7+
8+
import EATSSUDesign
9+
import SnapKit
10+
import Then
11+
import UIKit
12+
13+
/// μ‚¬μš©μžμ˜ λ‹‰λ„€μž„μ„ μ„€μ •ν•˜λŠ” ν™”λ©΄μ˜ View
14+
final class MyInfoView: BaseUIView {
15+
// MARK: - Properties
16+
17+
/// μ‚¬μš©μžκ°€ μž…λ ₯ν•œ λ‹‰λ„€μž„ κ°’
18+
var userNickname: String = ""
19+
20+
// MARK: - UI Components
21+
22+
/// λ‹‰λ„€μž„ μ„€μ • μ•ˆλ‚΄ 문ꡬ
23+
private let nickNameLabel = UILabel().then {
24+
$0.text = "EAT-SSUμ—μ„œ μ‚¬μš©ν• \nλ‹‰λ„€μž„μ„ μ„€μ •ν•΄ μ£Όμ„Έμš”"
25+
$0.numberOfLines = 2
26+
$0.font = EATSSUDesignFontFamily.Pretendard.bold.font(size: 18)
27+
}
28+
29+
/// λ‹‰λ„€μž„ μž…λ ₯ ν•„λ“œ
30+
let inputNickNameTextField = ESTextField(placeholder: ESTextLiteral.Nickname.inputNickName)
31+
32+
/// λ‹‰λ„€μž„ 쀑볡 확인 λ²„νŠΌ
33+
let nicknameDoubleCheckButton = ESButton(size: .small, title: "쀑볡 확인").then {
34+
$0.isEnabled = false
35+
}
36+
37+
/// λ‹‰λ„€μž„ 검증 κ²°κ³Ό λ©”μ‹œμ§€λ₯Ό ν‘œμ‹œν•˜λŠ” λ ˆμ΄λΈ”
38+
let nicknameValidationMessageLabel = UILabel().then {
39+
$0.text = ESTextLiteral.Nickname.hintInputNickName
40+
$0.textColor = EATSSUDesignAsset.Color.GrayScale.gray400.color
41+
$0.font = EATSSUDesignFontFamily.Pretendard.regular.font(size: 12)
42+
}
43+
44+
/// λ‹‰λ„€μž„ μž…λ ₯ ν•„λ“œ 및 검증 λ©”μ‹œμ§€λ₯Ό ν¬ν•¨ν•˜λŠ” StackView
45+
private lazy var setNickNameStackView = UIStackView(arrangedSubviews: [
46+
inputNickNameTextField,
47+
nicknameValidationMessageLabel,
48+
]).then {
49+
$0.axis = .vertical
50+
$0.spacing = 8.0
51+
}
52+
53+
/// μ™„λ£Œ λ²„νŠΌ
54+
let completeSettingNickNameButton = ESButton(size: .big, title: "μ™„λ£Œν•˜κΈ°").then {
55+
$0.isEnabled = false
56+
}
57+
58+
// MARK: - Initializer
59+
60+
override init(frame: CGRect) {
61+
super.init(frame: frame)
62+
setTextFieldDelegate()
63+
}
64+
65+
// MARK: - Functions
66+
67+
/// UI ꡬ성 μš”μ†Œλ₯Ό μΆ”κ°€ν•˜λŠ” λ©”μ„œλ“œ
68+
override func configureUI() {
69+
addSubviews(
70+
nickNameLabel,
71+
setNickNameStackView,
72+
completeSettingNickNameButton,
73+
nicknameDoubleCheckButton
74+
)
75+
}
76+
77+
/// λ ˆμ΄μ•„μ›ƒ μ„€μ • λ©”μ„œλ“œ
78+
override func setLayout() {
79+
nickNameLabel.snp.makeConstraints {
80+
$0.top.equalTo(safeAreaLayoutGuide).offset(20)
81+
$0.leading.equalToSuperview().inset(16)
82+
}
83+
setNickNameStackView.snp.makeConstraints {
84+
$0.top.equalTo(nickNameLabel.snp.bottom).offset(16)
85+
$0.leading.equalToSuperview().inset(16)
86+
$0.trailing.equalTo(nicknameDoubleCheckButton.snp.leading).offset(-5)
87+
}
88+
nicknameDoubleCheckButton.snp.makeConstraints {
89+
$0.top.equalTo(inputNickNameTextField)
90+
$0.width.equalTo(75)
91+
$0.height.equalTo(48)
92+
$0.trailing.equalToSuperview().inset(16)
93+
}
94+
inputNickNameTextField.snp.makeConstraints {
95+
$0.height.equalTo(48)
96+
}
97+
completeSettingNickNameButton.snp.makeConstraints {
98+
$0.horizontalEdges.equalToSuperview().inset(16)
99+
$0.bottom.equalTo(safeAreaLayoutGuide).inset(26)
100+
$0.height.equalTo(50)
101+
}
102+
}
103+
104+
/// λ‹‰λ„€μž„ μž…λ ₯ ν•„λ“œμ˜ delegate μ„€μ •
105+
func setTextFieldDelegate() {
106+
inputNickNameTextField.delegate = self
107+
}
108+
}
109+
110+
// MARK: - UITextFieldDelegate
111+
112+
extension MyInfoView: UITextFieldDelegate {
113+
/// μ‚¬μš©μžκ°€ Return ν‚€λ₯Ό λˆ„λ₯΄λ©΄ ν‚€λ³΄λ“œλ₯Ό λ‚΄λ¦Ό
114+
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
115+
textField.resignFirstResponder()
116+
return true
117+
}
118+
119+
/// μ‚¬μš©μžμ˜ λ‹‰λ„€μž„ μž…λ ₯ 값이 변경될 λ•Œ 호좜
120+
func textFieldDidChangeSelection(_ textField: UITextField) {
121+
guard let inputValue = textField.text?.trimmingCharacters(in: .whitespaces) else { return }
122+
123+
if inputValue.isEmpty {
124+
textFieldSettingWhenEmpty()
125+
return
126+
}
127+
checkNicknameValidation(textField)
128+
}
129+
130+
/// μž…λ ₯ ν•„λ“œλ₯Ό μ΄ˆκΈ°ν™”ν•  λ•Œ 호좜 (λ²„νŠΌ λΉ„ν™œμ„±ν™”)
131+
func textFieldShouldClear(_: UITextField) -> Bool {
132+
nicknameDoubleCheckButton.isEnabled = false
133+
completeSettingNickNameButton.isEnabled = false
134+
return true
135+
}
136+
}
137+
138+
// MARK: - Validation User Information
139+
140+
private extension MyInfoView {
141+
/// λ‹‰λ„€μž„ μž…λ ₯ 값이 없을 λ•Œ κΈ°λ³Έ λ©”μ‹œμ§€λ₯Ό ν‘œμ‹œ
142+
func textFieldSettingWhenEmpty() {
143+
nicknameValidationMessageLabel.text = NicknameTextFieldResultType.textFieldEmpty.hintMessage
144+
nicknameValidationMessageLabel.textColor = NicknameTextFieldResultType.textFieldEmpty.textColor
145+
}
146+
147+
/// λ‹‰λ„€μž„ μœ νš¨μ„± 검사
148+
func checkNicknameValidation(_ textField: UITextField) {
149+
if let userNickname = textField.text {
150+
if nicknameInputChanged(nickname: userNickname) {
151+
nicknameValidationMessageLabel.text = NicknameTextFieldResultType.nicknameTextFieldDoubleCheck.hintMessage
152+
nicknameValidationMessageLabel.textColor = NicknameTextFieldResultType.nicknameTextFieldDoubleCheck.textColor
153+
} else {
154+
nicknameValidationMessageLabel.text = NicknameTextFieldResultType.nicknameTextFieldOver.hintMessage
155+
nicknameValidationMessageLabel.textColor = NicknameTextFieldResultType.nicknameTextFieldOver.textColor
156+
}
157+
}
158+
}
159+
160+
/**
161+
λ‹‰λ„€μž„μ΄ λ³€κ²½λ˜μ—ˆμ„ λ•Œ μœ νš¨μ„± 검사λ₯Ό μˆ˜ν–‰ν•˜κ³  λ²„νŠΌ ν™œμ„±ν™” μ—¬λΆ€λ₯Ό μ„€μ •
162+
163+
- Parameter nickname: μ‚¬μš©μžκ°€ μž…λ ₯ν•œ λ‹‰λ„€μž„
164+
- Returns: λ‹‰λ„€μž„μ΄ μœ νš¨ν•œ 경우 `true`, κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ `false`
165+
*/
166+
func nicknameInputChanged(nickname: String) -> Bool {
167+
completeSettingNickNameButton.isEnabled = false
168+
169+
if nickname.count > 1, nickname.count < 9 {
170+
nicknameDoubleCheckButton.isEnabled = true
171+
return true
172+
} else {
173+
nicknameDoubleCheckButton.isEnabled = false
174+
return false
175+
}
176+
}
177+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
//
2+
// MyInfoViewController.swift
3+
// EATSSU
4+
//
5+
// Created by Jiwoong CHOI on 01/31/25.
6+
//
7+
8+
import Moya
9+
import UIKit
10+
11+
/// μ‚¬μš©μžμ˜ λ‹‰λ„€μž„μ„ μ„€μ • 및 검증할 수 μžˆλŠ” ν™”λ©΄μž…λ‹ˆλ‹€.
12+
final class MyInfoViewController: BaseViewController {
13+
// MARK: - Properties
14+
15+
/// ν˜„μž¬ ν‚€λ³΄λ“œ 높이λ₯Ό μ €μž₯ν•˜λŠ” λ³€μˆ˜μž…λ‹ˆλ‹€.
16+
var currentKeyboardHeight: CGFloat = 0.0
17+
18+
/// λ‹‰λ„€μž„ κ΄€λ ¨ API μš”μ²­μ„ μœ„ν•œ Moya Providerμž…λ‹ˆλ‹€.
19+
let nicknameProvider = MoyaProvider<UserNicknameRouter>(plugins: [ESMoyaLoggingPlugin()])
20+
21+
// MARK: - UI Components
22+
23+
/// μ‚¬μš©μž 정보 μž…λ ₯ 및 λ‹‰λ„€μž„ μ„€μ • UIλ₯Ό ν¬ν•¨ν•˜λŠ” λ·°μž…λ‹ˆλ‹€.
24+
let myInfoView = MyInfoView()
25+
26+
// MARK: - Life Cycle
27+
28+
override func viewDidLoad() {
29+
super.viewDidLoad()
30+
dismissKeyboard()
31+
}
32+
33+
override func viewWillAppear(_ animated: Bool) {
34+
super.viewWillAppear(animated)
35+
addKeyboardNotifications()
36+
}
37+
38+
override func viewWillDisappear(_ animated: Bool) {
39+
super.viewWillDisappear(animated)
40+
removeKeyboardNotifications()
41+
}
42+
43+
// MARK: - UI μ„€μ •
44+
45+
override func configureUI() {
46+
view.addSubviews(myInfoView)
47+
}
48+
49+
override func setLayout() {
50+
myInfoView.snp.makeConstraints {
51+
$0.edges.equalToSuperview()
52+
}
53+
}
54+
55+
override func setESNavigationBar() {
56+
super.setESNavigationBar()
57+
navigationItem.title = ESTextLiteral.Nickname.setNickName
58+
}
59+
60+
override func setButtonEvent() {
61+
myInfoView.completeSettingNickNameButton.addTarget(self, action: #selector(tappedCompleteNickNameButton), for: .touchUpInside)
62+
myInfoView.nicknameDoubleCheckButton.addTarget(self, action: #selector(tappedCheckButton), for: .touchUpInside)
63+
}
64+
65+
// MARK: - λ‹‰λ„€μž„ μ„€μ • 이벀트
66+
67+
/// "λ‹‰λ„€μž„ μ„€μ • μ™„λ£Œ" λ²„νŠΌμ„ λˆŒλ €μ„ λ•Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.
68+
@objc
69+
func tappedCompleteNickNameButton() {
70+
setUserNickname(nickname: myInfoView.inputNickNameTextField.text ?? "")
71+
}
72+
73+
/// "쀑볡 확인" λ²„νŠΌμ„ λˆŒλ €μ„ λ•Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.
74+
@objc
75+
func tappedCheckButton() {
76+
checkNickname(nickname: myInfoView.inputNickNameTextField.text ?? "")
77+
}
78+
79+
// MARK: - ν‚€λ³΄λ“œ 감지
80+
81+
/// ν‚€λ³΄λ“œ 이벀트 감지λ₯Ό μœ„ν•œ μ˜΅μ €λ²„λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.
82+
func addKeyboardNotifications() {
83+
NotificationCenter.default.addObserver(self,
84+
selector: #selector(keyboardWillShow(_:)),
85+
name: UIResponder.keyboardWillShowNotification,
86+
object: nil)
87+
NotificationCenter.default.addObserver(self,
88+
selector: #selector(keyboardWillHide(_:)),
89+
name: UIResponder.keyboardWillHideNotification,
90+
object: nil)
91+
}
92+
93+
/// ν‚€λ³΄λ“œ 이벀트 μ˜΅μ €λ²„λ₯Ό μ œκ±°ν•©λ‹ˆλ‹€.
94+
func removeKeyboardNotifications() {
95+
NotificationCenter.default.removeObserver(self,
96+
name: UIResponder.keyboardWillShowNotification,
97+
object: nil)
98+
NotificationCenter.default.removeObserver(self,
99+
name: UIResponder.keyboardWillHideNotification,
100+
object: nil)
101+
}
102+
103+
/// ν‚€λ³΄λ“œκ°€ λ‚˜νƒ€λ‚  λ•Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.
104+
@objc
105+
func keyboardWillShow(_ notification: Notification) {
106+
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
107+
let updateKeyboardHeight = keyboardSize.height
108+
let difference = updateKeyboardHeight - currentKeyboardHeight
109+
110+
myInfoView.completeSettingNickNameButton.frame.origin.y -= difference
111+
currentKeyboardHeight = updateKeyboardHeight
112+
}
113+
}
114+
115+
/// ν‚€λ³΄λ“œκ°€ μ‚¬λΌμ§ˆ λ•Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.
116+
@objc
117+
func keyboardWillHide(_ notification: Notification) {
118+
if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
119+
myInfoView.completeSettingNickNameButton.frame.origin.y += currentKeyboardHeight
120+
currentKeyboardHeight = 0.0
121+
}
122+
}
123+
}
124+
125+
// MARK: - λ„€νŠΈμ›Œν¬ μš”μ²­
126+
127+
extension MyInfoViewController {
128+
/// μ‚¬μš©μžμ˜ λ‹‰λ„€μž„μ„ μ„œλ²„μ— μ„€μ •ν•˜λŠ” API μš”μ²­μ„ λ³΄λƒ…λ‹ˆλ‹€.
129+
/// - Parameter nickname: μ‚¬μš©μžκ°€ μž…λ ₯ν•œ λ‹‰λ„€μž„
130+
func setUserNickname(nickname: String) {
131+
nicknameProvider.request(.setNickname(nickname: nickname)) { response in
132+
switch response {
133+
case let .success(moyaResponse):
134+
do {
135+
if let currentUserInfo = UserInfoManager.shared.getCurrentUserInfo() {
136+
UserInfoManager.shared.updateNickname(for: currentUserInfo, nickname: nickname)
137+
}
138+
self.showAlertController(title: "μ™„λ£Œ", message: "λ‹‰λ„€μž„ 섀정이 μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.", style: .cancel) {
139+
if let myPageViewController = self.navigationController?.viewControllers.first(where: { $0 is MyPageViewController }) {
140+
self.navigationController?.popToViewController(myPageViewController, animated: true)
141+
} else {
142+
let homeViewController = HomeViewController()
143+
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
144+
let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow })
145+
{
146+
keyWindow.replaceRootViewController(UINavigationController(rootViewController: homeViewController))
147+
}
148+
}
149+
}
150+
print(moyaResponse.statusCode)
151+
}
152+
case let .failure(err):
153+
print(err.localizedDescription)
154+
}
155+
}
156+
}
157+
158+
/// μ‚¬μš©μžκ°€ μž…λ ₯ν•œ λ‹‰λ„€μž„μ˜ 쀑볡 μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” API μš”μ²­μ„ λ³΄λƒ…λ‹ˆλ‹€.
159+
/// - Parameter nickname: μ‚¬μš©μžκ°€ μž…λ ₯ν•œ λ‹‰λ„€μž„
160+
func checkNickname(nickname: String) {
161+
nicknameProvider.request(.checkNickname(nickname: nickname)) { response in
162+
switch response {
163+
case let .success(moyaResponse):
164+
do {
165+
let responseData = try moyaResponse.map(BaseResponse<Bool>.self)
166+
let isSuccess = responseData.result
167+
if isSuccess {
168+
self.view.showToast(message: "μ‚¬μš© κ°€λŠ₯ν•œ λ‹‰λ„€μž„μ΄μ—μš”")
169+
self.myInfoView.completeSettingNickNameButton.isEnabled = true
170+
self.myInfoView.nicknameValidationMessageLabel.text = NicknameTextFieldResultType.nicknameTextFieldValid.hintMessage
171+
self.myInfoView.nicknameValidationMessageLabel.textColor = NicknameTextFieldResultType.nicknameTextFieldValid.textColor
172+
} else {
173+
self.view.showToast(message: "이미 μ‚¬μš© 쀑인 λ‹‰λ„€μž„μ΄μ—μš”")
174+
self.myInfoView.completeSettingNickNameButton.isEnabled = false
175+
self.myInfoView.nicknameValidationMessageLabel.text = NicknameTextFieldResultType.nicknameTextFieldDuplicated.hintMessage
176+
self.myInfoView.nicknameValidationMessageLabel.textColor = NicknameTextFieldResultType.nicknameTextFieldDuplicated.textColor
177+
}
178+
} catch let err {
179+
print(err.localizedDescription)
180+
}
181+
case let .failure(err):
182+
print(err.localizedDescription)
183+
}
184+
}
185+
}
186+
}

0 commit comments

Comments
Β (0)