How retrieve data from firestore in widget? - dart

In my users collection, fields like photoURL,name are stored.
I want to show this fields in my widgets.
Here is my code to get the current user.
Future<void> _getUserDoc() async {
final FirebaseAuth _auth = FirebaseAuth.instance;
final Firestore _firestore = Firestore.instance;
FirebaseUser user = await _auth.currentUser();
setState(() {
userRef = _firestore.collection('users').document(user.uid);
});
}
I don't know how to get data fields.
Here is my Widget for name.
Padding(
padding:
const EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0),
child: Text(
'Richie',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
fontSize: 17.0),
),
),
I want to show instead of Richie in Text widget, user name from firestore.
Thanks in Advance.

You can use FutureBuilder for displaying username, but also you need to get current user so if you aren't getting current user somewhere else you can use nested FutureBuilders
And you can check the current state of that future with connectionState property and show CircularProgressIndicator() while connectionState is waiting ;
Widget DisplayUserName() {
return FutureBuilder(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return Text('Awaiting result...');
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
return FutureBuilder(
future: Firestore.instance.collection('users').document(snapshot.data.uid).get(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> user) {
switch (user.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return CircularProgressIndicator();
case ConnectionState.done:
if (user.hasError)
return Text('Error: ${user.error}');
return Padding(
padding:
const EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0),
child: Text(
user.data['name'],// Im assuming in CloudFirestore your field name is name.
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
fontSize: 17.0),
),
);
}
return null; // unreachable
},
);
}
return null; // unreachable
},
);
}
if you have current user in global
Future<FirebaseUser> user;
// you may get it in initState
#override
void initState() {
user = FirebaseAuth.instance.currentUser();
super.initState();
}
This will be enough,
return FutureBuilder(
future: Firestore.instance.collection('users').document(user.uid).get(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> user) {
switch (user.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return Text('Awaiting result...');
case ConnectionState.done:
if (user.hasError)
return Text('Error: ${user.error}');
return Padding(
padding:
const EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0),
child: Text(
user.data['name'],
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
fontSize: 17.0),
),
);
}
return null; // unreachable
},
);

Related

How to manage form state with BLoC pattern?

