The getter 'uid' was called on null - firebase

Guys I have this login page with email and password and when the user is succesfully logged it takes him to a chatscreen. On the chatscreen I need to access users uid to check who is sending the message, but I am getting the "The getter 'uid' was called on null.". I am using bloc pattern to login with validators. How can I fix this situation?
class LoginScreen extends StatefulWidget {
FirebaseUser user;
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _loginBloc = LoginBloc();
#override
void initState() {
super.initState();
_loginBloc.outState.listen((state) async {
switch (state) {
case LoginState.SUCCESS:
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => ComercialUserScreen()));
break;
case LoginState.FAIL:
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Erro'),
content: Text('Revise seu email e senha'),
));
break;
case LoginState.LOADING:
case LoginState.IDLE:
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<LoginState>(
stream: _loginBloc.outState,
initialData: LoginState.LOADING,
// ignore: missing_return
builder: (context, snapshot) {
print(snapshot.data);
switch (snapshot.data) {
case LoginState.LOADING:
return Center(
child: CircularProgressIndicator(),
);
case LoginState.FAIL:
case LoginState.SUCCESS:
case LoginState.IDLE:
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
InputField(
icon: Icons.person_outline,
hint: 'Usuário',
obscure: false,
stream: _loginBloc.outEmail,
onChanged: _loginBloc.changeEmail,
),
InputField(
icon: Icons.lock_outline,
hint: 'Senha',
obscure: true,
stream: _loginBloc.outEmail,
onChanged: _loginBloc.changePassword,
),
SizedBox(
height: 32,
),
StreamBuilder<bool>(
stream: _loginBloc.outSubmitValid,
builder: (context, snapshot) {
return RaisedButton(
child: Text("Entrar"),
onPressed:
snapshot.hasData ? _loginBloc.submit : null,
);
})
],
);
}
}),
);
}
}
class LoginBloc extends BlocBase with LoginValidators{
FirebaseUser _currentUser;
final _emailController = BehaviorSubject<String>();
final _passwordController = BehaviorSubject<String>();
final _stateController = BehaviorSubject<LoginState>();
Stream<String> get outEmail => _emailController.stream.transform(validateEmail);
Stream<String> get outPassword =>_passwordController.stream.transform(validatePassword);
Stream<LoginState> get outState => _stateController.stream;
Stream<bool> get outSubmitValid => Observable.combineLatest2(
outEmail, outPassword, (a, b) => true);
Function(String) get changeEmail => _emailController.sink.add;
Function(String) get changePassword => _passwordController.sink.add;
StreamSubscription _streamSubscription;
LoginBloc(){
_streamSubscription = FirebaseAuth.instance.onAuthStateChanged.listen((user) async {
if(user != null) {
if(await verifyAdmins(user)) {
_stateController.add(LoginState.SUCCESS);
} else {
FirebaseAuth.instance.signOut();
_stateController.add(LoginState.FAIL);
}
} else {
_stateController.add(LoginState.IDLE);
}
});
}
void submit (){
final email = _emailController.value;
final password = _passwordController.value;
_stateController.add(LoginState.LOADING);
FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password
).catchError((e) {
_stateController.add(LoginState.FAIL);
});
}
Future<bool> verifyAdmins (FirebaseUser user) async {
return await Firestore.instance.collection('users').document(user.uid).get().then((doc)
{
if(doc.data != null){
return true;
} else {
return false;
}
}).catchError((e) {
return false;
});
}
#override
void dispose() {
_emailController.close();
_passwordController.close();
_stateController.close();
_streamSubscription.cancel();
// TODO: implement dispose
}
}
class _AdminChatState extends State<AdminChat> {
bool _isLoading = false;
void _sendMessage({String text, File imgFile}) async {
DocumentSnapshot snapshot;
FirebaseUser user = await FirebaseAuth.instance.currentUser();
Map<String, dynamic> data = {
"uid" : user.uid,
'name' : user.displayName,
'photo' : user.photoUrl,
'time' : Timestamp.now()
};
if (imgFile != null){
StorageUploadTask task = FirebaseStorage.instance.ref().child('users').child(
DateTime.now().millisecondsSinceEpoch.toString()
).putFile(imgFile);
setState(() {
_isLoading = true;
});
StorageTaskSnapshot taskSnapshot = await task.onComplete;
String url = await taskSnapshot.ref.getDownloadURL();
data['imgUrl'] = url;
setState(() {
_isLoading = false;
});
}
if(text != null) data["text"] = text;
Firestore.instance.collection("users").document(snapshot.documentID)
.collection('messages').add(data);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('hello'),
),
body: Column(
children: <Widget>[
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream:
Firestore.instance.collection('users').document(widget.snapshot.documentID)
.collection('messages').orderBy('time').snapshots(),
builder: (context, snapshot){
switch(snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
List<DocumentSnapshot> documents =
snapshot.data.documents.reversed.toList();
return ListView.builder(
itemCount: documents.length,
reverse: true,
itemBuilder: (context, index){
// ignore: unrelated_type_equality_checks
return ChatMessage(documents[index].data, true);
});
}
},
),
),
_isLoading ? LinearProgressIndicator() : Container(),
TextComposer(_sendMessage),
],
),
);
}
}

