Flutter: conditional bottom navigation bar, to show pages based on if condition - flutter

I have implemented a bottom navigation bar with the logic listed below, and I want to check if the user is logged in. If user is logged in on third tab I want to show the profile page instead of SignIn page. This is my code where I am displaying the bottom navigation bar, I am stuck on what to do after checkIsLoggedIn() async function.
After that Im building list of widgets to show the pages in 3 tabs.
code of which is below,
so in place of SignIn(), I need to show, if the user is logged in it shows signin other wise, it shows Profile page.
Please do help me out here.

This may help.
Future<void> checkIfLoggedIn() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var id = localStorage.getString('id');
if (id != null) {
setState(() {
_children[2] = ProfilePage();
});
}
}

Inside checkIfLoggedIn(), along with _isLoggedIn write the following code: _children[2] = Profile().

You can set the last BottomNavigationItem as below
BottomNavigationItem(
icon:_isLoggedIn ? Icons.person : Icons.key,
title:Text(_isLoggedIn ? 'Account' : 'Log in' )
)
and you can handle the click event and set the proper page in the build() by the same ternary operators using the _isLoggedIn variable
build(){
return Scaffold(
body:_isLoggedIn?ProfilePage():LoginPage()
);
}

Related

Flutter dispose provider notifyListners()

I have a simple controller like this
class MatchListController with ChangeNotifier {
List<MatchData> liveMatches = [];
MatchListController() {
getMatchList();
}
getMatchList() async {
debugPrint('match list api called');
var response = await ApiService().matchList();
if (response != null) {
final databody = json.decode(response);
notifyListeners();
}
}
}
When my page loads it runs the function getMatchList() which is fine but If I change the page between function and when it return data notifyListeners hit and app crash. I am using loading but I have tab menu so I can change the page from there What I want is if page is close then notifyListeners dispose.
The answer that khalil mentioned is correct, there is also another solution:
Since you are using loading, I assume you want to prevent the page from changing, so you can wrap the tab menu buttons with an AbsorbPointer widget, and use setState to change its absorbing state according to your loading state. Your loading state can simply be a boolean inside your stateful widget.

How can I change or override android/ios back button's action in flutter

I need to make a change in my page (changing a bool in setState etc...) when the user presses the back button.
I looked it up and I know people use WillPopScope to override the default "back" action, but in all of the examples they were just popping the page, and I need to do a custom function instead of that, and have no Idea how to do so.
my function looks like this, and I need to run in when the user pressed the back button:
Future<void> backToCats() async{
setState(() {
isLoaded=false;
});
if(isFromSearch){
loadCategories();
}
setState(() {
showingBrands=false;
isLoaded=true;
});
}
You can perform custom logic in the onWillPop argument of a WillPopScope widget. Just make sure to return true or false at the end to indicate whether the page is allowed to pop. WillPopScope will activate for the back button, and other actions that automatically navigate back such as swiping from the side of the screen on iOS.
For example, if you need to set a bool to false in your stateful widget, it would look something like this
WillPopScope(
onWillPop: () async {
setState(() => myBool = false);
return true;
}
child: ...
);

Flutter - re-run previous page code after execution returns to it