I am currently working on a side project to learn about Rx and BLoC pattern.
I would like to manage the form state without using any setState().
I already have a BLoC that manage my 'events' which are stored in a SQLite db and added after validating this form.
Do I need to create a need BLoC specifically for this UI part, and how ? Is it OK to keep a code like that ? Should I change my actual BLoC ?
You can find my current code here :
class _EventsAddEditScreenState extends State<EventsAddEditScreen> {
bool hasDescription = false;
bool hasLocation = false;
bool hasChecklist = false;
DateTime eventDate;
TextEditingController eventNameController = new TextEditingController();
TextEditingController descriptionController = new TextEditingController();
#override
Widget build(BuildContext context) {
final eventBloc = BlocProvider.of<EventsBloc>(context);
return BlocBuilder(
bloc: eventBloc,
builder: (BuildContext context, EventsState state) {
return Scaffold(
body: Stack(
children: <Widget>[
Column(children: <Widget>[
Expanded(
child: ListView(
shrinkWrap: true,
children: <Widget>[
_buildEventImage(context),
hasDescription ? _buildDescriptionSection(context) : _buildAddSection('description'),
_buildAddSection('location'),
_buildAddSection('checklist'),
//_buildDescriptionSection(context),
],
))
]),
new Positioned(
//Place it at the top, and not use the entire screen
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(
actions: <Widget>[
IconButton(icon: Icon(Icons.check), onPressed: () async{
if(this._checkAllField()){
String description = hasDescription ? this.descriptionController.text : null;
await eventBloc.dispatch(AddEvent(Event(this.eventNameController.text, this.eventDate,"balbla", description: description)));
print('Saving ${this.eventDate} ${eventNameController.text}');
}
},)
],
backgroundColor: Colors.transparent, //No more green
elevation: 0.0, //Shadow gone
),
),
],
),
);
},
);
}
Widget _buildAddSection(String sectionName) {
TextStyle textStyle = TextStyle(
color: Colors.black87, fontSize: 18.0, fontWeight: FontWeight.w700);
return Container(
alignment: Alignment.topLeft,
padding:
EdgeInsets.only(top: 20.0, left: 40.0, right: 40.0, bottom: 20.0),
child: FlatButton(
onPressed: () {
switch(sectionName){
case('description'):{
this.setState((){hasDescription = true;});
}
break;
case('checklist'):{
this.setState((){hasChecklist = true;});
}
break;
case('location'):{
this.setState((){hasLocation=true;});
}
break;
default:{
}
break;
}
},
padding: EdgeInsets.only(top: 0.0, left: 0.0),
child: Text(
'+ Add $sectionName',
style: textStyle,
),
),
);
}
Let's solve this step by step.
Your first question:
Do I need to create a need BLoC specifically for this UI part?
Well this relative of your needs and your app. You can have a BLoC for each screen if needed but you can have too a single BLoC for 2 or 3 widgets, there is no rule about it. If you think that in this case is a good approach implement another BLoC for your screen because the code will be more readable, organized and scaleable you can do this or if you think that is better make only one bloc with all inside you're free to this too.
Your second question: and how ?
Well in your code I only see setState calls in _buildAddSection so let's change this writing a new BLoc class and handle state changes with RxDart streams.
class LittleBloc {
// Note that all stream already start with an initial value. In this case, false.
final BehaviorSubject<bool> _descriptionSubject = BehaviorSubject.seeded(false);
Observable<bool> get hasDescription => _descriptionSubject.stream;
final BehaviorSubject<bool> _checklistSubject = BehaviorSubject.seeded(false);
Observable<bool> get hasChecklist => _checklistSubject.stream;
final BehaviorSubject<bool> _locationSubject = BehaviorSubject.seeded(false);
Observable<bool> get hasLocation => _locationSubject.stream;
void changeDescription(final bool status) => _descriptionSubject.sink.add(status);
void changeChecklist(final bool status) => _checklistSubject.sink.add(status);
void changeLocation(final bool status) => _locationSubject.sink.add(status);
dispose(){
_descriptionSubject?.close();
_locationSubject?.close();
_checklistSubject?.close();
}
}
Now I will use this BLoc in your widget. I will put the entire build method code below with the changes. Basically we'll use StreamBuilder to build widgets in widget tree.
final LittleBloc bloc = LittleBloc(); // Our instance of bloc
#override
Widget build(BuildContext context) {
final eventBloc = BlocProvider.of<EventsBloc>(context);
return BlocBuilder(
bloc: eventBloc,
builder: (BuildContext context, EventsState state) {
return Scaffold(
body: Stack(
children: <Widget>[
Column(children: <Widget>[
Expanded(
child: ListView(
shrinkWrap: true,
children: <Widget>[
_buildEventImage(context),
StreamBuilder<bool>(
stream: bloc.hasDescription,
builder: (context, snapshot){
hasDescription = snapshot.data; // if you want hold the value
if (snapshot.data)
return _buildDescriptionSection(context);//we got description true
return buildAddSection('description'); // we have description false
}
),
_buildAddSection('location'),
_buildAddSection('checklist'),
//_buildDescriptionSection(context),
],
),
),
]
),
new Positioned(
//Place it at the top, and not use the entire screen
top: 0.0,
left: 0.0,
right: 0.0,
child: AppBar(
actions: <Widget>[
IconButton(icon: Icon(Icons.check),
onPressed: () async{
if(this._checkAllField()){
String description = hasDescription ? this.descriptionController.text : null;
await eventBloc.dispatch(AddEvent(Event(this.eventNameController.text, this.eventDate,"balbla", description: description)));
print('Saving ${this.eventDate} ${eventNameController.text}');
}
},
),
],
backgroundColor: Colors.transparent, //No more green
elevation: 0.0, //Shadow gone
),
),
],
),
);
},
);
}
And no more setState calls in your _buildAddSection. Just need change a switch statement. The changes...calls will update the streams in BLoc class and this will make a rebuild of the widget that is listening the stream.
switch(sectionName){
case('description'):
bloc.changeDescription(true);
break;
case('checklist'):
bloc.changeChecklist(true);
break;
case('location'):
bloc.changeLocation(true);
break;
default:
// you better do something here!
break;
}
And don't forgot to call bloc.dispose() inside inside WidgetState dispose method.

How store someone userid in my friends collection and How retrieve data of that user using firestore with flutter?

I want to store my friend userid in my friends collection.
I don't know how store someone details in other user collection.
Here is my code to get the currentUser.
Future<void> _getUserDoc() async {
final FirebaseAuth _auth = FirebaseAuth.instance;
final Firestore _firestore = Firestore.instance;
FirebaseUser user = await _auth.currentUser();
setState(() {
userRef = _firestore.collection('users').document(user.uid);
});
}
Database Structure
USERS
-user1 (current user)
-name: John
-age: 20
--FRIENDS
----user2id
----user3id
-user2
-name: Richie
-age: 20
--FRIENDS
----user3id
This question has two parts-
1) How to store user2id and user3id in user1 FRIENDS collection.
2) How retrieve user2 data fields and shows in a widget.
Here is my Widget code, where I want to show name of user2.
Padding(
padding:
const EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0),
child: Text(
'20',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
fontSize: 17.0),
),
),
I want to show instead of 20 in Text widget, user2 age from firestore.
Thanks in Advance.
The easiest way I think store the other user DocumentReference's, if you store other users DocumentReference in your current user you can build them with FutureBuilder
inside the red box : friends is Array of other User DocumentReferences
For Example you have User Model
class UserModel {
final int age;
final String name;
final List<DocumentReference> friends;
UserModel(this.age, this.name, this.friends);
// to get from Firestore
UserModel.fromSnapshot(DocumentSnapshot snapshot):
age = snapshot['age'],
name = snapshot['name'],
friends = List.from(snapshot['friends']);
}
and I'm assume you get the current user from firestore
UserModel currentUser;
FutureBuilder(
future: currentUser.friends.first.get(), // this will take the first friend of current user
// or you can query the list here with where
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Center(child: Text('Connection State none'));
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
return Padding(
padding:
const EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0),
child: Text(
snapshot.data['age'],
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
fontSize: 17.0),
),
);
}
});
I hope this will handle your problem.

