How to get userdata from firestore when refreshing the browser? - firebase

I have a Flutter web application where I sign in and navigate to a homepage.
Here I display the name of the user and that is working fine until I refresh my browser.
When I refresh my browser it returns a null value, but when I navigate to another page and back again I retrieve the users name. So I hoping there is another way to do this so I get my users name after refreshing the browser.
When I try to retrieve the users email from FirebaseAuth instead of the usersname from Firestore it works fine when refreshing the browser. So I think it has something to do with how I retrieve it from Firestore.
Here is some of my code:
Main.dart
class MyApp extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
final FirebaseAuth auth = FirebaseAuth.instance;
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot)
{
if (snapshot.hasError) {
return (MaterialApp(
home: UserLoginPage(
),
));
}
if (snapshot.connectionState == ConnectionState.done) {
print('CONNECTED');
return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, snapshot) {
return MaterialApp(
home: snapshot.hasData && snapshot.data != null
? const UserHomePage()
: const UserLoginPage(),
routes: {
UserLoginPage.id: (context) => const UserLoginPage(),
UserHomePage.id: (context) => const UserHomePage(),
},
debugShowCheckedModeBanner: false,
);
}
);
}
return Column();
});
}
}
HomePage
class _UserHomePageState extends State<UserHomePage> {
final scaffoldkey = GlobalKey<ScaffoldState>();
User? user = FirebaseAuth.instance.currentUser;
Future _getUserData() async {
await FirebaseFirestore.instance.collection('users').doc(user?.uid)
.get()
.then((snapshot) async {
if (snapshot.exists) {
setState(() {
name = snapshot.data()!['Navn'];
print(name!);
});
}
});
}
DateTime now = DateTime.now();
#override
void initState() {
super.initState();
_getUserData();
}
//String
String? name = '';
String? formattedDate = DateFormat('yyyy-MM-dd').format(DateTime.now());
#override
Widget build(BuildContext context) {
var appBarHeight = kToolbarHeight;
return Scaffold(
key: scaffoldkey,
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: const Color.fromRGBO(119, 221, 167, 1),
title: const Text(
'Test',
style: TextStyle(
fontFamily: 'Poppins',
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
),
backgroundColor: Colors.white,
drawer: Container(
padding: EdgeInsets.only(top: appBarHeight + 1),
child: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(name!),
),
const SizedBox(
height: 10,
),
],
),
),
),
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 20,
),
Text('Hei, $name!',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
],
),
),
));
}
}

Related

Could someone tell me how to turn this into a listview.builder and still have it connected to firebase? btw the name of my collection is 'groceries'

Currently it is a listview, I know how to normally create a listview.builder but I don't know how to connect it to firebase. Im talking about the streambuilder and context and all that stuff. Really appreciate any help, Im new to flutter so sorry if this is an obvious/dumb question.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(FireApp());
}
class FireApp extends StatefulWidget {
#override
_FireAppState createState() => _FireAppState();
}
class _FireAppState extends State<FireApp> {
final TextController = TextEditingController();
bool isChecked = false;
#override
Widget build(BuildContext context) {
CollectionReference groceries =
FirebaseFirestore.instance.collection('groceries');
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: TextField(
controller: TextController,
),
),
body: Center(
child: StreamBuilder(
stream: groceries.orderBy('name').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView(
children: snapshot.data!.docs.map((grocery) {
return Center(
child: Row(
children: [
Container(color: Colors.red,height: 50,child: Text(grocery['name'])),
Checkbox(
materialTapTargetSize: MaterialTapTargetSize.padded,
value: isChecked,
activeColor: Colors.black,
checkColor: Colors.greenAccent,
onChanged: (bool) {
setState(() {
isChecked = !isChecked;
});
}
)],
),
);
}).toList(),
);
},
),
),
floatingActionButton: FloatingActionButton(onPressed: () {
groceries.add({
'name': TextController.text,
});
},),
),
);
}
}
StreamBuilder and listview.builder sample code given below
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: groceries.orderBy('name').snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
// your list of groceries
List groceriesList =
snapshot.data.docs.map((e) => e.data()).toList();
return ListView.builder(
itemCount: groceriesList.length,
itemBuilder: (context, i) {
// build your widget here.
return Center(
child: Row(
children: [
Container(
color: Colors.red,
height: 50,
child: Text(groceriesList[i]['name']),
),
Checkbox(
materialTapTargetSize: MaterialTapTargetSize.padded,
value: isChecked,
activeColor: Colors.black,
checkColor: Colors.greenAccent,
onChanged: (bool) {
setState(() => isChecked = !isChecked);
},
)
],
),
);
},
);
},
),

