How to get another users ID from Firebase in Flutter? - firebase

i'm trying to add user in my contacts by writing his uid from firebase. I need to write users id in textfield and on pressing button i need to firebase check this uid, and if it's exists, my app needs to add it in contacts. Is there any solutions? p.s i'm making messenger app and it's "Add new contact" function. It would be nice if someone tells me how to create chat using their ID or create separate "chat id" which would be same to 2 users. btw i'm using realtime database

To check if the user exsits, you can do something like this:
final users = FirebaseFirestore.instance.collection('users');
final userDoc =
await users.doc('PUT THE UID TO SEARCH FOR HERE').get();
if (userDoc.exists) {
// do something
}
To make this reusable convert it to a function:
Future<bool> userExists(String uid) async {
final users = FirebaseFirestore.instance.collection('users');
final userDoc =
await users.doc(uid).get();
return userDoc.exists;
}
Now you can call the function with any uid:
bool _userExists = await userExists('UID');
Here is a full code example:
import 'package:flutter/material.dart';
void main() {
runApp(App());
}
class App extends StatefulWidget {
#override
_AppState createState() => new _AppState();
}
class _AppState extends State<App> {
// This key is used to control the SnackBars
final key = GlobalKey<ScaffoldMessengerState>();
final textCtrlr = TextEditingController();
bool isLoading = false;
#override
void dispose() {
super.dispose();
textCtrlr.dispose();
}
Future<bool> userExists(String uid) async {
final users = FirebaseFirestore.instance.collection('users');
final userDoc = await users.doc(uid).get();
return userDoc.exists;
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ScaffoldMessenger(
key: key, // Assign the key to the ScaffoldMessenger
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
child: TextFormField(
controller: textCtrlr,
),
width: 200.0,
),
),
isLoading
? const SizedBox(
child: CircularProgressIndicator(
strokeWidth: 2.0,
),
width: 20.0,
height: 20.0,
)
: ElevatedButton(
onPressed: () async {
final uid = textCtrlr.text;
setState(() => isLoading = false);
final bool _userExists = await userExists(uid);
setState(() => isLoading = false);
if (_userExists) {
// The user exists and can
// be added to contacts
key.currentState?.showSnackBar(
SnackBar(
content: Text(
'User added!',
),
backgroundColor: Colors.green,
behavior: SnackBarBehavior.floating,
),
);
return;
}
// The user doesn't exist
key.currentState?.showSnackBar(
SnackBar(
content: Text(
'The user doesn\'t exist',
),
backgroundColor: Theme.of(context).errorColor,
behavior: SnackBarBehavior.floating,
),
);
},
child: const Text('Search for user'),
),
],
),
),
),
),
);
}
}

Related

I am unable to use Firebase Auth Package correctly

Everytime i run the code for the first time in my Android Studio Code, I have to hot reload it just to enable the submit button. I think the problem is that the current version of Auth package isn't returning FirebasAuth.instance.currentuser as a future but returning a User class. Here's my code.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class NewMessage extends StatefulWidget {
#override
_NewMessageState createState() => _NewMessageState();
}
class _NewMessageState extends State<NewMessage> {
var _enteredMssg = '';
var _controller = new TextEditingController();
void sendMessage() {
FocusScope.of(context).unfocus();
final user = FirebaseAuth.instance.currentUser;
print(user.uid);
FirebaseFirestore.instance.collection('chat').add({
'text': _enteredMssg,
'createdAt': Timestamp.now(),
'userId': user.uid,
});
// print(user.uid);
_controller.clear();
_enteredMssg = '';
}
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
top: 10,
),
padding: EdgeInsets.all(10),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(labelText: 'Send a message'),
onChanged: (value) {
_enteredMssg = value;
},
),
),
IconButton(
icon: Icon(Icons.send),
color: Theme.of(context).accentColor,
onPressed: _enteredMssg.trim().isEmpty ? null : sendMessage)
],
),
);
}
}
Go to the terminal and write -
Flutter pub get

onTap method for Flutter to open longitude and latitude stored in Firestore