display loading indicator while list is being populating from an api

am new to flutter ... and am calling an api in my app and i want to display a loading indicator while the api function is finished and every thing is retrieved from the api .. how to achieve this?
class _CompaniesPageState extends State<CompaniesPage> {
getcompanies() async {
var url = 'my link';
http
.post(url, body: json.encode({ 'token': globals.token }))
.then((response) {
// print("Response body: ${response.body}");
Map data = json.decode(response.body);
final companies =
(data['Companies'] as List).map((i) => new Company.fromJson(i));
setState(() {
for (final company in companies) {
if (!company.category.contains("الراعي") &&
!company.category.contains("الشريك") &&
!company.category.contains("الداعم")) {
if (company.logo != "") {
names.add(company.name);
logos.add(company.logo);
}
}
}
});
});
}
#override
Widget build(BuildContext context) {
getcompanies();
if (globals.isguest) {
return new Directionality(
.....
);
}
}
List<Widget> createCompaniesChildren() {
List<Widget> children = List<Widget>();
for (int i = 0; i < names.length; i++) {
children.add(
new Padding(
padding: new EdgeInsets.only(right: 15.0, left: 15.0),
child: new Image.network(
logos[i],
width: 346.0,
height: 180.0,
),
),
);
children.add(
new Padding(
padding: new EdgeInsets.only(right: 15.0, left: 15.0),
child: new Center(
child: new Text(
names[i],
style: new TextStyle(color: Colors.black, fontSize: 17.0),
textAlign: TextAlign.center,
),
),
),
);
children.add(new Divider());
}
return children;
}
how can i display a loading indicator while the list is being populating and then dismiss it once it's finished??
Tried this:
body: new Padding(
padding: new EdgeInsets.only(top: 15.0),
child: new Center(
child: new FutureBuilder(
future:
getcompanies(), // your async method that returns a future
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
// if data is loaded
if (snapshot.data != null) {
return new ListView.builder(
padding: new EdgeInsets.all(8.0),
itemExtent: 20.0,
itemBuilder: (BuildContext context, int i) {
return new Center(
child: new Text(
snapshot.data[i].name,
style: new TextStyle(
color: Colors.black, fontSize: 17.0),
textAlign: TextAlign.center,
),
);
},
);
} else {
// if data not loaded yet
return new CircularProgressIndicator();
}
}
},
),
),
),
but got this error: I/flutter (31276): Another exception was thrown: A build function returned null.
You could use the FutureBuilder class for that purpose.
Also instead of manually creating the companies list you could use a ListView.
Something like this:
new FutureBuilder(
future: getcompanies(), // your async method that returns a future
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
// if data is loaded
return new ListView.builder(
padding: new EdgeInsets.all(8.0),
itemExtent: 20.0,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int i) {
return new Center(
child: new Text(
snapshot.data[i].name,
style: new TextStyle(color: Colors.black, fontSize: 17.0),
textAlign: TextAlign.center,
),
);
},
).build(context);
} else {
// if data not loaded yet
return new CircularProgressIndicator();
}
},
)
Although you have already solved or got the answer. I will show you 2 Ways.
1. Using any builder like FutureBuilder, StreamBuilder....
FutureBuilder(
future: getcompanies(), // your async method that returns a future
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.active:
case ConnectionState.waiting:
return Padding(
padding: const EdgeInsets.only(top: 20),
child: Center(
child: CircularProgressIndicator()
),
);
case ConnectionState.none:
return Center(child: Text("Unable to connect right now"));
case ConnectionState.done:
if (snapshot.hasError) {
print("Error: ${snapshot.error}");
}
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int i) {
return new Center(
child: new Text(
snapshot.data[i].name,
style: new TextStyle(color: Colors.black, fontSize: 17.0),
textAlign: TextAlign.center,
),
);
},
);
}
},
),
2. Without using builder
Put this code before API call, Like
AlertDialog alert = AlertDialog(
content: Row(children: [
CircularProgressIndicator(
backgroundColor: Colors.red,
),
Container(margin: EdgeInsets.only(left: 10), child: Text("Loading...")),
]),
);
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return alert;
},
);
api.getcompanies();
And after getting API response
var response = api.getcompanies();
Navigator.pop(context);
Note : You can put the code into a method and then call it here

