article

Monday, February 7, 2022

SwiftUI Firebase Login Register Log Out - Firebase Auth

SwiftUI Firebase Login Register Log Out - Firebase Auth

Firebase Apple Open Source Development
https://github.com/firebase/firebase-ios-sdk

SDWebImageSwiftUI
https://github.com/SDWebImage/SDWebImageSwiftUI


ContentView.swift
 
//
//  ContentView.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI
import Firebase

struct ContentView: View {
    
    @State private var isUserCurrentlyLoggedOut: Bool = false
    
    var body: some View {
        NavigationView {
            if self.isUserCurrentlyLoggedOut {
                Home(isUserCurrentlyLoggedOut: $isUserCurrentlyLoggedOut)
            }else {
                LoginRegister(isUserCurrentlyLoggedOut: $isUserCurrentlyLoggedOut)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
LoginRegister.swift
 
//
//  LoginRegister.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI
import Firebase

struct LoginRegister: View {
    
    @State var isLoginMode = false
    @State var email = ""
    @State var password = ""
    @State var fname = ""
    @State var lname = ""
    
    @State private var shouldShowLoginAlert: Bool = false
    
    @State var StatusMessage = ""
    
    @Binding var isUserCurrentlyLoggedOut : Bool
    
    var body: some View {
        ScrollView {

            VStack(spacing: 16) {
                Picker(selection: $isLoginMode, label: Text("Picker here")) {
                    Text("Login")
                        .tag(true)
                    Text("Create Account")
                        .tag(false)
                }.pickerStyle(SegmentedPickerStyle())
                
                if !isLoginMode {
                    VStack {
                        Image(systemName: "person.fill")
                            .font(.system(size: 64))
                            .padding()
                            .foregroundColor(Color(.label))
                    }
                    .overlay(RoundedRectangle(cornerRadius: 64)
                                .stroke(Color.black, lineWidth: 3)
                    )
                    Group {
                        TextField("First Name", text: $fname)
                        TextField("Last Name", text: $lname)
                        TextField("Email", text: $email)
                            .keyboardType(.emailAddress)
                            .autocapitalization(.none)
                        SecureField("Password", text: $password)
                    }
                    .padding()
                    .background(Color.white)
                    .cornerRadius(10)
                    
                    Button {
                        handleAction()
                    } label: {
                        HStack {
                            Spacer()
                            Text("Create Account")
                                .foregroundColor(.white)
                                .padding(.vertical, 10)
                                .font(.system(size: 18, weight: .semibold))
                            Spacer()
                        }.background(Color.green)
  
                    }.cornerRadius(10)
                }else{
                    Image("Login")
                        .resizable()
                        .scaledToFill()
                        .frame(width: 128, height: 128)
                        .cornerRadius(64)
                    
                    Group {
                        TextField("Email", text: $email)
                            .keyboardType(.emailAddress)
                            .autocapitalization(.none)
                        SecureField("Password", text: $password)
                    }
                    .padding()
                    .background(Color.white)
                    .cornerRadius(10)
                    
                    Button {
                        loginUser()
                    } label: {
                        HStack {
                            Spacer()
                            Text("Login")
                                .foregroundColor(.white)
                                .padding(.vertical, 10)
                                .font(.system(size: 18, weight: .semibold))
                            Spacer()
                        }.background(Color.green)
  
                    }.cornerRadius(10)
                    .alert(isPresented: $shouldShowLoginAlert) {
                        Alert(title: Text("Email/Password incorrect"))
                    }
                }
                
                Text(self.StatusMessage)
                    .foregroundColor(Color.white)
                
            }.padding()
        } //End ScrollView
        .navigationViewStyle(StackNavigationViewStyle())
        .background(
            LinearGradient(gradient: Gradient(colors: [.white, .blue, .yellow]), startPoint: .top, endPoint: .bottom).edgesIgnoringSafeArea(.all)
        )
    }
    
    private func loginUser() {
        Auth.auth().signIn(withEmail: email, password: password) { result, err in
            if let err = err {
                print("Failed to login user:", err)
                self.StatusMessage = "Failed to login user: \(err)"
                self.shouldShowLoginAlert = true
                return
            }
  
            print("Successfully logged in as user: \(result?.user.uid ?? "")")
  
            self.StatusMessage = "Successfully logged in as user: \(result?.user.uid ?? "")"

            self.isUserCurrentlyLoggedOut = true
        }
    }
    
    private func handleAction() {
        createNewAccount()
    }
     
    private func createNewAccount() {
        Auth.auth().createUser(withEmail: email, password: password) { result, err in
            if let err = err {
                print("Failed to create user:", err)
                self.StatusMessage = "Failed to create user: \(err)"
                return
            }
            
            print("Successfully created user: \(result?.user.uid ?? "")")
  
            self.StatusMessage = "Successfully created user: \(result?.user.uid ?? "")"
            
            self.storeUserInformation()
        }
    }
    
    private func storeUserInformation() {
        guard let uid = Auth.auth().currentUser?.uid else { return }
        let userData = ["fname": self.fname, "lname": self.lname, "email": self.email, "profileImageUrl": "profileurl", "uid": uid]
        Firestore.firestore().collection("users")
            .document(uid).setData(userData) { err in
                if let err = err {
                    print(err)
                    self.StatusMessage = "\(err)"
                    return
                }
 
                print("Success")
            }
    }
}

struct LoginRegister_Previews: PreviewProvider {
    @State static var isUserCurrentlyLoggedOut = false
    static var previews: some View {
        LoginRegister(isUserCurrentlyLoggedOut: $isUserCurrentlyLoggedOut)
    }
}
Home.swift
 
//
//  Home.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI
import SDWebImageSwiftUI
import Firebase

struct Home: View {
    @State var shouldShowLogOutOptions = false
    
    @ObservedObject private var vm = MainMessagesViewModel()
    
    @Binding var isUserCurrentlyLoggedOut : Bool
    
    @State var index = 0
    
    var body: some View {
            
        VStack {
            //Text("User: \(vm.chatUser?.uid ?? "")")
            customNavBar

            ZStack {
                if self.index == 0 {
                    VStack {
                        Image("home")
                            .resizable()
                    }
                }
                else if self.index == 1 {
                    VStack {
                        Image("profile")
                            .resizable()
                    }
                }
                else if self.index == 2 {
                    Color.red.edgesIgnoringSafeArea(.top)
                    VStack {
                        Text("Notification").foregroundColor(Color.white)
                        Image(systemName: "bell.fill")
                            .resizable()
                            .frame(width: 200, height: 200)
                    }
                }
                else{
                    Color.yellow.edgesIgnoringSafeArea(.top)
                    VStack {
                        Text("Cart").foregroundColor(Color.white)
                        Image(systemName: "cart.fill")
                            .resizable()
                            .frame(width: 200, height: 200)
                    }
                }
            }
                 
            CustomTabBar(index: $index)
        }
        .navigationBarHidden(true)
        .animation(.spring())
    }
    
    private var customNavBar: some View {
        HStack(spacing: 16) {

            WebImage(url: URL(string: vm.chatUser?.profileImageUrl ?? ""))
                .resizable()
                .scaledToFill()
                .frame(width: 50, height: 50)
                .clipped()
                .cornerRadius(50)
                .overlay(RoundedRectangle(cornerRadius: 44)
                            .stroke(Color(.label), lineWidth: 1)
                )
                .shadow(radius: 5)
            
            VStack(alignment: .leading, spacing: 4) {
                let email = vm.chatUser?.email.replacingOccurrences(of: "@gmail.com", with: "") ?? ""
                Text(email)
                    .font(.system(size: 24, weight: .bold))
                
                HStack {
                    Circle()
                        .foregroundColor(.green)
                        .frame(width: 14, height: 14)
                    Text("online")
                        .font(.system(size: 12))
                        .foregroundColor(Color(.lightGray))
                }
                
            }
            
            Spacer()
            Button {
                shouldShowLogOutOptions.toggle()
            } label: {
                Image(systemName: "gear")
                    .font(.system(size: 24, weight: .bold))
                    .foregroundColor(Color(.label))
            }
        }
        .padding()
        .actionSheet(isPresented: $shouldShowLogOutOptions) {
            .init(title: Text("Settings"), message: Text("What do you want to do?"), buttons: [
                .destructive(Text("Sign Out"), action: {
                    print("handle sign out")
                    try? Auth.auth().signOut()
                    self.isUserCurrentlyLoggedOut = false
                }),
                    .cancel()
            ])
        }
    }
}

struct Home_Previews: PreviewProvider {
    @State static var isUserCurrentlyLoggedOut = false
    static var previews: some View {
        Home(isUserCurrentlyLoggedOut: $isUserCurrentlyLoggedOut)
    }
}
MainMessagesViewModel.swift
 
//
//  MainMessagesViewModel.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI
import SDWebImageSwiftUI
import Firebase

struct ChatUser {
    let uid, email, profileImageUrl: String
}

class MainMessagesViewModel: ObservableObject {
    
    @Published var errorMessage = ""
    @Published var chatUser: ChatUser?
    
    init() {
        
        fetchCurrentUser()
    }
    
    private func fetchCurrentUser() {

        guard let uid = Auth.auth().currentUser?.uid else {
            self.errorMessage = "Could not find firebase uid"
            return
        }
        
        
        Firestore.firestore().collection("users").document(uid).getDocument { snapshot, error in
            if let error = error {
                self.errorMessage = "Failed to fetch current user: \(error)"
                print("Failed to fetch current user:", error)
                return
            }
            
            self.errorMessage = "123"
            
            guard let data = snapshot?.data() else {
                self.errorMessage = "No data found"
                return
                
            }
            self.errorMessage = "Data: \(data.description)"
            let uid = data["uid"] as? String ?? ""
            let email = data["email"] as? String ?? ""
            let profileImageUrl = data["profileImageUrl"] as? String ?? ""
            
            self.chatUser = ChatUser(uid: uid, email: email, profileImageUrl: profileImageUrl)
            
            //self.errorMessage = chatUser.profileImageUrl
            
        }
    }
}
CustomTabBar.swift
 
//
//  CustomTabBar.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//

import SwiftUI
 
struct CustomTabBar : View {
     
    @Binding var index : Int
     
    var body: some View {
         
        HStack(spacing: 15) {
             
            HStack {
                Image(systemName: "house.fill")
                    .resizable()
                    .frame(width: 35, height: 30)
                 
                Text(self.index == 0 ? "Home" : "")
                    .fontWeight(.light)
                    .font(.system(size:14))
            }.padding(15)
            .background(self.index == 0 ? Color.green.opacity(0.5) : Color.clear)
            .clipShape(Capsule())
            .onTapGesture {
                self.index = 0
            }
             
            HStack {
                Image(systemName: "person.fill")
                    .resizable()
                    .frame(width: 35, height: 30)
                 
                Text(self.index == 1 ? "Profile" : "")
                    .fontWeight(.light)
                    .font(.system(size:14))
            }.padding(15)
            .background(self.index == 1 ? Color.blue.opacity(0.5) : Color.clear)
            .clipShape(Capsule())
            .onTapGesture {
                self.index = 1
            }
             
            HStack {
                Image(systemName: "bell.fill")
                    .resizable()
                    .frame(width: 35, height: 30)
                 
                Text(self.index == 2 ? "Notification" : "")
                    .fontWeight(.light)
                    .font(.system(size:14))
            }.padding(15)
            .background(self.index == 2 ? Color.red.opacity(0.5) : Color.clear)
            .clipShape(Capsule())
            .onTapGesture {
                self.index = 2
            }
             
            HStack {
                Image(systemName: "cart.fill")
                    .resizable()
                    .frame(width: 35, height: 30)
                 
                Text(self.index == 3 ? "Cart" : "")
                    .fontWeight(.light)
                    .font(.system(size:14))
            }.padding(15)
            .background(self.index == 3 ? Color.yellow.opacity(0.5) : Color.clear)
            .clipShape(Capsule())
            .onTapGesture {
                self.index = 3
            }
             
        }.padding(.top, 8)
        .frame(width: UIScreen.main.bounds.width)
        .background(Color.white)
        .animation(.default)
    }
}

struct CustomTabBar_Previews: PreviewProvider {
    @State static var index = 0
    static var previews: some View {
        CustomTabBar(index: $index)
    }
}
DevSwiftUIApp.swift
 
//
//  DevSwiftUIApp.swift
//  DevSwiftUI
//
//  Created by Cairocoders
//
 
import SwiftUI
import Firebase
 
@main
struct DevSwiftUIApp: App {
     
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
      
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
  
class AppDelegate: NSObject,UIApplicationDelegate{
      
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
          
        FirebaseApp.configure()
        return true
    }
}

Related Post