I am trying to create a search engine for electoral sections, once it finds the electoral
section by clicking on the item it should send me to a longitude and latitude that I have stored
in firestore and display it on Google maps as markers with flutter, but I cannot create the
method, what will be the most efficient way to do this?
class SearchPage extends StatefulWidget {
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
TextEditingController textEditingController = TextEditingController();
final database = Firestore.instance;
String searchString;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(30.0),
child: Container(
child: TextField(
onChanged: (val) {
setState(() {
searchString = val.toLowerCase();
});
},
controller: textEditingController,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () => textEditingController.clear()),
hintText: 'Buscar seccion',
hintStyle: TextStyle(
fontFamily: 'Antra', color: Colors.blueGrey)),
),
),
),
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: (searchString == null || searchString.trim() == ' ')
? Firestore.instance.collection('secciones').snapshots()
: Firestore.instance
.collection('secciones')
.where('searchIndex', arrayContains: searchString)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('We got an error ${snapshot.error}');
}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Cargando');
case ConnectionState.none:
return Text('Error de conexion');
case ConnectionState.done:
return Text('We are done!');
default:
return new ListView(
children: snapshot.data.documents
.map((DocumentSnapshot document) {
return new ListTile(
title: Text(document['estado']),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
return MapsScreen(
);
}),
);
});
}).toList());
}
},
),
)
],
),
)
],
));
}
}
This is the screen where you should send the position stored in firestore,
but I can't find out how to do it and I took the method from a video
tutorial in which they taught you how to show and store your current
location in Google maps.
class MapsScreen extends StatefulWidget{
final String partyNumber;
final String userId;
const MapsScreen({Key key, this.userId, this.partyNumber}) : super(key: key);
#override
_MapsScreenState createState() => _MapsScreenState();
}
class _MapsScreenState extends State<MapsScreen>{
GoogleMapController _mapController;
Location _location = Location();
StreamSubscription<LocationData> subscription;
#override
void initState(){
super.initState();
_initLocation();
}
_initLocation() async{
var _serviceEnabled = await _location.serviceEnabled();
if(!_serviceEnabled) {
_serviceEnabled = await _location.requestService();
if(!_serviceEnabled){
return;
}
}
var _permissionGranted = await _location.hasPermission();
if(_permissionGranted == PermissionStatus.DENIED){
_permissionGranted = await _location.requestPermission();
if(_permissionGranted != PermissionStatus.GRANTED){
print("Sin permisos de GPS");
return;
}
}
subscription = _location.onLocationChanged().listen((LocationData event) {
if(_mapController != null){
_mapController.animateCamera(
CameraUpdate.newLatLng(
LatLng(event.latitude, event.longitude),
),
);
}
Firestore.instance
.collection('seccion')
.document(widget.partyNumber)
.collection('people')
.document(widget.userId)
.setData({
'lat': event.latitude,
'lng': event.longitude,
});
print("${event.latitude}, ${event.longitude}");
});
}
#override
void dispose(){
if(subscription != null){
subscription.cancel();
}
Firestore.instance
.collection('seccion')
.document(widget.partyNumber)
.collection('people')
.document(widget.userId)
.delete();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Instituto Nacional Electoral"),
),
body: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(16.879860202903764, -99.9013661857768),
zoom: 15,
),
zoomGesturesEnabled: true,
myLocationEnabled: true,
myLocationButtonEnabled: true,
onMapCreated: (controller) => _mapController = controller,
),
);
}
}
I am not quite sure what exactly you are trying to accomplish.
I initially thought you had latitudes and longitudes stored somewhere in Firebase and wanted to display the marker in those locations.
I you wanted to do that, you would need to get the location data from Firebase and pass it into the GoogleMap. I am not familiar with the widget itself, but from the documentation as you can see here: https://github.com/flutter/plugins/blob/f3024731b090659edaa92d01416549c690f65678/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart#L112
the widget accepts a Set of Markers.
If you did a little in the repository you can see how to build a Marker. And then you can construct one or more from the location data in Firebase and pass them to the GoogleMap widget.
If that is what you want to accomplish. The code you posted saves the current user location to Firebase, so I am unsure what exactly your goal is.

null an the Display in Flutter but with the right Value in Future

