16

I understand there is PresentationButton and NavigationButton in order to change views in the latest SwiftUI. However I want to do a simple operation like below. When user clicks on SignIn button if credentials are correct it will sign them in but also do a segue (in this case change the view). However I could not check if they are correct in PresentationButton and I could not change the view in a normal button.

Is there another way to do that?

  @IBAction func signInClicked(_ sender: Any) {
        
        if emailText.text != "" && passwordText.text != "" {
            
            Auth.auth().signIn(withEmail: emailText.text!, password: passwordText.text!) { (userdata, error) in
                if error != nil {
                   //error
                } else {
                   performSegue(withIdentifier: "toFeedActivity", sender: nil)
                }
            }
        } else {
            //error
        }
    }
Kaushik Makwana
  • 142
  • 1
  • 14
Atils
  • 171
  • 1
  • 2
  • 4
  • I take it that you already know you are posting `UIKit` code, not `SwiftUI` code. That said, could you post you `SwiftUI` code? Also, have you actually tried searching this site? a very quick search on *"[SwiftUI] login" returns an accepted answer to what sounds like your *exact* issue from two days ago. Could you try it and be more specific if it doesn't answer your issue? –  Jun 27 '19 at 21:24

4 Answers4

36

Here's one way.

struct AppContentView: View {
    
    @State var signInSuccess = false
    
    var body: some View {
        return Group {
            if signInSuccess {
                AppHome()
            }
            else {
                LoginFormView(signInSuccess: $signInSuccess)
            }
        }
    }
}

struct LoginFormView : View {
    
    @State private var userName: String = ""
    @State private var password: String = ""
    
    @State private var showError = false
    
    @Binding var signInSuccess: Bool
    
    var body: some View {
        VStack {
            HStack {
                Text("User name")
                TextField("type here", text: $userName)
            }.padding()
            
            HStack {
                Text(" Password")
                TextField("type here", text: $password)
                    .textContentType(.password)
            }.padding()
            
            Button(action: {
                // Your auth logic
                if(self.userName == self.password) {
                    self.signInSuccess = true
                }
                else {
                    self.showError = true
                }
                
            }) {
                Text("Sign in")
            }
            
            if showError {
                Text("Incorrect username/password").foregroundColor(Color.red)
            }
        }
    }
}

struct AppHome: View {
    
    var body: some View {
        VStack {
        Text("Hello freaky world!")
        Text("You are signed in.")
        }
    }
}

RanLearns
  • 4,086
  • 5
  • 44
  • 81
SMP
  • 1,629
  • 7
  • 15
7

I had the same need in one of my app and I've found a solution...

Basically you need to insert your main view in a NavigationView, then add an invisible NavigationLink in you view, create a @state var that controls when you want to push the view and change it's value on your login callback...

That's the code:

struct ContentView: View {
    @State var showView = false
    var body: some View {
        NavigationView {
            VStack {
                Button(action: {
                    print("*** Login in progress... ***")
                    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                        self.showView = true
                    }
                }) {
                    Text("Push me and go on")
                }

                //MARK: - NAVIGATION LINKS
                NavigationLink(destination: PushedView(), isActive: $showView) {
                    EmptyView()
                }
            }
        }
    }
}


struct PushedView: View {
    var body: some View {
        Text("This is your pushed view...")
            .font(.largeTitle)
            .fontWeight(.heavy)
    }
}
DungeonDev
  • 1,176
  • 1
  • 12
  • 16
  • huge help, thank you. NavigationView and links (or lack thereof) were my issue. Had the authentication piece working prior but couldnt get the page/UI to change on successful auth. – Nubtacular Oct 16 '20 at 21:13
2

Try with state & .sheet

struct ContentView: View {
    @State var showingDetail = false

    var body: some View {
        Button(action: {
            self.showingDetail.toggle()
        }) {
            Text("Show Detail")
        }.sheet(isPresented: $showingDetail) {
            DetailView()
        }
    }
}
  • 2
    Here are some guidelines for [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). This provided answer may be correct, but it could benefit from an explanation. Code only answers are not considered "good" answers. From [review](https://stackoverflow.com/review). – Trenton McKinney Sep 27 '19 at 07:18
  • 1
    This is not what the OP wants to achieve. This will make a Modal and not a "segue" as intended in UIKit – Mattia Righetti Oct 08 '19 at 22:39
-2

You can use navigation link with tags so,

Here is the code:

first of all, declare tag var

@State var tag : Int? = nil

then create your button view:

Button("Log In", action: {
                        Auth.auth().signIn(withEmail: self.email, password: self.password, completion: { (user, error) in
                            if error == nil {
                                self.tag = 1
                                print("success")
                            }else{
                                print(error!.localizedDescription)
                            }
                        })

So when log in success tag will become 1 and when tag will become 1 your navigation link will get executed

Navigation Link code:

NavigationLink(destination: HomeView(), tag: 1, selection: $tag) {
                EmptyView()
                }.disabled(true)

if you are using Form use .disabled because here the empty view will be visible on form and you don't want your user to click on it and go to the homeView.