Flutter display user information using firebase auth - firebase

I would like to display the uid and email from Firebase Auth (just used for auth only!) in my Drawer.
I have this method to return the uid :
static Future<String> getUID() async {
User? user = await FirebaseAuth.instance.currentUser;
return user!.uid;
}
And this is my Drawer :
class DrawerMenu extends StatefulWidget {
final String pageName;
const DrawerMenu({Key? key, required this.pageName}) : super(key: key);
#override
_DrawerMenuState createState() => _DrawerMenuState();
}
class _DrawerMenuState extends State<DrawerMenu> {
#override
Widget build(BuildContext context) {
// print(MaterialLocalizations.of(context));
return Scaffold(
appBar: AppBar(title: Text('Title')),
body: Center(
child: DashboardPage(),
),
drawer: Drawer(
child: ListView(padding: EdgeInsets.all(0.0), children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text(LoginPageService.getUID().toString()), // HERE HERE HERE HERE
accountEmail: Text('random#gmail.com'),
currentAccountPicture: CircleAvatar(
backgroundImage: ExactAssetImage('assets/random.jpg'),
),
otherAccountsPictures: <Widget>[
CircleAvatar(
child: Text('A'),
backgroundColor: Colors.white60,
),
CircleAvatar(
child: Text('R'),
),
],
onDetailsPressed: () {},
...
...
...
I know that LoginPageService.getUID() will return a Future, so yes it should not be used like that.
But i don't know what's the best way for doing it and where to put the code.. in the widget ? or elsewhere ?
Should i use .then((value).... to get the uid..
Let me know if you have experience with it, and how you did it
Thanks for any help !

To complete the answer of #Youri you can do this :
static Future<User?> getCurrentUser() async {
return await auth.currentUser;
}
And in your drawer :
String? uid, name;
#override
void initState() {
super.initState();
LoginPageService.getCurrentUser().then((user) {
setState(() {
uid = user?.uid;
email = user?.email;
});
});
}
And then you can use it like that :
accountName: Text(name.toString()),

You could make use of the FutureBuilder for any async code. This widget automatically rebuilds whenever the status of the provided Future changes.
Please checkout this widget of the week video from Flutter for more information on this Widget.
FutureBuilder (Flutter Widget of the Week)

Related

_CastError (Null check operator used on a null value) because it requires loading

So I am creating an Instagram clone and when I open the feed screen, an error that says '_CastError (Null check operator used on a null value)' pops up.
But when I left it for a minute it was replaced by the feed screen normally
So it turns out it wants to load, but I am not sure how can I make it do so.
Here is the code(The bolded line is the one that requires time):
`
class PostCard extends StatefulWidget {`
`final snap;`
`const PostCard({Key? key, required this.snap}) : super(key: key);`
`#override`
`State<PostCard> createState() => _PostCardState();`
`}`
`class _PostCardState extends State<PostCard> {`
`bool isLikeAnimating = false;`
`int commentLen = 0;`
`bool isLoading = false;`
`#override`
`Widget build(BuildContext context) {`
`
** final UserProvider userProvider = Provider.of<UserProvider>(context);**`
`return isLoading`
`? const Center(`
`child: CircularProgressIndicator(),`
`)`
`: Container(`
`color: Colors.white,`
`padding: EdgeInsets.symmetric(vertical: 10),`
`child: Column(`
`children: [`
`Container( //inside here are the contents of the post`
`);`
`}`
`}`
`Feed Screen:`
`StreamBuilder(`
`stream: stream,`
`builder: (context,`
`AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {`
`if (snapshot.connectionState == ConnectionState.waiting) {`
`return Center(`
`child: CircularProgressIndicator(),`
`);`
`}`
`return ListView.builder(`
`itemCount: snapshot.data!.docs.length,`
`itemBuilder: (context, index) => PostCard(`
`snap: snapshot.data!.docs[index],`
`),`
`);`
`}));`
I am following the same course. I will search the solution in the Discord server and I found it:
Change the code in user_provider.dart like this:
class UserProvider with ChangeNotifier {
User? _user;
final AuthMethods _authMethods = AuthMethods();
User? get getUser => _user;
Future<void> refreshUser() async {
User user = await _authMethods.getUserDetails();
_user = user;
notifyListeners();
}
}
And this is the code for add_post_screen.dart:
#override
Widget build(BuildContext context) {
final User? user = Provider.of<UserProvider>(context).getUser;
return user == null
? const Center(
child: CircularProgressIndicator(
color: Colors.black,
))
: _file == null
? Center(
child: IconButton(
icon: const Icon(Icons.upload),
onPressed: () => _selectImage(context),
),
)
: Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey,
leading: IconButton(
icon: const Icon(Icons.arrow_back), onPressed: () {}),
Following that you have to change your user_provider.dart as follows:
class UserProvider with ChangeNotifier {
User? _user;
final AuthMethods _authMethods = AuthMethods();
// Change it
User? get getUser => _user;
// update the value of an user
Future<void> refreshUser() async {
User user = await _authMethods.getUserDetails();
_user = user;
notifyListeners();
}
}
And in your post_card.dart you have to add a verification when the user == null, if it's null you have to put a CircularProgressIndicator, else the next of your code that show all the posts:
#override
Widget build(BuildContext context) {
final model.User? user = Provider.of<UserProvider>(context).getUser;
/*Fixing error related with null value located in user provider*/
return user == null
? const Center(
child: CircularProgressIndicator(
color: Colors.white,
),
)
: Container(//the rest of your code)

How to sort a list of users through cloud firestore that contain a uid with flutter?

I am trying to make a leaderboard system for a game that I am coming up within flutter and I can't seem to find a way to sort the different users depending on their high score due to the fact that high score data is stored inside the document which is the uid?
Right now I have it set up to just display the different users in the order at which they sign in at. Thanks for all the help in advance!
// My home page
class Home extends StatelessWidget {
final AuthService _auth = AuthService();
final HighscoreData highscoreData;
Home({Key key, this.highscoreData}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamProvider<List<HighscoreData>>.value(
value: DatabaseService().brews,
child: Scaffold(
backgroundColor: Colors.brown[50],
body: HighscoreList(),
),
);
}
}
// List of different players highscores
class HighscoreList extends StatefulWidget {
#override
_HighscoreListState createState() => _HighscoreListState();
}
class _HighscoreListState extends State<HighscoreList> {
#override
Widget build(BuildContext context) {
final differentHighScores = Provider.of<List<HighscoreData>>(context) ?? [];
return ListView.builder(
itemCount: differentHighScores.length,
itemBuilder: (BuildContext context, int index){
return PlayerHighscoreTile(highscoreData: differentHighScores[index]);
},
);
}
}
// The template tile for each different highscore
class PlayerHighscoreTile extends StatelessWidget {
final HighscoreData highscoreData;
PlayerHighscoreTile({ this.highscoreData });
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
child: ListTile(
leading: CircleAvatar(
radius: 25.0,
backgroundColor: Colors.brown,
),
title: Text(highscoreData.name),
trailing: Text(highscoreData.score),
),
),
);
}
}
Here is my Database class if it helps at all
class DatabaseService {
final String uid;
DatabaseService({ this.uid });
// Collection reference
final CollectionReference<Map<String, dynamic>> brewCollection = FirebaseFirestore.instance.collection('brews');
Future updateUserData( String name, score) async {
return await brewCollection.doc(uid).set({
'score' : score,
'name' : name,
});
}
// Brew list from snapshot
List<HighscoreData> _brewListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc){
return HighscoreData(
name: doc.get('name') ?? '',
score: doc.get('score') ?? '0'
);
}).toList();
}
// Get brews stream
Stream<List<HighscoreData>> get brews {
return brewCollection.snapshots().map(_brewListFromSnapshot);
}
UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
return UserData(
uid: uid,
name: snapshot.get('name'),
score: snapshot.get('score'),
);
}
// Get user document
Stream<UserData> get userData {
return brewCollection.doc(uid).snapshots().map(_userDataFromSnapshot);
}
}
I just found out how to do this by adding a sortBy() function as it grabs the different data from firebase.
Stream<List<HighscoreData>> get brews {
return brewCollection.orderBy('').snapshots().map(_brewListFromSnapshot);
}

'package:flutter/src/widget/text.dart': Fasiled assertion: line 378 pos 10; 'data != null': A non-null String must be provided to a Text widget

I got red screen on the mobile phone when accessing record_patien.
here's the code
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:sensor_detak_jantung/models/sensor.dart';
import 'package:sensor_detak_jantung/models/user.dart';
import 'package:sensor_detak_jantung/screens/authenticate/sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
import 'package:sensor_detak_jantung/services/db_path.dart';
class RecordPatient extends StatefulWidget {
const RecordPatient({Key key}) : super(key: key);
#override
_RecordPatient createState() => _RecordPatient();
}
class _RecordPatient extends State<RecordPatient> {
final databaseReference = FirebaseDatabase.instance.reference();
final _auth = firebase_auth.FirebaseAuth.instance;
final TextEditingController tokenController = TextEditingController();
User userInfo;
firebase_auth.User _user;
Sensor sensorInfo;
final _formKey = GlobalKey<FormState>();
String bpm;
void initState(){
super.initState();
this._user = _auth.currentUser;
if(_user != null) {
This is where i try to get BPM value
databaseReference.child('Sensor').once().then((DataSnapshot snapshot) {
bpm = snapshot.value['BPM']['Data'];
});
This is for user, this code run smoothly on other class.
databaseReference.child(USER_KEY).child(_user.uid).once().then((snapshot) {
userInfo = User.fromSnapshot(snapshot);
setState(() { });
});
}
}
AppBar title(){
return AppBar(
backgroundColor: Colors.red[400],
elevation: 0.0,
title: Text('Hi ${userInfo?.userName}'),
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person),
label: Text('logout'),
onPressed: () async {
_auth.signOut().then((value) {
Navigator.pushReplacement(context, new MaterialPageRoute(builder: (context) => SignIn()));
setState(() {});
});
},
),
],
);
}
#override
Widget build(BuildContext context) {
print (bpm);
return Scaffold(
body: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(22.0, 0.0, 22.0, 22.0),
children: [
SizedBox(height: 40),
title(),
SizedBox(height: 40),
Text (bpm),
],
),
),
);
}
}
this happen when i try to get Sensor value and users value.
im still learning and experimenting, if someone can explain me why this error happen in easy way is much appreciated.
As written in the error, the Text widget is getting a null value, which is an error when we pass something like this to the text Text(null).
In your code, this is only possible at this text widget where bpm might be null.
Text (bpm),
So you can simply do this,
databaseReference.child('Sensor').once().then((DataSnapshot snapshot) {
bpm = snapshot.value['BPM']['Data']??"";
});
to fix the error.
It seems snapshot.value['BPM']['Data']; returns null, so your Text() widget has null as its value, which is not allowed. You should add a null check before assigning the value of bpm to the Text widget, perhaps something like this:
SizedBox(height: 40),
title(),
SizedBox(height: 40),
(bpm == null)?Text ("No BPM received"):Text(bpm),