I am pretty new in Flutter and i can not solve this problem.
i have a really simple application. it is just a login with google an a User is created in Firebase, that user have a counter and a button this button increased the counter (int _user.count++).
Then my problem: after the login in the next window, it is not visible the count variable until I click "plus" button. the variable is right and the query with fireStore work great I got the variable but if I do not click the button I got an the display in the place of the variable "null".
Thanks a lot for you Help and Time, I really hope that you can help me. maybe it is a tiny problem I have not found information about it but it is happen when some start to learn.
MyDAO: Hier the Method Future it is the responsable of make the Query to FireStore.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:gauth/user_model.dart';
import 'package:rxdart/rxdart.dart';
final UserDAO userDAO = UserDAO();
class UserDAO {
final Firestore _db = Firestore.instance;
PublishSubject loading;
Observable<Future<QuerySnapshot>> profile;
void updateData(UserModel user) async {
DocumentReference documentReference =
_db.collection("users").document(user.uid);
return documentReference.setData({
"uid": user.uid,
"userName": user.name,
"email": user.email,
"photoUrl": user.photoUrl,
"count": user.count,
"lastIn": DateTime.now()
}, merge: true);
}
Future<QuerySnapshot> readDateFutur(String email) async {
// loading.add(true);
QuerySnapshot querySnapshot = await (_db
.collection("users")
.where("email", isEqualTo: email)
.getDocuments());
// loading.add(false);
return querySnapshot;
}
}
hier in the method "void initState()" I hold the variable _user.couner, that works.
class PlusCounter extends StatefulWidget {
UserModel user;
PlusCounter(this.user);
#override
_PlusCounterState createState() => _PlusCounterState();
}
class _PlusCounterState extends State<PlusCounter> {
UserModel _user;
PublishSubject loading;
#override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
_user = widget.user;
//loading.add(false);
userDAO.readDateFutur(_user.email).then((QuerySnapshot docs) {
if (docs.documents.isNotEmpty) {
print("::::::::::NOESTOY VACIO:::::::::::::::::::::");
print(docs.documents.last.data["count"]);
if (docs.documents.last.data["count"] != null) {
_user.count = docs.documents.last.data["count"];
} else {
_user.count = 0;
}
} else {
print(":::::::::::ESTOY VACIO:::::::::::::::::");
_user.count = 0;
}
});
});
}
void _plus() {
setState(() {
_user.count++;
});
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text("Cuantas veces te has \n lavado las manos:"),
Text("${_user.count}"),
MaterialButton(
onPressed: () {
_plus();
},
child: Text("Plus"),
textColor: Colors.white,
color: Colors.blue,
),
MaterialButton(
onPressed: () => userDAO.updateData(_user),
child: Text("Guardar"),
textColor: Colors.white,
color: Colors.blue,
),
],
);
}
}
WelcomePage code is this one.
class userDataWelcome extends StatelessWidget {
UserModel _userModel;
userDataWelcome(this._userModel);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Welcome"),
),
body: Center(
child: Column(
children: <Widget>[
Center(
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(_userModel.photoUrl),
),
),
),
),
Text("${_userModel.name}"),
PlusCounter(_userModel),
MaterialButton(
onPressed: () => authService.SingOut(),
child: Text("Logout"),
textColor: Colors.white,
color: Colors.deepOrange,
)
],
),
),
);
}
}
Then I really do not why I need to click "plus" button before I can see the Value of _user.count, because I just see null in otherwise. just again I want to say Thanks for your help.
Try wrapping this line in initStat() _user.count = docs.documents.last.data["count"]; in setState((){}); like this
setState((){
_user.count = docs.documents.last.data["count"];
)};

The getter 'email' was called on null

I'm trying to make a chat between two people using Flutter and Firebase but I'm facing an error when I connect into my app using Firebase's signInWithEmailAndPassword, it tells me:
The getter 'email' was called on null. Receiver: null Tried calling:
email
And Flutter also tells me the error come from the MaterialApp widget from my main.dart which doesn't help me to find the error..
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:social/responsive/size_config.dart';
import 'settings.dart';
import 'home.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedInUser;
class ActivityFeed extends StatefulWidget {
static const String id = 'activity_feed_screen';
#override
_ActivityFeedState createState() => _ActivityFeedState();
}
class _ActivityFeedState extends State<ActivityFeed> {
final _auth = FirebaseAuth.instance;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
UserInfo(),
FlatButton(
child: Icon(
Icons.settings,
color: Colors.white,
),
onPressed: () {
Navigator.pushNamed(context, Settings.id);
},
),
FlatButton(
child: Icon(
Icons.not_interested,
color: Colors.white,
),
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, Home.id);
},
),
],
),
),
)
],
),
);
}
}
class UserInfo extends StatefulWidget {
#override
_UserInfoState createState() => _UserInfoState();
}
class _UserInfoState extends State<UserInfo> {
String email = loggedInUser.email;
String username;
#override
void initState() {
super.initState();
getUsername();
}
void getUsername() async {
DocumentReference docRef = _firestore.collection('users').document(email);
docRef.get().then((snapshot) {
if (snapshot.exists) {
username = snapshot.data['username'];
}
});
}
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Column(
children: <Widget>[
Text(
'Welcome $username',
style: TextStyle(
fontFamily: 'Amatic',
fontSize: SizeConfig.safeBlockHorizontal * 10),
),
],
)
;
}
}
So basically what I am just trying to display 'Welcome' + the username, but it doesn't want,
my Firebase Database have one collection named 'users', where the document names are the email the user used when he created his account.
All the Register/Log-In process seems to work fine.
If someone has a clue of what is happening that would be awesome, thanks.
You initialize username as null. You can either check it on the widget tree
username != null ? Text(
'Welcome $username',
style: TextStyle(
fontFamily: 'Amatic',
fontSize: SizeConfig.safeBlockHorizontal * 10),
) : CircularProgressIndicator()
and set it via setState()
setState(() {
username = snapshot.data['username'];
});
Another solution is to change
String username;
to
String username = '';
You should use a state management method by the way. setState() is very primitive and you will end up having sphagetti code if you use it as a state management solution.

