Provider isn't notified when users sign up - flutter

Context
I am trying to build an app, using Flutter, which requires the users to sign up and/or sign in.
Using a provider, I was able to determine at each launch of the app if the user was already signed in or not, thus showing respectively the MainScreen or the SignInScreen, as you can see from the code below.
void main() {
runApp(Stuff());
}
class Stuff extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<FirebaseUser>.value(value: AuthService().onAuthChanged),
],
child: Consumer<FirebaseUser>(builder: (context, user, _) {
return MaterialApp(
title: 'Stuff',
home: user != null ? MainScreen() : SignInScreen(),
routes: {
'/main_screen' : (context) => MainScreen(),
'/signup_screen': (context) => SignUpScreen(),
'/signin_screen': (context) => SignInScreen(),
},
);
}),
);
}
}
where AuthService for now is just the following:
class AuthService{
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
#override
Stream<FirebaseUser> get onAuthChanged => _firebaseAuth.onAuthStateChanged;
}
If the user is not signed in, then theSignInScreen is shown, and after the sign in process the StreamProvider is notified correctly and the home property of the MaterialApp updates automatically showing the MainScreen.
Problem
When users get to the SignInScreen they have the choice to either log in or get to another the SignUpScreen to sign up (app screen), like this:
GestureDetector(
child: Text('Sign Up.'),
onTap: () {
Navigator.pushReplacementNamed(context, '/signup_screen');
},
),
If they choose to sign in, when they're done, the home is correctly updated and the MainScreen is shown as I said above. But if they choose to sign up, when they're done, nothing happens. All listeners are notified, but the StreamProvider doesn't receive this notification. The only reason I can think of for this behavior, is that the SignUpScreen is outside the scope of the Provider, but the widget tree seems to suggets that it is.
Widget Tree
It it possibile that the problem is pushReplacementNamed?
P.S: I should mention that the GestureDetector is part of the following method that I pass to the appBar property of Scaffold.
PreferredSize _buildAppBar() {
return PreferredSize(
preferredSize: Size.fromHeight(MediaQuery.of(context).size.height * 0.18),
child: Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.18),
padding: EdgeInsets.only(left: 45.0, right: 45.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Sign In'),
SizedBox(
height: 2.5,
),
Row(
children: [
Text('Have an account already?'),
SizedBox(
width: 4.0,
),
GestureDetector(
child: Text('Sign In.'),
onTap: () {
Navigator.pushReplacementNamed(context, '/signin_screen');
},
),
],
),
],
),
),
);
}

I think the issue here is because you don't notify Stuff widget when user signs in. You can wrap it a Streambuilder in order to listen to AuthState changes like this.
class Stuff extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider<AuthService>(create: (_) => AuthService()),
],
child: Consumer<AuthService>(builder: (context, auth, _) {
return StreamBuilder<FirebaseUser>(ctx,AsyncSnapshot<FirebaseUser> snapshot)=> MaterialApp(
title: 'Stuff',
home: snapshot.data!= null && snapshot.data.user != null ? MainScreen() : SignInScreen(),
routes: {
'/main_screen' : (context) => MainScreen(),
'/signup_screen': (context) => SignUpScreen(),
'/signin_screen': (context) => SignInScreen(),
},
);
}),
);
}
}

Related

Error: Could not find the correct Provider<Networkprovider> above this Widget