The command await FirebaseAuth.instance.currentUser(); in the _AdminChatState doesn't return any data so when you try to insert data based on the user is returns null. This happens because you can't use await while the state hasn't initialized. If that happened the entire class would wait with nothing show until the user was returned. Furthermore, you use a storage query with the same logic. If you want a state widget to run something when it starts up you can use the initState() function. If you want do display a progress bar while waiting for the data to return a FutureBuilder or StreamBuilder are great choices.

Related

Trying to load the data as I scroll my listview

I am trying to make the page load data as i scroll, so I made a scroll listener in my list builder then i made a fetch next function in my future builder.
But how can i call my fetchNext function which is in my future builder to call in my void scrollListener() {}.
Is it even right to paginate the data like this. Please help.
This is the list builder
class PostGridScreen extends StatefulWidget {
final String type, city, state;
PostGridScreen({this.type, this.city, this.state});
#override
_PostGridScreenState createState() => _PostGridScreenState();
}
class _PostGridScreenState extends State<PostGridScreen>
with AutomaticKeepAliveClientMixin {
Future _getPosts;
int documentLimit = 5;
bool _hasNext = true;
bool _isFetchingUsers = false;
final _usersSnapshot = <DocumentSnapshot>[];
final scrollController = ScrollController();
var refreshKey = GlobalKey<RefreshIndicatorState>();
#override
void initState() {
_fetchPosts();
// scrollController.addListener(scrollListener);
super.initState();
}
#override
void dispose() {
scrollController.dispose();
super.dispose();
}
void scrollListener() {}
Future _fetchPosts() {
return _getPosts = Provider.of<BaseProvider>(context, listen: false)
.getPosts(widget.type, widget.city, widget.state, documentLimit);
}
Future<Null> refreshList() async {
refreshKey.currentState?.show(atTop: false);
await Future.delayed(Duration(seconds: 2));
setState(() {
_fetchPosts();
});
return null;
}
#override
Widget build(BuildContext context) {
super.build(context);
return RefreshIndicator(
onRefresh: () => refreshList(),
child: FutureBuilder(
key: PageStorageKey('Page1'),
future: _getPosts,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
controller: scrollController,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
//Fetch Next
Future fetchNextUsers() async {
if (_isFetchingUsers) return;
_isFetchingUsers = true;
try {
_getPosts =
Provider.of<BaseProvider>(context, listen: false)
.getPosts(
widget.type,
widget.city,
widget.state,
documentLimit,
startAfter: _usersSnapshot.isNotEmpty
? _usersSnapshot.last
: null);
_usersSnapshot.addAll(snapshot.data);
if (snapshot.data.length < documentLimit)
_hasNext = false;
} catch (e) {}
_isFetchingUsers = false;
}
//Tile
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => PostDetailScreen(
post: snapshot.data[index],
),
));
},
child: Padding(
padding: EdgeInsets.only(
top: 10,
bottom: 3.0,
right: 20.0,
left: 20.0,
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: const Offset(
5.0,
5.0,
),
blurRadius: 10.0,
spreadRadius: 2.0,
), //BoxShadow
],
color: Colors.blue,
borderRadius: BorderRadius.circular(20.0),
image: DecorationImage(
image: NetworkImage(
snapshot.data[index]["imageUrl"],
),
fit: BoxFit.cover,
),
),
height: 190.0,
width: 100,
),
),
);
},
);
} else {
return Center(
child: Text("Loading..."),
);
}
}),
);
}
#override
bool get wantKeepAlive => true;
}
This is the base provider
class BaseProvider with ChangeNotifier {
final CollectionReference postsCollection =
FirebaseFirestore.instance.collection("posts");
//Fetching Data
Future getPosts(String type, String city, String state, int limit,
{DocumentSnapshot startAfter}) async {
try {
if (startAfter == null) {
QuerySnapshot<Map<String, dynamic>> response = await FirebaseFirestore
.instance
.collection("posts")
.where('type', isEqualTo: type)
.where('sellercity', isEqualTo: city)
.where('sellerstate', isEqualTo: state)
.limit(limit)
.get();
return response.docs;
} else {
QuerySnapshot<Map<String, dynamic>> response = await FirebaseFirestore
.instance
.collection("posts")
.where('type', isEqualTo: type)
.where('sellercity', isEqualTo: city)
.where('sellerstate', isEqualTo: state)
.startAfterDocument(startAfter)
.limit(limit)
.get();
return response.docs;
}
} catch (e) {
print(e.toString());
return e;
}
}
}
if I understood correctly you want that your app doesn't load and render everything in a list at once and render them just in time it is shown to the user.
for achieving this you have to implement lazy loading which ListView.builder do this completely on its own so you don't need to worry about it

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.