Add image from gallery to user document id using Flutter and Firebase

I am developing an app, and I want to create a user profile for each logged-in user. With my code now, I am able to get the user information from the cloud Firestore of each user uid document, but I want the user to be able to add an image to firebase storage, and then get this image, add to the specific user uid doc, and display on the app. Basically, I know how to get the data I have already, I just don't know how to update the user doc, especially with images.
Here is the code I have for the user profile:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:tradie_app/scr/providers/authService.dart';
import 'package:tradie_app/scr/screens/edit_company_email.dart';
import 'package:tradie_app/scr/widgets/loading.dart';
import 'home.dart';
class CompanyProfile extends StatefulWidget {
#override
_CompanyProfileState createState() => _CompanyProfileState();
}
class _CompanyProfileState extends State<CompanyProfile> {
// Keep track of the form for validation
final _formKey = GlobalKey<FormState>();
// Loading Icon
bool loading = false;
final AuthService _authService = AuthService();
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;
Future getCompanyNameData() async {
final CollectionReference users =
_firebaseFirestore.collection("Companies");
final String uid = _firebaseAuth.currentUser.uid;
final result = await users.doc(uid).get();
return result.data()["companyName"];
}
Future getCompanyEmailData() async {
final CollectionReference users =
_firebaseFirestore.collection("Companies");
final String uid = _firebaseAuth.currentUser.uid;
final result = await users.doc(uid).get();
return result.data()["companyEmail"];
}
#override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
backgroundColor: Colors.white,
title: Text(
"Create the company profile",
style: TextStyle(
color: Colors.black,
),
),
elevation: 0.0,
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
accountName: FutureBuilder(
future: getCompanyNameData(),
builder: (_, AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
}
return Text(snapshot.data);
},
),
),
ListTile(
leading: Icon(Icons.logout),
title: Text(
"Log Out",
),
onTap: () async {
await _authService.signOut();
},
),
],
),
),
body: Padding(
padding: const EdgeInsets.all(18.0),
child: SingleChildScrollView(
child: Container(
child: Form(
key: _formKey,
child: Column(
children: [
Row(
children: [
Text(
"Company name: ",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
),
),
],
),
SizedBox(
height: 10.0,
),
Row(
children: [
FutureBuilder(
future: getCompanyNameData(),
builder: (_, AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
}
return Text(
snapshot.data,
style: TextStyle(
color: Colors.black, fontSize: 15.0),
);
},
),
],
),
SizedBox(
height: 20.0,
),
Row(
children: [
Text(
"Company email: ",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
),
),
],
),
SizedBox(
height: 10.0,
),
Row(
children: [
FutureBuilder(
future: getCompanyEmailData(),
builder: (_, AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
}
return Text(
snapshot.data,
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
);
},
),
IconButton(
icon: Icon(Icons.edit),
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
EditCompanyEmailScreen(),
),
),
),
],
),
SizedBox(
height: 20.0,
),
Row(
children: [
Text(
"Company phone number: ",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
),
),
],
),
SizedBox(
height: 20.0,
),
// Here is where I want to add the image
Row(
children: <Widget>[],
),
],
),
),
),
),
),
);
}
}
To select the image from gallery add this plugin. And then call this function to select the image.
File _image;
selectImageFromGallery() async
{
final picker=ImagePicker();
setState(() {
inProcess=true;
});
final imageFile= await picker.getImage(source: ImageSource.gallery);
if(imageFile!=null)
{
_image=File(imageFile.path);
}
setState(() {
inProcess=false;
});
}
after selecting the image run this function to store image to firebase and get url of the image.
Future<String> uploadFile(File image) async
{
String downloadURL;
String postId=DateTime.now().millisecondsSinceEpoch.toString();
Reference ref = FirebaseStorage.instance.ref().child("images").child("post_$postId.jpg");
await ref.putFile(image);
downloadURL = await ref.getDownloadURL();
return downloadURL;
}
now lets upload and update data in firestore docs and storage.
uploadToFirebase()async
{
String url=await uploadFile(_image); // this will upload the file and store url in the variable 'url'
await users.doc(uid).update({ //use update to update the doc fields.
'url':url
});
}
To show the selected image add this in your Ui:-
Container(
height: 200,
width: 200,
decoration: BoxDecoration(image: DecorationImage(image: FileImage(_image,),fit: BoxFit.contain)),
)
After adding this image make a button for upload:-
RaisedButton()
{
onPressed:(){
uploadToFirebase();
},
child:Text("Upload"),
}
After selecting the image user will click on this button to upload and save sata to firebase.
You need to upload the image chosen from gallery to your firebase storage and then use the url in your firestore.
here is a samle code to upload the image to storage
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
final ref = firebase_storage.FirebaseStorage.instance.ref().child("profile-pic/abc.jpg");
final imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
final uploadTask = ref.putFile(imageFile);
final snapshot = await uploadTask.whenComplete(() => null);
imageUrl = await snapshot.ref.getDownloadURL();
use the imageUrl and update it in your firestore collection for the user.
You can fetch the url and display image whenever you need.