I'm trying to figure out the best way to implement the proper navigation flow of a flutter app I'm building that involves a 3rd party authentication page (Azure AD B2C). Currently I have a page that serves simply as a "navigate to 3rd party auth login" page which is set as the initialRoute for my app. The first time through, it runs exactly the way I want it to, but I'm not able to figure out how to get that 'navigate to auth' page to re-run when navigated back to (after logout) so that the user ends up back at the 3rd party auth login page.
Basically what I'd like to do is, on logout - have the app navigate back to that page specified as the initialRoute page, and upon that page being navigated back to, have it re-launch the 3rd party auth login page just like it did the first time it executed.
I tried just awaiting the call to Navigator.push() and then calling setState((){}) afterwards, and that does re-display the page, but it just leaves that initial page sitting there, and doesn't end up triggering the execution the way it did the first time. initState() does not fire again, so neither does any of my code that's in there.
I've tried various methods off the Navigator object trying to reload the page or navigate to itself again, or just calling goToLogin() again after the await Navigator.push() call, nothing works.
Here's what I'm currently doing :
User launches the app, the initialRoute is LoginRedirect
class LoginRedirect extends StatefulWidget {
#override
_LoginRedirectState createState() => _LoginRedirectState();
}
class _LoginRedirectState extends State<LoginRedirect> {
#override
void initState() {
Utility.getConfig().then((value) {
config = value;
oauth = AadOAuth(config);
goToLogin(context);
});
super.initState();
}
void goToLogin(BuildContext context) async {
setState(() {
loading = true;
});
try {
await oauth.login(); // this launches the 3rd party auth screen which returns here after user signs in
String accessToken = await oauth.getAccessToken();
navigateToDashboard();
setState(() {
loading = false;
});
} on Exception catch (error) {
setState(() {
loading = false;
});
}
}
void navigateToDashboard() {
await navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => Dashboard()));
// right here is where I'd like to call goToLogin() again after I Navigator.popUntil() back to this
// page, but if I try that I get an error page about how 'The specified child already
// has a parent. You must call removeView() on the child's parent first., java.lang
// .IllegalStateException and something about the bottom overflowed by 1063 pixels
}
}
After getting some config values and calling oauth.login() then I call a navigateToDashboard() method that pushes the Dashboard page on to the navigation stack.
Elsewhere in the code I have a logout button that ends up calling this code:
oauth.logout();
Navigator.popUntil(context, ModalRoute.withName('/LoginRedirect'));
which returns execution to where I called await Navigator.push() previously. But I can't figure out what I need to do there to have that LoginRedirect page execute again. I can't call goToLogin() again or it errors/crashes. I can't call initState() again, calling setState() doesn't do anything. I'm kinda stumped here, I thought this would be easy.
When logging out try: Navigator.pushReplacementNamed(context, "/LoginRedirect"); instead of Navigator.popUntil(context, ModalRoute.withName('/LoginRedirect'));

pop a specific route with result in auto route flutter

I'm using auto_route as my app's navigation system. I need to do something like the finish() function in android activity which closes the current activity that it's being called from. How can I achieve this in flutter?
As shown here:
In your router config specify which data type is returned.
e.g.: (here a Set is returned)
AutoRoute<Set<User>>(
page: UserSelectPage,
),
In your Page, you have to pop the values:
onPressed: () async {
await AutoRouter.of(context).pop(yourValues);
},
Then in your code you can call this to push the page and work with the return value.
onPressed: () async {
final Set<User>? users = await AutoRouter.of(context)
.push<Set<User>>(UserSelectPageRoute());
if (users != null) {
await doOtherStuffWithYourNewData(users);
}
}

Conditional bottom navigation bar

I have bottom navigation bar which consist of 5 icon which will redirect to 5 screen correspondingly.
The fifth icon is Account screen so when no session it must redirect to Login screen and then load the Account screen. But after login when user tap the Account icon just redirect to Account screen.
How to achieve this? How can I use if condition to determine which layout to load? Error says missing identifier expexted ')'
You can easily achieve this with by passing an async function for the onPressed of Account icon. Your async function would look something like.
Example:
//On Home Page, for account icon pressed
Future<void> checkCredsAndNavigate(){
bool loggedIn = _checkIfLoggedIn(); // this might be a function that gets status of user login, you can fetch from prefs, state, etc.
if(!loggedIn){
var data = await Navigator.of(context).pushNamed('YOUR_LOGIN_ROUTE_NAME');
if(data == null){ // Check for data, will be null when user cancels login
return;
}
}
Navigator.of(context).pushNamed('YOUR_ACCOUNT_ROUTE_NAME');
}
//On Login page,
// On successful login call
Navigator.of(context).pop(data); // this data can be anything like user id, or just a boolean indicating successful login,etc.
//To cancel login, call
Navigator.of(context).pop();
Hope this helps!