Redirecting without any error - displayName

While working with firebase authentication weird error without any notes happen to me.
This time application stops after I press set name button. Instantly in VScode I am redirected to this page:
As I said there is no error in debug console, no notes. No expections to see.
I guess there is something wrong with setting displayName but not clearly what.
This is full code of the class:
class Verified extends StatefulWidget {
#override
_VerifiedState createState() => _VerifiedState();
}
class _VerifiedState extends State<Verified> {
final formKey = GlobalKey<FormState>();
final nameController = TextEditingController();
final _auth = FirebaseAuth.instance;
validate(displayName) {
if (formKey.currentState.validate()) {
setName(displayName);
}
}
setName(displayName) async {
try {
await _auth.currentUser.updateProfile(displayName: displayName);
} catch (e) {
log(e.code.toString());
}
log(_auth.currentUser.displayName.toString());
}
#override
Widget build(BuildContext context) {
return Material(
child: Padding(
padding: const EdgeInsets.all(100.0),
child: Column(
children: [
Text('choose your username'),
Form(
key: formKey,
child: TextFormField(
controller: nameController,
decoration: InputDecoration(hintText: 'name'),
),
),
RaisedButton(
child: Text('set name'),
onPressed: () => validate(nameController))
],
),
),
);
}
}
Thank you in advance
SOLUTION
When I remove from function actions with _auth.currentUser everything works, I also moved this function to the place where the user was logged in/registered and it also worked.
So as I think the error was because firebase saw no user and the solution is to use .currentUser in the same class/function as registering/logging in or saving user after those actions.

