# Login / Logout Flow: SwiftUI and EnvironmentObject

EnvironmentObject is useful when you want to create a dependency in a higher component of the layout tree and use it on a lower component without having to pass it down the tree through every child component.

We will now use EnvironmentObject to monitor when a user logs in and out.

1. When the user is successfully logged in (isLoggedIn = true), they are directed to the rest of the application views.
1. When a user is logged out (isLoggedIn = false) at any point within the app, they are directed to the login page.


![Login Logout Flow: SwiftUI](https://cdn.hashnode.com/res/hashnode/image/upload/v1636360017555/VIb0LbEjr.png)

We need the following components:

1. User State View Model
1. Application Switcher
1. Login Screen
1. Home Screen (Our Application Views)

### User State View Model
The user state view model tracks and broadcasts the user status. We store this view model in an EnvironmentObject.

```swift
import Foundation

enum UserStateError: Error{
    case signInError, signOutError
}

@MainActor
class UserStateViewModel: ObservableObject {
    
    @Published var isLoggedIn = false
    @Published var isBusy = false
    
    func signIn(email: String, password: String) async -> Result<Bool, UserStateError>  {
        isBusy = true
        do{
            try await Task.sleep(nanoseconds:  1_000_000_000)
            isLoggedIn = true
            isBusy = false
            return .success(true)
        }catch{
            isBusy = false
            return .failure(.signInError)
        }
    }
    
    func signOut() async -> Result<Bool, UserStateError>  {
        isBusy = true
        do{
            try await Task.sleep(nanoseconds: 1_000_000_000)
            isLoggedIn = false
            isBusy = false
            return .success(true)
        }catch{
            isBusy = false
            return .failure(.signOutError)
        }
    }
}
```
We make our view model instance available to all child views, starting from the ApplicationSwitcher view

### Application Switcher

```swift
import SwiftUI

@main
struct LoginFlowApp: App {
    
    @StateObject var userStateViewModel = UserStateViewModel()
    
    var body: some Scene {
        WindowGroup {
            NavigationView{
                ApplicationSwitcher()
            }
            .navigationViewStyle(.stack)
            .environmentObject(userStateViewModel)
        }
    }
}

struct ApplicationSwitcher: View {
    
    @EnvironmentObject var vm: UserStateViewModel
    
    var body: some View {
        if (vm.isLoggedIn) {
                HomeScreen()
        } else {
            LoginScreen()
        }
        
    }
}
```

### Login Screen

The Login screen uses the UserStateViewModel to invoke signIn

```swift
import SwiftUI

struct LoginScreen: View {
    
    @EnvironmentObject var vm: UserStateViewModel
    @State var email = ""
    @State var password = ""
    
    fileprivate func EmailInput() -> some View {
        TextField("Email", text: $email)
            .keyboardType(.emailAddress)
            .disableAutocorrection(true)
            .autocapitalization(.none)
            .textFieldStyle(.roundedBorder)
    }
    
    fileprivate func PasswordInput() -> some View {
        SecureField("Password", text: $password)
            .textFieldStyle(.roundedBorder)
    }
    
    fileprivate func LoginButton() -> some View {
        Button(action: {
            Task {
                await vm.signIn(
                    email: email,
                    password:password
                )
            }
        }) {
            Text("Sign In")
        }
    }
    
    var body: some View {
        
        VStack{
            if(vm.isBusy){
                ProgressView()
            }else{
                Text("Login Screen").font(.title)
                EmailInput()
                PasswordInput()
                LoginButton()
            }
        }.padding()
        
    }
}
```
### Home Screen with Logout Button

The Home screen uses the UserStateViewModel to invoke signOut

```swift
import SwiftUI

struct HomeScreen: View {
    
    @EnvironmentObject var vm: UserStateViewModel
    
    var body: some View {
        
        if(vm.isBusy){
            ProgressView()
        }else{
            Text("Home Screen")
                .navigationTitle("Home")
                .toolbar {
                   
                        Button {
                            Task{
                                await vm.signOut()
                            }
                        } label: {
                            Image(systemName:  "rectangle.portrait.and.arrow.right")
                        }
             
                    
                }
        }
    }
}
```


![1_FjHwFObdKFT5PNCqd_zW3A.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636360203295/xU0_gTE5X.gif)