I am new to flutter and was trying out the implementation of Network Connectivity with the Flutter Provider. I got across this error and have tried every bit of code on the Internet from changing the context and changing the place where the Provider might lie so that the child widgets will get the context. When I am trying to get the value of res in welcome. dart I am getting the error.
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that Welcome is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately
main.dart
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider(
create: (context) => Networkprovider().networkController.stream,
initialData: Networkprovider().initRes),
],
child: MaterialApp(
theme: ThemeData(),
initialRoute: Welcome.id,
routes: {
Welcome.id: (context) => Welcome(),
NavigatorPage.id: (context) => const NavigatorPage(),
},
),
);
}
}
NetworkProvider.dart
class Networkprovider extends ChangeNotifier {
late StreamSubscription<ConnectivityResult> _subscription;
late StreamController<ConnectivityResult> _networkController;
late ConnectivityResult initRes = ConnectivityResult.none;
StreamSubscription<ConnectivityResult> get subscription => _subscription;
StreamController<ConnectivityResult> get networkController =>
_networkController;
Networkprovider() {
startup();
}
void startup() {
_networkController = StreamController<ConnectivityResult>();
networkStatusChangeListener();
}
void networkStatusChangeListener() async {
_networkController.sink.add(await Connectivity().checkConnectivity());
_subscription = Connectivity().onConnectivityChanged.listen((event) {
_networkController.sink.add(event);
});
}
void disposeStreams() {
_subscription.cancel();
_networkController.close();
}
}
Welcome.dart
class Welcome extends StatelessWidget {
static String id = "welcome_screen";
const Welcome({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var res = Provider.of<Networkprovider>(context);
return SafeArea(
child: Scaffold(
backgroundColor: MAIN_BACKGROUND_COLOR,
body: SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: const <Widget>[
Image(image: AssetImage("assets/images/Magnet_logo.png"))
],
),
),
const Padding(
padding: EdgeInsets.all(20.0),
child:
Image(image: AssetImage("assets/images/Mannify_logo.png")),
),
const Padding(
padding: EdgeInsets.all(10.0),
child: Spinner(),
),
],
),
),
),
);
}
}
Declare ChangeNotifierProvider like this
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Networkprovider()),
],
child: <your widget>,
)
then access like this
final provider = Provider.of<Networkprovider>(context);

How to handle authenticated routes and their redirects after successful auth?

Flutter Web(Navigator 2.0/Router API):
How to handle authenticated routes and their redirects after successful auth?
e.g.
I have these kind of routes on my system
/book/xyz (authenticated user)
/author/abc/book/xyz (authenticated user)
/authentication (non-authenticated user)
/info (non-authenticated user)
If user opens this URL directly, I wanted to ask user to login first, at that time route will be redirected to..
/authentication
Once logged in, I would like to user to navigate previously opened URL if any else home..
Seems like this kind of things may help, any thoughts - how we can achieve similar things?
https://stackoverflow.com/a/43171515/2145844
I have tried few samples for Navigation 2.0 / Router API, yes I can understand the concepts a bit..
Some of the references, I have looked at..
https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade
https://github.com/orestesgaolin/navigator_20_example
https://github.com/flutter/flutter/tree/master/dev/benchmarks/test_apps/stocks
Here is how to do it using VRouter >=1.2
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:vrouter/vrouter.dart';
void main() {
runApp(BooksApp());
}
class Book {
final String title;
final Author author;
Book(this.title, this.author);
}
class Author {
String name;
Author(this.name);
}
class AppState extends ChangeNotifier {
bool _isAuthenticated = false;
bool get isAuthenticated => _isAuthenticated;
void authenticate() {
if (isAuthenticated) return;
_isAuthenticated = true;
notifyListeners();
}
}
class BooksApp extends StatelessWidget {
final List<Book> books = [
Book('Stranger in a Strange Land', Author('Robert A. Heinlein')),
Book('Foundation', Author('Isaac Asimov')),
Book('Fahrenheit 451', Author('Ray Bradbury')),
];
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AppState(),
child: Builder(
builder: (BuildContext context) {
return VRouter(
routes: [
VWidget(path: '/login', widget: AuthenticationScreen()),
VWidget(path: '/info', widget: InfoWidget()),
VGuard(
beforeEnter: (vRedirector) =>
authenticationCheck(context, vRedirector: vRedirector),
stackedRoutes: [
VWidget(
path: '/',
widget: BooksListScreen(books: books),
stackedRoutes: [
VWidget(
path: r'book/:bookId(\d+)',
widget: Builder(builder: (BuildContext context) {
return BookDetailsScreen(
book: books[int.parse(context.vRouter.pathParameters['bookId']!)],
);
}),
),
],
),
VWidget(
path: '/authors',
widget: AuthorsListScreen(authors: books.map((e) => e.author).toList()),
stackedRoutes: [
VWidget(
path: r'/author/:authorId(\d+)',
widget: Builder(builder: (BuildContext context) {
return AuthorDetailsScreen(
author: books[int.parse(context.vRouter.pathParameters['authorId']!)]
.author,
);
}),
),
],
),
],
),
],
);
},
),
);
}
Future<void> authenticationCheck(BuildContext context, {required VRedirector vRedirector}) async {
if (!Provider.of<AppState>(context, listen: false).isAuthenticated) {
vRedirector.to('/login', queryParameters: {'redirectedFrom': '${vRedirector.toUrl}'});
}
}
}
class AuthenticationScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
Provider.of<AppState>(context, listen: false).authenticate();
context.vRouter.to(context.vRouter.queryParameters['redirectedFrom'] == null
? '/'
: context.vRouter.queryParameters['redirectedFrom']!);
},
child: Text('Click to login'),
),
);
}
}
class InfoWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Text('Some info but actually there is nothing'),
);
}
}
class BooksListScreen extends StatelessWidget {
final List<Book> books;
BooksListScreen({required this.books});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
for (var book in books)
ListTile(
title: Text(book.title),
subtitle: Text(book.author.name),
onTap: () => context.vRouter.to('/book/${books.indexOf(book)}'),
)
],
),
);
}
}
class AuthorsListScreen extends StatelessWidget {
final List<Author> authors;
AuthorsListScreen({required this.authors});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
ElevatedButton(
onPressed: () => context.vRouter.to('/'),
child: Text('Go to Books Screen'),
),
for (var author in authors)
ListTile(
title: Text(author.name),
onTap: () => context.vRouter.to('/author/${authors.indexOf(author)}'),
)
],
),
);
}
}
class BookDetailsScreen extends StatelessWidget {
final Book book;
BookDetailsScreen({required this.book});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(book.title, style: Theme.of(context).textTheme.headline6),
ElevatedButton(
onPressed: () {
context.vRouter.to('/author/${context.vRouter.pathParameters['bookId']}');
},
child: Text(book.author.name),
),
],
),
),
);
}
}
class AuthorDetailsScreen extends StatelessWidget {
final Author author;
AuthorDetailsScreen({required this.author});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(author.name, style: Theme.of(context).textTheme.headline6),
],
),
),
);
}
}
The trick is to use a VGuard which, before entering the stackedRoutes, checks whether or not the user is authenticated.
I used queryParameters to store where the user it redirected from, however you could use historyState if you did not want where the user is redirected from appear in the url. That being said, I still prefer queryParameters in that case since is allows link sharing.
You can use qlevar_router to do this.
from the example, in the link, you can define a Middleware with redirectGuard to check if the user can access this page or its children, otherwise just give the route to redirect to.
you can see this in the example project too.
if you give the right to access to Child 4 it will go to Child 4 otherwise you will be navigated to Child 2.

