From 54361f3a6db82c6f64c0c5f57ac175fb20def8db Mon Sep 17 00:00:00 2001 From: mmaybei Date: Sun, 14 Jul 2024 19:37:38 +0900 Subject: [PATCH 01/17] =?UTF-8?q?feat/#170=20ResponseDTO=EC=97=90=20succes?= =?UTF-8?q?s=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift b/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift index b3347ed2..1f25daff 100644 --- a/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift +++ b/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift @@ -9,6 +9,7 @@ import Foundation /// 제네릭 ResponseBody 구조체 정의 struct ResponseBodyDTO: Codable { + let success: Bool let data: T? let error: ErrorResponse? } From 9d64503409df1d496487918a601144b8ac01ee89 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Sun, 14 Jul 2024 20:50:42 +0900 Subject: [PATCH 02/17] =?UTF-8?q?fix/#170=20=ED=99=88=20=EB=B7=B0=20?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum/Source/Home/View/TodayPromiseView.swift | 2 +- KkuMulKum/Source/Home/ViewController/HomeViewController.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/KkuMulKum/Source/Home/View/TodayPromiseView.swift b/KkuMulKum/Source/Home/View/TodayPromiseView.swift index ba67fde6..f0f9512f 100644 --- a/KkuMulKum/Source/Home/View/TodayPromiseView.swift +++ b/KkuMulKum/Source/Home/View/TodayPromiseView.swift @@ -106,7 +106,7 @@ final class TodayPromiseView: BaseView { } let prepareButton = UIButton().then { - $0.setTitle("준비 중", style: .body05, color: .maincolor) + $0.setTitle("준비 시작", style: .body05, color: .maincolor) $0.setLayer(borderWidth: 1, borderColor: .maincolor, cornerRadius: 16) } diff --git a/KkuMulKum/Source/Home/ViewController/HomeViewController.swift b/KkuMulKum/Source/Home/ViewController/HomeViewController.swift index 976bc923..b8e1fa13 100644 --- a/KkuMulKum/Source/Home/ViewController/HomeViewController.swift +++ b/KkuMulKum/Source/Home/ViewController/HomeViewController.swift @@ -199,6 +199,7 @@ private extension HomeViewController { func setPrepareUI() { setProgressButton(rootView.todayPromiseView.prepareButton) + rootView.todayPromiseView.moveButton.setTitle("준비 중", for: .normal) setEnableButton(rootView.todayPromiseView.moveButton) setDisableButton(rootView.todayPromiseView.arriveButton) From 8ce81d70674ee0f52bfba3b7ac67c0d14dad3f41 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Sun, 14 Jul 2024 22:23:48 +0900 Subject: [PATCH 03/17] =?UTF-8?q?feat/#170=20UI=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum.xcodeproj/project.pbxproj | 8 + .../MeetingInfo/View/SetReadyInfoView.swift | 179 ++++++++++++++++++ .../SetReadyInfoViewController.swift | 23 +++ 3 files changed, 210 insertions(+) create mode 100644 KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift create mode 100644 KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index 5383ae98..a4ad639d 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -66,6 +66,8 @@ A3DD9C3F2C41BAD000E58A13 /* MeetingListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C362C41BAD000E58A13 /* MeetingListView.swift */; }; A3DD9C402C41BAD000E58A13 /* MeetingListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C382C41BAD000E58A13 /* MeetingListViewController.swift */; }; A3DD9C412C41BAD000E58A13 /* MeetingListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C3A2C41BAD000E58A13 /* MeetingListViewModel.swift */; }; + A3DD9C5A2C43F99800E58A13 /* SetReadyInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C592C43F99700E58A13 /* SetReadyInfoView.swift */; }; + A3DD9C5C2C43F9A800E58A13 /* SetReadyInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C5B2C43F9A800E58A13 /* SetReadyInfoViewController.swift */; }; A3FB184D2C3BF45F001483E5 /* MakeMeetingsRequestModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3FB184C2C3BF45F001483E5 /* MakeMeetingsRequestModel.swift */; }; A3FB184F2C3BF4BC001483E5 /* MakeMeetingsResponseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3FB184E2C3BF4BB001483E5 /* MakeMeetingsResponseModel.swift */; }; A3FB18512C3BF531001483E5 /* RegisterMeetingsResponseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3FB18502C3BF531001483E5 /* RegisterMeetingsResponseModel.swift */; }; @@ -200,6 +202,8 @@ A3DD9C362C41BAD000E58A13 /* MeetingListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingListView.swift; sourceTree = ""; }; A3DD9C382C41BAD000E58A13 /* MeetingListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingListViewController.swift; sourceTree = ""; }; A3DD9C3A2C41BAD000E58A13 /* MeetingListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingListViewModel.swift; sourceTree = ""; }; + A3DD9C592C43F99700E58A13 /* SetReadyInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetReadyInfoView.swift; sourceTree = ""; }; + A3DD9C5B2C43F9A800E58A13 /* SetReadyInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetReadyInfoViewController.swift; sourceTree = ""; }; A3FB184C2C3BF45F001483E5 /* MakeMeetingsRequestModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeMeetingsRequestModel.swift; sourceTree = ""; }; A3FB184E2C3BF4BB001483E5 /* MakeMeetingsResponseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeMeetingsResponseModel.swift; sourceTree = ""; }; A3FB18502C3BF531001483E5 /* RegisterMeetingsResponseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterMeetingsResponseModel.swift; sourceTree = ""; }; @@ -1048,6 +1052,7 @@ DE6D4D052C3F14D80005584B /* MeetingInfoView.swift */, DE6D4D062C3F14D80005584B /* MeetingMemberCell.swift */, DE6D4D072C3F14D80005584B /* MeetingPromiseCell.swift */, + A3DD9C592C43F99700E58A13 /* SetReadyInfoView.swift */, ); path = View; sourceTree = ""; @@ -1057,6 +1062,7 @@ children = ( DE6D4D092C3F14D80005584B /* InvitationCodePopUpViewController.swift */, DE6D4D0A2C3F14D80005584B /* MeetingInfoViewController.swift */, + A3DD9C5B2C43F9A800E58A13 /* SetReadyInfoViewController.swift */, ); path = ViewController; sourceTree = ""; @@ -1434,6 +1440,7 @@ DD39766F2C41B54400E2A4C4 /* InviteCodeService.swift in Sources */, DE6D4D172C3F14D80005584B /* MeetingInfoViewModel.swift in Sources */, 78AED1372C3D98D1000AD80A /* NicknameView.swift in Sources */, + A3DD9C5C2C43F9A800E58A13 /* SetReadyInfoViewController.swift in Sources */, A3FB185B2C3BF7DF001483E5 /* MeetingMembersResponseModel.swift in Sources */, DD3072222C3C0DA300416D9F /* PromiseParticipantListResponseModel.swift in Sources */, DD3976862C41C2AD00E2A4C4 /* HomeView.swift in Sources */, @@ -1453,6 +1460,7 @@ DD931B762C3DC16100526452 /* PromiseInfoView.swift in Sources */, DD3072242C3C0EB200416D9F /* MyPromiseReadyInfoRequestModel.swift in Sources */, DD3976872C41C2AD00E2A4C4 /* TodayPromiseView.swift in Sources */, + A3DD9C5A2C43F99800E58A13 /* SetReadyInfoView.swift in Sources */, 789873332C3D1A7B00435E96 /* LoginViewModel.swift in Sources */, 782B40752C3DBFBA008B0CA7 /* ProfileView.swift in Sources */, DED5DBEE2C34529A006ECE7E /* BaseView.swift in Sources */, diff --git a/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift b/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift new file mode 100644 index 00000000..07504279 --- /dev/null +++ b/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift @@ -0,0 +1,179 @@ +// +// SetReadyInfoView.swift +// KkuMulKum +// +// Created by 예삐 on 7/14/24. +// + +import UIKit + +import SnapKit +import Then + +final class SetReadyInfoView: BaseView { + + + // MARK: - Property + + private let infoLabel = UILabel().then { + $0.setText("준비 정보를 입력해보세요!", style: .head01, color: .gray8) + } + + private let readyTimeLabel = UILabel().then { + $0.setText("준비 시간", style: .body03, color: .gray8) + } + + private let readyTimeView = UIStackView(axis: .horizontal).then { + $0.spacing = 8 + $0.alignment = .fill + $0.distribution = .fill + } + + private let readyHourTextField = UITextField().then { + $0.setText( + placeholder: "00", + textColor: .gray8, + backgroundColor: .white, + placeholderColor: .gray3, + style: .body02 + ) + $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) + $0.addPadding(left: 16, right: 16) + } + + private let readyHourLabel = UILabel().then { + $0.setText("시간", style: .body03, color: .gray8) + } + + private let readyMinuteTextField = UITextField().then { + $0.setText( + placeholder: "00", + textColor: .gray8, + backgroundColor: .white, + placeholderColor: .gray3, + style: .body02 + ) + $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) + $0.addPadding(left: 16, right: 16) + } + + private let readyMinuteLabel = UILabel().then { + $0.setText("분", style: .body03, color: .gray8) + } + + private let moveTimeLabel = UILabel().then { + $0.setText("이동 시간", style: .body03, color: .gray8) + } + + private let moveTimeView = UIStackView(axis: .horizontal).then { + $0.spacing = 8 + $0.alignment = .fill + $0.distribution = .fill + } + + private let moveHourTextField = UITextField().then { + $0.setText( + placeholder: "00", + textColor: .gray8, + backgroundColor: .white, + placeholderColor: .gray3, + style: .body02 + ) + $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) + $0.addPadding(left: 16, right: 16) + } + + private let moveHourLabel = UILabel().then { + $0.setText("시간", style: .body03, color: .gray8) + } + + private let moveMinuteTextField = UITextField().then { + $0.setText( + placeholder: "00", + textColor: .gray8, + backgroundColor: .white, + placeholderColor: .gray3, + style: .body02 + ) + $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) + $0.addPadding(left: 16, right: 16) + } + + private let moveMinuteLabel = UILabel().then { + $0.setText("분", style: .body03, color: .gray8) + } + + private let doneButton = CustomButton(title: "완료", isEnabled: false) + + + // MARK: - UI Setting + + override func setupView() { + addSubviews(infoLabel, readyTimeLabel, readyTimeView, moveTimeView, moveTimeLabel, doneButton) + readyTimeView.addArrangedSubviews( + readyHourTextField, + readyHourLabel, + readyMinuteTextField, + readyMinuteLabel + ) + moveTimeView.addArrangedSubviews( + moveHourTextField, + moveHourLabel, + moveMinuteTextField, + moveMinuteLabel + ) + } + + override func setupAutoLayout() { + infoLabel.snp.makeConstraints { + $0.top.equalToSuperview().offset(60) + $0.leading.equalToSuperview().offset(20) + } + + doneButton.snp.makeConstraints { + $0.leading.trailing.equalToSuperview().inset(20) + $0.bottom.equalToSuperview().offset(-64) + $0.height.equalTo(Screen.height(52)) + } + + readyTimeLabel.snp.makeConstraints { + $0.top.equalTo(infoLabel.snp.bottom).offset(20) + $0.leading.equalToSuperview().offset(20) + } + + readyTimeView.snp.makeConstraints { + $0.top.equalTo(readyTimeLabel.snp.bottom).offset(12) + $0.leading.equalToSuperview().offset(20) + } + + readyHourTextField.snp.makeConstraints { + $0.width.equalTo(56) + $0.height.equalTo(44) + } + + readyMinuteTextField.snp.makeConstraints { + $0.width.equalTo(56) + $0.height.equalTo(44) + } + + moveTimeLabel.snp.makeConstraints { + $0.top.equalTo(readyTimeView.snp.bottom).offset(16) + $0.leading.equalToSuperview().offset(20) + } + + moveTimeView.snp.makeConstraints { + $0.top.equalTo(moveTimeLabel.snp.bottom).offset(12) + $0.leading.equalToSuperview().offset(20) + } + + moveHourTextField.snp.makeConstraints { + $0.width.equalTo(56) + $0.height.equalTo(44) + } + + moveMinuteTextField.snp.makeConstraints { + $0.width.equalTo(56) + $0.height.equalTo(44) + } + } +} diff --git a/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift new file mode 100644 index 00000000..318ecc0c --- /dev/null +++ b/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift @@ -0,0 +1,23 @@ +// +// SetReadyInfoViewController.swift +// KkuMulKum +// +// Created by 예삐 on 7/14/24. +// + +import UIKit + +final class SetReadyInfoViewController: BaseViewController { + + + // MARK: - Property + + private let rootView = SetReadyInfoView() + + + // MARK: - LifeCycle + + override func loadView() { + self.view = rootView + } +} From 30d7e17a54f28aae00e07dfa7e1af7e194d843d9 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Sun, 14 Jul 2024 22:43:59 +0900 Subject: [PATCH 04/17] =?UTF-8?q?fix/#170=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=ED=95=84=EB=93=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=EA=B0=80=EC=9D=B4=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Resource/Component/CustomTextField.swift | 4 +- .../MeetingInfo/View/SetReadyInfoView.swift | 48 ++----------------- 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/KkuMulKum/Resource/Component/CustomTextField.swift b/KkuMulKum/Resource/Component/CustomTextField.swift index bdcfc24d..1a21b976 100644 --- a/KkuMulKum/Resource/Component/CustomTextField.swift +++ b/KkuMulKum/Resource/Component/CustomTextField.swift @@ -37,9 +37,9 @@ private extension CustomTextField { textColor: .black, backgroundColor: .white, placeholderColor: .gray3, - style: .body04 + style: .body02 ) - addPadding(left: 12) + addPadding(left: 18) setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) setAutoType() } diff --git a/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift b/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift index 07504279..8607c1d4 100644 --- a/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift +++ b/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift @@ -29,33 +29,13 @@ final class SetReadyInfoView: BaseView { $0.distribution = .fill } - private let readyHourTextField = UITextField().then { - $0.setText( - placeholder: "00", - textColor: .gray8, - backgroundColor: .white, - placeholderColor: .gray3, - style: .body02 - ) - $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) - $0.addPadding(left: 16, right: 16) - } + private let readyHourTextField = CustomTextField(placeHolder: "00") private let readyHourLabel = UILabel().then { $0.setText("시간", style: .body03, color: .gray8) } - private let readyMinuteTextField = UITextField().then { - $0.setText( - placeholder: "00", - textColor: .gray8, - backgroundColor: .white, - placeholderColor: .gray3, - style: .body02 - ) - $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) - $0.addPadding(left: 16, right: 16) - } + private let readyMinuteTextField = CustomTextField(placeHolder: "00") private let readyMinuteLabel = UILabel().then { $0.setText("분", style: .body03, color: .gray8) @@ -71,33 +51,13 @@ final class SetReadyInfoView: BaseView { $0.distribution = .fill } - private let moveHourTextField = UITextField().then { - $0.setText( - placeholder: "00", - textColor: .gray8, - backgroundColor: .white, - placeholderColor: .gray3, - style: .body02 - ) - $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) - $0.addPadding(left: 16, right: 16) - } + private let moveHourTextField = CustomTextField(placeHolder: "00") private let moveHourLabel = UILabel().then { $0.setText("시간", style: .body03, color: .gray8) } - private let moveMinuteTextField = UITextField().then { - $0.setText( - placeholder: "00", - textColor: .gray8, - backgroundColor: .white, - placeholderColor: .gray3, - style: .body02 - ) - $0.setLayer(borderWidth: 1, borderColor: .gray3, cornerRadius: 8) - $0.addPadding(left: 16, right: 16) - } + private let moveMinuteTextField = CustomTextField(placeHolder: "00") private let moveMinuteLabel = UILabel().then { $0.setText("분", style: .body03, color: .gray8) From a9a040909877e7c285c0b8583f828ff00dfd2d38 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Sun, 14 Jul 2024 23:48:12 +0900 Subject: [PATCH 05/17] =?UTF-8?q?feat/#170=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=83=89=EC=83=81=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?delegate=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MeetingInfo/View/SetReadyInfoView.swift | 8 +++--- .../SetReadyInfoViewController.swift | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift b/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift index 8607c1d4..944d8c8e 100644 --- a/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift +++ b/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift @@ -29,13 +29,13 @@ final class SetReadyInfoView: BaseView { $0.distribution = .fill } - private let readyHourTextField = CustomTextField(placeHolder: "00") + let readyHourTextField = CustomTextField(placeHolder: "00") private let readyHourLabel = UILabel().then { $0.setText("시간", style: .body03, color: .gray8) } - private let readyMinuteTextField = CustomTextField(placeHolder: "00") + let readyMinuteTextField = CustomTextField(placeHolder: "00") private let readyMinuteLabel = UILabel().then { $0.setText("분", style: .body03, color: .gray8) @@ -51,13 +51,13 @@ final class SetReadyInfoView: BaseView { $0.distribution = .fill } - private let moveHourTextField = CustomTextField(placeHolder: "00") + let moveHourTextField = CustomTextField(placeHolder: "00") private let moveHourLabel = UILabel().then { $0.setText("시간", style: .body03, color: .gray8) } - private let moveMinuteTextField = CustomTextField(placeHolder: "00") + let moveMinuteTextField = CustomTextField(placeHolder: "00") private let moveMinuteLabel = UILabel().then { $0.setText("분", style: .body03, color: .gray8) diff --git a/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift index 318ecc0c..9505e57a 100644 --- a/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift @@ -20,4 +20,29 @@ final class SetReadyInfoViewController: BaseViewController { override func loadView() { self.view = rootView } + + override func viewDidLoad() { + view.backgroundColor = .white + setTextFieldDelegate() + } + + private func setTextFieldDelegate() { + rootView.readyHourTextField.delegate = self + rootView.readyMinuteTextField.delegate = self + rootView.moveHourTextField.delegate = self + rootView.moveMinuteTextField.delegate = self + } +} + + +// MARK: - UITextFieldDelegate + +extension SetReadyInfoViewController: UITextFieldDelegate { + func textFieldDidBeginEditing(_ textField: UITextField) { + textField.layer.borderColor = UIColor.maincolor.cgColor + } + + func textFieldDidEndEditing(_ textField: UITextField) { + textField.layer.borderColor = UIColor.gray3.cgColor + } } From 365f445569a7c28126bc8030a0f141a4534db4de Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 15 Jul 2024 01:14:05 +0900 Subject: [PATCH 06/17] =?UTF-8?q?feat/#170=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=9E=85=EB=A0=A5=20=EC=A0=9C=ED=95=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum.xcodeproj/project.pbxproj | 16 +++- .../SetReadyInfoViewController.swift | 48 ----------- .../ReadyStatus}/View/SetReadyInfoView.swift | 0 .../SetReadyInfoViewController.swift | 79 +++++++++++++++++++ .../ViewModel/SetReadyInfoViewModel.swift | 9 +++ 5 files changed, 102 insertions(+), 50 deletions(-) delete mode 100644 KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift rename KkuMulKum/Source/{MeetingInfo => Promise/ReadyStatus}/View/SetReadyInfoView.swift (100%) create mode 100644 KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift create mode 100644 KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index a4ad639d..48f170ea 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -68,6 +68,7 @@ A3DD9C412C41BAD000E58A13 /* MeetingListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C3A2C41BAD000E58A13 /* MeetingListViewModel.swift */; }; A3DD9C5A2C43F99800E58A13 /* SetReadyInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C592C43F99700E58A13 /* SetReadyInfoView.swift */; }; A3DD9C5C2C43F9A800E58A13 /* SetReadyInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C5B2C43F9A800E58A13 /* SetReadyInfoViewController.swift */; }; + A3DD9C5F2C441F8E00E58A13 /* SetReadyInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C5E2C441F8E00E58A13 /* SetReadyInfoViewModel.swift */; }; A3FB184D2C3BF45F001483E5 /* MakeMeetingsRequestModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3FB184C2C3BF45F001483E5 /* MakeMeetingsRequestModel.swift */; }; A3FB184F2C3BF4BC001483E5 /* MakeMeetingsResponseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3FB184E2C3BF4BB001483E5 /* MakeMeetingsResponseModel.swift */; }; A3FB18512C3BF531001483E5 /* RegisterMeetingsResponseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3FB18502C3BF531001483E5 /* RegisterMeetingsResponseModel.swift */; }; @@ -204,6 +205,7 @@ A3DD9C3A2C41BAD000E58A13 /* MeetingListViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingListViewModel.swift; sourceTree = ""; }; A3DD9C592C43F99700E58A13 /* SetReadyInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetReadyInfoView.swift; sourceTree = ""; }; A3DD9C5B2C43F9A800E58A13 /* SetReadyInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetReadyInfoViewController.swift; sourceTree = ""; }; + A3DD9C5E2C441F8E00E58A13 /* SetReadyInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetReadyInfoViewModel.swift; sourceTree = ""; }; A3FB184C2C3BF45F001483E5 /* MakeMeetingsRequestModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeMeetingsRequestModel.swift; sourceTree = ""; }; A3FB184E2C3BF4BB001483E5 /* MakeMeetingsResponseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeMeetingsResponseModel.swift; sourceTree = ""; }; A3FB18502C3BF531001483E5 /* RegisterMeetingsResponseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterMeetingsResponseModel.swift; sourceTree = ""; }; @@ -562,6 +564,14 @@ path = MeetingList; sourceTree = ""; }; + A3DD9C5D2C441F6600E58A13 /* ViewModel */ = { + isa = PBXGroup; + children = ( + A3DD9C5E2C441F8E00E58A13 /* SetReadyInfoViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; DD3976692C41769900E2A4C4 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -728,6 +738,7 @@ DD3976952C41CC2200E2A4C4 /* ViewController */ = { isa = PBXGroup; children = ( + A3DD9C5B2C43F9A800E58A13 /* SetReadyInfoViewController.swift */, DDAF1C882C3D6E3D008A37D3 /* ReadyStatusViewController.swift */, ); path = ViewController; @@ -736,6 +747,7 @@ DD3976962C41CC2C00E2A4C4 /* View */ = { isa = PBXGroup; children = ( + A3DD9C592C43F99700E58A13 /* SetReadyInfoView.swift */, DD931B6A2C3D9EBB00526452 /* ReadyStatusView.swift */, DD931B712C3DA92700526452 /* EnterReadyInfoButtonView.swift */, DD931B732C3DAB9A00526452 /* ReadyPlanInfoView.swift */, @@ -883,6 +895,7 @@ DD931B672C3D9D9C00526452 /* ReadyStatus */ = { isa = PBXGroup; children = ( + A3DD9C5D2C441F6600E58A13 /* ViewModel */, DD3976952C41CC2200E2A4C4 /* ViewController */, DD3976962C41CC2C00E2A4C4 /* View */, ); @@ -1052,7 +1065,6 @@ DE6D4D052C3F14D80005584B /* MeetingInfoView.swift */, DE6D4D062C3F14D80005584B /* MeetingMemberCell.swift */, DE6D4D072C3F14D80005584B /* MeetingPromiseCell.swift */, - A3DD9C592C43F99700E58A13 /* SetReadyInfoView.swift */, ); path = View; sourceTree = ""; @@ -1062,7 +1074,6 @@ children = ( DE6D4D092C3F14D80005584B /* InvitationCodePopUpViewController.swift */, DE6D4D0A2C3F14D80005584B /* MeetingInfoViewController.swift */, - A3DD9C5B2C43F9A800E58A13 /* SetReadyInfoViewController.swift */, ); path = ViewController; sourceTree = ""; @@ -1428,6 +1439,7 @@ DD3072162C3BFE4E00416D9F /* UpcomingPromiseListResponseModel.swift in Sources */, A3FB18572C3BF704001483E5 /* MeetingListResponseModel.swift in Sources */, DE254AB22C31197B00A4015E /* UIButton+.swift in Sources */, + A3DD9C5F2C441F8E00E58A13 /* SetReadyInfoViewModel.swift in Sources */, DE6D4D162C3F14D80005584B /* MeetingInfoViewController.swift in Sources */, DE159D322C406E1600425101 /* MyPageAlarmSettingView.swift in Sources */, 78B9286C2C29402C006D9942 /* AppDelegate.swift in Sources */, diff --git a/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift deleted file mode 100644 index 9505e57a..00000000 --- a/KkuMulKum/Source/MeetingInfo/ViewController/SetReadyInfoViewController.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// SetReadyInfoViewController.swift -// KkuMulKum -// -// Created by 예삐 on 7/14/24. -// - -import UIKit - -final class SetReadyInfoViewController: BaseViewController { - - - // MARK: - Property - - private let rootView = SetReadyInfoView() - - - // MARK: - LifeCycle - - override func loadView() { - self.view = rootView - } - - override func viewDidLoad() { - view.backgroundColor = .white - setTextFieldDelegate() - } - - private func setTextFieldDelegate() { - rootView.readyHourTextField.delegate = self - rootView.readyMinuteTextField.delegate = self - rootView.moveHourTextField.delegate = self - rootView.moveMinuteTextField.delegate = self - } -} - - -// MARK: - UITextFieldDelegate - -extension SetReadyInfoViewController: UITextFieldDelegate { - func textFieldDidBeginEditing(_ textField: UITextField) { - textField.layer.borderColor = UIColor.maincolor.cgColor - } - - func textFieldDidEndEditing(_ textField: UITextField) { - textField.layer.borderColor = UIColor.gray3.cgColor - } -} diff --git a/KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift similarity index 100% rename from KkuMulKum/Source/MeetingInfo/View/SetReadyInfoView.swift rename to KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift new file mode 100644 index 00000000..e3eec8e8 --- /dev/null +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift @@ -0,0 +1,79 @@ +// +// SetReadyInfoViewController.swift +// KkuMulKum +// +// Created by 예삐 on 7/14/24. +// + +import UIKit + +final class SetReadyInfoViewController: BaseViewController { + + + // MARK: - Property + + private let rootView = SetReadyInfoView() + + + // MARK: - LifeCycle + + override func loadView() { + self.view = rootView + } + + override func viewDidLoad() { + view.backgroundColor = .white + setTextFieldDelegate() + } + + private func setTextFieldDelegate() { + rootView.readyHourTextField.delegate = self + rootView.readyMinuteTextField.delegate = self + rootView.moveHourTextField.delegate = self + rootView.moveMinuteTextField.delegate = self + + rootView.readyHourTextField.keyboardType = .numberPad + rootView.readyMinuteTextField.keyboardType = .numberPad + rootView.moveHourTextField.keyboardType = .numberPad + rootView.moveMinuteTextField.keyboardType = .numberPad + } +} + + +// MARK: - UITextFieldDelegate + +extension SetReadyInfoViewController: UITextFieldDelegate { + func textFieldDidBeginEditing(_ textField: UITextField) { + textField.layer.borderColor = UIColor.maincolor.cgColor + } + + func textFieldDidEndEditing(_ textField: UITextField) { + textField.layer.borderColor = UIColor.gray3.cgColor + validateTextField(textField) + } + + func textField( + _ textField: UITextField, + shouldChangeCharactersIn range: NSRange, + replacementString string: String + ) -> Bool { + let allowedCharacters = CharacterSet.decimalDigits + let characterSet = CharacterSet(charactersIn: string) + return allowedCharacters.isSuperset(of: characterSet) + } + + private func validateTextField(_ textField: UITextField) { + guard let text = textField.text, let value = Int(text) else { return } + + if textField == rootView.readyHourTextField || textField == rootView.moveHourTextField { + if value >= 24 { + textField.text = "23" + } + } + if textField == rootView.readyMinuteTextField || textField == rootView.moveMinuteTextField { + if value >= 60 { + textField.text = "59" + } + } + } +} diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift new file mode 100644 index 00000000..a460520e --- /dev/null +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift @@ -0,0 +1,9 @@ +// +// SetReadyInfoViewModel.swift +// KkuMulKum +// +// Created by 예삐 on 7/15/24. +// + +import UIKit + From 2b6e671b6be53d8bd259f9f6a5bce4415314d93c Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 15 Jul 2024 06:42:34 +0900 Subject: [PATCH 07/17] =?UTF-8?q?fix/#170=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EB=A1=9C=EC=A7=81=20=EB=B7=B0=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인쌤과의 QA 하에 토스트 텍스트 크기 변경했습니다 --- KkuMulKum/Resource/Util/Toast.swift | 2 +- .../ReadyStatus/View/SetReadyInfoView.swift | 2 +- .../SetReadyInfoViewController.swift | 44 ++++++++++++------- .../ViewModel/SetReadyInfoViewModel.swift | 31 +++++++++++++ 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/KkuMulKum/Resource/Util/Toast.swift b/KkuMulKum/Resource/Util/Toast.swift index 68a7a14e..7eed5875 100644 --- a/KkuMulKum/Resource/Util/Toast.swift +++ b/KkuMulKum/Resource/Util/Toast.swift @@ -39,7 +39,7 @@ private extension Toast { $0.textColor = .white $0.textAlignment = .center $0.text = message - $0.font = .pretendard(.body02) + $0.font = .pretendard(.body06) $0.clipsToBounds = true $0.numberOfLines = 0 $0.sizeToFit() diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift index 944d8c8e..623e123f 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift @@ -63,7 +63,7 @@ final class SetReadyInfoView: BaseView { $0.setText("분", style: .body03, color: .gray8) } - private let doneButton = CustomButton(title: "완료", isEnabled: false) + let doneButton = CustomButton(title: "완료", isEnabled: false) // MARK: - UI Setting diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift index e3eec8e8..5c8f1c09 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift @@ -14,6 +14,8 @@ final class SetReadyInfoViewController: BaseViewController { private let rootView = SetReadyInfoView() + private let viewModel = SetReadyInfoViewModel() + // MARK: - LifeCycle @@ -24,6 +26,7 @@ final class SetReadyInfoViewController: BaseViewController { override func viewDidLoad() { view.backgroundColor = .white setTextFieldDelegate() + bindViewModel() } private func setTextFieldDelegate() { @@ -36,6 +39,30 @@ final class SetReadyInfoViewController: BaseViewController { rootView.readyMinuteTextField.keyboardType = .numberPad rootView.moveHourTextField.keyboardType = .numberPad rootView.moveMinuteTextField.keyboardType = .numberPad + + rootView.readyHourTextField.accessibilityIdentifier = "readyHour" + rootView.readyMinuteTextField.accessibilityIdentifier = "readyMinute" + rootView.moveHourTextField.accessibilityIdentifier = "moveHour" + rootView.moveMinuteTextField.accessibilityIdentifier = "moveMinute" + } + + private func bindViewModel() { + viewModel.isValid.bind { [weak self] isValid in + if isValid { + self?.rootView.doneButton.isEnabled = true + } + } + + viewModel.errMessage.bind { [weak self] err in + if !err.isEmpty { + self?.showToast(err) + } + } + } + + func showToast(_ message: String, bottomInset: CGFloat = 128) { + guard let view else { return } + Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) } } @@ -49,7 +76,7 @@ extension SetReadyInfoViewController: UITextFieldDelegate { func textFieldDidEndEditing(_ textField: UITextField) { textField.layer.borderColor = UIColor.gray3.cgColor - validateTextField(textField) + viewModel.validateTextField(for: textField) } func textField( @@ -61,19 +88,4 @@ extension SetReadyInfoViewController: UITextFieldDelegate { let characterSet = CharacterSet(charactersIn: string) return allowedCharacters.isSuperset(of: characterSet) } - - private func validateTextField(_ textField: UITextField) { - guard let text = textField.text, let value = Int(text) else { return } - - if textField == rootView.readyHourTextField || textField == rootView.moveHourTextField { - if value >= 24 { - textField.text = "23" - } - } - if textField == rootView.readyMinuteTextField || textField == rootView.moveMinuteTextField { - if value >= 60 { - textField.text = "59" - } - } - } } diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift index a460520e..a572e2a4 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift @@ -7,3 +7,34 @@ import UIKit +final class SetReadyInfoViewModel { + var isValid = ObservablePattern(false) + var errMessage = ObservablePattern("") + +// var readyHour = ObservablePattern(nil) +// var readyMinute = ObservablePattern(nil) +// var moveHour = ObservablePattern(nil) +// var moveMinute = ObservablePattern(nil) + + func validateTextField(for textField: UITextField) { + guard let text = textField.text, let time = Int(text) else { return } + + if textField.accessibilityIdentifier == "readyHour" || textField.accessibilityIdentifier == "moveHour" { + if time >= 24 { + textField.text = "23" + errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" + print(errMessage.value) + return + } + } else if textField.accessibilityIdentifier == "readyMinute" || textField.accessibilityIdentifier == "moveMinute" { + if time >= 60 { + textField.text = "59" + errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" + print(errMessage.value) + return + } + } + + isValid.value = true + } +} From 01d5ea1fe4460eed9c9e758708043e739f053e58 Mon Sep 17 00:00:00 2001 From: hooni Date: Mon, 15 Jul 2024 13:40:36 +0900 Subject: [PATCH 08/17] =?UTF-8?q?feat/#178=20=EC=86=8C=EC=85=9C=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum.xcodeproj/project.pbxproj | 14 +++ .../Network/DTO/TargetType/LoginService.swift | 96 +++++++++++++++++++ .../Login/VIewModel/LoginViewModel.swift | 86 ++++++++++++----- .../ViewController/LoginViewController.swift | 49 +++++++--- 4 files changed, 205 insertions(+), 40 deletions(-) create mode 100644 KkuMulKum/Network/DTO/TargetType/LoginService.swift diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index 95951034..2eba4399 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -62,6 +62,7 @@ 78B928752C29402E006D9942 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 78B928742C29402E006D9942 /* Assets.xcassets */; }; 78B928782C29402E006D9942 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78B928762C29402E006D9942 /* LaunchScreen.storyboard */; }; 78BD61202C43F557005752FD /* SwiftKeychainWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = 78BD611F2C43F557005752FD /* SwiftKeychainWrapper */; }; + 78BD61272C446A97005752FD /* LoginService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78BD61262C446A97005752FD /* LoginService.swift */; }; A3DD9C3D2C41BAD000E58A13 /* MeetingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C322C41BAD000E58A13 /* MeetingTableViewCell.swift */; }; A3DD9C3E2C41BAD000E58A13 /* MeetingDummyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C342C41BAD000E58A13 /* MeetingDummyModel.swift */; }; A3DD9C3F2C41BAD000E58A13 /* MeetingListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C362C41BAD000E58A13 /* MeetingListView.swift */; }; @@ -196,6 +197,7 @@ 78B928742C29402E006D9942 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 78B928772C29402E006D9942 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 78B928792C29402E006D9942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 78BD61262C446A97005752FD /* LoginService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginService.swift; sourceTree = ""; }; A3DD9C322C41BAD000E58A13 /* MeetingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingTableViewCell.swift; sourceTree = ""; }; A3DD9C342C41BAD000E58A13 /* MeetingDummyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingDummyModel.swift; sourceTree = ""; }; A3DD9C362C41BAD000E58A13 /* MeetingListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingListView.swift; sourceTree = ""; }; @@ -508,6 +510,14 @@ path = KkuMulKum; sourceTree = ""; }; + 78BD61252C446A84005752FD /* TargetType */ = { + isa = PBXGroup; + children = ( + 78BD61262C446A97005752FD /* LoginService.swift */, + ); + path = TargetType; + sourceTree = ""; + }; A3DD9C332C41BAD000E58A13 /* Cell */ = { isa = PBXGroup; children = ( @@ -1111,6 +1121,7 @@ DE9E18852C3BC8F000DB76B4 /* DTO */ = { isa = PBXGroup; children = ( + 78BD61252C446A84005752FD /* TargetType */, DE9E18872C3BC90300DB76B4 /* Model */, DE9E18862C3BC8F900DB76B4 /* ResponseBody */, ); @@ -1393,6 +1404,7 @@ A3FB184F2C3BF4BC001483E5 /* MakeMeetingsResponseModel.swift in Sources */, DD3976852C41C2AD00E2A4C4 /* UpcomingPromiseModel.swift in Sources */, DEF725DB2C3F3BBF008C87C7 /* Toast.swift in Sources */, + 78BD61272C446A97005752FD /* LoginService.swift in Sources */, DD43937A2C412F4500EC1799 /* FinishCreateViewController.swift in Sources */, DE254AAC2C31192400A4015E /* UILabel+.swift in Sources */, DE254AB72C3119D000A4015E /* ReuseIdentifiable.swift in Sources */, @@ -1543,6 +1555,7 @@ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; + NEW_SETTING = ""; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; @@ -1600,6 +1613,7 @@ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; + NEW_SETTING = ""; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; diff --git a/KkuMulKum/Network/DTO/TargetType/LoginService.swift b/KkuMulKum/Network/DTO/TargetType/LoginService.swift new file mode 100644 index 00000000..6ba0227e --- /dev/null +++ b/KkuMulKum/Network/DTO/TargetType/LoginService.swift @@ -0,0 +1,96 @@ +// +// LoginService.swift +// KkuMulKum +// +// Created by 이지훈 on 7/15/24. +// +import Foundation +import Moya + +enum LoginService { + case appleLogin(identityToken: String, fcmToken: String) + case kakaoLogin(accessToken: String, fcmToken: String) +} + +extension LoginService: TargetType { + var baseURL: URL { + print("Attempting to get baseURL") + guard let privacyInfo = Bundle.main.privacyInfo else { + print("PrivacyInfo.plist not found") + fatalError("PrivacyInfo.plist not found") + } + + guard let urlString = privacyInfo["BASE_URL"] as? String else { + print("BASE_URL not found in PrivacyInfo.plist") + fatalError("BASE_URL not found in PrivacyInfo.plist") + } + + print("BASE_URL from PrivacyInfo.plist: \(urlString)") + + guard let url = URL(string: urlString) else { + print("Invalid BASE_URL in PrivacyInfo.plist: \(urlString)") + fatalError("Invalid BASE_URL in PrivacyInfo.plist: \(urlString)") + } + + print("Successfully created URL: \(url)") + return url + } + + var path: String { + print("Getting path: /api/v1/auth/signin") + return "/api/v1/auth/signin" + } + + var method: Moya.Method { + print("HTTP Method: POST") + return .post + } + + var task: Task { + switch self { + case let .appleLogin(_, fcmToken): + print("Creating task for Apple Login with fcmToken: \(fcmToken)") + return .requestParameters( + parameters: ["provider": "APPLE", "fcmToken": fcmToken], + encoding: JSONEncoding.default + ) + case let .kakaoLogin(_, fcmToken): + print("Creating task for Kakao Login with fcmToken: \(fcmToken)") + return .requestParameters( + parameters: ["provider": "KAKAO", "fcmToken": fcmToken], + encoding: JSONEncoding.default + ) + } + } + + var headers: [String : String]? { + switch self { + case .appleLogin(let identityToken, _): + print("Setting headers for Apple Login") + return ["Authorization": identityToken, "Content-Type": "application/json"] + case .kakaoLogin(let accessToken, _): + print("Setting headers for Kakao Login") + return ["Authorization": accessToken, "Content-Type": "application/json"] + } + } +} + +extension Bundle { + var privacyInfo: [String: Any]? { + print("Attempting to read PrivacyInfo.plist") + guard let url = self.url(forResource: "PrivacyInfo", withExtension: "plist") else { + print("PrivacyInfo.plist file not found") + return nil + } + guard let data = try? Data(contentsOf: url) else { + print("Failed to read data from PrivacyInfo.plist") + return nil + } + guard let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any] else { + print("Failed to serialize PrivacyInfo.plist") + return nil + } + print("Successfully read PrivacyInfo.plist") + return result + } +} diff --git a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift index cfb801eb..ec2870cf 100644 --- a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift +++ b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift @@ -4,24 +4,27 @@ // // Created by 이지훈 on 7/9/24. // - import UIKit import AuthenticationServices import KakaoSDKUser import KakaoSDKAuth - +import Moya enum LoginState { case notLoggedIn case loggedIn(userInfo: String) + case needOnboarding } class LoginViewModel: NSObject { var loginState: ObservablePattern = ObservablePattern(.notLoggedIn) var error: ObservablePattern = ObservablePattern("") + private let provider = MoyaProvider(plugins: [NetworkLoggerPlugin(configuration: .init(logOptions: .verbose))]) + func performAppleLogin(presentationAnchor: ASPresentationAnchor) { + print("Performing Apple Login") let request = ASAuthorizationAppleIDProvider().createRequest() request.requestedScopes = [.fullName, .email] @@ -31,12 +34,15 @@ class LoginViewModel: NSObject { controller.performRequests() } - func performKakaoLogin(presentationAnchor: UIWindow) { + func performKakaoLogin() { + print("Performing Kakao Login") if UserApi.isKakaoTalkLoginAvailable() { + print("Kakao Talk is available, using Kakao Talk login") UserApi.shared.loginWithKakaoTalk { [weak self] (oauthToken, error) in self?.handleKakaoLoginResult(oauthToken: oauthToken, error: error) } } else { + print("Kakao Talk is not available, using Kakao Account login") UserApi.shared.loginWithKakaoAccount { [weak self] (oauthToken, error) in self?.handleKakaoLoginResult(oauthToken: oauthToken, error: error) } @@ -45,27 +51,59 @@ class LoginViewModel: NSObject { private func handleKakaoLoginResult(oauthToken: OAuthToken?, error: Error?) { if let error = error { + print("Kakao Login Error: \(error.localizedDescription)") self.error.value = error.localizedDescription return } - if let _ = oauthToken { - fetchKakaoUserInfo() + if let token = oauthToken?.accessToken { + print("Kakao Login Successful, access token: \(token)") + loginToServer(with: .kakaoLogin(accessToken: token, fcmToken: "dummy_fcm_token")) + } else { + print("Kakao Login Error: No access token") + self.error.value = "No access token received" } } - private func fetchKakaoUserInfo() { - UserApi.shared.me() { [weak self] (user, error) in - if let error = error { - self?.error.value = error.localizedDescription - return - } - - if let nickname = user?.kakaoAccount?.profile?.nickname { - self?.loginState.value = .loggedIn(userInfo: "Kakao user: \(nickname)") + private func loginToServer(with loginService: LoginService) { + print("Attempting to login to server") + provider.request(loginService) { [weak self] result in + switch result { + case .success(let response): + print("Received response from server: \(response)") + do { + let loginResponse = try response.map(SocialLoginResponseModel.self) + print("Successfully mapped response: \(loginResponse)") + self?.handleLoginResponse(loginResponse) + } catch { + print("Failed to decode response: \(error)") + self?.error.value = "Failed to decode response: \(error.localizedDescription)" + } + case .failure(let error): + print("Network error: \(error)") + self?.error.value = "Network error: \(error.localizedDescription)" } } } + + private func handleLoginResponse(_ response: SocialLoginResponseModel) { + print("Handling login response") + if let name = response.name { + print("Login successful, user name: \(name)") + loginState.value = .loggedIn(userInfo: name) + } else { + print("Login successful, but no name provided. Needs onboarding.") + loginState.value = .needOnboarding + } + + // TODO: 토큰 저장 + if let accessToken = response.accessToken, let refreshToken = response.refreshToken { + print("Received tokens - Access: \(accessToken), Refresh: \(refreshToken)") + // Save tokens to secure storage + } else { + print("Warning: No tokens received in response") + } + } } extension LoginViewModel: ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { @@ -73,32 +111,30 @@ extension LoginViewModel: ASAuthorizationControllerDelegate, ASAuthorizationCont controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization ) { - guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else { - print("Authorization failed: Credential is not of type ASAuthorizationAppleIDCredential") + print("Apple authorization completed") + guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential, + let identityToken = appleIDCredential.identityToken, + let tokenString = String(data: identityToken, encoding: .utf8) else { + print("Failed to get Apple ID Credential or identity token") return } - let userName = appleIDCredential.fullName?.givenName ?? "Apple user" - loginState.value = .loggedIn(userInfo: "Apple user: \(userName)") - - /// 액세스 토큰 출력 - if let identityToken = appleIDCredential.identityToken, - let tokenString = String(data: identityToken, encoding: .utf8) { - print("Apple Login Access Token: \(tokenString)") - } + print("Apple Login Successful, identity token: \(tokenString)") + loginToServer(with: .appleLogin(identityToken: tokenString, fcmToken: "dummy_fcm_token")) } func authorizationController( controller: ASAuthorizationController, didCompleteWithError error: Error ) { + print("Apple authorization error: \(error.localizedDescription)") self.error.value = error.localizedDescription } func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { + print("Providing presentation anchor for Apple Login") let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene let window = windowScene?.windows.first - return window! } } diff --git a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift index 4be171fa..2fc3f78d 100644 --- a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift +++ b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift @@ -6,6 +6,7 @@ // import UIKit + import AuthenticationServices class LoginViewController: BaseViewController { @@ -15,16 +16,19 @@ class LoginViewController: BaseViewController { override func loadView() { view = loginView + print("LoginViewController loadView called") } override func viewDidLoad() { super.viewDidLoad() + print("LoginViewController viewDidLoad called") bindViewModel() setupAction() } override func setupAction() { super.setupAction() + print("Setting up actions for LoginViewController") let appleTapGesture = UITapGestureRecognizer( target: self, @@ -38,7 +42,6 @@ class LoginViewController: BaseViewController { ) loginView.kakaoLoginImageView.addGestureRecognizer(kakaoTapGesture) - /// 더미 버튼 loginView.dummyNextButton.addTarget( self, action: #selector(dummyNextButtonTapped), @@ -47,45 +50,61 @@ class LoginViewController: BaseViewController { } private func bindViewModel() { + print("Binding ViewModel in LoginViewController") loginViewModel.loginState.bind(with: self) { owner, state in switch state { case .notLoggedIn: - print("Not logged in") + print("Login State: Not logged in") case .loggedIn(let userInfo): - print("Logged in: \(userInfo)") + print("Login State: Logged in with user info: \(userInfo)") + owner.navigateToMainScreen() + case .needOnboarding: + print("Login State: Need onboarding") + owner.navigateToOnboardingScreen() } } loginViewModel.error.bind(with: self) { owner, error in if !error.isEmpty { - // TODO: 추후 에러처리 추가예정 -> Keychain 연결 이후 - print("Error occurred: \(error)") + print("Login Error: \(error)") + owner.showErrorAlert(message: error) } } } @objc private func appleLoginTapped() { + print("Apple Login button tapped") loginViewModel.performAppleLogin(presentationAnchor: view.window!) } @objc private func kakaoLoginTapped() { - loginViewModel.performKakaoLogin(presentationAnchor: view.window!) + print("Kakao Login button tapped") + loginViewModel.performKakaoLogin() } - // TODO: 추후 서버연결후 삭제예정 @objc private func dummyNextButtonTapped() { -// _ = NicknameViewController() -// let welcomeViewController = NicknameViewController() -// welcomeViewController.modalPresentationStyle = .fullScreen -// present(welcomeViewController, animated: true, completion: nil) - - // TODO: 프로필 설정부터 네비게이션으로 플로우 동작 - + print("Dummy Next button tapped") let viewController = NicknameViewController() let navigationController = UINavigationController(rootViewController: viewController) navigationController.modalTransitionStyle = .crossDissolve navigationController.modalPresentationStyle = .fullScreen present(navigationController, animated: true) } + + private func navigateToMainScreen() { + print("Navigating to Main Screen") + // TODO: Implement navigation to main screen + } + + private func navigateToOnboardingScreen() { + print("Navigating to Onboarding Screen") + // TODO: Implement navigation to onboarding screen + } + + private func showErrorAlert(message: String) { + print("Showing error alert with message: \(message)") + let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + present(alert, animated: true) + } } - From 24e384e5ce785e8bdbed306bfb4f2ec94df58829 Mon Sep 17 00:00:00 2001 From: hooni Date: Mon, 15 Jul 2024 16:40:31 +0900 Subject: [PATCH 09/17] =?UTF-8?q?feat/#178=20=EC=86=8C=EC=85=9C=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=ED=99=94=EB=A9=B4=EC=A0=84=ED=99=98=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 자잘한 주석및 컨벤션 수정 --- .../Model/Auth/SocialLoginRequestModel.swift | 2 + .../Model/Auth/SocialLoginResponseModel.swift | 19 +++++- .../Network/DTO/TargetType/LoginService.swift | 24 ++----- .../Login/VIewModel/LoginViewModel.swift | 65 ++++++++++++------- .../ViewController/LoginViewController.swift | 36 ++++++---- 5 files changed, 91 insertions(+), 55 deletions(-) diff --git a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift index bb35bb9c..71f83e0b 100644 --- a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift +++ b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift @@ -9,4 +9,6 @@ import Foundation struct SocialLoginRequestModel: RequestModelType { let provider: String? + let fcmToken: String + } diff --git a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift index c7ca4889..a2837e58 100644 --- a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift +++ b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift @@ -8,5 +8,22 @@ import Foundation struct SocialLoginResponseModel: ResponseModelType { - let name, accessToken, refreshToken: String? + let success: Bool + let data: LoginData? + let error: ErrorData? +} + +struct LoginData: Codable { + let name: String? + let jwtTokenDto: JwtTokenDto +} + +struct JwtTokenDto: Codable { + let accessToken: String + let refreshToken: String +} + +struct ErrorData: Codable { + let code: Int + let message: String } diff --git a/KkuMulKum/Network/DTO/TargetType/LoginService.swift b/KkuMulKum/Network/DTO/TargetType/LoginService.swift index 6ba0227e..468135ff 100644 --- a/KkuMulKum/Network/DTO/TargetType/LoginService.swift +++ b/KkuMulKum/Network/DTO/TargetType/LoginService.swift @@ -16,23 +16,17 @@ extension LoginService: TargetType { var baseURL: URL { print("Attempting to get baseURL") guard let privacyInfo = Bundle.main.privacyInfo else { - print("PrivacyInfo.plist not found") fatalError("PrivacyInfo.plist not found") } guard let urlString = privacyInfo["BASE_URL"] as? String else { - print("BASE_URL not found in PrivacyInfo.plist") fatalError("BASE_URL not found in PrivacyInfo.plist") } - - print("BASE_URL from PrivacyInfo.plist: \(urlString)") - + guard let url = URL(string: urlString) else { - print("Invalid BASE_URL in PrivacyInfo.plist: \(urlString)") fatalError("Invalid BASE_URL in PrivacyInfo.plist: \(urlString)") } - print("Successfully created URL: \(url)") return url } @@ -42,20 +36,17 @@ extension LoginService: TargetType { } var method: Moya.Method { - print("HTTP Method: POST") return .post } var task: Task { switch self { case let .appleLogin(_, fcmToken): - print("Creating task for Apple Login with fcmToken: \(fcmToken)") return .requestParameters( parameters: ["provider": "APPLE", "fcmToken": fcmToken], encoding: JSONEncoding.default ) case let .kakaoLogin(_, fcmToken): - print("Creating task for Kakao Login with fcmToken: \(fcmToken)") return .requestParameters( parameters: ["provider": "KAKAO", "fcmToken": fcmToken], encoding: JSONEncoding.default @@ -66,10 +57,8 @@ extension LoginService: TargetType { var headers: [String : String]? { switch self { case .appleLogin(let identityToken, _): - print("Setting headers for Apple Login") return ["Authorization": identityToken, "Content-Type": "application/json"] case .kakaoLogin(let accessToken, _): - print("Setting headers for Kakao Login") return ["Authorization": accessToken, "Content-Type": "application/json"] } } @@ -77,20 +66,19 @@ extension LoginService: TargetType { extension Bundle { var privacyInfo: [String: Any]? { - print("Attempting to read PrivacyInfo.plist") guard let url = self.url(forResource: "PrivacyInfo", withExtension: "plist") else { - print("PrivacyInfo.plist file not found") return nil } guard let data = try? Data(contentsOf: url) else { - print("Failed to read data from PrivacyInfo.plist") return nil } - guard let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any] else { - print("Failed to serialize PrivacyInfo.plist") + guard let result = try? PropertyListSerialization.propertyList( + from: data, + options: [], + format: nil + ) as? [String: Any] else { return nil } - print("Successfully read PrivacyInfo.plist") return result } } diff --git a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift index ec2870cf..cd2c06b4 100644 --- a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift +++ b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift @@ -20,9 +20,15 @@ enum LoginState { class LoginViewModel: NSObject { var loginState: ObservablePattern = ObservablePattern(.notLoggedIn) var error: ObservablePattern = ObservablePattern("") - - private let provider = MoyaProvider(plugins: [NetworkLoggerPlugin(configuration: .init(logOptions: .verbose))]) - + + private let provider = MoyaProvider( + plugins: [NetworkLoggerPlugin( + configuration: .init( + logOptions: .verbose + ) + )] + ) + func performAppleLogin(presentationAnchor: ASPresentationAnchor) { print("Performing Apple Login") let request = ASAuthorizationAppleIDProvider().createRequest() @@ -35,14 +41,13 @@ class LoginViewModel: NSObject { } func performKakaoLogin() { - print("Performing Kakao Login") if UserApi.isKakaoTalkLoginAvailable() { - print("Kakao Talk is available, using Kakao Talk login") + print("Kakao Talk is available") UserApi.shared.loginWithKakaoTalk { [weak self] (oauthToken, error) in self?.handleKakaoLoginResult(oauthToken: oauthToken, error: error) } } else { - print("Kakao Talk is not available, using Kakao Account login") + print("Kakao Talk is not available") UserApi.shared.loginWithKakaoAccount { [weak self] (oauthToken, error) in self?.handleKakaoLoginResult(oauthToken: oauthToken, error: error) } @@ -58,7 +63,7 @@ class LoginViewModel: NSObject { if let token = oauthToken?.accessToken { print("Kakao Login Successful, access token: \(token)") - loginToServer(with: .kakaoLogin(accessToken: token, fcmToken: "dummy_fcm_token")) + loginToServer(with: .kakaoLogin(accessToken: token, fcmToken: "")) } else { print("Kakao Login Error: No access token") self.error.value = "No access token received" @@ -66,7 +71,6 @@ class LoginViewModel: NSObject { } private func loginToServer(with loginService: LoginService) { - print("Attempting to login to server") provider.request(loginService) { [weak self] result in switch result { case .success(let response): @@ -79,6 +83,7 @@ class LoginViewModel: NSObject { print("Failed to decode response: \(error)") self?.error.value = "Failed to decode response: \(error.localizedDescription)" } + case .failure(let error): print("Network error: \(error)") self?.error.value = "Network error: \(error.localizedDescription)" @@ -88,25 +93,37 @@ class LoginViewModel: NSObject { private func handleLoginResponse(_ response: SocialLoginResponseModel) { print("Handling login response") - if let name = response.name { - print("Login successful, user name: \(name)") - loginState.value = .loggedIn(userInfo: name) - } else { - print("Login successful, but no name provided. Needs onboarding.") - loginState.value = .needOnboarding - } - - // TODO: 토큰 저장 - if let accessToken = response.accessToken, let refreshToken = response.refreshToken { - print("Received tokens - Access: \(accessToken), Refresh: \(refreshToken)") - // Save tokens to secure storage + if response.success { + if let data = response.data { + if let name = data.name { + print("Login successful, user name: \(name)") + loginState.value = .loggedIn(userInfo: name) + } else { + print("Login successful, but no name provided. Needs onboarding.") + loginState.value = .needOnboarding + } + + let tokens = data.jwtTokenDto + print("Received tokens - Access: \(tokens.accessToken), Refresh: \(tokens.refreshToken)") + // TODO: 키체인에 토큰 저장 로직추가 예정 + } else { + print("Warning: No data received in response") + error.value = "No data received" + } } else { - print("Warning: No tokens received in response") + if let error = response.error { + print("Login failed: \(error.message)") + self.error.value = error.message + } else { + print("Login failed: Unknown error") + self.error.value = "Unknown error occurred" + } } } } -extension LoginViewModel: ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { +extension LoginViewModel: ASAuthorizationControllerDelegate, + ASAuthorizationControllerPresentationContextProviding { func authorizationController( controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization @@ -120,9 +137,9 @@ extension LoginViewModel: ASAuthorizationControllerDelegate, ASAuthorizationCont } print("Apple Login Successful, identity token: \(tokenString)") - loginToServer(with: .appleLogin(identityToken: tokenString, fcmToken: "dummy_fcm_token")) + loginToServer(with: .appleLogin(identityToken: tokenString, fcmToken: "")) } - + func authorizationController( controller: ASAuthorizationController, didCompleteWithError error: Error diff --git a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift index 2fc3f78d..3ee04ab9 100644 --- a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift +++ b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift @@ -16,19 +16,16 @@ class LoginViewController: BaseViewController { override func loadView() { view = loginView - print("LoginViewController loadView called") } override func viewDidLoad() { super.viewDidLoad() - print("LoginViewController viewDidLoad called") bindViewModel() setupAction() } override func setupAction() { super.setupAction() - print("Setting up actions for LoginViewController") let appleTapGesture = UITapGestureRecognizer( target: self, @@ -50,7 +47,6 @@ class LoginViewController: BaseViewController { } private func bindViewModel() { - print("Binding ViewModel in LoginViewController") loginViewModel.loginState.bind(with: self) { owner, state in switch state { case .notLoggedIn: @@ -73,17 +69,14 @@ class LoginViewController: BaseViewController { } @objc private func appleLoginTapped() { - print("Apple Login button tapped") loginViewModel.performAppleLogin(presentationAnchor: view.window!) } @objc private func kakaoLoginTapped() { - print("Kakao Login button tapped") loginViewModel.performKakaoLogin() } - + @objc private func dummyNextButtonTapped() { - print("Dummy Next button tapped") let viewController = NicknameViewController() let navigationController = UINavigationController(rootViewController: viewController) navigationController.modalTransitionStyle = .crossDissolve @@ -92,13 +85,32 @@ class LoginViewController: BaseViewController { } private func navigateToMainScreen() { - print("Navigating to Main Screen") - // TODO: Implement navigation to main screen + DispatchQueue.main.async { + let mainTabBarController = MainTabBarController() + + let navigationController = UINavigationController(rootViewController: mainTabBarController) + + navigationController.isNavigationBarHidden = true + navigationController.modalPresentationStyle = .fullScreen + navigationController.modalTransitionStyle = .crossDissolve + + self.present(navigationController, animated: true, completion: nil) + + } } private func navigateToOnboardingScreen() { - print("Navigating to Onboarding Screen") - // TODO: Implement navigation to onboarding screen + DispatchQueue.main.async { + let nicknameViewController = NicknameViewController() + if let navigationController = self.navigationController { + navigationController.pushViewController(nicknameViewController, animated: true) + } else { + let navigationController = UINavigationController(rootViewController: nicknameViewController) + navigationController.modalPresentationStyle = .fullScreen + navigationController.modalTransitionStyle = .crossDissolve + self.present(navigationController, animated: true, completion: nil) + } + } } private func showErrorAlert(message: String) { From a511709e35d8be177da548af8a5a35a734f46476 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 15 Jul 2024 19:08:35 +0900 Subject: [PATCH 10/17] =?UTF-8?q?feat/#170=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EA=B0=92=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=ED=99=9C=EC=84=B1=ED=99=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 100 ++++++++++++------ .../ViewModel/SetReadyInfoViewModel.swift | 63 +++++++---- 2 files changed, 110 insertions(+), 53 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift index 5c8f1c09..82fa57e4 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift @@ -13,7 +13,6 @@ final class SetReadyInfoViewController: BaseViewController { // MARK: - Property private let rootView = SetReadyInfoView() - private let viewModel = SetReadyInfoViewModel() @@ -28,8 +27,46 @@ final class SetReadyInfoViewController: BaseViewController { setTextFieldDelegate() bindViewModel() } +} + + +// MARK: - UITextFieldDelegate + +extension SetReadyInfoViewController: UITextFieldDelegate { + func textFieldDidBeginEditing(_ textField: UITextField) { + textField.layer.borderColor = UIColor.maincolor.cgColor + } + + func textFieldDidEndEditing(_ textField: UITextField) { + textField.layer.borderColor = UIColor.gray3.cgColor + viewModel.updateTime( + textField: textField.accessibilityIdentifier ?? "", + time: textField.text ?? "" + ) + viewModel.checkValid( + readyHourText: rootView.readyHourTextField.text ?? "", + readyMinuteText: rootView.readyMinuteTextField.text ?? "", + moveHourText: rootView.moveHourTextField.text ?? "", + moveMinuteText: rootView.moveMinuteTextField.text ?? "" + ) + } - private func setTextFieldDelegate() { + func textField( + _ textField: UITextField, + shouldChangeCharactersIn range: NSRange, + replacementString string: String + ) -> Bool { + let allowedCharacters = CharacterSet.decimalDigits + let characterSet = CharacterSet(charactersIn: string) + return allowedCharacters.isSuperset(of: characterSet) + } +} + + +// MARK: - Function + +private extension SetReadyInfoViewController { + func setTextFieldDelegate() { rootView.readyHourTextField.delegate = self rootView.readyMinuteTextField.delegate = self rootView.moveHourTextField.delegate = self @@ -46,11 +83,33 @@ final class SetReadyInfoViewController: BaseViewController { rootView.moveMinuteTextField.accessibilityIdentifier = "moveMinute" } - private func bindViewModel() { + func showToast(_ message: String, bottomInset: CGFloat = 128) { + guard let view else { return } + Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) + } + + + // MARK: - Data Bind + + func bindViewModel() { + viewModel.readyHour.bind { [weak self] readyHour in + self?.rootView.readyHourTextField.text = readyHour + } + + viewModel.readyMinute.bind { [weak self] readyMinute in + self?.rootView.readyMinuteTextField.text = readyMinute + } + + viewModel.moveHour.bind { [weak self] moveHour in + self?.rootView.moveHourTextField.text = moveHour + } + + viewModel.moveMinute.bind { [weak self] moveMinute in + self?.rootView.moveMinuteTextField.text = moveMinute + } + viewModel.isValid.bind { [weak self] isValid in - if isValid { - self?.rootView.doneButton.isEnabled = true - } + self?.rootView.doneButton.isEnabled = isValid } viewModel.errMessage.bind { [weak self] err in @@ -59,33 +118,4 @@ final class SetReadyInfoViewController: BaseViewController { } } } - - func showToast(_ message: String, bottomInset: CGFloat = 128) { - guard let view else { return } - Toast().show(message: message, view: view, position: .bottom, inset: bottomInset) - } -} - - -// MARK: - UITextFieldDelegate - -extension SetReadyInfoViewController: UITextFieldDelegate { - func textFieldDidBeginEditing(_ textField: UITextField) { - textField.layer.borderColor = UIColor.maincolor.cgColor - } - - func textFieldDidEndEditing(_ textField: UITextField) { - textField.layer.borderColor = UIColor.gray3.cgColor - viewModel.validateTextField(for: textField) - } - - func textField( - _ textField: UITextField, - shouldChangeCharactersIn range: NSRange, - replacementString string: String - ) -> Bool { - let allowedCharacters = CharacterSet.decimalDigits - let characterSet = CharacterSet(charactersIn: string) - return allowedCharacters.isSuperset(of: characterSet) - } } diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift index a572e2a4..f4722307 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift @@ -11,30 +11,57 @@ final class SetReadyInfoViewModel { var isValid = ObservablePattern(false) var errMessage = ObservablePattern("") -// var readyHour = ObservablePattern(nil) -// var readyMinute = ObservablePattern(nil) -// var moveHour = ObservablePattern(nil) -// var moveMinute = ObservablePattern(nil) + var readyHour = ObservablePattern("") + var readyMinute = ObservablePattern("") + var moveHour = ObservablePattern("") + var moveMinute = ObservablePattern("") - func validateTextField(for textField: UITextField) { - guard let text = textField.text, let time = Int(text) else { return } + //TODO: 준비 및 이동 시간 분 단위로 계산 + var readyTime: Int = 0 + var moveTime: Int = 0 + + func updateTime(textField: String, time: String) { + guard let time = Int(time) else { return } - if textField.accessibilityIdentifier == "readyHour" || textField.accessibilityIdentifier == "moveHour" { - if time >= 24 { - textField.text = "23" + switch textField { + case "readyHour": + if (0...23).contains(time) { + readyHour.value = String(time) + } else { + readyHour.value = "23" + errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" + } + case "readyMinute": + if (0...59).contains(time) { + readyMinute.value = String(time) + } else { + readyMinute.value = "59" + errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" + } + case "moveHour": + if (0...23).contains(time) { + moveHour.value = String(time) + } else { + moveHour.value = "23" errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" - print(errMessage.value) - return } - } else if textField.accessibilityIdentifier == "readyMinute" || textField.accessibilityIdentifier == "moveMinute" { - if time >= 60 { - textField.text = "59" + case "moveMinute": + if (0...59).contains(time) { + moveMinute.value = String(time) + } else { + moveMinute.value = "59" errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" - print(errMessage.value) - return } + default: + break + } + } + + func checkValid(readyHourText: String, readyMinuteText: String, moveHourText: String, moveMinuteText: String) { + if !readyHourText.isEmpty && !readyMinuteText.isEmpty && !moveHourText.isEmpty && !moveMinuteText.isEmpty { + isValid.value = true + } else { + isValid.value = false } - - isValid.value = true } } From 8140d1e4e1270b6513a4baab8ac649fefa487a1d Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 15 Jul 2024 19:13:31 +0900 Subject: [PATCH 11/17] =?UTF-8?q?chore/#170=20=EC=BB=A8=EB=B2=A4=EC=85=98?= =?UTF-8?q?=20=EB=A7=9E=EC=B6=B0=EC=84=9C=20=EA=B0=9C=ED=96=89!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyStatus/ViewModel/SetReadyInfoViewModel.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift index f4722307..8fa0e082 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift @@ -57,8 +57,14 @@ final class SetReadyInfoViewModel { } } - func checkValid(readyHourText: String, readyMinuteText: String, moveHourText: String, moveMinuteText: String) { - if !readyHourText.isEmpty && !readyMinuteText.isEmpty && !moveHourText.isEmpty && !moveMinuteText.isEmpty { + func checkValid( + readyHourText: String, + readyMinuteText: String, + moveHourText: String, + moveMinuteText: String + ) { + if !readyHourText.isEmpty && !readyMinuteText.isEmpty + && !moveHourText.isEmpty && !moveMinuteText.isEmpty { isValid.value = true } else { isValid.value = false From e584c6a45807008ca177c9300ac3b4c13294f464 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 15 Jul 2024 19:48:16 +0900 Subject: [PATCH 12/17] =?UTF-8?q?chore/#170=20=EC=98=A4=ED=86=A0=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Promise/ReadyStatus/View/SetReadyInfoView.swift | 10 +++++----- .../ReadyStatus/ViewModel/SetReadyInfoViewModel.swift | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift b/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift index 623e123f..e93d7234 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/View/SetReadyInfoView.swift @@ -86,7 +86,7 @@ final class SetReadyInfoView: BaseView { override func setupAutoLayout() { infoLabel.snp.makeConstraints { - $0.top.equalToSuperview().offset(60) + $0.top.equalTo(self.safeAreaLayoutGuide.snp.top).offset(24) $0.leading.equalToSuperview().offset(20) } @@ -97,12 +97,12 @@ final class SetReadyInfoView: BaseView { } readyTimeLabel.snp.makeConstraints { - $0.top.equalTo(infoLabel.snp.bottom).offset(20) + $0.top.equalTo(infoLabel.snp.bottom).offset(24) $0.leading.equalToSuperview().offset(20) } readyTimeView.snp.makeConstraints { - $0.top.equalTo(readyTimeLabel.snp.bottom).offset(12) + $0.top.equalTo(readyTimeLabel.snp.bottom).offset(16) $0.leading.equalToSuperview().offset(20) } @@ -117,12 +117,12 @@ final class SetReadyInfoView: BaseView { } moveTimeLabel.snp.makeConstraints { - $0.top.equalTo(readyTimeView.snp.bottom).offset(16) + $0.top.equalTo(readyTimeView.snp.bottom).offset(20) $0.leading.equalToSuperview().offset(20) } moveTimeView.snp.makeConstraints { - $0.top.equalTo(moveTimeLabel.snp.bottom).offset(12) + $0.top.equalTo(moveTimeLabel.snp.bottom).offset(16) $0.leading.equalToSuperview().offset(20) } diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift index 8fa0e082..d349a74c 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift @@ -5,7 +5,7 @@ // Created by 예삐 on 7/15/24. // -import UIKit +import Foundation final class SetReadyInfoViewModel { var isValid = ObservablePattern(false) From 18f621db24702a807e8063e1444451fc177ab2d1 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 15 Jul 2024 20:55:09 +0900 Subject: [PATCH 13/17] =?UTF-8?q?fix/#170=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=95=A1=EC=85=98=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 유효성 검사를 textFieldDidChange 메소드로 변경하여 텍스트필드 오류 수정 --- .../SetReadyInfoViewController.swift | 46 ++++++++++++++++--- .../ViewModel/SetReadyInfoViewModel.swift | 37 ++++++--------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift index 82fa57e4..5e93f1f6 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift @@ -23,10 +23,48 @@ final class SetReadyInfoViewController: BaseViewController { } override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white - setTextFieldDelegate() bindViewModel() } + + override func setupDelegate() { + setTextFieldDelegate() + } + + override func setupAction() { + rootView.readyHourTextField.addTarget( + self, + action: #selector(textFieldDidChange), + for: .editingChanged + ) + rootView.readyMinuteTextField.addTarget( + self, + action: #selector(textFieldDidChange), + for: .editingChanged + ) + rootView.moveHourTextField.addTarget( + self, + action: #selector(textFieldDidChange), + for: .editingChanged + ) + rootView.moveMinuteTextField.addTarget( + self, + action: #selector(textFieldDidChange), + for: .editingChanged + ) + } + + @objc + private func textFieldDidChange(_ textField: UITextField) { + viewModel.checkValid( + readyHourText: rootView.readyHourTextField.text ?? "", + readyMinuteText: rootView.readyMinuteTextField.text ?? "", + moveHourText: rootView.moveHourTextField.text ?? "", + moveMinuteText: rootView.moveMinuteTextField.text ?? "" + ) + } } @@ -43,12 +81,6 @@ extension SetReadyInfoViewController: UITextFieldDelegate { textField: textField.accessibilityIdentifier ?? "", time: textField.text ?? "" ) - viewModel.checkValid( - readyHourText: rootView.readyHourTextField.text ?? "", - readyMinuteText: rootView.readyMinuteTextField.text ?? "", - moveHourText: rootView.moveHourTextField.text ?? "", - moveMinuteText: rootView.moveMinuteTextField.text ?? "" - ) } func textField( diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift index d349a74c..8e40a3c0 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewModel/SetReadyInfoViewModel.swift @@ -20,38 +20,27 @@ final class SetReadyInfoViewModel { var readyTime: Int = 0 var moveTime: Int = 0 + private func validTime(time: Int, range: ClosedRange, defaultValue: String) -> String { + if range.contains(time) { + return String(time) + } else { + errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" + return defaultValue + } + } + func updateTime(textField: String, time: String) { guard let time = Int(time) else { return } switch textField { case "readyHour": - if (0...23).contains(time) { - readyHour.value = String(time) - } else { - readyHour.value = "23" - errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" - } + readyHour.value = validTime(time: time, range: 0...23, defaultValue: "23") case "readyMinute": - if (0...59).contains(time) { - readyMinute.value = String(time) - } else { - readyMinute.value = "59" - errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" - } + readyMinute.value = validTime(time: time, range: 0...59, defaultValue: "59") case "moveHour": - if (0...23).contains(time) { - moveHour.value = String(time) - } else { - moveHour.value = "23" - errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" - } + moveHour.value = validTime(time: time, range: 0...23, defaultValue: "23") case "moveMinute": - if (0...59).contains(time) { - moveMinute.value = String(time) - } else { - moveMinute.value = "59" - errMessage.value = "시간은 23시간 59분까지만 입력할 수 있어요!" - } + moveMinute.value = validTime(time: time, range: 0...59, defaultValue: "59") default: break } From ed0cfb8cbb38aa691b5f697cea11b657947acbf2 Mon Sep 17 00:00:00 2001 From: mmaybei Date: Mon, 15 Jul 2024 21:10:27 +0900 Subject: [PATCH 14/17] =?UTF-8?q?fix/#170=20=EC=9C=A0=EC=A7=84=EC=9D=B4=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A6=AC=EB=B7=B0=20=EA=B0=9C=ED=81=B0?= =?UTF-8?q?=EB=B0=98=EC=98=81!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetReadyInfoViewController.swift | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift index 5e93f1f6..47126132 100644 --- a/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift +++ b/KkuMulKum/Source/Promise/ReadyStatus/ViewController/SetReadyInfoViewController.swift @@ -99,20 +99,18 @@ extension SetReadyInfoViewController: UITextFieldDelegate { private extension SetReadyInfoViewController { func setTextFieldDelegate() { - rootView.readyHourTextField.delegate = self - rootView.readyMinuteTextField.delegate = self - rootView.moveHourTextField.delegate = self - rootView.moveMinuteTextField.delegate = self + let textFields: [(UITextField, String)] = [ + (rootView.readyHourTextField, "readyHour"), + (rootView.readyMinuteTextField, "readyMinute"), + (rootView.moveHourTextField, "moveHour"), + (rootView.moveMinuteTextField, "moveMinute") + ] - rootView.readyHourTextField.keyboardType = .numberPad - rootView.readyMinuteTextField.keyboardType = .numberPad - rootView.moveHourTextField.keyboardType = .numberPad - rootView.moveMinuteTextField.keyboardType = .numberPad - - rootView.readyHourTextField.accessibilityIdentifier = "readyHour" - rootView.readyMinuteTextField.accessibilityIdentifier = "readyMinute" - rootView.moveHourTextField.accessibilityIdentifier = "moveHour" - rootView.moveMinuteTextField.accessibilityIdentifier = "moveMinute" + textFields.forEach { (textField, identifier) in + textField.delegate = self + textField.keyboardType = .numberPad + textField.accessibilityIdentifier = identifier + } } func showToast(_ message: String, bottomInset: CGFloat = 128) { From f8c63566360d77d845e9c121db7d88659d2b1ac2 Mon Sep 17 00:00:00 2001 From: hooni Date: Mon, 15 Jul 2024 22:00:34 +0900 Subject: [PATCH 15/17] =?UTF-8?q?refactor/#178=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EB=B0=8F=20DTO=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum.xcodeproj/project.pbxproj | 4 ++ .../Model/Auth/SocialLoginRequestModel.swift | 3 +- .../Model/Auth/SocialLoginResponseModel.swift | 18 +++------ .../DTO/ResponseBody/ResponseBodyDTO.swift | 2 + .../Network/DTO/TargetType/LoginService.swift | 37 +++---------------- KkuMulKum/Resource/Bundle.swift | 23 ++++++++++++ .../Login/VIewModel/LoginViewModel.swift | 30 +++++++-------- .../ViewController/LoginViewController.swift | 25 +++++-------- 8 files changed, 66 insertions(+), 76 deletions(-) create mode 100644 KkuMulKum/Resource/Bundle.swift diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index 5ff740c3..4e5c75fb 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -63,6 +63,7 @@ 78B928782C29402E006D9942 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78B928762C29402E006D9942 /* LaunchScreen.storyboard */; }; 78BD61202C43F557005752FD /* SwiftKeychainWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = 78BD611F2C43F557005752FD /* SwiftKeychainWrapper */; }; 78BD61272C446A97005752FD /* LoginService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78BD61262C446A97005752FD /* LoginService.swift */; }; + 78BD612B2C4550A6005752FD /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78BD612A2C4550A6005752FD /* Bundle.swift */; }; A3DD9C3D2C41BAD000E58A13 /* MeetingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C322C41BAD000E58A13 /* MeetingTableViewCell.swift */; }; A3DD9C3E2C41BAD000E58A13 /* MeetingDummyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C342C41BAD000E58A13 /* MeetingDummyModel.swift */; }; A3DD9C3F2C41BAD000E58A13 /* MeetingListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C362C41BAD000E58A13 /* MeetingListView.swift */; }; @@ -205,6 +206,7 @@ 78B928772C29402E006D9942 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 78B928792C29402E006D9942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 78BD61262C446A97005752FD /* LoginService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginService.swift; sourceTree = ""; }; + 78BD612A2C4550A6005752FD /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = ""; }; A3DD9C322C41BAD000E58A13 /* MeetingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingTableViewCell.swift; sourceTree = ""; }; A3DD9C342C41BAD000E58A13 /* MeetingDummyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingDummyModel.swift; sourceTree = ""; }; A3DD9C362C41BAD000E58A13 /* MeetingListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingListView.swift; sourceTree = ""; }; @@ -1053,6 +1055,7 @@ DE254AA62C3118B300A4015E /* Extension */, DE254AB52C3119BC00A4015E /* Util */, DE254ABA2C311C3100A4015E /* Font */, + 78BD612A2C4550A6005752FD /* Bundle.swift */, ); path = Resource; sourceTree = ""; @@ -1540,6 +1543,7 @@ DD43937B2C412F4500EC1799 /* CreateMeetingViewController.swift in Sources */, DE8247FD2C36E7C7000601BC /* MoyaLoggingPlugin.swift in Sources */, DDAF1C842C3D5D19008A37D3 /* ViewModelType.swift in Sources */, + 78BD612B2C4550A6005752FD /* Bundle.swift in Sources */, DD3072262C3C0F0B00416D9F /* TardyInfoModel.swift in Sources */, DE254AB92C311AB300A4015E /* Screen.swift in Sources */, ); diff --git a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift index 71f83e0b..cd4074dd 100644 --- a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift +++ b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginRequestModel.swift @@ -8,7 +8,6 @@ import Foundation struct SocialLoginRequestModel: RequestModelType { - let provider: String? + let provider: String let fcmToken: String - } diff --git a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift index a2837e58..61acb79b 100644 --- a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift +++ b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift @@ -7,23 +7,17 @@ import Foundation -struct SocialLoginResponseModel: ResponseModelType { - let success: Bool - let data: LoginData? - let error: ErrorData? -} - -struct LoginData: Codable { +struct UserData: ResponseModelType { let name: String? let jwtTokenDto: JwtTokenDto + + enum CodingKeys: String, CodingKey { + case name + case jwtTokenDto // 서버 응답과 + } } struct JwtTokenDto: Codable { let accessToken: String let refreshToken: String } - -struct ErrorData: Codable { - let code: Int - let message: String -} diff --git a/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift b/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift index b3347ed2..e07306af 100644 --- a/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift +++ b/KkuMulKum/Network/DTO/ResponseBody/ResponseBodyDTO.swift @@ -9,6 +9,7 @@ import Foundation /// 제네릭 ResponseBody 구조체 정의 struct ResponseBodyDTO: Codable { + let success: Bool let data: T? let error: ErrorResponse? } @@ -18,3 +19,4 @@ struct ErrorResponse: Codable { let code: Int let message: String } + diff --git a/KkuMulKum/Network/DTO/TargetType/LoginService.swift b/KkuMulKum/Network/DTO/TargetType/LoginService.swift index 468135ff..28817bcd 100644 --- a/KkuMulKum/Network/DTO/TargetType/LoginService.swift +++ b/KkuMulKum/Network/DTO/TargetType/LoginService.swift @@ -4,6 +4,7 @@ // // Created by 이지훈 on 7/15/24. // + import Foundation import Moya @@ -14,24 +15,15 @@ enum LoginService { extension LoginService: TargetType { var baseURL: URL { - print("Attempting to get baseURL") - guard let privacyInfo = Bundle.main.privacyInfo else { - fatalError("PrivacyInfo.plist not found") - } - - guard let urlString = privacyInfo["BASE_URL"] as? String else { - fatalError("BASE_URL not found in PrivacyInfo.plist") - } - - guard let url = URL(string: urlString) else { - fatalError("Invalid BASE_URL in PrivacyInfo.plist: \(urlString)") + guard let privacyInfo = Bundle.main.privacyInfo, + let urlString = privacyInfo["BASE_URL"] as? String, + let url = URL(string: urlString) else { + fatalError("Invalid BASE_URL in PrivacyInfo.plist") } - return url } var path: String { - print("Getting path: /api/v1/auth/signin") return "/api/v1/auth/signin" } @@ -63,22 +55,3 @@ extension LoginService: TargetType { } } } - -extension Bundle { - var privacyInfo: [String: Any]? { - guard let url = self.url(forResource: "PrivacyInfo", withExtension: "plist") else { - return nil - } - guard let data = try? Data(contentsOf: url) else { - return nil - } - guard let result = try? PropertyListSerialization.propertyList( - from: data, - options: [], - format: nil - ) as? [String: Any] else { - return nil - } - return result - } -} diff --git a/KkuMulKum/Resource/Bundle.swift b/KkuMulKum/Resource/Bundle.swift new file mode 100644 index 00000000..33200100 --- /dev/null +++ b/KkuMulKum/Resource/Bundle.swift @@ -0,0 +1,23 @@ +// +// Bundle.swift +// KkuMulKum +// +// Created by 이지훈 on 7/15/24. +// + +import Foundation + +extension Bundle { + var privacyInfo: [String: Any]? { + guard let url = self.url(forResource: "PrivacyInfo", withExtension: "plist"), + let data = try? Data(contentsOf: url), + let result = try? PropertyListSerialization.propertyList( + from: data, + options: [], + format: nil + ) as? [String: Any] else { + return nil + } + return result + } +} diff --git a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift index cd2c06b4..4484d67f 100644 --- a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift +++ b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift @@ -4,9 +4,10 @@ // // Created by 이지훈 on 7/9/24. // -import UIKit +import UIKit import AuthenticationServices + import KakaoSDKUser import KakaoSDKAuth import Moya @@ -21,13 +22,12 @@ class LoginViewModel: NSObject { var loginState: ObservablePattern = ObservablePattern(.notLoggedIn) var error: ObservablePattern = ObservablePattern("") - private let provider = MoyaProvider( - plugins: [NetworkLoggerPlugin( - configuration: .init( - logOptions: .verbose - ) - )] - ) + private let provider: MoyaProvider + + init(provider: MoyaProvider = MoyaProvider(plugins: [NetworkLoggerPlugin(configuration: .init(logOptions: .verbose))])) { + self.provider = provider + super.init() + } func performAppleLogin(presentationAnchor: ASPresentationAnchor) { print("Performing Apple Login") @@ -63,7 +63,7 @@ class LoginViewModel: NSObject { if let token = oauthToken?.accessToken { print("Kakao Login Successful, access token: \(token)") - loginToServer(with: .kakaoLogin(accessToken: token, fcmToken: "")) + loginToServer(with: .kakaoLogin(accessToken: token, fcmToken: "dummy_fcm_token")) } else { print("Kakao Login Error: No access token") self.error.value = "No access token received" @@ -76,7 +76,7 @@ class LoginViewModel: NSObject { case .success(let response): print("Received response from server: \(response)") do { - let loginResponse = try response.map(SocialLoginResponseModel.self) + let loginResponse = try response.map(ResponseBodyDTO.self) print("Successfully mapped response: \(loginResponse)") self?.handleLoginResponse(loginResponse) } catch { @@ -91,7 +91,7 @@ class LoginViewModel: NSObject { } } - private func handleLoginResponse(_ response: SocialLoginResponseModel) { + private func handleLoginResponse(_ response: ResponseBodyDTO) { print("Handling login response") if response.success { if let data = response.data { @@ -105,7 +105,7 @@ class LoginViewModel: NSObject { let tokens = data.jwtTokenDto print("Received tokens - Access: \(tokens.accessToken), Refresh: \(tokens.refreshToken)") - // TODO: 키체인에 토큰 저장 로직추가 예정 + // TODO: 토큰 저장 로직 구현 } else { print("Warning: No data received in response") error.value = "No data received" @@ -120,10 +120,10 @@ class LoginViewModel: NSObject { } } } + } -extension LoginViewModel: ASAuthorizationControllerDelegate, - ASAuthorizationControllerPresentationContextProviding { +extension LoginViewModel: ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { func authorizationController( controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization @@ -137,7 +137,7 @@ extension LoginViewModel: ASAuthorizationControllerDelegate, } print("Apple Login Successful, identity token: \(tokenString)") - loginToServer(with: .appleLogin(identityToken: tokenString, fcmToken: "")) + loginToServer(with: .appleLogin(identityToken: tokenString, fcmToken: "dummy_fcm_token")) } func authorizationController( diff --git a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift index 21286186..228e1104 100644 --- a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift +++ b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift @@ -6,13 +6,21 @@ // import UIKit - import AuthenticationServices class LoginViewController: BaseViewController { private let loginView = LoginView() - private let loginViewModel = LoginViewModel() + private let loginViewModel: LoginViewModel + + init(viewModel: LoginViewModel = LoginViewModel()) { + self.loginViewModel = viewModel + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } override func loadView() { view = loginView @@ -77,32 +85,19 @@ class LoginViewController: BaseViewController { } @objc private func dummyNextButtonTapped() { -// _ = NicknameViewController() -// let welcomeViewController = NicknameViewController() -// welcomeViewController.modalPresentationStyle = .fullScreen -// present(welcomeViewController, animated: true, completion: nil) - - // TODO: 프로필 설정부터 네비게이션으로 플로우 동작 - let viewController = MainTabBarController() - viewController.modalPresentationStyle = .fullScreen - present(viewController, animated: true) } private func navigateToMainScreen() { DispatchQueue.main.async { let mainTabBarController = MainTabBarController() - let navigationController = UINavigationController(rootViewController: mainTabBarController) - navigationController.isNavigationBarHidden = true navigationController.modalPresentationStyle = .fullScreen navigationController.modalTransitionStyle = .crossDissolve - self.present(navigationController, animated: true, completion: nil) - } } From 241a5397d185e9cd1eb110183d8be257e4dc032b Mon Sep 17 00:00:00 2001 From: hooni Date: Mon, 15 Jul 2024 22:19:35 +0900 Subject: [PATCH 16/17] =?UTF-8?q?fix/#178=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KkuMulKum.xcodeproj/project.pbxproj | 18 +++-- .../Model/Auth/SocialLoginResponseModel.swift | 2 +- ...ginService.swift => LoginTargetType.swift} | 5 +- KkuMulKum/Resource/{ => Bundle}/Bundle.swift | 0 .../Login/VIewModel/LoginViewModel.swift | 68 +++++++++++-------- .../ViewController/LoginViewController.swift | 4 +- 6 files changed, 57 insertions(+), 40 deletions(-) rename KkuMulKum/Network/DTO/TargetType/{LoginService.swift => LoginTargetType.swift} (95%) rename KkuMulKum/Resource/{ => Bundle}/Bundle.swift (100%) diff --git a/KkuMulKum.xcodeproj/project.pbxproj b/KkuMulKum.xcodeproj/project.pbxproj index 4e5c75fb..b381a529 100644 --- a/KkuMulKum.xcodeproj/project.pbxproj +++ b/KkuMulKum.xcodeproj/project.pbxproj @@ -62,7 +62,7 @@ 78B928752C29402E006D9942 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 78B928742C29402E006D9942 /* Assets.xcassets */; }; 78B928782C29402E006D9942 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78B928762C29402E006D9942 /* LaunchScreen.storyboard */; }; 78BD61202C43F557005752FD /* SwiftKeychainWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = 78BD611F2C43F557005752FD /* SwiftKeychainWrapper */; }; - 78BD61272C446A97005752FD /* LoginService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78BD61262C446A97005752FD /* LoginService.swift */; }; + 78BD61272C446A97005752FD /* LoginTargetType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78BD61262C446A97005752FD /* LoginTargetType.swift */; }; 78BD612B2C4550A6005752FD /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78BD612A2C4550A6005752FD /* Bundle.swift */; }; A3DD9C3D2C41BAD000E58A13 /* MeetingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C322C41BAD000E58A13 /* MeetingTableViewCell.swift */; }; A3DD9C3E2C41BAD000E58A13 /* MeetingDummyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3DD9C342C41BAD000E58A13 /* MeetingDummyModel.swift */; }; @@ -205,7 +205,7 @@ 78B928742C29402E006D9942 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 78B928772C29402E006D9942 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 78B928792C29402E006D9942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 78BD61262C446A97005752FD /* LoginService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginService.swift; sourceTree = ""; }; + 78BD61262C446A97005752FD /* LoginTargetType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginTargetType.swift; sourceTree = ""; }; 78BD612A2C4550A6005752FD /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = ""; }; A3DD9C322C41BAD000E58A13 /* MeetingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingTableViewCell.swift; sourceTree = ""; }; A3DD9C342C41BAD000E58A13 /* MeetingDummyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingDummyModel.swift; sourceTree = ""; }; @@ -529,11 +529,19 @@ 78BD61252C446A84005752FD /* TargetType */ = { isa = PBXGroup; children = ( - 78BD61262C446A97005752FD /* LoginService.swift */, + 78BD61262C446A97005752FD /* LoginTargetType.swift */, ); path = TargetType; sourceTree = ""; }; + 78BD612C2C455680005752FD /* Bundle */ = { + isa = PBXGroup; + children = ( + 78BD612A2C4550A6005752FD /* Bundle.swift */, + ); + path = Bundle; + sourceTree = ""; + }; A3DD9C332C41BAD000E58A13 /* Cell */ = { isa = PBXGroup; children = ( @@ -1042,6 +1050,7 @@ DE254AA32C31107C00A4015E /* Resource */ = { isa = PBXGroup; children = ( + 78BD612C2C455680005752FD /* Bundle */, DEBA03302C3C2972002ED8F2 /* ViewController.swift */, DD39768B2C41C36B00E2A4C4 /* Color.xcassets */, 78B928742C29402E006D9942 /* Assets.xcassets */, @@ -1055,7 +1064,6 @@ DE254AA62C3118B300A4015E /* Extension */, DE254AB52C3119BC00A4015E /* Util */, DE254ABA2C311C3100A4015E /* Font */, - 78BD612A2C4550A6005752FD /* Bundle.swift */, ); path = Resource; sourceTree = ""; @@ -1462,7 +1470,7 @@ A3FB184F2C3BF4BC001483E5 /* MakeMeetingsResponseModel.swift in Sources */, DD3976852C41C2AD00E2A4C4 /* UpcomingPromiseModel.swift in Sources */, DEF725DB2C3F3BBF008C87C7 /* Toast.swift in Sources */, - 78BD61272C446A97005752FD /* LoginService.swift in Sources */, + 78BD61272C446A97005752FD /* LoginTargetType.swift in Sources */, DD43937A2C412F4500EC1799 /* FinishCreateViewController.swift in Sources */, DE254AAC2C31192400A4015E /* UILabel+.swift in Sources */, DE254AB72C3119D000A4015E /* ReuseIdentifiable.swift in Sources */, diff --git a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift index 61acb79b..46e6c3dc 100644 --- a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift +++ b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift @@ -13,7 +13,7 @@ struct UserData: ResponseModelType { enum CodingKeys: String, CodingKey { case name - case jwtTokenDto // 서버 응답과 + case jwtTokenDto // 서버 응답맞춰 수정 } } diff --git a/KkuMulKum/Network/DTO/TargetType/LoginService.swift b/KkuMulKum/Network/DTO/TargetType/LoginTargetType.swift similarity index 95% rename from KkuMulKum/Network/DTO/TargetType/LoginService.swift rename to KkuMulKum/Network/DTO/TargetType/LoginTargetType.swift index 28817bcd..f5c09c89 100644 --- a/KkuMulKum/Network/DTO/TargetType/LoginService.swift +++ b/KkuMulKum/Network/DTO/TargetType/LoginTargetType.swift @@ -6,14 +6,15 @@ // import Foundation + import Moya -enum LoginService { +enum LoginTargetType { case appleLogin(identityToken: String, fcmToken: String) case kakaoLogin(accessToken: String, fcmToken: String) } -extension LoginService: TargetType { +extension LoginTargetType: TargetType { var baseURL: URL { guard let privacyInfo = Bundle.main.privacyInfo, let urlString = privacyInfo["BASE_URL"] as? String, diff --git a/KkuMulKum/Resource/Bundle.swift b/KkuMulKum/Resource/Bundle/Bundle.swift similarity index 100% rename from KkuMulKum/Resource/Bundle.swift rename to KkuMulKum/Resource/Bundle/Bundle.swift diff --git a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift index 4484d67f..64abe953 100644 --- a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift +++ b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift @@ -13,18 +13,26 @@ import KakaoSDKAuth import Moya enum LoginState { - case notLoggedIn - case loggedIn(userInfo: String) + case notLogin + case login(userInfo: String) case needOnboarding } class LoginViewModel: NSObject { - var loginState: ObservablePattern = ObservablePattern(.notLoggedIn) + var loginState: ObservablePattern = ObservablePattern(.notLogin) var error: ObservablePattern = ObservablePattern("") - private let provider: MoyaProvider + private let provider: MoyaProvider - init(provider: MoyaProvider = MoyaProvider(plugins: [NetworkLoggerPlugin(configuration: .init(logOptions: .verbose))])) { + init( + provider: MoyaProvider = MoyaProvider( + plugins: [NetworkLoggerPlugin( + configuration: .init( + logOptions: .verbose + ) + )] + ) + ) { self.provider = provider super.init() } @@ -70,8 +78,8 @@ class LoginViewModel: NSObject { } } - private func loginToServer(with loginService: LoginService) { - provider.request(loginService) { [weak self] result in + private func loginToServer(with loginTarget: LoginTargetType) { + provider.request(loginTarget) { [weak self] result in switch result { case .success(let response): print("Received response from server: \(response)") @@ -92,34 +100,34 @@ class LoginViewModel: NSObject { } private func handleLoginResponse(_ response: ResponseBodyDTO) { - print("Handling login response") - if response.success { - if let data = response.data { - if let name = data.name { - print("Login successful, user name: \(name)") - loginState.value = .loggedIn(userInfo: name) + print("Handling login response") + if response.success { + if let data = response.data { + if let name = data.name { + print("Login successful, user name: \(name)") + loginState.value = .login(userInfo: name) + } else { + print("Login successful, but no name provided. Needs onboarding.") + loginState.value = .needOnboarding + } + + let tokens = data.jwtTokenDto + print("Received tokens - Access: \(tokens.accessToken), Refresh: \(tokens.refreshToken)") + // TODO: 토큰 저장 로직 구현 } else { - print("Login successful, but no name provided. Needs onboarding.") - loginState.value = .needOnboarding + print("Warning: No data received in response") + error.value = "No data received" } - - let tokens = data.jwtTokenDto - print("Received tokens - Access: \(tokens.accessToken), Refresh: \(tokens.refreshToken)") - // TODO: 토큰 저장 로직 구현 - } else { - print("Warning: No data received in response") - error.value = "No data received" - } - } else { - if let error = response.error { - print("Login failed: \(error.message)") - self.error.value = error.message } else { - print("Login failed: Unknown error") - self.error.value = "Unknown error occurred" + if let error = response.error { + print("Login failed: \(error.message)") + self.error.value = error.message + } else { + print("Login failed: Unknown error") + self.error.value = "Unknown error occurred" + } } } - } } diff --git a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift index 228e1104..a6a86acc 100644 --- a/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift +++ b/KkuMulKum/Source/Onboarding/Login/ViewController/LoginViewController.swift @@ -57,9 +57,9 @@ class LoginViewController: BaseViewController { private func bindViewModel() { loginViewModel.loginState.bind(with: self) { owner, state in switch state { - case .notLoggedIn: + case .notLogin: print("Login State: Not logged in") - case .loggedIn(let userInfo): + case .login(let userInfo): print("Login State: Logged in with user info: \(userInfo)") owner.navigateToMainScreen() case .needOnboarding: From ddeaec31189ea117d8f513a283306e946bfc4a1d Mon Sep 17 00:00:00 2001 From: hooni Date: Mon, 15 Jul 2024 22:28:33 +0900 Subject: [PATCH 17/17] =?UTF-8?q?fix/#178=20DTO=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=A4=EC=85=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Network/DTO/Model/Auth/SocialLoginResponseModel.swift | 8 ++++---- .../Onboarding/Login/VIewModel/LoginViewModel.swift | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift index 46e6c3dc..37bbff1d 100644 --- a/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift +++ b/KkuMulKum/Network/DTO/Model/Auth/SocialLoginResponseModel.swift @@ -7,17 +7,17 @@ import Foundation -struct UserData: ResponseModelType { +struct SocialLoginResponseModel: ResponseModelType { let name: String? - let jwtTokenDto: JwtTokenDto + let jwtTokenDTO: JwtTokenDTO enum CodingKeys: String, CodingKey { case name - case jwtTokenDto // 서버 응답맞춰 수정 + case jwtTokenDTO = "jwtTokenDto" } } -struct JwtTokenDto: Codable { +struct JwtTokenDTO: Codable { let accessToken: String let refreshToken: String } diff --git a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift index 64abe953..5e874191 100644 --- a/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift +++ b/KkuMulKum/Source/Onboarding/Login/VIewModel/LoginViewModel.swift @@ -84,7 +84,7 @@ class LoginViewModel: NSObject { case .success(let response): print("Received response from server: \(response)") do { - let loginResponse = try response.map(ResponseBodyDTO.self) + let loginResponse = try response.map(ResponseBodyDTO.self) print("Successfully mapped response: \(loginResponse)") self?.handleLoginResponse(loginResponse) } catch { @@ -99,7 +99,7 @@ class LoginViewModel: NSObject { } } - private func handleLoginResponse(_ response: ResponseBodyDTO) { + private func handleLoginResponse(_ response: ResponseBodyDTO) { print("Handling login response") if response.success { if let data = response.data { @@ -111,7 +111,7 @@ class LoginViewModel: NSObject { loginState.value = .needOnboarding } - let tokens = data.jwtTokenDto + let tokens = data.jwtTokenDTO print("Received tokens - Access: \(tokens.accessToken), Refresh: \(tokens.refreshToken)") // TODO: 토큰 저장 로직 구현 } else {