Root Controller UINavigationBar disappears after user logout with Firebase - ios

I'm facing a slight problem with my UINavigationBar.
I have a an Initial Root View Controller (ViewController) followed by 2 View Controllers (LoginMRNViewController and LoginOTPViewController) that are used to login the user with One Time Password. I also have NavigationController used to navigate the user to his/her homepage after logging in.
In the homepage, I have a (Logout) button, that logs out the user with Firebase and navigates him/her to the Initial Root View Controller (ViewController).
The UINavigationBar works like a charm, however, whenever the user logout, he is navigated to the Initial Root View Controller (ViewController) but the UINavigationBar completely disappears!
My logout function:
#IBAction func logoutPressed(_ sender: Any) {
do {
try Auth.auth().signOut()
self.performSegue(withIdentifier: "goToLoginScreen", sender: self)
print ("User logged out")
} catch let error {
print ("Failed to logout with error", error)
}
}
Here's how my Storyboard looks like.
EDIT:
I tried to put this in my Initial Root View Controller (ViewController) and the other 2 View Controllers (LoginMRNViewController and LoginOTPViewController) in the ViewWillAppear method, but unfortunately it did not work.
self.navigationController?.setNavigationBarHidden(false, animated: false)
tabBarController?.tabBar.isHidden = false
Here's how my updated Storyboard look like.

Don't add the another NavigationController to hide back button.
Add navigationItem.setHidesBackButton(true, animated: true) to hide back button.
Then on logout simply add self.navigationController?.popToRootViewController(animated: true)
It should work as expected.

Related

Xcode all segues show up the same

I'm having some trouble going from my login VC which is a collectionVC to my main vc which is a navigation controller. No matter what type of segue I choose, i get this gap at the top where you can see the previous login VC, with the possibility to drag from the top of the current navigationVC to dismiss it. I've tried using all the different segues but they all show up like this for some reason. My loginVC has a login button, and changes to the navigation VC with the following code:
// Login user
func loginUser() {
Auth.auth().signIn(withEmail: emailTxtFld.text!, password: PasswrdTxtFld.text!) { (user, error) in
if error != nil {
print(error!)
} else {
print("Login succesfull!")
self.performSegue(withIdentifier: "goToMain", sender: self)
}
}
}
#IBAction func loginBtnTapped(_ sender: Any) {
loginUser()
}
I've connected the loginVC to the main VC with a segue, not the login button itself. The first slide of the navigation VC is a collectionview, the second is blank.
This is not a problem of segue, it is a problem with the ModalPresentationStyle of the presented view controller that, from iOS 13, defaults to automatic.
This means that (most of the) view controllers will be presented in this fashion.
You just need to set this modal presentation style to fullscreen in one of this points:
when you instantiate the view controller
when you prepare for segue
or in the viewDidLoad of the viewController itself
in storyboard segue https://stackoverflow.com/a/56530134/8517882
in storyboard view controller https://stackoverflow.com/a/57546875/8517882
Thank you Enricoza for explaining this to me. Since I made a segue using the storyboard I was able to make the segue full screen by following the seccond answer in this post: Presenting modal in iOS 13 fullscreen

How to pop previous view controller from current view controller?

I have a dashboard, then a login screen and profile screen. Once I reach profile screen I want login screen to be removed so that when I press back button, I am taken to dashboard instead of login. All these are view controllers of a navigation view controller and I display tge using present method.
I have a senario where login can appear anywhere during using navigation. Example: Dashboard, Screen 2, Screen 3, Login, Profile. Here, I have to remove login and when user taps back from profile, it should display Screen 3.
If you are logged-in already and you have to move to top viewController you can do
window.rootViewController.dismiss(animated: true, completion: nil)
But If you are using navigationController then this will work:
navigationController.popToRootViewController(animated: true)
Implement the following in your login view controller:
override func viewWillDisappear(_ animated: Bool) {
var navigationArray = navigationController?.viewControllers
let count = navigationArray?.count
navigationArray?.remove(at: count! - 2)
navigationController?.viewControllers = navigationArray!
}
This removes the current view controller(the login VC in your case) from the navigation stack just when it is about to disappear. So when you tap the back button from the next VC it will always take you to the VC preceding the login.
This is generic answer, not for the answer of this question only.
When popping, you may kick out the viewControllers from your navigation Controller, would solve your problem
extension UINavigationController {
public func removeViewController(classes : [String]) {
var vcs = [UIViewControllers]()
for viewController in self.viewControllers {
let name = viewController.className
if !classes.contains(name) {
vcs.append(viewController)
}
}
if classes.count < vcs.count {
self.viewControllers = vcs
}
}
}
now think you have 3 viewControllers , dashboard, login, profile. you want to remove login and Move Back from profile to dashboard
In profile's View Controller
override func viewDidLoad() {
super.viewDidLoad()
//your works
let viewControllersToRemove = [String(describing: type(of:login))]
navigationController.removeViewController(classes : viewControllersToRemove)
}

Back Button with Multiple Sources