Flutter State Restoration of ListView or BLoC

I'm trying to restore my listview widget after android kills my app from memory by using RootRestorationScope:
runApp(RootRestorationScope(
child: MaterialApp(home: MyApp()),
restorationId: "root",
));
and making my own restorable widget using extends RestorableValue:
class RestorableListBloc extends RestorableValue<ListBloc> {
#override
ListBloc createDefaultValue() {
return ListBloc(
repository: Repository(),
)..add(
Fetch(),
);
}
#override
void didUpdateValue(ListBloc oldValue) {
if (oldValue.state != value.state) {
notifyListeners();
}
}
#override
ListBloc fromPrimitives(Object data) {
print('data: ' + data);
return ListBloc(repository: data);
}
#override
Object toPrimitives() {
return value.repository;
}
}
Where ListBloc is a Bloc that controls what's in my listview widget (collection of timers right now in case anyone's curious).
I extend the class with the restoration mixing and call the bloc inside of a multibloc providers widget as follows:
class _MyAppState extends State<MyApp> with RestorationMixin {
SpeedDialGenerator speedDial = SpeedDialGenerator();
RestorableListBloc _test = RestorableListBloc();
final assetsAudioPlayer = AssetsAudioPlayer();
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => DrawerCubit(value: false),
child: Scaffold(
backgroundColor: Colors.blue[50],
drawer: SafeArea(
child: AppDrawer(),
),
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: Text('Myapp'),
centerTitle: true,
actions: [
IconButton(
icon: Image.asset('assets/images/myapp_white.png'),
onPressed: () {},
),
],
),
body: Stack(children: [
HourglassBackground(),
MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => _test.value,
),
BlocProvider(
create: (context) => AppStateCubit(),
)
],
child: BlocBuilder<ListBloc, ListState>(
builder: (context, state) {
if (state is Failure) {
return Center(
child: Text('Oops something went wrong!'),
);
}
if (state is Loaded) {
return Stack(children: [
HomePage(state: state, displayNotification: () => {}),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 10, 10),
child: BlocProvider(
create: (context) => TimerpopupCubit(),
child: speedDial.buildSpeedDial(context)),
),
]);
}
return Center(
child: CircularProgressIndicator(),
);
},
)),
]),
),
);
}
#override
String get restorationId => 'root';
#override
void restoreState(RestorationBucket oldBucket, bool initialRestore) {
registerForRestoration(_test, restorationId);
}
Unfortunately, everytime I run the app I get:
The following assertion was thrown building Builder:
'package:flutter/src/services/restoration.dart': Failed assertion: line 592 pos 12: 'debugIsSerializableForRestoration(value)': is not true.
There's not much documentation and I know this is a relatively new feature of flutter, but from what I gather this means that you can't currently restore a BLoC?
Is there a way around this or some other approach I should look at?
Thanks
There are some approaches such as using HydratedBloc library that has built in feature to save its state.
Or you can implement your own local database and when user re run app, the repository returns first local data and returns remote one.