A non-null String must be provided to a Text widget flutter

I have this problem with this code. I tried to solve the problem, but I did not succeed. Please Help
Please see the screenshots to understand the problem well
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 370 pos 10: 'data != null'
Pictures description error
null in firebase
The users email address.Will be null if signing in anonymously.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
class ChatScreen extends StatefulWidget {
static const Id = 'chat_screen';
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
// ignore: deprecated_member_use
final _firestore = Firestore.instance;
final _auth = FirebaseAuth.instance;
// ignore: deprecated_member_use
FirebaseUser loggedInUser;
String messageText;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
// ignore: await_only_futures
final user = await _auth.currentUser;
if (user != null) {
loggedInUser = user;
print(loggedInUser.email);
}
} catch (e) {
print(e);
}
}
// void getMessages() async {
// // ignore: deprecated_member_use
// final messages = await _firestore.collection('Messages').getDocuments();
// // ignore: deprecated_member_use
// for (var message in messages.docs) {
// print(message.data());
// }
// }
void messagesStream() async {
await for (var snapshot in _firestore.collection('Messages').snapshots()) {
for (var message in snapshot.docs) {
print(message.data());
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
messagesStream();
//_auth.signOut();
//Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('Messages').snapshots(),
// ignore: missing_return
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
));
}
// ignore: deprecated_member_use
final messages = snapshot.data.documents;
List<Messagebubble> messagebubbles = [];
for (var message in messages) {
final messageText = message.data()['text'];
final messagesendar = message.data()['Sender'];
final messagebubble = Messagebubble(
sendar: messagesendar,
text: messageText,
);
messagebubbles.add(messagebubble);
}
return Expanded(
child: ListView(
padding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 20.0,
),
children: messagebubbles,
),
);
},
),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
_firestore.collection('Messages').add({
'text': messageText,
'Sender': loggedInUser,
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class Messagebubble extends StatelessWidget {
Messagebubble({
Key key,
this.sendar,
this.text,
}) : super(key: key);
final String sendar;
final String text;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
children: [
Text(
sendar,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
Material(
borderRadius: BorderRadius.circular(30.0),
elevation: 5.0,
color: Colors.lightBlueAccent,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
child: Text(
text,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
You just need to check whether the text that you are passing is null or not. If it is null, you can show that the user is Anonymous.
final messageText = message.data()['text'];
final messagesendar = message.data()['Sender'] ?? 'Anonymous'; // If null then use 'Anonymous'
final messagebubble = Messagebubble(
sendar: messagesendar,
text: messageText,
);
Flutter doesn't allow you to pass null to Text widgets.

How to make a streambuilder return data in other screens

I am new in Flutter, I have a question about an implementation I want to add my app, I would appreciate your answers, let me know if you need me to give you more information.
I hope, this is clear.
Here is the implementation I want to add my app...
I have a streambuilder in my home page(see below code implementing a container that has a streambuilder as a child) that gets data from firebase(the data is users information) and returns a Listview.builder that builds a list of containers with data like name and email(for each user) in my home screen...now, how can I replace the listView.builder and instead of having those users in a listview.builder, I actually want those users information to be saved one by one into different screens(like creating a user profile for each user).
This is the streambuilder:
Container(
///this is a regular streambuilder as a child of a container
child: StreamBuilder(
stream: Firestore.instance.collection('users').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(themeColor),
),
);
} else {
///THIS IS THE LISTVIEW.BUILDER
return ListView.builder(
padding: EdgeInsets.all(10.0),
///These are some methods that build the containers list with the users information
itemBuilder: (context, index) =>
buildItem(context, snapshot.data.documents[index]),
itemCount: snapshot.data.documents.length,
);
}
},
),
),
COMPLETE CODE FOR MY HOMEPAGE
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:jobly10/chat_implementation/settings.dart';
import 'chat.dart';
import 'const.dart';
import '../main.dart';
class HomeListViewUsers extends StatefulWidget {
final String currentUserId;
HomeListViewUsers({Key key, this.currentUserId}) : super(key: key);
#override
State createState() => HomeListViewUsersState(currentUserId: currentUserId);
}
class HomeListViewUsersState extends State<HomeListViewUsers> {
HomeListViewUsersState({Key key, #required this.currentUserId});
final String currentUserId;
final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final GoogleSignIn googleSignIn = GoogleSignIn();
bool isLoading = false;
List<Choice> choices = const <Choice>[
const Choice(title: 'Settings', icon: Icons.settings),
const Choice(title: 'Log out', icon: Icons.exit_to_app),
];
#override
void initState() {
super.initState();
registerNotification();
configLocalNotification();
}
void registerNotification() {
firebaseMessaging.requestNotificationPermissions();
firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
Platform.isAndroid
? showNotification(message['notification'])
: showNotification(message['aps']['alert']);
return;
}, onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return;
}, onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
});
firebaseMessaging.getToken().then((token) {
print('token: $token');
Firestore.instance
.collection('users')
.document(currentUserId)
.updateData({'pushToken': token});
}).catchError((err) {
Fluttertoast.showToast(msg: err.message.toString());
});
}
void configLocalNotification() {
var initializationSettingsAndroid =
new AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = new IOSInitializationSettings();
var initializationSettings = new InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
void onItemMenuPress(Choice choice) {
if (choice.title == 'Log out') {
handleSignOut();
} else {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Settings()));
}
}
void showNotification(message) async {
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
Platform.isAndroid
? 'com.dfa.flutterchatdemo'
: 'com.duytq.flutterchatdemo',
'Flutter chat demo',
'your channel description',
playSound: true,
enableVibration: true,
importance: Importance.Max,
priority: Priority.High,
);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
print(message);
await flutterLocalNotificationsPlugin.show(0, message['title'].toString(),
message['body'].toString(), platformChannelSpecifics,
payload: json.encode(message));
}
Future<Null> handleSignOut() async {
this.setState(() {
isLoading = true;
});
await FirebaseAuth.instance.signOut();
await googleSignIn.disconnect();
await googleSignIn.signOut();
this.setState(() {
isLoading = false;
});
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => MyApp()),
(Route<dynamic> route) => false);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Chat Screen',
style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: WillPopScope(
child: Stack(
children: <Widget>[
// List
Container(
///here the chats users are called
child: StreamBuilder(
stream: Firestore.instance.collection('users').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(themeColor),
),
);
} else {
///THIS IS THE LISTVIEW.BUILDER
return ListView.builder(
padding: EdgeInsets.all(10.0),
///These are some methods that build the containers list with the users information
itemBuilder: (context, index) =>
buildItem(context, snapshot.data.documents[index]),
itemCount: snapshot.data.documents.length,
);
}
},
),
),
// Loading
Positioned(
child: isLoading
? Container(
child: Center(
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(themeColor)),
),
color: Colors.white.withOpacity(0.8),
)
: Container(),
)
],
),
// onWillPop: onBackPress,
),
);
}
Widget buildItem(BuildContext context, DocumentSnapshot document) {
if (document['id'] == currentUserId) {
return Container();
} else {
return Container(
child: FlatButton(
child: Row(
children: <Widget>[
Material(
child: document['profileImageUrl-'] != null
? CachedNetworkImage(
placeholder: (context, url) => Container(
child: CircularProgressIndicator(
strokeWidth: 1.0,
valueColor:
AlwaysStoppedAnimation<Color>(themeColor),
),
width: 50.0,
height: 50.0,
padding: EdgeInsets.all(15.0),
),
//i just cange this
imageUrl: document['profileImageUrl'],
width: 50.0,
height: 50.0,
fit: BoxFit.cover,
)
: Icon(
Icons.account_circle,
size: 50.0,
color: greyColor,
),
borderRadius: BorderRadius.all(Radius.circular(25.0)),
clipBehavior: Clip.hardEdge,
),
Flexible(
child: Container(
child: Column(
children: <Widget>[
Container(
child: Text(
'Name: ${document['nickname']}',
style: TextStyle(color: primaryColor),
),
alignment: Alignment.centerLeft,
margin: EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 5.0),
),
Container(
child: Text(
'email: ${document['email']}',
style: TextStyle(color: primaryColor),
),
alignment: Alignment.centerLeft,
margin: EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 5.0),
),
Container(
child: Text(
'About me: ${document['aboutMe'] ?? 'Not available'}',
style: TextStyle(color: primaryColor),
),
alignment: Alignment.centerLeft,
margin: EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 0.0),
)
],
),
margin: EdgeInsets.only(left: 20.0),
),
),
],
),
onPressed: () {
///here is the flat button to go to messages
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Chat(
peerId: document.documentID,
peerAvatar: document['photoUrl'],
),
),
);
},
color: greyColor2,
padding: EdgeInsets.fromLTRB(25.0, 10.0, 25.0, 10.0),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
),
margin: EdgeInsets.only(bottom: 10.0, left: 5.0, right: 5.0),
);
}
}
}
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
If you want each item in the ListView.builder to be 'tappable' and send you to a profile screen containing the tapped user's information, try wrapping each ListView element in a GestureDetector:
return ListView.builder(
padding: EdgeInsets.all(10.0),
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
GestureDetector(
onTap: Navigator.push(context,
MaterialPageRoute(builder: (context) => UserProfile(user_name, user_age, user_etc)),);
child: buildItem(context, snapshot.data.documents[index])
),
);
You can pass info from your Stream into a newly made UserProfile (or something to that effect) page, which is navigated to by tapping on either of the ListView panels.
Alternatively, in your buildItem widget definition, you can return a GestureDetector (which will wrap your current Container) instead and place the onTap logic in there.