Flutter refresh data in my listview

UPDATE
This is the StreamBuilder code:
I am trying currently to update with a timer that runs a Stream.fromFuture which updates the data, but with the flicker and scroll weirdness.
new StreamBuilder(
initialData: myInitialData,
stream: msgstream,
builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Waiting to start');
case ConnectionState.waiting:
return new Text('');
default:
if (snapshot.hasError) {
return new Text('Error: ${snapshot.error}');
} else {
myInitialData = snapshot.data;
return new RefreshIndicator(
child: new ListView.builder(
itemBuilder: (context, index) {
Stream<List<Map>> msgstream2;
Future<List<Map>> _responseDate = ChatDB.instance.getMessagesByDate(snapshot.data[index]['msgkey'], snapshot.data[index]['msgdate']);
msgstream2 = new Stream.fromFuture(_responseDate);
return new StreamBuilder(
initialData: myInitialData2,
stream: msgstream2,
builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Waiting to start');
case ConnectionState.waiting:
return new Text('');
default:
List messList;
var mybytes;
File myimageview;
Image newimageview;
String imgStr;
String vidStr;
String vidimgstr;
myInitialData2 = snapshot.data;
List<dynamic> json = snapshot.data;
List messagelist = [];
json.forEach((element) {
DateTime submitdate =
DateTime.parse(element['submitdate']).toLocal();
String myvideo = (element['chatvideo']);
String myimage = element['chatimage'];
String myvideoimage = element['chatvideoimage'];
File imgfile;
File vidfile;
File vidimgfile;
bool vidInit = false;
Future<Null> _launched;
String localAssetPath;
String localVideoPath;
String mymessage = element['message'].replaceAll("[\u2018\u2019]", "'");
//print('MYDATE: '+submitdate.toString());
_checkFile(File file) async {
var checkfile = await file.exists();
print('VIDEXISTS: '+checkfile.toString());
}
Future<Null> _launchVideo(String url, bool isLocal) async {
if (await canLaunchVideo(url, isLocal)) {
await launchVideo(url, isLocal);
} else {
throw 'Could not launch $url';
}
}
void _launchLocal() =>
setState(() => _launched = _launchVideo(localVideoPath, true)
);
Widget _showVideo() {
return new Flexible(
child: new Card(
child: new Column(
children: <Widget>[
new ListTile(subtitle: new Text('Video'), title: new Text(element['referralname']),),
new GestureDetector(
onTap: _launchLocal,
child: new Image.file(
vidimgfile,
width: 150.0,
),
),
],
),
)
);
}
if (myimage != "") {
imgStr = element['chatimage'];
imgfile = new File(imgStr);
}
if (myvideo != "") {
vidStr = element['chatvideo'];
vidimgstr = element['chatvideoimage'];
vidimgfile = new File(vidimgstr);
localVideoPath = '$vidStr';
}
_showLgPic() {
Route route = new MaterialPageRoute(
settings: new RouteSettings(name: "/ShowPic"),
builder: (BuildContext context) => new ShowPic(
image: imgfile,
),
);
Navigator.of(context).push(route);
}
Widget _showGraphic() {
Widget mywidget;
if (myimage != "") {
mywidget = new GestureDetector(
child: new Image.file(
imgfile,
width: 300.0,
),
onTap: _showLgPic,
);
} else if (myvideo != "") {
mywidget = _showVideo();
} else {
mywidget = new Container();
}
return mywidget;
}
messagelist.add(
new Container(
//width: 300.0,
padding: new EdgeInsets.all(10.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Container(
padding: new EdgeInsets.only(bottom: 5.0),
child: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new CircleAvatar(
child: new Text(
element['sendname'][0],
style: new TextStyle(fontSize: 15.0),
),
radius: 12.0,
),
new Text(' '),
new Text(
element['sendname'],
style: new TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold),
),
new Text(' '),
new Text(
new DateFormat.Hm().format(submitdate),
style: new TextStyle(
color: Colors.grey, fontSize: 12.0),
),
],
),
),
new Row(
children: <Widget>[
new Text(' '),
new Flexible(
child: new Text(mymessage),
)
],
),
new Container(
width: 150.0,
child: new Row(
children: <Widget>[
new Text(' '),
_showGraphic()
],
)),
],
),
),
);
});
return new Column(children: messagelist);
}
}
);
/*return new MyChatWidget(
datediv: snapshot.data[index]['msgdate'],
msgkey: snapshot.data[index]['msgkey'],
);*/
},
//itemBuilder: _itemBuilder,
controller: _scrollController,
reverse: true,
itemCount: snapshot.data.length,
),
onRefresh: _onRefresh
);
}
}
}),
I started with a Future> from a local sqlite DB. I take that future and use the data to to get another Future> from the DB. I use Listview.builder to build the widget, etc... All works great, but need to refresh the data in realtime as messages come in and get updated in the DB. I converted the furtures to streams and use a timer to go get new data, but of course my screen flickers and eventhough the data refreshes its ugly.
So I am trying to figure out a better way to get the data to update without the flicker and not affect the user if they are scrolling on the page looking at messages.
I currently do the 2 futures, because one is used to build Date Dividers between messages for each Date. I have been looking at have a StreamController and subscribing to it, but not clear how to update the data in the controller as the the data needs to be full when they come to the page and then added to as the new messages sync.
So I have been looking at something like this that I found:
class Server {
StreamController<List<Map>> _controller = new StreamController.broadcast();
void addMessage(int message) {
var newmsg = await database.rawQuery('select c.*, date(submitdate, "localtime") as msgtime from v_groupchats g join chats c on c.id = g.id where (oid = $oid or prid = $prid) and c.msgkey not in (select msgkey from chatArchive) order by submitdate desc');
_controller.add(message);
}
Stream get messages => _controller.stream;
}
This is not complete, just hoping it helps someone with some ideas for me.
Thanks in advance for any help.
This flickering is most likely the result of your:
case ConnectionState.waiting:
return new Text('');
Because every time you fetch data, your stream will enter a brief moment of ConnectionState.waiting before it is ConnectionState.done. And what you did was tell the UI to display essentially nothing Text('') every time while it fetches data. Even if it only takes like 50ms, it's noticeable to the human eye...
So if you don't care while your stream is fetching data, then remove that check. Otherwise, you could change your layout into a Stack and overlay a loading animation somewhere, or just something to indicate that it's currently fetching data.
(note that I was able to see this flickering when I tried to test your setup with a simulated Future.delayed(const Duration(milliseconds: 50), () => data), and we can perceive quicker still)

