In flutter how to navigate to specific home page based on the type of user logged in? - flutter

I have a requirement in my application to include two types of users.
one type of user (user_1) will have access to a form page after logging in and the second type (admin) of user will have access to the filled in forms of user_1?
The login screen is the same for both the users. Based on the login credentials, it will be decided whether to navigate user_1 page or admin page.
How to go about this in flutter? To navigate to different home pages for different users?

I had the same thing to do.
I use shared preference to know who is the person (in your case an admin or not). Shared preference is a persistent and secured way to stored data. Here the page of the plug in.
In my initialization page I check the shared preference and redirect to the page depending the result.
/// You can put the logo of your app
class LoadingScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
isLogged(context);
return Scaffold(
body: Center(
child: Icon(
Icons.beach_access,
),
),
);
}
}
Future isLogged(context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String isAdmin = prefs.getBool('isAdmin');
if (uid == null) {
/// If it's the first time, there is no shared preference registered
Navigator.pushNamedAndRemoveUntil(...);
} else {
if (isAdmin) {
/// If the user is an admin
Navigator.pushNamedAndRemoveUntil(...);
} else {
/// If the user is not an admin
Navigator.pushNamedAndRemoveUntil(...);
}
}
}
You just have to set up the shared preference when the user connect:
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('isAdmin', true);
And don't forget to lunch your loading/initialization screen in your main.dart

Here is a way I use to manage this:
void main() async {
String _defaultHome = "/user_home";
bool user = await Helper.getLoggeduser();
if (user.isAdmin) {
_defaultHome = "/admin_home";
}
runApp(App(home: _defaultHome));
}
Then in the App class :
class App extends StatelessWidget {
final String home;
App({
#required this.home,
});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
initialRoute: home,
routes: routes,
);
}
}
Of course, don't forget to import everything necessary.

Related

Flutter firebase auth login is not updating to home page