How to rebuild the whole view in flutter everytime view enters the screen

I want my page to hit the API always whenever it enters a page.
For example, I am having 2 screens i.e FirstSCreen and SecondScreen.
In FirstScreen I am calling an API to fetch some data. So if the user navigates from FirstScreen to SecondScreen and then comes back to FirstScreen by pressing the back button It should hit the API in FirstScreen again.
I want to know is there any inbuilt function in flutter where I should call my methods so that it can work every time it enters the screen. I have tried using didUpdateWidget() but it is not working the way I want.
initState() is also called only once the widget is loaded ..
Please explain me
You can use async await for it. Let's say you have a button that change the route.
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondScreen(),
),
);
ApiCall();
},
The ApiCall function will call only when user push the back on the second screen.
I have an example that might help. However, it might not cover all scenarios where your FirstScreen will always call a specific function whenever the page is displayed after coming from a different page/screen, or specifically resuming the app (coming from background -- not to be confused when coming from another screen or popping).
My example however, will always call a function when you come back from a specific screen, and you can re-implement it to other navigation functions to ensure that a specific function is always called when coming back to FirstScreen from other screens.
main.dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
home_page.dart
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: RaisedButton(
onPressed: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => SecondPage()))
.then((value) => _reload(value)),
child: Text('Navigate to Next Page'),
),
)
],
),
);
}
Future<void> _reload(var value) async {
print(
'Home Page resumed after popping/closing SecondPage with value {$value}. Do something.');
}
}
second_page.dart
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
Navigator.pop(context, 'Passed Value');
/// It's important that returned value (boolean) is false,
/// otherwise, it will pop the navigator stack twice;
/// since Navigator.pop is already called above ^
return false;
},
child: Scaffold(
appBar: AppBar(),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(child: Text('Second Page')),
],
),
),
);
}
}
#Rick's answer works like a charm even for Riverpod state management as I coul d not get the firstscreen to rebuild to show changes to the 'used' status of a coupon on the second screen where there is a button to use it.
So I did on the details page:
return WillPopScope(
onWillPop: () async {
//final dumbo = ref.read(userProvider.notifier).initializeUser();
Navigator.pop(context);
return false; //true;
},
Then on the coupons list page, each coupon card has:
child: Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24.0),
side: BorderSide(
color: coupons[index].isUsed
? Colors.grey
: Colors.blue),
),
child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
//go to Details screen with Coupon instance
//https://api.flutter.dev/flutter/widgets/Navigator/pushNamed.html
Navigator.pushNamed(context, '/details',
arguments: coupons[index].couponId)
.then((_) => _reload());
/*Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => DetailsScreen(
coupon: coupons[index],
),
),
);*/
},
where I used _ since there is no parameter.
Then the function in class CouponScreen is:
void _reload() {
setState(() {});
}
I believe setState(){} is what triggers the rebuild. I apologize for the formatting but it's very difficult to copy and paste Flutter code that is nested deeply.

How to handle a different login navigation flow?

