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 } }