Within my app, I want to create a user profile controller, which can be navigated to from several different controllers. I would like it to have a back button that will take the user back to whichever controller they came from.
How do I do this?
Dismiss
Add UIButton for back navigation somewhere to your UserProfileController. Then in UserProfileController create action and set it as action of your button. This action dismisses your UserProfileController (so you get back to previous UIViewController)
#IBAction func backButtonPressed(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
UINavigationController
Alternatively you can have previous ViewControllers embed in UINavigationController. Then you will be able to tap to back button (which is set by default) in UINavigationBar which gets you to previous UIViewController

How to maintain correct order of Login page and Home page with firebase login in ios?

This may sound very basic. But I couldn't find a way out.
I'm using firebase authentication if this is necessary to know beforehand.
The initial view controller is set as LoginViewController. I've two buttons here: Signup & Login. The Signup button presents another view controller modally where user can opt for signing up. After successful sign-up, the SignUpViewController is dismissed, so the LoginViewController appears. Inside the LoginViewController's viewDidAppear(_:) I check for current user and if available redirect user to HomeViewController:
class LoginViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let _ = Auth.auth().currentUser {
// This is a modal segue
performSegue(withIdentifier: "SegueToHomeViewController", sender: self)
}
}
}
When tapping Logout button in HomeViewController, the controller is just dismissed with signing out user.
class HomeViewController: UIViewController {
#IBAction func logoutButtonDidTouch(_ sender: UIBarButtonItem) {
do {
try Auth.auth().signOut()
// This dismiss lands user to the LoginViewController again
// So user has chance to login again with `Login` button this time
dismiss(animated: true, completion: nil)
} catch {
print(error)
}
}
}
Everything is working fine so far. But there is a subtle misbehavior. Because every time the app is launched the LoginViewController appears and then redirect to HomeViewController which isn't so good as user experience.
So, what I want is if the user is logged-in already the first view s/he will see is HomeViewController other than LoginViewController. But if user didn't log in before, s/he will be landed on the LoginViewController.
Yes, I could check from the AppDelegate's application(_:didFinishLaunchingWithOptionss:) for current user and if found, navigate directly to HomeViewController. But then I would lose the LoginViewController when user taps on Logout in HomeViewController.
At a glance this is pretty much what I need to accomplish:
Anything even without the code example is appreciated.
try to check in loadView() function , or you can create an entry view controller with background image like splash screen , make it your initial view and set your check func in viewWillAppear of it's class
I had a similar dilemma, and solved it by adding a 'Splash' ViewController as the entry controller for the App. I have styled it identical to the LaunchScreen.storyboard. In the SplashVC I check for a valid User Token and if present it will send direct to the main app (in my case this is a TabBarController). In my TabBarController I set a Firebase addStateDidChangeListener which will direct back to the LoginVC if the User Token ever becomes invalid.
I also use the Splash VC to run async code to check subscription status, and write login details to Firebase.
Please excuse the quick and dirty schematic.
There is no lose when you logout you can easily show any VC anyTime without a segue , jsut give every viewController an identifier and set it to UIApplication.shared.keyWindow?.rootViewController
let loginView = self.storyboard?.instantiateViewController(withIdentifier: "loginView") as! loginVC
let nav = UINavigationController(rootViewController: loginView)
nav.navigationBar.isHidden = true
UIApplication.shared.keyWindow?.rootViewController = nav

Change view upon google sign in ios

I've added Google sign in to my app which is working but I can't seem to get my view to change upon a successful sign in programmatically.
This is my demo story board. The grey box being the sign in button, I've added a button "move page manually" with a segue from the login screen to the tab bar controller screen. Clicking this works as expected, I need the same to happen automatically when the app detects the user is signed in.
When the user opens the app the first screen is a view controller "login screen" if the user is logged in checked by the below code I want to forward them to the home screen (first tab). Please let me know if there's a better/faster way of doing this instead if possible.
Loginscreen :
override func viewDidLoad() {
super.viewDidLoad()
// Google sign in
GIDSignIn.sharedInstance().uiDelegate = self
// Check if they're already signed in
GIDSignIn.sharedInstance().signInSilently()
// check if the user is signed in
if (GIDSignIn.sharedInstance().hasAuthInKeychain()){
print("signed in")
// Forward the user here straight away...
} else {
print ("not signed in")
// Need to handle the forwarding once they sign in.
}
}
You can either add a Segue from your login screen to whichever ViewController you want and write your code like so:
if (GIDSignIn.sharedInstance().hasAuthInKeychain()){
print("signed in")
performSegueWithIdentifier("your_segue_name", sender: self)
// Forward the user here straight away...
}
Or you can present the ViewController modally by:
if (GIDSignIn.sharedInstance().hasAuthInKeychain()){
let storyboard = UIStoryboard(name: "Yourstoryboardname(Example: Main)", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("yourviewcontrollertobepresented") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
You need to NAME your viewcontroller which you want to be present. To do that, you click on your ViewController in storyboard and in the Identity inspector you'll find Storyboard ID. Name it what you want and give the same name in instantiateViewControllerWithIdentifier("yourviewcontrollertobepresented")

Resources