``` import UIKit import Foundation import Firebase import FirebaseDatabase import FirebaseAuth import GoogleSignIn import FBSDKLoginKit import SCLAlertView import UserNotifications import FirebaseStorage class SignupViewController: UIViewController{ @IBOutlet weak var usernameTextfield: UITextField! @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var passwordTextField: UITextField! @IBOutlet weak var reenterPasswordTextField: UITextField! @IBOutlet weak var signupButton: UIButton! @IBOutlet weak var errorlabel: UILabel! @IBOutlet weak var passwordEye: UIImageView! @IBOutlet weak var cameraButton: UIImageView! @IBOutlet weak var googleBtn: UIButton! @IBOutlet weak var fbBtn: UIButton! var database: DatabaseReference! private let storage = Storage.storage().reference() override func viewDidLoad() { super.viewDidLoad() setupGoogleButton() passwordTextField.isSecureTextEntry = true reenterPasswordTextField.isSecureTextEntry = true passwordEye.isUserInteractionEnabled = true passwordEye.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(eyeSelected))) setUpElements() cameraButton.isUserInteractionEnabled = true cameraButton.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(cameraButtonPressed))) let spacerView = UIView(frame:CGRect(x:0, y:0, width:30, height:10)) passwordTextField.leftViewMode = UITextField.ViewMode.always passwordTextField.leftView = spacerView let spacerView2 = UIView(frame:CGRect(x:0, y:0, width:30, height:10)) emailTextField.leftViewMode = UITextField.ViewMode.always emailTextField.leftView = spacerView2 let spacerView3 = UIView(frame:CGRect(x:0, y:0, width:30, height:10)) reenterPasswordTextField.leftViewMode = UITextField.ViewMode.always reenterPasswordTextField.leftView = spacerView3 let spacerView4 = UIView(frame:CGRect(x:0, y:0, width:30, height:10)) usernameTextfield.leftViewMode = UITextField.ViewMode.always usernameTextfield.leftView = spacerView4 cameraButton.layer.masksToBounds = true cameraButton.layer.cornerRadius = 80 cameraButton.contentMode = .scaleToFill fbBtn.layer.cornerRadius = fbBtn.frame.width / 2 fbBtn.layer.masksToBounds = true database = Database.database().reference() guard let urlString = UserDefaults.standard.value(forKey: "url") as? String, let url = URL(string: urlString) else { return } let task = URLSession.shared.dataTask(with: url, completionHandler: { data, _, error in guard let data = data, error == nil else{ return } DispatchQueue.main.async { let image = UIImage(data: data) self.cameraButton.image = image } }) task.resume() } func setupGoogleButton(){ googleBtn.layer.cornerRadius = googleBtn.frame.width/2 googleBtn.layer.masksToBounds = true GIDSignIn.sharedInstance()?.presentingViewController = self } func handleGoogleSignIn(){ GIDSignIn.sharedInstance().signIn() } func setUpElements() { //Hides error label errorlabel.alpha = 0 } func validateFields() -> String? { if usernameTextfield.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || emailTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" { SCLAlertView().showError("Try Again",subTitle:"😱Please fill in all of the fields😱") } let cleanedPassword = passwordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines) if Utilities.isPasswordValid(cleanedPassword) == false { SCLAlertView().showError("Try Again",subTitle:"😱Please make sure your password is at least 8 characters.😱") } return nil } @IBAction func didChangeSegement(_ sender:UISegmentedControl){ if sender.selectedSegmentIndex == 1{ let vc = storyboard?.instantiateViewController(identifier: "loginVC") as! LoginViewController vc.modalPresentationStyle = .fullScreen present(vc, animated: true) } } func transitionToHome() { let vc = storyboard?.instantiateViewController(identifier: "tabVC") as! TabBarViewController vc.modalPresentationStyle = .fullScreen present(vc, animated: true) } @IBAction func signUpTapped(_ sender: UIButton) { let error = validateFields() if error != nil { print(error!) sender.shake() SCLAlertView().showError("Uh Oh",subTitle:"Something went wrong") }else if reenterPasswordTextField.text! != passwordTextField.text!{ sender.shake() SCLAlertView().showError("Try Again",subTitle:"😱Your passwords do not match.😱") }else { usernameTextfield.resignFirstResponder() emailTextField.resignFirstResponder() passwordTextField.resignFirstResponder() let username = usernameTextfield.text!.trimmingCharacters(in: .whitespacesAndNewlines) let email = emailTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines) let password = passwordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines) DatabaseManager.shared.userExists(with: email, completion: { [weak self] exists in guard !exists else{ sender.shake() SCLAlertView().showError("Uh Oh",subTitle:"😱This account alreeady exists.😱") return } let email2 = email.replacingOccurrences(of: ".", with: "-") let safeEmail = email2.replacingOccurrences(of: "@", with: "-") Auth.auth().createUser(withEmail: email, password: password, completion: { authResult, error in guard authResult != nil, error == nil else { sender.shake() SCLAlertView().showError("Uh Oh",subTitle: "Something went wrong") print(safeEmail) print(error!) return } UserDefaults.standard.setValue(email, forKey: "email") UserDefaults.standard.setValue(username, forKey: "username") let newUser = UserModel(username: username, email: email, password: password) DatabaseManager.shared.insertUser(with: newUser, completion: { success in if success { guard let image = self?.cameraButton.image, let data = image.pngData() else { return } let filename = newUser.profilePictureURL StorageManager.shared.uploadProfilePicture(with: data, fileName: filename, completion: { result in switch result { case .success(let downloadUrl): UserDefaults.standard.set(downloadUrl, forKey: "profile_picture_url") UserDefaults.standard.set(true, forKey: "isLoggedIn") UserDefaults.standard.synchronize() self?.transitionToHome() case .failure( _): SCLAlertView().showError("Failed to upload Image", subTitle:"😱Choose another image.😱") } }) } }) }) }) } } @objc private func eyeSelected(){ passwordTextField.isSecureTextEntry.toggle() if passwordTextField.isSecureTextEntry == true{ passwordEye.image = UIImage(systemName: "eye") }else{ passwordEye.image = UIImage(systemName: "eye.fill") } } @IBAction func googleBtnPressed(_ sender: Any) { if GIDSignIn.sharedInstance()?.currentUser != nil{ return }else{ GIDSignIn.sharedInstance()?.signIn() if let user = GIDSignIn.sharedInstance()?.currentUser{ DatabaseManager.shared.userExists(with: user.profile.email, completion: { [weak self] exists in guard !exists else{ SCLAlertView().showError("Uh Oh",subTitle:"😱This account alreeady exists.😱") return } let email2 = user.profile.email.replacingOccurrences(of: ".", with: "-") let safeEmail = email2.replacingOccurrences(of: "@", with: "-") Auth.auth().createUser(withEmail: safeEmail, password: "null (Google User)", completion: { [weak self] authResult, error in guard authResult != nil, error == nil else { SCLAlertView().showError("Uh Oh",subTitle: "Something went wrong") return } UserDefaults.standard.setValue(user.profile.email, forKey: "email") UserDefaults.standard.setValue(user.profile.name, forKey: "username") let newUser = UserModel(username: user.profile.name, email: user.profile.email, password: "null (Google User)") DatabaseManager.shared.insertUser(with: newUser, completion: { [weak self] success in if success { if user.profile.hasImage { guard let url = user.profile.imageURL(withDimension: 200) else{ return } URLSession.shared.dataTask(with: url, completionHandler: { data, _, _ in guard let data = data else{ return } let fileName = newUser.profilePictureURL StorageManager.shared.uploadProfilePicture(with: data, fileName: fileName, completion: { [weak self] result in switch result { case .success(let downloadUrl): UserDefaults.standard.set(downloadUrl, forKey: "profile_picture_url") let vc = self?.storyboard?.instantiateViewController(identifier: "tabBarVC") as! TabBarViewController vc.modalPresentationStyle = .fullScreen self?.present(vc, animated: true) case .failure( _): SCLAlertView().showError("Failed to upload Image", subTitle:"😱Choose another image.😱") } }) }).resume() } } }) }) }) } } } @IBAction func fbBtnPressed(_ sender: Any) { let fbLoginManager = LoginManager() fbLoginManager.logIn(permissions: ["public_profile", "email", "picture.type(large)"], from: self) { [weak self] (result, error) in if error != nil { SCLAlertView().showError("Oof",subTitle:"😱Error signing you in.😱") return } guard let accessToken = AccessToken.current else { SCLAlertView().showError("Oof",subTitle:"😱Try again without Facebook😱") return } let credential = FacebookAuthProvider.credential(withAccessToken: accessToken.tokenString) Auth.auth().signIn(with: credential, completion: { (user, error) in if error != nil { SCLAlertView().showError("Oof",subTitle:"😱Error signing you in.😱") return } else { let user = Auth.auth().currentUser! DatabaseManager.shared.userExists(with: user.email!, completion: { exists in guard !exists else{ SCLAlertView().showError("Uh Oh",subTitle:"😱This account alreeady exists.😱") return } let email2 = user.email!.replacingOccurrences(of: ".", with: "-") let safeEmail = email2.replacingOccurrences(of: "@", with: "-") Auth.auth().createUser(withEmail: safeEmail, password: "null (Facebook User)", completion: { [weak self] authResult, error in guard authResult != nil, error == nil else { SCLAlertView().showError("Uh Oh",subTitle: "Something went wrong") return } UserDefaults.standard.setValue(user.email!, forKey: "email") UserDefaults.standard.setValue(user.displayName!, forKey: "username") let newUser = UserModel(username: user.displayName!, email: user.email!, password: "null (Facebook User)") DatabaseManager.shared.insertUser(with: newUser, completion: { [weak self] success in if success { guard let url = user.photoURL else{ return } URLSession.shared.dataTask(with: url, completionHandler: { data, _, _ in guard let data = data else{ return } let fileName = newUser.profilePictureURL StorageManager.shared.uploadProfilePicture(with: data, fileName: fileName, completion: { [weak self] result in switch result { case .success(let downloadUrl): UserDefaults.standard.set(downloadUrl, forKey: "profile_picture_url") self?.transitionToHome() case .failure( _): SCLAlertView().showError("Failed to upload Image", subTitle:"😱Choose another image.😱") } }) }).resume() } }) }) }) } }) } } @objc private func cameraButtonPressed(){ presentPhotoActionSheet() } } extension SignupViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func presentPhotoActionSheet(){ let actionSheet = UIAlertController(title: "Profile Picture", message: "Which way would you like to select a profile picture", preferredStyle: .actionSheet) actionSheet.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler:nil)) actionSheet.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: { [ weak self ] _ in self?.presentCamera() })) actionSheet.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { [ weak self ] _ in self?.presentPhotoPicker() })) present(actionSheet, animated: true) } func presentCamera(){ let vc = UIImagePickerController() vc.sourceType = .camera vc.delegate = self vc.allowsEditing = true present(vc, animated: true) } func presentPhotoPicker(){ let vc = UIImagePickerController() vc.sourceType = .photoLibrary vc.delegate = self vc.allowsEditing = true present(vc, animated: true) } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true, completion: nil) print(info) guard let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else{ return } guard let imageData = selectedImage.pngData() else{ return } storage.child("images/" + "filename" + ".png").putData(imageData, metadata: nil, completion: { _, error in guard error == nil else{ SCLAlertView().showError("Image can't be uploaded",subTitle:"😱Please choose another image😱") return } self.storage.child("images/file.png").downloadURL(completion: { url, error in guard let url = url, error == nil else{ return } let urlString = url.absoluteString UserDefaults.standard.set(urlString, forKey: "url") }) }) self.cameraButton.image = selectedImage } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true, completion: nil) } } ```