I am trying to update the home of MaterialApp widget depending on whether the user has sign up or not.
Below is the code inside the state of ``MaterialApp```
String? _userUid;
#override
void initState() {
FirebaseAuth.instance.authStateChanges().listen((user) {
//print('changed');
print(user?.uid);
updateUser(user?.uid);
});
super.initState();
}
void updateUser(String? USER_UID) {
setState(() {
_userUid = USER_UID;
});
}
Below is the code for the home property
home: _userUid == null ? const Onbaording2() : const HomeScreen(),
Somewhere inside the widget tree
final user = await _firebaseAuth.createUserWithEmailAndPassword(
email: email!,
password: password!,
);
After running the code above, there is a user created in firebase but the screen does not change.
Also the signOut works perfectly by signing me out when I use firebaseAuth.instance.signOut();
even if you change your variable it will not be redirected to the home screen because materialapp is only called when you first load or restart the app so rather than adding this condtion in home page or other way can be
#override
void initState() {
FirebaseAuth.instance.authStateChanges().listen((user) {
//print('changed');
print(user?.uid);
if(user == null){ navigate to onboarding }
else{ navigate to home page }
});
super.initState();
}

Flutter what is the best approach to use navigator and ChangeNotifierProvider together

I'm new to flutter, this question may be a very basic one.
I have a firebase phone auth login page to implement this,
if the user is logged in, then navigate to home page
else if the user is a new user, then navigate to the sign-up page
The problem is, whenever the values are changed at the provider, the consumer will get notified and rebuild the build method. I won't be able to listen to them within the build method and return a Navigator.of(context).pushNamed(). Any idea what is the right way to use ChangeNotifierProvider along with listeners and corresponding page navigation?
I have Login class and provider class as below,
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => LoginProvider(),
child: Consumer<LoginProvider>(builder: (context, loginState, child) {
return Scaffold(
...
body: RaisedButton(
onPressed: **loginState.doLogin(_textController.text, context);**
...
)
}),
);
}
}
class LoginProvider with ChangeNotifier {
bool _navigateToSignup = false;
bool get navigateToSignup => _navigateToSignup;
Future doLogin(String mobile, BuildContext context) async {
FirebaseAuth _auth = FirebaseAuth.instance;
_auth.verifyPhoneNumber(
...
verificationCompleted: (AuthCredential credential) async {
UserCredential result = await _auth.signInWithCredential(credential);
User user = result.user;
// if user is new user navigate to signup
// do not want to use Navigator.of(context).pushNamed('/signupPage'); here, instead would like to notify listeners at login page view and then use navigator.
if (user.metadata.creationTime == user.metadata.lastSignInTime) {
_navigateToSignup = true;
} else {
if (result.user != null) {
_navigateToHome = true;
//Navigator.of(context).pushNamedAndRemoveUntil('/homePage', ModalRoute.withName('/'));
}
}
notifyListeners();
},
...
);
}
}
Thanks in advance.
There are several approaches, you choose the one that suits you best.
Pass the context to the ChangeNotifier as you are already doing. I don't like this as well, but some people do it.
Pass a callback to your ChangeNotifier that will get called when you need to navigate. This callback will be executed by your UI code.
Same as 2, but instead of a callback export a Stream and emit an event indicating you need to Navigate. Then you just listen to that Stream on your UI and navigate from there.
Use a GlobalKey for your Navigator and pass it to your MaterialApp, than you can use this key everywhere. More details here.

Manage social user details in Google Flutter application

I am a beginner in developing Flutter application, and try to create a sample application for educational purpose. Last few weeks I decided to do a sample application in flutter that have no inbuilt login or register section because it's have social login options like Facebook and Google. I searched the web and got many code examples for how to implement Facebook and Google authentication in Flutter application.
I have a doubt about this social login implementation maybe it's happening because of lack of working experience in mobile application architecture level. At this point I am asking a question to myself "How to manage social login users in applications"
I have a solution like if the user can login ed successfully, store the user details into our (Firebase) db check the user email exists in database if there is no matching entries in db it will create a new user in database or if exists update the last login date time of that particular user. Because this application shows some user related data in other forms, it's work on the basis of logined userid, so I need to store the logined user details in the database.
Your proposed solution is good enough. The returned id is unique for your app.
Use the id returned to your app as the identifier for users in your app.
Checkout this answer on unique id
Just leaving the social_login plugin here
// Import package
import 'package:social_login/social_login.dart';
// Instantiate it
final socialLogin = SocialLogin();
//Before calling any methods, set the configuration
socialLogin.setConfig(SocialConfig(
facebookAppId: FACEBOOK_APP_ID,
googleWebClientId: GOOGLE_WEB_CLIENT_ID, /*In case a Google tokenId is needed*/
twitterConsumer: TWITTER_CONSUMER_KEY,
twitterSecret: TWITTER_CONSUMER_SECRET,
));
// Get current logged user
final FacebookUser facebookUser = await socialLogin.getCurrentFacebookUser();
final GoogleUser googleUser = await socialLogin.getCurrentGoogleUser();
final TwitterUser twitterUser = await socialLogin.getCurrentTwitterUser();
//Log in social networks
final FacebookUser facebookUser = await socialLogin.logInFacebookWithPermissions(FacebookPermissions.DEFAULT);
final GoogleUser googleUser = await socialLogin.logInGoogle();
final TwitterUser twitterUser = await socialLogin.logInTwitter();
//Log out from social networks
await socialLogin.logOutFacebook();
await socialLogin.logOutGoogle();
await socialLogin.logOutTwitter();
By using the built-in sign in using Firebase Authentication SDK (Official Guide), you will be able to obtain login information for different platforms like Google, Twitter, Facebook and even Github.
You do not need to code your own login/signup, everything is handle hassle free by using the right function from Firebase.
After that you will have the login information like so (this is from email login but Facebook, Google, Twitter and Github is available):
You can then link either the identifier or the User UID to the information in your database.
Oh and last but not least, do remember to set the persistence setting for the login provider to keep user login after they close their apps.
You should split Flutter app into 2 parts:
The "main" part of the app. It shows user related data.
Sign in/Sign up part.
The logic is quite simple. On the app start you check if the user is authenticated. If yes, navigate him to the main screen. If not, present him a sign up screen. Here's how it can be achieved using Firebase as a backend:
final currentUser = await FirebaseAuth.instance.currentUser();
if (currentUser != null){
// We're good: the user is authenticated.
// Show him the main screen.
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => HomeScreen()
));
} else {
// The user is not logged in.
// Show him the sign in/sign up screen.
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => SignInScreen()
));
}
Maybe this example meet your needs:
https://github.com/instaflutter/flutter-login-screen-firebase-auth-facebook-login
If you need some help to understand, i can help you!
you should go with the token logic (which is used by google and facebook).
you should generate a token to each user and store it in your data base . through this token you can mange every thing about the user .
when you call facebook authtinicating it will give you back a token for specific user .
this token when you send it again to facebook or google they will respond back with the details of the user .
so you can work like them .. create a token for the user and recall it for the info from your data base .. and you can store the token responded from facebook and match it in the future ..
the purpose of my answer to go and search for token concept cause it will give you a lot of benefits .
The idea is simple. The users get logged in with facebook/google/instagram and get an accessToken from the services mentioned above. This token has to be sent with each request that need authentication.
Use flutter storage to save the persist the token: https://pub.dev/packages/flutter_secure_storage
I will post you an example of one of my flutter app where I implemented the login with instagram.
Resuming the code below:
loginService.dart is responsible for login api calls and saving the token into the storage
main.dart is the first view of the app. Here if the user is not logged in the Login widget is shown ( the LoginWidget is in login.dart ).
login.dart is the view of the login page. There is a button that calls functions from LoginService class
Here's the code:
~/lib/service/loginService.dart
import 'dart:async';
import 'dart:convert' as JSON;
import 'package:http/http.dart' as http;
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:choose/model/User.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:choose/config.dart' as config;
String apiBaseUrl = config.apiBase;
String apiPort = config.port;
class LoginService {
String clientID;
String secretID;
String redirectURI;
final FlutterSecureStorage storage = new FlutterSecureStorage();
final String authKey = "token";
LoginService(this.clientID, this.secretID, this.redirectURI);
String get authenticationURI {
return "https://api.instagram.com/oauth/authorize/?client_id=$clientID&redirect_uri=$redirectURI&response_type=code";
}
String get authorizationURI {
return "https://api.instagram.com/oauth/access_token";
}
Future<User> authenticate() async {
clean();
FlutterWebviewPlugin _flutterWebviewPlugin = FlutterWebviewPlugin();
// Stream<String> onCode = await _openServer();
_flutterWebviewPlugin.launch(
authenticationURI
);
Completer<User> loginCompleter = Completer();
_flutterWebviewPlugin.onStateChanged.listen((viewState) async {
String url = viewState.url;
int indexOfCode = url.lastIndexOf("?code=");
if(url != null && indexOfCode >= 0 && viewState.type == WebViewState.finishLoad) {
String code = url.substring(url.indexOf('?code=') + 6, url.length);
http.Response userResponse = await http.get(
"${config.endpoints['getUserByCode']}?code=$code",
);
if(userResponse.statusCode == 200) {
User user = User.fromMap(JSON.jsonDecode(userResponse.body));
saveToken(user.token);
loginCompleter.complete(user);
} else {
loginCompleter.completeError("User not found");
}
_flutterWebviewPlugin.close();
}
});
return loginCompleter.future;
}
void saveToken(token) async {
storage.write(key: authKey, value: token);
}
void clean() async {
storage.delete(key: authKey);
}
Future<String> getToken() async {
return storage.read(key: authKey);
}
static Future<String> getStaticToken() async {
FlutterSecureStorage storage = FlutterSecureStorage();
return storage.read(key: "token");
}
}
~lib/main.dart
import 'package:choose/friends.dart';
import 'package:choose/model/User.dart';
import 'package:flutter/material.dart';
import 'package:choose/login.dart';
import 'package:choose/service/loginService.dart';
import 'package:web_socket_channel/io.dart';
import 'feed.dart';
import 'notification.dart';
import 'newPost.dart';
import 'config.dart' as config;
void main() => runApp(MyApp());
LoginService loginService = new LoginService(
"71b818abd18043fb8b7c1833912b62ae",
"3d9d6f87d2354085a74534c13bdda51f",
config.endpoints['authorize'],
);
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
routes: {
'/feed': (context) => DefaultTabController(
length: 2,
child: FeedWidget()
),
'/newpost': (context) => NewPost(),
'/notifications': (context) => NotificationWidget(
channel: IOWebSocketChannel.connect(config.websocketURI)
),
'/friends': (context) => FriendsWidget(),
}
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
User user;
String label = 'Continue with Instagram';
void openLoginPage() async {
try {
User _user = await loginService.authenticate();
this.openPostPage();
} catch(e) {
this.setState(() {
label = 'Try Again';
});
}
}
void openPostPage() async {
print(await loginService.getToken());
print("token");
Navigator.pushReplacementNamed(context, '/feed');
}
void actionDelegator() {
if(user != null) {
return openPostPage();
} else {
return openLoginPage();
}
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Login(loginAction: actionDelegator, user: user, label: label);
}
}
~/lib/service/login.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:choose/model/User.dart';
class Login extends StatefulWidget {
Login({this.loginAction, this.user, this.label});
final loginAction;
final User user;
final String label;
_Login createState() => _Login();
}
class _Login extends State<Login> {
String imageURI = "https://www.travelcontinuously.com/wp-content/uploads/2018/04/empty-avatar.png";
#override
Widget build(BuildContext context) {
if(widget.user != null && widget.user.profilePicture != '' ) {
imageURI = widget.user.profilePicture;
}
return Container (
color: Colors.green,
child: Column (
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar (
backgroundColor: Colors.transparent,
radius: 50.0,
backgroundImage: NetworkImage(imageURI, scale: 2.0),
),
Container(
padding: EdgeInsets.all(0.0),
margin: EdgeInsets.all(20.0),
color: Colors.transparent,
child: MaterialButton(
elevation: 5.0,
color: Color.fromRGBO(193, 53, 132, 1.0),
child: FlatButton.icon(
label: Text(widget.label, style: TextStyle(color: Color.fromRGBO(255,220,128, 1.0), fontWeight: FontWeight.w900, fontSize: 16.0)),
icon: Icon(FontAwesomeIcons.instagram, color: Color.fromRGBO(255,220,128, 1.0)),
),
onPressed: () async {
widget.loginAction();
},
)
)
],
),
);
}
}
(Someone might find this helpful). For easy oauth in flutter, Try visa - https://github.com/e-oj/visa
Here's an example with Facebook auth (It also supports google, twitch, discord, and Github):
import 'package:visa/auth-data.dart';
import 'package:visa/fb.dart';
class AuthPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
/// Simply Provide all the necessary credentials
body: FaceBookAuth().visa.authenticate(
clientID: '139732240983759',
redirectUri: 'https://www.e-oj.com/oauth',
scope: 'public_profile,email',
state: 'fbAuth',
onDone: done
)
);
}
}
and the "done" callback:
done(AuthData authData){
print(authData);
/// You can pass the [AuthData] object to a
/// post-authentication screen. It contaions
/// all the user and OAuth data collected during
/// the authentication process. In this example,
/// our post-authentication screen is "complete-profile".
Navigator.pushReplacementNamed(
context, '/complete-profile', arguments: authData
);
}

How to open the last page from which user terminated the app in flutter?

I am noob in flutter and i have made the app of about 6-8 pages.All i want is to continue from last screen from which the user leave or terminated the app completely.
Also is it possible using mobx??
You can persist the route name every time you open a new route then look for the last rout every time you open the app:
String lastRouteKey = 'last_route';
void main() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
String lastRoute = preferences.getString(lastRouteKey);
runApp(MyApp(lastRoute));
}
class MyApp extends StatelessWidget {
final String lastRoute;
MyApp(this.lastRoute);
#override
Widget build(BuildContext context) {
bool hasLastRoute = getWidgetByRouteName(lastRoute) != null;
return MaterialApp(
home: Foo(),
initialRoute: hasLastRoute ? lastRoute : '/',
onGenerateRoute: (RouteSettings route) {
persistLastRoute(route.name);
return MaterialPageRoute(
builder: (context) => getWidgetByRouteName(route.name),
);
},
);
}
Widget getWidgetByRouteName(String routeName) {
switch (routeName) {
case '/': return MainWidget();
// Put all your routes here.
default: return null;
}
}
void persistLastRoute(String routeName) async {
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.setString(lastRouteKey, routeName);
}
}
Note that this is not 100% precise, since persisting is asynchronous and the user may close the app before it finishes. However, it usually happens really fast and should work almost all the times.
Declare a global variable gv.strCurPage.
In the initstate of each page, set gv.strCurPage equal to current page name, e.g. 'page3'. Then, store this value into SharePreferences.
At the very beginning of main() inside main.dart, retrieve that value from SharePreference, store it in gv.strCurPage, if this value is empty, set gv.strCurPage = 'page1'.
In runApp(), set the first page, using a switch statement, according to the value of gv.strCurPage.
i.e. when user open the app for the first time, the first page is page1. Then, suppose the user naviagate to page5, a value 'page5' will be stored in sharepreference, and retrieved next time the user open the app. so 'page5' will become the first page of the app in next open.

Flutter - How to pass user data to all views

I'm new to the flutter world and mobile app development and struggling with how I should pass user data throughout my app.
I've tried several things, but none seem great and I'm sure there are best practice patterns I should be following.
Because it makes examples easier, I'm using firebase for authentication.
I currently have a separate route for logging in. Once I'm logged in I want the User model in most views for checking permissions on what to show, displaying user info in the drawer, etc...
Firebase has an await firebaseAuth.currentUser(); Is it best practice to call this everywhere you might need the user? and if so, where is the best spot to place this call?
The flutter codelab shows a great example of authenticating users before allowing writes. However, if the page needs to check auth to determine what to build, the async call can't go in the build method.
initState
One method I've tried is to override initState and kick off the call to get the user. When the future completes I call setState and update the user.
FirebaseUser user;
#override
void initState() {
super.initState();
_getUserDetail();
}
Future<Null> _getUserDetail() async {
User currentUser = await firebaseAuth.currentUser();
setState(() => user = currentUser);
}
This works decent but seems like a lot of ceremony for each widget that needs it. There is also a flash when the screen loads without the user and then gets updated with the user upon the future's completion.
Pass the user through the constructor
This works too but is a lot of boilerplate to pass the user through all routes, views, and states that might need to access them. Also, we can't just do popAndPushNamed when transitioning routes because we can't pass a variable to it. We have to change routes similar to this:
Navigator.push(context, new MaterialPageRoute(
builder: (BuildContext context) => new MyPage(user),
));
Inherited Widgets
https://medium.com/#mehmetf_71205/inheriting-widgets-b7ac56dbbeb1
This article showed a nice pattern for using InheritedWidget. When I place the inherited widget at the MaterialApp level, the children aren't updating when the auth state changed (I'm sure I'm doing it wrong)
FirebaseUser user;
Future<Null> didChangeDependency() async {
super.didChangeDependencies();
User currentUser = await firebaseAuth.currentUser();
setState(() => user = currentUser);
}
#override
Widget build(BuildContext context) {
return new UserContext(
user,
child: new MaterialApp(
title: 'TC Stream',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new LoginView(title: 'TC Stream Login', analytics: analytics),
routes: routes,
),
);
}
FutureBuilder
FutureBuilder also seems like a decent option but seems to be a lot of work for each route. In the partial example below, _authenticateUser() is getting the user and setting state upon completion.
#override
Widget build(BuildContext context) {
return new FutureBuilder<FirebaseUser>(
future: _authenticateUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return _buildProgressIndicator();
}
if (snapshot.connectionState == ConnectionState.done) {
return _buildPage();
}
},
);
}
I'd appreciate any advice on best practice patterns or links to resources to use for examples.
I'd recommend investigating inherited widgets further; the code below shows how to use them with asynchronously updating data:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(new MaterialApp(
title: 'Inherited Widgets Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Inherited Widget Example'),
),
body: new NamePage())));
}
// Inherited widget for managing a name
class NameInheritedWidget extends InheritedWidget {
const NameInheritedWidget({
Key key,
this.name,
Widget child}) : super(key: key, child: child);
final String name;
#override
bool updateShouldNotify(NameInheritedWidget old) {
print('In updateShouldNotify');
return name != old.name;
}
static NameInheritedWidget of(BuildContext context) {
// You could also just directly return the name here
// as there's only one field
return context.inheritFromWidgetOfExactType(NameInheritedWidget);
}
}
// Stateful widget for managing name data
class NamePage extends StatefulWidget {
#override
_NamePageState createState() => new _NamePageState();
}
// State for managing fetching name data over HTTP
class _NamePageState extends State<NamePage> {
String name = 'Placeholder';
// Fetch a name asynchonously over HTTP
_get() async {
var res = await http.get('https://jsonplaceholder.typicode.com/users');
var name = json.decode(res.body)[0]['name'];
setState(() => this.name = name);
}
#override
void initState() {
super.initState();
_get();
}
#override
Widget build(BuildContext context) {
return new NameInheritedWidget(
name: name,
child: const IntermediateWidget()
);
}
}
// Intermediate widget to show how inherited widgets
// can propagate changes down the widget tree
class IntermediateWidget extends StatelessWidget {
// Using a const constructor makes the widget cacheable
const IntermediateWidget();
#override
Widget build(BuildContext context) {
return new Center(
child: new Padding(
padding: new EdgeInsets.all(10.0),
child: const NameWidget()));
}
}
class NameWidget extends StatelessWidget {
const NameWidget();
#override
Widget build(BuildContext context) {
final inheritedWidget = NameInheritedWidget.of(context);
return new Text(
inheritedWidget.name,
style: Theme.of(context).textTheme.display1,
);
}
}
I prefer to use Services with Locator, using Flutter get_it.
Create a UserService with a cached data if you like:
class UserService {
final Firestore _db = Firestore.instance;
final String _collectionName = 'users';
CollectionReference _ref;
User _cachedUser; //<----- Cached Here
UserService() {
this._ref = _db.collection(_collectionName);
}
User getCachedUser() {
return _cachedUser;
}
Future<User> getUser(String id) async {
DocumentSnapshot doc = await _ref.document(id).get();
if (!doc.exists) {
log("UserService.getUser(): Empty companyID ($id)");
return null;
}
_cachedUser = User.fromDocument(doc.data, doc.documentID);
return _cachedUser;
}
}
Then create create a Locator
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton(() => new UserService());
}
And instantiate in main()
void main() {
setupLocator();
new Routes();
}
That's it! You can call your Service + cachedData everywhere using:
.....
UserService _userService = locator<UserService>();
#override
void initState() {
super.initState();
_user = _userService.getCachedUser();
}
I crashed into another problem because of this problem you can check it out here
So the solution I came up with is a bit untidy,I created a separate Instance dart page and imported it to every page.
GoogleSignInAccount Guser = googleSignIn.currentUser;
FirebaseUser Fuser;
I stored the user there on login and checked on every StateWidget if it was null
Future<Null> _ensureLoggedIn() async {
if (Guser == null) Guser = await googleSignIn.signInSilently();
if (Fuser == null) {
await googleSignIn.signIn();
analytics.logLogin();
}
if (await auth.currentUser() == null) {
GoogleSignInAuthentication credentials =
await googleSignIn.currentUser.authentication;
await auth.signInWithGoogle(
idToken: credentials.idToken,
accessToken: credentials.accessToken,
);
}
This is my old code I did cleaned it up on my current app but I don't have that code now in handy. Just check out for null user and log it in again
I did it for most of the Firebase instances too because I have more than 3 pages on my app and Inherited Widgets was just too much work
You can use the GetX package to check whether or not the user is logged in, get user data and have it accessible throughout your app
For my lazy mathod,
i just create new file like userdata.dart and then put any variable on it for example like dynamic Profile = null
inside userdata.dart
//only put this or anything u want.
dynamic Profile = null;
at startingpage.dart
//import that file
import '../userdata.dart';
class startingpage extends ...{
...
//set data to store..
Profile = 'user profile';
...
}
to use the data just declare and use in
anotherpage.dart
//import that file
import '../userdata.dart';
class anotherpage extends...{
...
}
class .. State ...{
...
//set the data to variable
dynamic userdata = Profile;
print('this is my lazy pass data' + userdata.toString());
...
}