I'm using Firebase and SwiftUI to log in as a user. I have everything working but can't figure out how to navigate to the next page once the user is successfully logged in. NavigationLinks seem weird to me so I'm wondering if there's any other way to navigate to the next view. The LoginView contains the login screen and the LoginViewModel does the sign-in procedure with Firebase. The issue is that if I return views based on a variable in the root view, it doesn't change the view once any view other than the root view is opened (i.e if I navigate to the Login view, it won't go to the main view after the login button is pressed).
ContentView (The root view displaying all the other views):
import SwiftUI
struct ContentView: View {
@StateObject var userLoggedIn = LoginViewModel()
var body: some View {
if !userLoggedIn.isLoggedIn {
LoginView()
}
else {
MainView()
}
}
}
LoginView:
import SwiftUI
import FirebaseAuth
struct LoginView: View {
@State private var email: String = ""
@State private var password: String = ""
@State private var isEditing = false
@State private var showPassword = false
@State private var radius = 300
private var canLogIn: Bool {
return !email.isEmpty && !password.isEmpty
}
let loginView = LoginViewModel()
@ViewBuilder
var body: some View {
return NavigationView(content: {
VStack {
Spacer()
.frame(height: 150)
Text("PET SUPPORT").foregroundColor(Color.petSupportText)
.font(Font.custom("Permanent Marker", size: 36))
.padding()
Group {
HStack {
Text("EMAIL")
.font(Font.custom("Permanent Marker", size: 18))
.padding(.top, 10)
Spacer()
}
TextField("Email", text: $email) {
isEditing in self.isEditing = isEditing
}
.autocapitalization(.none)
.keyboardType(.emailAddress)
.disableAutocorrection(true)
.padding(.top, 20)
Divider()
.foregroundColor(.black)
}
Group {
HStack {
Text("PASSWORD")
.font(Font.custom("Permanent Marker", size: 18))
.padding(.top, 10)
Spacer()
}
ZStack {
if showPassword {
TextField("Password", text: $password)
}
else {
SecureField("Password", text: $password)
}
}
.frame(height: 20)
.autocapitalization(.none)
.overlay(Image(systemName: showPassword ? "eye.slash" : "eye").onTapGesture { showPassword.toggle() }, alignment: .trailing)
.disableAutocorrection(true)
.padding(.top, 20)
Divider()
.foregroundColor(.black)
}
Spacer();
Group {
Button(action: {
loginView.login(email: email, password: password)
radius = 2000
MainView()
}, label: {
Text("Login")
})
.foregroundColor(.white)
.font(Font.custom("Permanent Marker", size: 18.0))
.padding(.horizontal, 20)
.padding()
.background(Color.petSupportBlue)
.cornerRadius(70.0)
.disabled(!canLogIn)
}
Spacer()
}
.padding(.horizontal, 30)
.ignoresSafeArea()
})
}
}
LoginViewModel:
import Foundation
import Firebase
class LoginViewModel: ObservableObject {
@Published var isLoggedIn = false
func login(email: String, password: String) {
Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
if let error = error {
print(error.localizedDescription)
} else {
print("Logged In!")
self.isLoggedIn = true
}
}
}
}
MainView:
import SwiftUI
struct MainView: View {
var body: some View {
Text("Hello, World!")
}
}
If you don't want to deal with NavigationLink, as @Paulw11 mentioned in the comments, you can conditionally display a logged in/logged out view based on a property you set on an ObservableObject. You can even add animations/transitions. See below for a simple example:
class LoginManager : ObservableObject {
@Published var isLoggedIn = false
func login() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation {
self.isLoggedIn = true
}
}
}
}
struct ContentView : View {
@StateObject var loginManager = LoginManager()
var body: some View {
if loginManager.isLoggedIn {
LoggedInView()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.transition(.move(edge: .leading))
} else {
LoginView(loginManager: loginManager)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.transition(.move(edge: .leading))
}
}
}
struct LoginView : View {
@ObservedObject var loginManager : LoginManager
var body: some View {
Button("Login") {
loginManager.login()
}
}
}
struct LoggedInView : View {
var body: some View {
Text("Logged in!")
}
}
I might also consider, if I were you, using at authStateListener and setting the logged in property based on that. That way, if the app is re-opened and the user is still logged in, they'll be transitioned to the logged-in page automatically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With