Cloud Firestore not updating correctly when record is added in Flutter

I am developing a Flutter app and I am using the cloud_firestore plugin. I have a collection of submissions and I am using the StreamBuilder to display them (which I am assuming will update when the stream changes). I literally took the example from the plugin examples as there is not much documentation on how to do things using the plugin. When I added a record, the list of documents that I am displaying gets longer, but it seems to be copying one of the submissions instead of inserting the new submission. The new submission does not show after it is added. Here is the code for how I am displaying the list:
// At the top of the class home.dart.
final submissions = Firestore.instance.collection('submissions');
// This is in submission-list.dart and the above submissions
// is passed in to the contructor
Widget build(BuildContext context) {
return new StreamBuilder<QuerySnapshot>(
stream: submissions
.where('owner_uid', isEqualTo: this.user.uid)
.orderBy('timestamp', descending: true)
.snapshots,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
var date = _formatDate(document['timestamp']);
String body = _constructCardBody(document['weight'],
bodyFat: document['bodyFat']);
String id = document.documentID;
return new SubmissionCard(id: id, title: date, body: body, submissions: submissions);
}).toList(),
);
},
);
}
Here is submission-card.dart in full:
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import '../utils/logger.dart';
import './block-button.dart';
class SubmissionCard extends StatefulWidget {
final String id;
final String title;
final String body;
final CollectionReference submissions;
SubmissionCard({this.id, this.title, this.body, this.submissions});
#override
State<StatefulWidget> createState() =>
new _SubmissionCardState(id: this.id, title: this.title, body: this.body, submissions: this.submissions);
}
class _SubmissionCardState extends State<SubmissionCard> {
final String id;
final String title;
final String body;
bool showActionButtons = false;
final CollectionReference submissions;
_SubmissionCardState({this.id, this.title, this.body, this.submissions});
void _showEditScreen() {}
void _showActionButtons() {
setState(() {
showActionButtons = true;
});
}
void _hideActionButtons() {
setState(() {
showActionButtons = false;
});
}
Future<Null> _deleteSubmission() async {
try {
await submissions.document(id).delete();
await Logger.log('error', 'stackTrace');
} catch (error, stackTrace) {
await Logger.log(error, stackTrace);
}
}
void _closeDialog() {
Navigator.of(context).pop();
_hideActionButtons();
}
Future<Null> _warnAboutDeletion() async {
return showDialog(
context: context,
child: new SimpleDialog(
title: new Text('Are you sure?'),
children: <Widget>[
new SimpleDialogOption(
onPressed: () {
this._deleteSubmission();
this._closeDialog();
},
child: new Text("I'm sure. Delete it."),
),
new SimpleDialogOption(
onPressed: _closeDialog,
child: new Text("Nope. Take me back."),
),
],
)
);
}
#override
Widget build(BuildContext context) {
return new GestureDetector(
onLongPress: _showActionButtons,
onTap: _hideActionButtons,
child: new Card(
elevation: showActionButtons ? 8.0 : 2.0,
key: new GlobalKey(),
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new ListTile(
trailing: showActionButtons
? new Row(
children: <Widget>[
new IconButton(
padding: const EdgeInsets.all(0.0),
icon: const Icon(Icons.edit),
onPressed: _showEditScreen,
color: Colors.black12,
splashColor: Colors.black26,
highlightColor: Colors.black12,
),
new IconButton(
padding: const EdgeInsets.all(0.0),
icon: const Icon(Icons.delete),
onPressed: _warnAboutDeletion,
color: Colors.redAccent,
splashColor: Colors.black26,
highlightColor: Colors.black12,
),
],
)
: new Container(),
isThreeLine: true,
title: new Text(title),
subtitle: new Text(
body,
style: new TextStyle(height: 3.0),
),
),
],
),
),
);
}
}
Link to repo: https://github.com/dericgw/bodwatch
Before, when I have worked with Firebase, this collection would automatically update. I have never seen this weird behavior before. Now, I am new to Flutter and Dart, so I could be missing something for sure.
You need to add the indexing in firebase console.
In your case, you need to a multiple indexes.
1. owner_uid, ascending
2. timestamp, descending
And the problem should solve.

Resources