Value is retrieved only after hot reload in flutter

I'm kinda new to flutter, I've been building a small app using firebase as the backend, whenever I try to load data from firebase I'm not able to fetch the value until I reload the app, this isn't the entire code,
I think the widgets are loading before the data itself, could really use ur help, is there any way that I could use the state to refresh the value?
mycode:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import "package:flutter/material.dart";
import 'package:mine_app/textingpage.dart';
class FriendsPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _FriendsPage();
}
}
class Friends {
final int theirTexts;
final String username;
final int myTexts;
final int totalTexts;
final String friendId;
Friends(this.theirTexts,this.totalTexts,this.username,this.myTexts,this.friendId);
Friends.fromMap(DocumentSnapshot map)
:assert(map["username"]!=null),
assert(map["myTexts"]!=null),
assert(map["theirTexts"]!=null),
assert(map["totalTexts"]!=null),
assert(map["uid"]!=null),
username = map["username"],
myTexts = map["myTexts"],
theirTexts = map["theirTexts"],
totalTexts = map["totalTexts"],
friendId = map["uid"];
}
class _FriendsPage extends State<FriendsPage> {
String user;
String globalid = "";
Future<void> getuser() async {
user = (await FirebaseAuth.instance.currentUser()).uid;
}
#override
void initState() {
getuser();
super.initState();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff723881),
centerTitle: true,
title: Text(
"Chats",
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.people), text: "People"),
Tab(icon: Icon(Icons.search), text: "Find"),
],
indicatorColor: Colors.white,
),
),
body: TabBarView(
children: <Widget>[
Container(
child: snapShotBuilder(context)
),
Container()
],
)),
);
}
Widget snapShotBuilder(BuildContext context){
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("users").document(user).collection("friends").snapshots(),
builder:(context,snapshot){
if (!snapshot.hasData) {
return LinearProgressIndicator();
}
return myListView(context,snapshot.data.documents);
} );
}
Widget myListView(BuildContext context,List<DocumentSnapshot> snapshot){
return Container(
child: ListView(
children: snapshot.map((data)=>myfriends(Friends.fromMap(data))).toList(),
),
);
}
Widget myfriends(Friends friend) {
return Container(
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.all(5.0),
child: ListTile(
onTap:(){
setState(() {
globalid = friend.friendId;
});
print(friend.friendId);
Navigator.push(context, MaterialPageRoute(builder: (context)=>ChatPage(userid:friend.friendId)));
},
trailing: Container(
// margin: EdgeInsets.only(top:30.0,left:10.0,right:0.0),
child: Text(
friend.totalTexts.toString(),),
leading: Container(
width: 60.0,
height: 60.0,
),
title: Text(friend.username,),
),
);
}
}
Yo need to setState() in getUser() and also check if snapshot has data or not also.so the modified code will be
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import "package:flutter/material.dart";
import 'package:mine_app/textingpage.dart';
class FriendsPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _FriendsPage();
}
}
class Friends {
final int theirTexts;
final String username;
final int myTexts;
final int totalTexts;
final String friendId;
Friends(this.theirTexts,this.totalTexts,this.username,this.myTexts,this.friendId);
Friends.fromMap(DocumentSnapshot map)
:assert(map["username"]!=null),
assert(map["myTexts"]!=null),
assert(map["theirTexts"]!=null),
assert(map["totalTexts"]!=null),
assert(map["uid"]!=null),
username = map["username"],
myTexts = map["myTexts"],
theirTexts = map["theirTexts"],
totalTexts = map["totalTexts"],
friendId = map["uid"];
}
class _FriendsPage extends State<FriendsPage> {
String user;
String globalid = "";
Future<void> getuser() async{
setState((){
user = (await FirebaseAuth.instance.currentUser()).uid;
});
}
#override
void initState() {
getuser();
super.initState();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff723881),
centerTitle: true,
title: Text(
"Chats",
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.people), text: "People"),
Tab(icon: Icon(Icons.search), text: "Find"),
],
indicatorColor: Colors.white,
),
),
body: TabBarView(
children: <Widget>[
Container(
child: snapShotBuilder(context)
),
Container()
],
)),
);
}
Widget snapShotBuilder(BuildContext context){
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("users").document(user).collection("friends").snapshots(),
builder:(context,snapshot){
if (snapshot.hasData) {
return myListView(context,snapshot.data.documents);
}else if(snapshot.hasError){
return Center(
child:Text(snapshot.error.toString()));
}else{
return LinearProgressIndicator();
}
} );
}
Widget myListView(BuildContext context,List<DocumentSnapshot> snapshot){
return Container(
child: ListView(
children: snapshot.map((data)=>myfriends(Friends.fromMap(data))).toList(),
),
);
}
Widget myfriends(Friends friend) {
return Container(
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.all(5.0),
child: ListTile(
onTap:(){
setState(() {
globalid = friend.friendId;
});
print(friend.friendId);
Navigator.push(context, MaterialPageRoute(builder: (context)=>ChatPage(userid:friend.friendId)));
},
trailing: Container(
// margin: EdgeInsets.only(top:30.0,left:10.0,right:0.0),
child: Text(
friend.totalTexts.toString(),),
leading: Container(
width: 60.0,
height: 60.0,
),
title: Text(friend.username,),
),
);
}
}
You are right. Widget is built at once after call of initState but you getting user data using Future so it is possilbe that Future is not completed yet. So you just need to wrap your main widget with FutureBuilder:
#override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: getUser(), // <-- your future
builder: (context,snapshot) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xff723881),
centerTitle: true,
title: Text(
"Chats",
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.people), text: "People"),
Tab(icon: Icon(Icons.search), text: "Find"),
],
indicatorColor: Colors.white,
),
),
body: TabBarView(
children: <Widget>[
Container(
child: snapShotBuilder(context)
),
Container()
],
),
),
),
},
);
}

Resources