Saving a value as a string with Flutter Firestore Firebase

I want to save a value from my Cloud Firestore as a string. I am using Flutter with Dart. I have been able to save it when building the page using MaterialepageRoute:
MaterialPageRoute(
builder: (context) => MainScreen(
currentUserId: firebaseUser.uid,
currentUserGender: document['gender'],
currentUserPreference: document['preference'],
)),
But this isn't an option with all of my pages, so I have to look for something else. I want to get the value from my Firestore Database, and then save it as a string, since I want to:
if (currentUserGender == 'male') {
//then do something
}
I have no idea how to do this, I have thought about using a Class, maybe the "get"-function with Firebase, but none have worked. I am not really sure how to do this, so any help is appreciated. I am able to get the currentUser. Here is a picture of my database:
https://imgur.com/KL7HX6P
Thanks in advance.
A Minimal Example: To fetch a Single Document Fields. Swap Collection & Document name in the code with your Own Names.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class GetUser extends StatefulWidget {
#override
_GetUserState createState() => _GetUserState();
}
class _GetUserState extends State<GetUser> {
Map<String, dynamic> userDetails = {};
Future<Null> getUser() async {
await Firestore.instance
.collection('users') // Your Collections Name
.document('eMAE4XF9cTYS12MpfOuWBW4P2WH3') // Your user Document Name
.get()
.then((val) {
userDetails.addAll(val.data);
}).whenComplete(() {
print('Data Fetched');
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
textColor: Colors.white,
color: Theme.of(context).accentColor,
onPressed: () async {
await getUser();
},
child: Text('Get User Detail from Cloud'),
),
userDetails.length > 0
? Column(
children: <Widget>[
Text('${userDetails['gender']}'),
Text('${userDetails['id']}'),
Text('${userDetails['nickname']}'),
userDetails['gender'] == 'male'
? Text('Its Boy')
: Text('Girl'),
],
)
: Text('No user Data, Please Fetch'),
],
),
),
);
}
}

Resources