How to correctly perform a future on a FirebaseQuery using FirebaseAnimatedList in Flutter?

My FirebaseQuery is not correctly awaiting for information when I initially view the FirebaseAnimatedList. Once I leave the page and come back everything's as expected. Here is my code...
var fb = FirebaseDatabase.instance.reference();
var allUsers = FirebaseDatabase.instance
.reference()
.child('users')
.orderByChild('displayName');
#override
Future <Null> _getFriends(value) async {
try {
Map myMap = await value; //store each map
String n;
String p;
var titles = await myMap.values;
for (var items in titles) {
n = (items['displayName']);
p = (items['photo']);
}
await name.add(n);
await photos.add(p);
} catch (error) {}
}
child: new FirebaseAnimatedList(
query: fb,
padding: new EdgeInsets.all(15.0),
//sort: ,
reverse: false,
itemBuilder: (_, DataSnapshot usersSnap,
Animation<double> animation, int Index) {
return new StreamBuilder<Event>(
stream: fb
.child('users')
.orderByChild('displayName')
.onValue,
builder: (BuildContext context,
AsyncSnapshot<Event> event) {
switch (event.connectionState) {
case ConnectionState.none:
_getFriends(event.data.snapshot.value);
return new InkWell(
splashColor: Colors.blueAccent,
onTap: null,
child: new ListTile(
leading: new CircleAvatar(
backgroundImage: new AssetImage(
'assets/placeholder.png'),
radius: 35.0,
),
title: new Text(name[Index],
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
color: Colors.black
),)
),
);

Resources