I am trying to set up a navigation when logged out (forgot password, signup/login) compared to when logged in (home, sign out, lots of stuff).
I am at a complete loss as to how to do this. All the suggestions I see drop out one part of the system, a single page to show a login, but that doesn't work here. If I make the navigation shared, then every page in the rest of the app would need a logged in check, which sounds a bit irritating. Is there an easy way to swap out the navigation setups? Add in navigation dynamically, maybe based on the user logged in/out status?
Could I just subclass the navigation class itself and handle it that way, maybe?
In React Native you can do this by swapping out the navigator you are using between a logged in one and a logged out one. Looking for something that has a similar outcome to that.
React-Native allows nesting navigators, but flutter doesn't. There are multiple ways of doing it though without nesting any navigators after all, a simple example of how it can be done with flutter is shown below.
Example:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
// Main Application
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Example',
// Routes
routes: <String, WidgetBuilder>{
'/': (_) => new Login(), // Login Page
'/home': (_) => new Home(), // Home Page
'/signUp': (_) => new SignUp(), // The SignUp page
'/forgotPassword': (_) => new ForgotPwd(), // Forgot Password Page
'/screen1':(_) => new Screen1(), // Any View to be navigated from home
},
);
}
}
// The login page
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text("Login Page"),
// The button on pressed, logs-in the user to and shows Home Page
new FlatButton(
onPressed: () =>
Navigator.of(context).pushReplacementNamed("/home"),
child: new Text("Login")),
// Takes user to sign up page
new FlatButton(
onPressed: () => Navigator.of(context).pushNamed("/signUp"),
child: new Text("SignUp")),
// Takes user to forgot password page
new FlatButton(
onPressed: () =>
Navigator.of(context).pushNamed("/forgotPassword"),
child: new Text("Forgot Password")),
],
),
),
);
}
}
// Home page
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text("Home Page"),
// Logs out user instantly from home
new FlatButton(
onPressed: () => Navigator.of(context).pushReplacementNamed("/"),
child: new Text("Logout")),
// Takes user to Screen1
new FlatButton(
onPressed: () => Navigator.of(context).pushNamed("/screen1"),
child: new Text("Screen 1")),
],
),
),
);
}
}
// Sign Up Page
class SignUp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text("Sign Up Page"),
// To make an api call with SignUp data and take back user to Login Page
new FlatButton(
onPressed: () {
//api call to sign up the user or whatever
Navigator.of(context).pop();
},
child: new Text("SignUp")),
],
),
),
);
}
}
// Forgot Password page
class ForgotPwd extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text("Sign Up"),
// Make api call to resend password and take user back to Login Page
new FlatButton(
onPressed: () {
//api call to reset password or whatever
Navigator.of(context).pop();
},
child: new Text("Resend Passcode")),
],
),
),
);
}
}
// Any Screen
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text("Screen 1"),
// Takes the user to the view from which the user had navigated to this view
new FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: new Text("Back")),
// Takes back the user to Home page and Logs out the user
new FlatButton(
onPressed: () async {
Navigator.of(context).popUntil(ModalRoute.withName("/home")); // Use popUntill if you want to reset all routes untill now and completely logout user
Navigator.of(context).pushReplacementNamed("/");
// Just to show login page and resume back after login
// Navigator.of(context).pushNamed('/Login');
// On login page after successful login Navigator.of(context).pop();
// the app will resume with its last route.
},
child: new Text("Logout")),
],
),
),
);
}
}
Note: I'm not saying this is the best approach, but the example shows one of the simple ways of doing it.
Hope that helps!
You can do this
import 'package:app/pages/home.page.dart';
import 'package:app/pages/login.page.dart';
import 'package:app/services/auth.service.dart';
import 'package:flutter/material.dart';
AuthService appAuth = new AuthService();
void main() async {
// add this, and it should be the first line in main method
WidgetsFlutterBinding.ensureInitialized();
// Set default home.
Widget _defaultHome = new LoginPage();
// Get result of the login function.
bool _result = await appAuth.login();
if (_result) {
_defaultHome = new HomePage();
}
// Run app!
runApp(new MaterialApp(
title: 'App',
home: _defaultHome,
routes: <String, WidgetBuilder>{
// Set routes for using the Navigator.
'/home': (BuildContext context) => new HomePage(),
'/login': (BuildContext context) => new LoginPage()
},
));
}
Detail Explanation here https://medium.com/#anilcan/how-to-use-dynamic-home-page-in-flutter-83080da07012
You can use this below code:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MyApp',
debugShowCheckedModeBanner: false,
home: Builder(
builder: (_) {
final _user = Hive.box<User>('user').get(0);
if (_user != null) {
if (_user.nameFamily.isNotEmpty) {
return Dashboard();
} else {
return Profile();
}
}
return SignUP();
},
),
...
);
}
}