UID call on null and provider failing to pass on data with TypeError (type 'FirebaseUser' is not a subtype of type 'String')

I tried to reach user data to determine Admin role and pass on to Future Builder. Depending on Admin, the result will be determine if which widget will be available.
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
floatingActionButton:
FutureBuilder(
future: _getProfileData(user, authNotifier),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
_isAdmin = snapshot.data['isAdmin'] ?? false;
}
return Container(
child: Column(
children: <Widget>[
adminFeature(),
]
));
}),
The widget below provides information on user.
Widget adminFeature() {
if(_isAdmin == true) {
return
FloatingActionButton(
backgroundColor:CompanyColors.blue[500],
child: const Icon(Icons.add),onPressed: () {
var foodNotifier = Provider.of<FoodNotifier>(context, listen: false);
foodNotifier.currentFood = null;
Navigator.of(context).push(
MaterialPageRoute(builder: (BuildContext context) {
return FoodForm(
isUpdating: false,
);
}),
);
});
} else {
return Container();
}
}
_getProfileData(User user, AuthNotifier authNotifier) async {
final uid = await Provider.of<AuthNotifier>(context, listen: false).getCurrentUser();
await Firestore.instance
.collection('Users')
.document(uid)
.get().then((result) {
user.isAdmin = result.data['isAdmin'];
});
}
Below, this is the provider. It works for all the apps, but I fail to get the user data and pass on to a widget.
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => AuthNotifier(),
),
ChangeNotifierProvider(
create: (context) => FoodNotifier(),
),
ChangeNotifierProvider(create: (context) => ThemeProvider(isLightTheme: false)),
ChangeNotifierProvider(create: (context) => UserxProvider()),
ChangeNotifierProvider(create: (context) => UsersProvider()),
],
child: MyApp());
}
Notifier is mentionned below:
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
Future<String> getCurrentUID() async {
return (await _firebaseAuth.currentUser()).uid;
}
// GET CURRENT USER
Future getCurrentUser() async {
return await _firebaseAuth.currentUser();
}
In your _getProfileData method, you should change the following:
await Provider.of(context, listen: false)
to
await Provider.of<UserxProvider>(context, listen: false)
// or UsersProvider, whichever you're trying to call
The problem is that when you call Provider without specifying the model that you want (i.e., the type), it becomes Provider.of<dynamic> and hence you're getting that error message.

Getting null value (Firestore query result) in Flutter app

I have an application and In this i'm making a query for get user details by the e-mail account.
I'm using Future class to get data and fill my variable but the widget Text always show null value.
Please let me now if i am doing something wrong.
class _HomePageAppState extends State<HomePageApp> {
String _emailUsuario;
Usuario usuario;
void initState() {
super.initState();
Autenticacao().getCurrentUser().then((user) {
setState(() {
if (user != null) {
_emailUsuario = user.email.toString(); //the user email is returnig correctly
recuperarDadosUsuarioFirebase().then((ds) {
usuario = Usuario(
email: _emailUsuario,
nome: ds['nome'] != null ? ds['nome'] : null,
);
});
}
});
});
}
Future<DocumentSnapshot> recuperarDadosUsuarioFirebase() async {
DocumentSnapshot ds;
await Firestore.instance
.collection('usuarios')
.document(_emailUsuario)
.get()
.then((DocumentSnapshot _ds) {
ds = _ds;
});
return ds;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.white10,
child: ListView(
children: <Widget>[
Text('Bem vindo ${usuario.nome} !!!'),
],
),
),
);
}
}
U might want to use Future Builder for such async work cause build method was called before usuario is assign so like this :
FutureBuilder(
future: getCurrentUser(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
}
// after getting data
},
);
Method getCurrentUser() needs to be created :)

