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