API data from provider seems to get lost during Navigation - flutter

I am a beginner level Flutter developer trying to resolve the issue with the Navigation stack.
In the existing app:
When user logs in to the app, login api call is shooted
Homescreen is rendered with Navigator.popUntill method
All the APIs in the providers get shooted and the respective tabs/screens get filled with api data.
Now, I want to include Onboarding screens before Homescreen, so I made below changes:
Navigator.push method used to include Onboarding screens.
After onboarding screens are over, user clicks on "To app" button
On click of "To app" button, the login call is made again
User is redirected to Homescreen with Navigator.popUntill method.
But now the data from providers is lost as the respective screens do not show any data. I am pretty sure that something is going wrong with the Navigation stack when I use Navigator.push method to add Onboarding screens but I do not have much expertise in Flutter to debug the issue. Need help with restoring the provider data when navigating to Onboarding screens.

I think that the cause isn't in a navigation stack. Probably you placed Provider widget lower than navigation (MaterialApp).
Try something like that or show your code for better understanding.
Provider(
create: (context) => ClassThatCallsAPI(),
child: MaterialApp(
// Navigator placed here and any route will
// get the same data from provider
// and also can put some

Related

How to prevent going back to previous page on Flutter Web via browser back button?

After a user successfully logged in in my Flutter web app, it should be taken to a dashboard view.
The user then should not be able to navigate back to the login screen by pressing the browser back button.
I tried a lot of things, replacing the route, popping the route and then pushing the next route, all did not work.
Also using WillPopScope in the dashboard page does not work. Pressing the browser back button does not fire onWillPop.
Found some similar questions, but they all end up suggesting WillPopScope or replacing the route, both did not work for me.
Any idea what I could do?
Seems like you can't intercept the browser back buttons.
I solved the problem by using a RouteGuard of the auto_route package which intercepts the navigation and checks if the user is authenticated or not. If the user is already authenticated, the navigation to the Signin page is canceled.
Check the auto_route package for examples and further explanation: https://pub.dev/packages/auto_route#route-guards
Wrap it inside a WillPopScope and return false
WillPopScope(
onWillPop: () async => Future.value(false),
child: DashboardView(),
),

How to determine if a Widget is Stateful or Stateless in Flutter?

I understand the basics here. If my data is going to change it should be stateful so I can update it otherwise stateless.
My question is more oriented in a bottomnavigation scenario. So, I have 3 tabs in my bottomnavigator (Profile, Home, Settings). The entry point is Home which is a stateful Widget.
The other two Widgets I want to basically populate the information in them with the api data.
The Problem
If I am in the Home screen and I click in the Profile icon in the bottomnavigator it does not load the information from the api. Even if it does, If I click in the Home screen and click again in the Profile screen to go back, the information does not refresh.
Solution
So what would be the way to handle this? I expect that if I click in each of the bottomnavigation items the information is refreshed with the api data. Is this because the Widgets are Stateful or Stateless or I am missing something else?
By default, the pages in Bottom Navigation bar refreshes/rebuild when they are are tapped on.
Make sure a few things in your app-
You are not using a "indexed stack" or any similar widget for these pages. These widgets preserves the state of your page
The navigation is taking place on its own. You have not defined any Navigator.Push etc for tap's in navigation bar.
You should call the API inside the initState method of that particular page. Like if you need profile details, call the api for profile information inside the initState method of Profile Tab and not the "Scaffold" page which has the navigation bar.

How to navigate to a specific Route at app start and show another one when popping in Flutter?

The question is, how to achieve this with a clean navigation approach in Flutter.
So to better understand the question, here's an example:
The user taps on a messenger notification and the app opens. The first screen to show is a setup screen, which verifies if the user authenticated and does some app related stuff. The next screen should be the chat with the corresponding message. After closing this chat screen, the user lands on the screen containing a list with all chats. After closing this one, the user lands on the home screen of the app.
What is the best and cleanest approach to handle such a scenario? Should I use a separate navigation package like auto_route or what do u suggest?
Or is this a deep link scenario? How to implement such a scenario?
Define static String id for all screen,after define them under MaterialApp as
routes (map<Sting, Function>) after you have to give parameter to initial route still under MaterialApp, now you can use these routes by using Navigator.pushNaned and Navigator.pop function.

Flutter navigation pop from which screen

Is there anyway to check route name of last screen after pop? When application start and land on home screen, there are several widgets like view profile, product carousel and so on.
Scenario: User navigate into product listing page, then detail page, click purchase and perform actions. After user purchased, shows purchased successful screen, call Navigator.of(context).popUntil(routeName) back to home screen.
What I want to achieve: After land in home screen, programmatically call api to refresh my balance. Route Observer able to detect navigation back to home screen with didPopNext() method. But this is called no matter it pop from which screen. Therefore the api will repeatedly called which is not ideal. How do I know it was pop from purchased successful screen instead of product listing screen?
Grateful on any helps and hints!
If you where using pop() then you have an option to return some data to previous route but since you are using popUntil() you won't be able to do this. So I think you should clear every route and push home route again from purchased successful page using either pushAndRemoveUntil() or pushNamedAndRemoveUntil(). That means you can now pass an argument to home screen by which you can decide whether to call the API or not.
Navigator.of(context).pushNamedAndRemoveUntil(
'/',
(Route<dynamic> route) => false,
arguments: []
);
Another option would be to figure out a way to return data using popUntil(), Something like this, maybe?

How to intercept Navigator.pop and block navigation back conditionally?

I'm looking for a way to intercept navigation back conditionally.
User/server can modify global state of the app like authentication, causing page to navigate to login form, but when user navigates to screen A then presses back button twice, user is still able to see widgets that are supposed to be available only for logged in session.
I've tried all I could thought of:
onGenerateRoute in MaterialApp but it's not triggered when back button is pressed
WillPop is a solution to that, but all top-level widgets would have to be wrapped in it and I need to remember to pass auth state to all the widgets, it's not really scalable solution, but could work
navigatorObservers is notified about Navigator.pop events seems not to be able to prevent navigation
Ideally, would like to avoid 3rd party dependencies with hooks on every widget like back_button_interceptor.
It should also work with statelesswidgets, where dispose() method is not available.
Is there any way to get something like single class/point of failure "navigator interceptor" which would return true/false and be able to modify route in flight based on a condition?
Looking into the implementation of WillPopScope, it makes use of the addScopedWillPopCallback() function of the ModalRoute.
https://api.flutter.dev/flutter/widgets/ModalRoute/addScopedWillPopCallback.html
If you implemented a router with onGenerateRoute it should be possible to add an universal check for every route you push. Maybe you could even make a customized Route class inherited from MaterialPageRoute that includes that logic.
If i understood your problem right,i feel like intercepting back navigation is the wrong approach. I would rather try to remove the unauthorized pages from the navigation stack when navigating back to the login screen with Navigator.pushNamedAndRemoveUntil()