how to get data from firebase in flutter

I am building a flutter app and using cloud-firestore,
this is how my database looks like
I want a function that retrieves all documents in the collection called "Driver List" in an array of strings
that what I had already used but it gets them back in a listview in a new screen
class DriverList extends StatelessWidget {#overrideWidget build(BuildContext context) {
return new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('DriverList').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['name']),
subtitle: new Text(document['phone']),
);
}).toList(),
);
},
);
}
}
This has some additional logic to remove potentially duplicate records, but you can use something like the following to retrieve data from Firestore.
We get access to a collection reference, then list the results of the query, then create local model objects for the data returned by Firestore, and then we return the a list of those model objects.
static Future<List<AustinFeedsMeEvent>> _getEventsFromFirestore() async {
CollectionReference ref = Firestore.instance.collection('events');
QuerySnapshot eventsQuery = await ref
.where("time", isGreaterThan: new DateTime.now().millisecondsSinceEpoch)
.where("food", isEqualTo: true)
.getDocuments();
HashMap<String, AustinFeedsMeEvent> eventsHashMap = new HashMap<String, AustinFeedsMeEvent>();
eventsQuery.documents.forEach((document) {
eventsHashMap.putIfAbsent(document['id'], () => new AustinFeedsMeEvent(
name: document['name'],
time: document['time'],
description: document['description'],
url: document['event_url'],
photoUrl: _getEventPhotoUrl(document['group']),
latLng: _getLatLng(document)));
});
return eventsHashMap.values.toList();
}
Source: https://github.com/dazza5000/austin-feeds-me-flutter/blob/master/lib/data/events_repository.dart#L33
Getting one time data:
var collection = FirebaseFirestore.instance.collection('DriverList');
var querySnapshot = await collection.get();
for (var queryDocumentSnapshot in querySnapshot.docs) {
Map<String, dynamic> data = queryDocumentSnapshot.data();
var name = data['name'];
var phone = data['phone'];
}
Getting data each time it changes, using a StreamBuilder:
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection('DriverList').snapshots(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.hasData) {
final docs = snapshot.data!.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (_, i) {
final data = docs[i].data();
return ListTile(
title: Text(data['name']),
subtitle: Text(data['phone']),
);
},
);
}
return Center(child: CircularProgressIndicator());
},
)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class LoadDataFromFirestore extends StatefulWidget {
#override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
#override
void initState() {
super.initState();
getDriversList().then((results) {
setState(() {
querySnapshot = results;
});
});
}
QuerySnapshot querySnapshot;
#override
Widget build(BuildContext context) {
return Scaffold(
body: _showDrivers(),
);
}
//build widget as prefered
//i'll be using a listview.builder
Widget _showDrivers() {
//check if querysnapshot is null
if (querySnapshot != null) {
return ListView.builder(
primary: false,
itemCount: querySnapshot.documents.length,
padding: EdgeInsets.all(12),
itemBuilder: (context, i) {
return Column(
children: <Widget>[
//load data into widgets
Text("${querySnapshot.documents[i].data['activation']}"),
Text("${querySnapshot.documents[i].data['car1']}"),
Text("${querySnapshot.documents[i].data['car2']}"),
Text("${querySnapshot.documents[i].data['car5']}"),
Text("${querySnapshot.documents[i].data['name']}"),
Text("${querySnapshot.documents[i].data['phone']}"),
],
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}
//get firestore instance
getDriversList() async {
return await Firestore.instance.collection('DriversList').getDocuments();
}
}
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder(
stream:
FirebaseFirestore.instance.collection('messages').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
}
if (snapshot.hasData) {
final messages = snapshot.data!.docs;
List<Text> messageWigdets = [];
for (var message in messages) {
final messageText = message['text'];
final messageSender = message['sender'];
final messageWigdet =
Text('$messageText from $messageSender');
messageWigdets.add(messageWigdet);
}
return Expanded(
child: ListView(
children: [...messageWigdets],
),
);
}
return const CircularProgressIndicator.adaptive();
},
),

Resources