From 6953ce3e3ec4c429c9a9724aee065c161f36a89d Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Wed, 9 Aug 2023 19:27:53 +0900 Subject: [PATCH] =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../Contents.json | 21 ++ .../btn_radio_select_normal.png | Bin 0 -> 509 bytes .../Contents.json | 21 ++ .../btn_radio_select_selected.png | Bin 0 -> 668 bytes .../ic_camera.imageset/Contents.json | 21 ++ .../ic_camera.imageset/ic_camera.png | Bin 0 -> 479 bytes .../ic_logo.imageset/Contents.json | 21 ++ .../ic_logo.imageset/ic_logo.png | Bin 0 -> 56036 bytes SodaLive/Sources/Common/BaseView.swift | 38 ++ SodaLive/Sources/ContentView.swift | 3 + .../Sources/ImagePicker/ImagePicker.swift | 48 +++ .../Sources/Keyboard/KeyboardHandler.swift | 29 ++ .../NavigationBar/DetailNavigationBar.swift | 45 +++ SodaLive/Sources/User/Gender.swift | 12 + SodaLive/Sources/User/Login/LoginView.swift | 23 +- .../Sources/User/SignUp/SignUpRequest.swift | 18 + SodaLive/Sources/User/SignUp/SignUpView.swift | 347 ++++++++++++++++++ .../Sources/User/SignUp/SignUpViewModel.swift | 187 ++++++++++ 19 files changed, 830 insertions(+), 8 deletions(-) create mode 100644 SodaLive/Resources/Assets.xcassets/btn_radio_select_normal.imageset/Contents.json create mode 100644 SodaLive/Resources/Assets.xcassets/btn_radio_select_normal.imageset/btn_radio_select_normal.png create mode 100644 SodaLive/Resources/Assets.xcassets/btn_radio_select_selected.imageset/Contents.json create mode 100644 SodaLive/Resources/Assets.xcassets/btn_radio_select_selected.imageset/btn_radio_select_selected.png create mode 100644 SodaLive/Resources/Assets.xcassets/ic_camera.imageset/Contents.json create mode 100644 SodaLive/Resources/Assets.xcassets/ic_camera.imageset/ic_camera.png create mode 100644 SodaLive/Resources/Assets.xcassets/ic_logo.imageset/Contents.json create mode 100644 SodaLive/Resources/Assets.xcassets/ic_logo.imageset/ic_logo.png create mode 100644 SodaLive/Sources/Common/BaseView.swift create mode 100644 SodaLive/Sources/ImagePicker/ImagePicker.swift create mode 100644 SodaLive/Sources/Keyboard/KeyboardHandler.swift create mode 100644 SodaLive/Sources/NavigationBar/DetailNavigationBar.swift create mode 100644 SodaLive/Sources/User/Gender.swift create mode 100644 SodaLive/Sources/User/SignUp/SignUpRequest.swift create mode 100644 SodaLive/Sources/User/SignUp/SignUpView.swift create mode 100644 SodaLive/Sources/User/SignUp/SignUpViewModel.swift diff --git a/SodaLive.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SodaLive.xcworkspace/xcshareddata/swiftpm/Package.resolved index 48985a2..3aa7930 100644 --- a/SodaLive.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/SodaLive.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -113,8 +113,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/exyte/PopupView.git", "state" : { - "revision" : "68349a0ae704b9a7041f756f3f4f460ddbf7ba8d", - "version" : "2.6.0" + "revision" : "1b99d6e9872ef91fd57aaef657661b5a00069638", + "version" : "1.3.1" } }, { diff --git a/SodaLive/Resources/Assets.xcassets/btn_radio_select_normal.imageset/Contents.json b/SodaLive/Resources/Assets.xcassets/btn_radio_select_normal.imageset/Contents.json new file mode 100644 index 0000000..b9e05de --- /dev/null +++ b/SodaLive/Resources/Assets.xcassets/btn_radio_select_normal.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "btn_radio_select_normal.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SodaLive/Resources/Assets.xcassets/btn_radio_select_normal.imageset/btn_radio_select_normal.png b/SodaLive/Resources/Assets.xcassets/btn_radio_select_normal.imageset/btn_radio_select_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..40f508ac966062c49d4154dd31575a7b3d1d66f6 GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw3=&b&bO2H;>5jgR3=A9lx&I`x0{M)^LGDfr z>(0r%1aiy*d_r8^3w$nJx^(&S<=eM!U%7JS>eZ`{9z6mwfFeKul)8598if7s-8&%n z>C>k`l{a3p^a4%bD+%%oW?1l2v@nLl`RK1@lA9~t-iEvb+T-o%;uzv_eChPtn+_{* zxK2$GnKk?0|MT-!y*x5UW$lj2S0<5%`4pNAw?F%nG}EJ{8GFadKA~(bn4jn=lK1PFGEkvwbl{&XIfk6Eg74y`}oU?nmymEzS-SN zKfWxzKjYYC>2GTJ%=X%L+0VVN#R%`d{J-{g{G{xc-=tQnZM(31#ZR-d?Vq%gg*9*Z zTn^M-xh|}AY1C?0c3v5+hiioPazFPwzV&tFTZ`TEietOc3j2tn)6t_BLouGQUjlp6PWJp6P~P4k*s`dDnh3Ab!t1L1Cr`y**zJHyxai!_gMR zD#{r$@4~@`K9wsx8_ZZt9aelz@|E9}x1pPFSJKAQvQpX`8rh_mZcyZtlHYhxRC?yY wMA>NJRjjF(^)()3l|-I0yBf4Cg8e@OU-0bpCwCT}1_n5Tr>mdKI;Vst0CD&7+W-In literal 0 HcmV?d00001 diff --git a/SodaLive/Resources/Assets.xcassets/btn_radio_select_selected.imageset/Contents.json b/SodaLive/Resources/Assets.xcassets/btn_radio_select_selected.imageset/Contents.json new file mode 100644 index 0000000..12acf8c --- /dev/null +++ b/SodaLive/Resources/Assets.xcassets/btn_radio_select_selected.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "btn_radio_select_selected.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SodaLive/Resources/Assets.xcassets/btn_radio_select_selected.imageset/btn_radio_select_selected.png b/SodaLive/Resources/Assets.xcassets/btn_radio_select_selected.imageset/btn_radio_select_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..57f23d15227225e1b3e3ca753b4b007263233a8d GIT binary patch literal 668 zcmV;N0%QG&P)Px#T2M?>MMrQ<)6@UVx&O?#|IN7n&AI>2zyHj){?5Ap z$+r8=x&O_$|1&c)nQ;Hixc@vlL1j^vLqJQ3ex^`OTBDT6XkmGYX5MyNxs+}7R7Z4w zV9Std?0j>Sxu@k*!m2L-000bhQchC<2%x6LbQk?Y_p{$046{f800GEJL_t(Y$E8>8 zwt^rK^aEWf9Yn;eZtwq^mpUnEnsj!48q*H5%d#ZNCeo_N#90!_v&f1nO`=g2g0KLI zqKu+eC|vqr1BR@&IEe||Yt$5ioTT1N|^?2|9P)5{!?-HQ3*Y%hp-ajW8?b zIePy~+w7qAYkK6fXprCVrP;;BZ<{a)7wBTRA-jW^0!w|Ud8J&-cj%K3d~FVJ^`TEM ztBIyGsQVH5J})IIU-i*Pie3osUzH-}`cUIBc~osj>>Lms^D z%58b_S~pS9v)_d~i}n}QUbl58Q^3R&*Jqg-=hzvOj$0i0HtiDUL_+=Imv>A-CWOhp zF^)V=>p?s+OE$|eR;pMGBbyD-ZO#sKw&NS%G}U;vjb? zhIQv;UIIBb0X`wF?gc*o$p!rX7tFx@`h@6>NvlFFqrT49%4uBVzvWX~ z>?WXbrZM(74x;j6=|FfdwO8trFzAv+V z&ADT~&+aq2>C0Uooq21Mf7bNu*&`nht>r)W^;K7|`+nE`wx`;nz2ol11s0}@cufBK zcNhQsd=uo_^pKu_#ihMA%Ww&G+zUquvF4Iz~Na8H``1AFMNMVn0`ZJL>VH84-6X zk|wz}f4*{{ge}0DXJ$FwmlprJ zrTRn99NvRg>#wi}R7u2H|LOH=|NrychiHu#&&A5VM~R5`>=&7|=6QbqieKOU%$^q_ XtGe)lgUjL{9F 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 UXy?PyLjVA90~7t~o6a%+1AAj|7ytkO literal 0 HcmV?d00001 diff --git a/SodaLive/Sources/Common/BaseView.swift b/SodaLive/Sources/Common/BaseView.swift new file mode 100644 index 0000000..3a65447 --- /dev/null +++ b/SodaLive/Sources/Common/BaseView.swift @@ -0,0 +1,38 @@ +// +// BaseView.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import SwiftUI + +struct BaseView: View { + + let content: Content + + @Binding var isLoading: Bool + + init(isLoading: Binding = .constant(false), @ViewBuilder content: () -> Content) { + self._isLoading = isLoading + self.content = content() + } + + var body: some View { + ZStack { + Color.black.ignoresSafeArea() + + content + + if isLoading { + LoadingView() + } + } + } +} + +struct BaseView_Previews: PreviewProvider { + static var previews: some View { + BaseView(isLoading: .constant(false)) {} + } +} diff --git a/SodaLive/Sources/ContentView.swift b/SodaLive/Sources/ContentView.swift index 45b1a83..35c5288 100644 --- a/SodaLive/Sources/ContentView.swift +++ b/SodaLive/Sources/ContentView.swift @@ -20,6 +20,9 @@ struct ContentView: View { case .splash: SplashView() + case .signUp: + SignUpView() + default: EmptyView() .frame(width: 0, height: 0, alignment: .topLeading) diff --git a/SodaLive/Sources/ImagePicker/ImagePicker.swift b/SodaLive/Sources/ImagePicker/ImagePicker.swift new file mode 100644 index 0000000..728af30 --- /dev/null +++ b/SodaLive/Sources/ImagePicker/ImagePicker.swift @@ -0,0 +1,48 @@ +// +// ImagePicker.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import SwiftUI + +struct ImagePicker: UIViewControllerRepresentable { + + @Binding var isShowing: Bool + @Binding var selectedImage: UIImage? + + let sourceType: UIImagePickerController.SourceType + + func makeUIViewController(context: Context) -> UIImagePickerController { + let picker = UIImagePickerController() + picker.delegate = context.coordinator + return picker + } + + func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) { + } + + func makeCoordinator() -> Coordinator { + return Coordinator(self) + } +} + +class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { + let parent: ImagePicker + + init(_ parent: ImagePicker) { + self.parent = parent + } + + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { + if let image = info[.originalImage] as? UIImage { + parent.selectedImage = image + parent.isShowing = false + } + } + + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + parent.isShowing = false + } +} diff --git a/SodaLive/Sources/Keyboard/KeyboardHandler.swift b/SodaLive/Sources/Keyboard/KeyboardHandler.swift new file mode 100644 index 0000000..f350acf --- /dev/null +++ b/SodaLive/Sources/Keyboard/KeyboardHandler.swift @@ -0,0 +1,29 @@ +// +// KeyboardHandler.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import SwiftUI +import Combine + +final class KeyboardHandler: ObservableObject { + @Published private(set) var keyboardHeight: CGFloat = 0 + + private var cancellable: AnyCancellable? + + private let keyboardWillShow = NotificationCenter.default + .publisher(for: UIResponder.keyboardWillShowNotification) + .compactMap { ($0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height } + + private let keyboardWillHide = NotificationCenter.default + .publisher(for: UIResponder.keyboardWillHideNotification) + .map { _ in CGFloat.zero } + + init() { + cancellable = Publishers.Merge(keyboardWillShow, keyboardWillHide) + .subscribe(on: DispatchQueue.main) + .assign(to: \.self.keyboardHeight, on: self) + } +} diff --git a/SodaLive/Sources/NavigationBar/DetailNavigationBar.swift b/SodaLive/Sources/NavigationBar/DetailNavigationBar.swift new file mode 100644 index 0000000..1d4d0ba --- /dev/null +++ b/SodaLive/Sources/NavigationBar/DetailNavigationBar.swift @@ -0,0 +1,45 @@ +// +// DetailNavigationBar.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import SwiftUI + +struct DetailNavigationBar: View { + + let title: String + var backAction: (() -> Void)? = nil + + var body: some View { + HStack(spacing: 0) { + Button { + if let backAction = backAction { + backAction() + } else { + AppState.shared.back() + } + } label: { + Image("ic_back") + .resizable() + .frame(width: 20, height: 20) + + Text(title) + .font(.custom(Font.bold.rawValue, size: 18.3)) + .foregroundColor(Color(hex: "eeeeee")) + } + + Spacer() + } + .padding(.horizontal, 13.3) + .frame(height: 50) + .background(Color.black) + } +} + +struct DetailNavigationBar_Previews: PreviewProvider { + static var previews: some View { + DetailNavigationBar(title: "이전으로") + } +} diff --git a/SodaLive/Sources/User/Gender.swift b/SodaLive/Sources/User/Gender.swift new file mode 100644 index 0000000..104be57 --- /dev/null +++ b/SodaLive/Sources/User/Gender.swift @@ -0,0 +1,12 @@ +// +// Gender.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import Foundation + +enum Gender: String, Codable { + case MALE, FEMALE, NONE +} diff --git a/SodaLive/Sources/User/Login/LoginView.swift b/SodaLive/Sources/User/Login/LoginView.swift index 211efce..13356ec 100644 --- a/SodaLive/Sources/User/Login/LoginView.swift +++ b/SodaLive/Sources/User/Login/LoginView.swift @@ -13,9 +13,7 @@ struct LoginView: View { @ObservedObject var viewModel = LoginViewModel() var body: some View { - ZStack { - Color.black.ignoresSafeArea() - + BaseView(isLoading: $viewModel.isLoading) { VStack(spacing: 0) { HomeNavigationBar(title: "로그인") {} @@ -69,9 +67,22 @@ struct LoginView: View { Spacer() } - - if viewModel.isLoading { - LoadingView() + } + .popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) { + GeometryReader { geo in + HStack { + Spacer() + Text(viewModel.errorMessage) + .padding(.vertical, 13.3) + .frame(width: geo.size.width - 66.7, alignment: .center) + .font(.custom(Font.medium.rawValue, size: 12)) + .background(Color(hex: "9970ff")) + .foregroundColor(Color.white) + .multilineTextAlignment(.center) + .cornerRadius(20) + .padding(.top, 66.7) + Spacer() + } } } } diff --git a/SodaLive/Sources/User/SignUp/SignUpRequest.swift b/SodaLive/Sources/User/SignUp/SignUpRequest.swift new file mode 100644 index 0000000..f43837a --- /dev/null +++ b/SodaLive/Sources/User/SignUp/SignUpRequest.swift @@ -0,0 +1,18 @@ +// +// SignUpRequest.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import Foundation + +struct SignUpRequest: Encodable { + let email: String + let password: String + let nickname: String + let gender: Gender + let isAgreeTermsOfService: Bool + let isAgreePrivacyPolicy: Bool + let container: String = "ios" +} diff --git a/SodaLive/Sources/User/SignUp/SignUpView.swift b/SodaLive/Sources/User/SignUp/SignUpView.swift new file mode 100644 index 0000000..dc70a50 --- /dev/null +++ b/SodaLive/Sources/User/SignUp/SignUpView.swift @@ -0,0 +1,347 @@ +// +// SignUpView.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import SwiftUI + +struct SignUpView: View { + + @ObservedObject var viewModel = SignUpViewModel() + + @StateObject var keyboardHandler = KeyboardHandler() + + @State private var isShowPhotoPicker = false + + var body: some View { + BaseView(isLoading: $viewModel.isLoading) { + GeometryReader { proxy in + VStack(spacing: 0) { + DetailNavigationBar(title: viewModel.step == .step2 ? "프로필 설정" : "회원가입") { + viewModel.prevStep() + } + + ScrollView(.vertical, showsIndicators: false) { + VStack(spacing: 13.3) { + if viewModel.step == .step1 { + EmailPasswordView() + + TermsOfServiceAgreeView() + + Text("다음") + .font(.custom(Font.bold.rawValue, size: 18.3)) + .foregroundColor(Color.white) + .padding(.vertical, 16) + .frame(width: screenSize().width - 53.4) + .background(Color(hex: "9970ff")) + .cornerRadius(10) + .padding(.vertical, 13.7) + .frame(width: screenSize().width - 26.7) + .background(Color(hex: "222222")) + .cornerRadius(16.7) + .padding(.top, 13.3) + .onTapGesture { viewModel.nextStep() } + } else { + ZStack { + if let selectedImage = viewModel.profileImage { + Image(uiImage: selectedImage) + .resizable() + .scaledToFill() + .frame(width: 80, height: 116.8, alignment: .top) + .background(Color(hex: "3e3358")) + .cornerRadius(10) + } else { + Image("ic_logo") + .resizable() + .scaledToFill() + .frame(width: 80, height: 116.8, alignment: .top) + .background(Color(hex: "3e3358")) + .cornerRadius(10) + } + + Image("ic_camera") + .padding(10) + .background(Color(hex: "9970ff")) + .cornerRadius(30) + .offset(x: 40, y: 40) + } + .frame(alignment: .bottomTrailing) + .padding(.top, 13.3) + .onTapGesture { + isShowPhotoPicker = true + } + + VStack(spacing: 16.7) { + UserTextField( + title: "닉네임", + hint: "닉네임을 입력해 주세요", + isSecure: false, + variable: $viewModel.nickname + ) + .padding(.horizontal, 13.3) + + GenderSelectView() + } + .padding(.vertical, 20) + .frame(width: screenSize().width - 26.7, alignment: .leading) + .background(Color(hex: "222222")) + .cornerRadius(6.7) + + Text("회원가입") + .font(.custom(Font.bold.rawValue, size: 18.3)) + .foregroundColor(Color.white) + .padding(.vertical, 16) + .frame(width: screenSize().width - 53.4) + .background(Color(hex: "9970ff")) + .cornerRadius(10) + .padding(.vertical, 13.7) + .frame(width: screenSize().width - 26.7) + .background(Color(hex: "222222")) + .cornerRadius(16.7) + .padding(.top, 13.3) + .onTapGesture { viewModel.signUp() } + } + + Rectangle() + .foregroundColor(Color.black) + .frame(width: screenSize().width, height: keyboardHandler.keyboardHeight) + + if proxy.safeAreaInsets.bottom > 0 { + Rectangle() + .foregroundColor(Color.black) + .frame(width: proxy.size.width, height: 15.3) + } + } + } + } + .edgesIgnoringSafeArea(.bottom) + .onTapGesture { + hideKeyboard() + } + } + + if isShowPhotoPicker { + ImagePicker( + isShowing: $isShowPhotoPicker, + selectedImage: $viewModel.profileImage, + sourceType: .photoLibrary + ) + } + } + .popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) { + GeometryReader { geo in + HStack { + Spacer() + Text(viewModel.errorMessage) + .padding(.vertical, 13.3) + .padding(.horizontal, 6.7) + .frame(width: geo.size.width - 66.7, alignment: .center) + .font(.custom(Font.medium.rawValue, size: 12)) + .background(Color(hex: "9970ff")) + .foregroundColor(Color.white) + .multilineTextAlignment(.leading) + .fixedSize(horizontal: false, vertical: true) + .cornerRadius(20) + .padding(.top, 66.7) + Spacer() + } + } + } + } + + @ViewBuilder + func EmailPasswordView() -> some View { + VStack(spacing: 26.7) { + UserTextField( + title: "이메일", + hint: "이메일 주소를 입력해 주세요", + isSecure: false, + variable: $viewModel.email, + keyboardType: .emailAddress + ) + .padding(.horizontal, 13.3) + + UserTextField( + title: "비밀번호", + hint: "비밀번호 (영문, 숫자 포함 8~20자)", + isSecure: true, + variable: $viewModel.password, + keyboardType: .emailAddress + ) + .padding(.horizontal, 13.3) + + UserTextField( + title: "비밀번호 확인", + hint: "비밀번호를 다시 입력해 주세요", + isSecure: true, + variable: $viewModel.passwordConfirm, + keyboardType: .emailAddress + ) + .padding(.horizontal, 13.3) + } + .padding(.vertical, 20) + .frame(width: screenSize().width - 26.7) + .background(Color(hex: "222222")) + .cornerRadius(6.7) + .padding(.top, 13.3) + } + + @ViewBuilder + func GenderSelectView() -> some View { + VStack(alignment: .leading, spacing: 13.3) { + Text("성별") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + .padding(.leading, 6.7) + + HStack(spacing: 0) { + HStack(spacing: 13.3) { + Image( + viewModel.gender == .FEMALE ? + "btn_radio_select_selected" : + "btn_radio_select_normal" + ).resizable() + .frame(width: 20, height: 20) + + Text("여자") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color(hex: "eeeeee")) + } + .contentShape(Rectangle()) + .onTapGesture { + if viewModel.gender != .FEMALE { + viewModel.gender = .FEMALE + } + } + + Spacer() + + HStack(spacing: 13.3) { + Image( + viewModel.gender == .MALE ? + "btn_radio_select_selected" : + "btn_radio_select_normal" + ).resizable() + .frame(width: 20, height: 20) + + Text("남자") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color(hex: "eeeeee")) + } + .contentShape(Rectangle()) + .onTapGesture { + if viewModel.gender != .MALE { + viewModel.gender = .MALE + } + } + + Spacer() + + HStack(spacing: 13.3) { + Image( + viewModel.gender == .NONE ? + "btn_radio_select_selected" : + "btn_radio_select_normal" + ).resizable() + .frame(width: 20, height: 20) + + Text("공개 안 함") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color(hex: "eeeeee")) + } + .contentShape(Rectangle()) + .onTapGesture { + if viewModel.gender != .NONE { + viewModel.gender = .NONE + } + } + + Spacer() + } + .padding(.leading, 6.7) + } + .frame(width: screenSize().width - 53.4) + } + + @ViewBuilder + func TermsOfServiceAgreeView() -> some View { + VStack(spacing: 0) { + Text("약관 동의") + .font(.custom(Font.bold.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + .frame(width: screenSize().width - 60, height: 50, alignment: .leading) + + Rectangle() + .frame(width: screenSize().width - 53.4, height: 1) + .foregroundColor(Color(hex: "909090")) + + HStack(spacing: 6.7) { + Text("이용약관 (필수)") + .font(.custom(Font.medium.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Text("(필수)") + .font(.custom(Font.medium.rawValue, size: 12)) + .foregroundColor(Color(hex: "9970ff")) + + Spacer() + + Image( + viewModel.isAgreeTerms ? + "btn_select_checked" : + "btn_select_normal" + ).resizable() + .frame(width: 20, height: 20) + } + .frame(width: screenSize().width - 60, height: 50, alignment: .leading) + .contentShape(Rectangle()) + .onTapGesture { + viewModel.isAgreeTerms.toggle() + } + + Rectangle() + .frame(width: screenSize().width - 53.4, height: 1) + .foregroundColor(Color(hex: "909090")) + + HStack(spacing: 6.7) { + Text("개인정보수집 동의") + .font(.custom(Font.medium.rawValue, size: 12)) + .foregroundColor(Color(hex: "eeeeee")) + + Text("(필수)") + .font(.custom(Font.medium.rawValue, size: 12)) + .foregroundColor(Color(hex: "9970ff")) + + Spacer() + + Image( + viewModel.isAgreePrivacyPolicy ? + "btn_select_checked" : + "btn_select_normal" + ).resizable() + .frame(width: 20, height: 20) + } + .frame(width: screenSize().width - 60, height: 50, alignment: .leading) + .contentShape(Rectangle()) + .onTapGesture { + viewModel.isAgreePrivacyPolicy.toggle() + } + + Rectangle() + .frame(width: screenSize().width - 53.4, height: 1) + .foregroundColor(Color(hex: "909090")) + } + .padding(.vertical, 13.3) + .frame(width: screenSize().width - 26.7) + .background(Color(hex: "222222")) + .cornerRadius(6.7) + } +} + +struct SignUpView_Previews: PreviewProvider { + static var previews: some View { + SignUpView() + } +} diff --git a/SodaLive/Sources/User/SignUp/SignUpViewModel.swift b/SodaLive/Sources/User/SignUp/SignUpViewModel.swift new file mode 100644 index 0000000..910223c --- /dev/null +++ b/SodaLive/Sources/User/SignUp/SignUpViewModel.swift @@ -0,0 +1,187 @@ +// +// SignUpViewModel.swift +// SodaLive +// +// Created by klaus on 2023/08/09. +// + +import UIKit +import Combine + +import Moya + +final class SignUpViewModel: ObservableObject { + private let repository = UserRepository() + private var subscription = Set() + + @Published var errorMessage = "" + @Published var isShowPopup = false + @Published var isLoading = false + + @Published var email = "" + @Published var nickname = "" + @Published var gender: Gender = .NONE + + @Published var password = "" + @Published var passwordConfirm = "" + + @Published var profileImage: UIImage? = nil + + @Published var isAgreeTerms = false + @Published var isAgreePrivacyPolicy = false + + enum Step { + case step1, step2 + } + + @Published private(set) var step = Step.step1 + + func prevStep() { + if step == .step1 { + AppState.shared.back() + } else { + step = .step1 + } + } + + func nextStep() { + if validateStep1() { + step = .step2 + } + } + + func signUp() { + if validateStep2() { + isLoading = true + + let request = SignUpRequest( + email: email, + password: password, + nickname: nickname, + gender: gender, + isAgreeTermsOfService: true, + isAgreePrivacyPolicy: true + ) + + var multipartData = [MultipartFormData]() + + let encoder = JSONEncoder() + encoder.outputFormatting = .withoutEscapingSlashes + let jsonData = try? encoder.encode(request) + + if let jsonData = jsonData { + if let profileImage = profileImage, let imageData = profileImage.jpegData(compressionQuality: 0.8) { + multipartData.append( + MultipartFormData( + provider: .data(imageData), + name: "profileImage", + fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000).jpg", + mimeType: "image/*") + ) + } + + multipartData.append(MultipartFormData(provider: .data(jsonData), name: "request")) + + repository.signUp(parameters: multipartData) + .sink { result in + switch result { + case .finished: + DEBUG_LOG("finish") + case .failure(let error): + ERROR_LOG(error.localizedDescription) + } + } receiveValue: { response in + self.isLoading = false + let responseData = response.data + do { + let jsonDecoder = JSONDecoder() + let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) + + if let data = decoded.data, decoded.success { + UserDefaults.set(data.profileImage, forKey: .profileImage) + UserDefaults.set(data.nickname, forKey: .nickname) + UserDefaults.set(data.userId, forKey: .userId) + UserDefaults.set(data.email, forKey: .email) + UserDefaults.set(data.token, forKey: .token) + AppState.shared.back() + } else { + if let message = decoded.message { + self.errorMessage = message + } else { + self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + } + + self.isShowPopup = true + } + } catch { + self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.isShowPopup = true + } + } + .store(in: &subscription) + } else { + self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.isShowPopup = true + self.isLoading = false + } + } + } + + private func validateStep1() -> Bool { + if email.trimmingCharacters(in: .whitespaces).isEmpty || !validateEmail() { + errorMessage = "올바른 이메일을 입력하세요" + isShowPopup = true + return false + } + + if password.trimmingCharacters(in: .whitespaces).isEmpty { + errorMessage = "비밀번호를 입력하세요" + isShowPopup = true + return false + } + + if !validatePassword() { + errorMessage = "영문, 숫자 포함 8자 이상의 비밀번호를 입력해 주세요." + isShowPopup = true + return false + } + + if password != passwordConfirm { + errorMessage = "비밀번호가 일치하지 않습니다." + isShowPopup = true + return false + } + + if !isAgreeTerms || !isAgreePrivacyPolicy { + errorMessage = "약관에 동의하셔야 회원가입이 가능합니다." + isShowPopup = true + return false + } + + return true + } + + func validateStep2() -> Bool { + if nickname.trimmingCharacters(in: .whitespaces).isEmpty || nickname.trimmingCharacters(in: .whitespaces).count < 2 { + errorMessage = "닉네임은 2자 이상 입력해 주세요." + isShowPopup = true + return false + } + + return true + } + + private func validateEmail() -> Bool { + let emailRegEx = "^.+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*$" + + let predicate = NSPredicate(format:"SELF MATCHES %@", emailRegEx) + return predicate.evaluate(with: email) + } + + private func validatePassword() -> Bool { + let passwordRegEx = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d$@!%*#?&]{8,}$" + + let predicate = NSPredicate(format:"SELF MATCHES %@", passwordRegEx) + return predicate.evaluate(with: password) + } +}