// // 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() } }