Flutter how to update ListView in FutureBuilder - firebase

I want to update my listview which is created in futurebuilder, I want to update this on slider change
FlutterSlider(
values: [150],
min: 0,
max: 150,
onDragging: (handlerIndex, lowerValue, upperValue) {
radius = upperValue;
users.clear();
fut = _gdb.getUsersInRadius(radius);
},
),
and code of futurebuilder and list view
Expanded(
child: FutureBuilder(
future: fut,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if(!snapshot.hasData && snapshot.connectionState == ConnectionState.done){
return Center(
child: Text("No users"));
}else if(snapshot.connectionState == ConnectionState.waiting){
return SpinKitWave(color: Theme.of(context).primaryColor);
}
return StreamBuilder(
stream: snapshot.data,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if(!snapshot.hasData){
return Center(
child: SpinKitWave(
color: Theme.of(context).primaryColor,
));
}else{
print(snapshot.data.length);
users.addAll(snapshot.data);
return ListView.builder(
controller: _scrollController ,
itemCount: users.length,
itemBuilder: (BuildContext ctx, int index){
return GestureDetector(
onTap: (){
Navigator.pushNamed(context, '/userWidget', arguments: users[index]);
},
child: Card(
child: Column(
children: [
Text(users[index].data['username']),
FutureBuilder(
future: FirebaseStorage.instance.ref().child('profilepics').child('${users[index].documentID}.jpg').getDownloadURL(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if(!snapshot.hasData){
return CircleAvatar();
}
return CircleAvatar(backgroundImage: NetworkImage(snapshot.data) ,) ;//.network(snapshot.data)
},
),
Text(users[index].data['city'] == null ? "No city" : users[index].data['city'] )
],
),
),
);
});
}
},
);
},
),
)
When user will change value of slider new users nearby will be loaded to listview and old will be deleted
Users are downloaded from Firestore using Geoflutterfire,

just call setState when doing fut = _gdb.getUsersInRadius(radius);
About the slider part
FlutterSlider(
values: [sliderValue], // initialize it with 150
min: 0,
max: 150,
onDragging: (handlerIndex, lowerValue, upperValue) {
radius = upperValue;
users.clear();
setState(){(){
sliderValue = upperValue; // update it like this.
fut = _gdb.getUsersInRadius(radius);
}}
},
),

Related

How to create streambuilder and listview with Firebase Realtime database data (Flutter chat app)

I'm building a flutter chat app for my personal learning project where the data will be retrieved from Firebase Realtime database.
I got this code from a tutorial but it is showing errors. How to solve this?
StreamBuilder(
stream: dbRef.onValue,
builder: (context, snapshot) {
if (snapshot.hasData) {
print("Error on the way");
messages.clear();
DataSnapshot dataValues = snapshot.data.snapshot; //Error: The getter snapshot is not defined for the type 'Object';
Map<dynamic, dynamic> values = dataValues.value;
values.forEach((key, values) {
messages.add(values);
});
return new ListView.builder(
shrinkWrap: true,
itemCount: messages.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Name: " + messages[index]["Text"]),
Text("Time: " + messages[index]["TextTime"]),
],
),
);
},
);
}
},
),
This solved the problem.
StreamBuilder(
stream: _dbRef.onValue,
builder: (context, snapshot) {
List<Message> messageList = [];
if (snapshot.hasData &&
snapshot.data != null &&
(snapshot.data! as DatabaseEvent).snapshot.value !=
null) {
final myMessages = Map<dynamic, dynamic>.from(
(snapshot.data! as DatabaseEvent).snapshot.value
as Map<dynamic, dynamic>); //typecasting
myMessages.forEach((key, value) {
final currentMessage = Map<String, dynamic>.from(value);
messageList.add(Message(
author: currentMessage['Author'],
authorId: currentMessage['Author_ID'],
text: currentMessage['Text'],
time: currentMessage['Time'],));
}); //created a class called message and added all messages in a List of class message
return ListView.builder(
reverse: true,
itemCount: messageList.length,
itemBuilder: (context, index) {
return ChattingDesign(
message: messageList[index],
dbpathToMsgChnl:
'TextChannels/${widget.channels['ChannelName']}/Messages',
showName: shouldShowName(
index,
messageList.length - 1,
messageList,
),
);
},
);
} else {
return Center(
child: Text(
'Say Hi...',
style: TextStyle(
color: Colors.white,
fontSize: 21,
fontWeight: FontWeight.w400),
),
);
}
},
),
According to the DataSnapshot Class Documentation there is no field called snapshot
I think there is a typo in your code.
Try this
StreamBuilder(
stream: dbRef.onValue,
builder: (context, snapshot) {
if (snapshot.hasData) {
print("Error on the way");
messages.clear();
DataSnapshot dataValues = snapshot.data! as DataSnapshot ; //here's the typo;
Map<dynamic, dynamic> values = dataValues.value;
values.forEach((key, values) {
messages.add(values);
});
return new ListView.builder(
shrinkWrap: true,
itemCount: messages.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Name: " + messages[index]["Text"]),
Text("Time: " + messages[index]["TextTime"]),
],
),
);
},
);
}
},
),

How to retrieve data from Firebase Realtime to the flutter app in a lisview

I am looking to retrieve data stored in Firebase Realtime database and display it in a new page in a lisview, how can I achieve that. So far I can retrieve and print it out in a console terminal.
My code is below:
class BarcodesResultPreviewWidget extends StatelessWidget {
FirebaseDatabase.instance.reference().child('ScannedResults');
body: Column(
children: <Widget>[
previewView,
//printing scanned results
Expanded(
child: ListView.builder(
itemBuilder: (context, position) {
return BarcodeItemWidget(preview.barcodeItems[position]);
},
itemCount: preview.barcodeItems.length,
),
),
FlatButton(
color: Colors.grey,
child: Text('Save',),
onPressed: () {
databaseRef.push().set({
'ScannedItem': preview.barcodeItems
.map((barCodeItem) => barCodeItem.toJson())
.toString(),
});
},
),
To fetch the data into a new page and build listview, try something like this:
return Scaffold(
body: FutureBuilder(
future: databaseRef.once(),
// future: FirebaseDatabase.instance
// .reference()
// .child("ScannedResults")
// .once(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return new Text('Loading....');
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
List scannedItemsValues = [];
snapshot.data.value.forEach(
(_, values) => scannedItemsValues.add(values["ScannedItem"]));
print(scannedItemsValues);
return ListView.builder(
itemCount: scannedItemsValues.length,
itemBuilder: (BuildContext context, int index) {
// build your listView here
print(scannedItemsValues[index]);
return Text(scannedItemsValues[index]);
},
);
},
),
);

how do i replace CARD with a for loop in flutter

i want to replace the card with for loop. here's the body for my screen where i am showing the output
body: FutureBuilder<List>
(
future: db.getAllRecords("EMPLOYEE"),
initialData: List(),
builder: (context,snapshot){
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, int position){
final item =snapshot.data[position];
return Card(
child:ListTile(
title: Text(
snapshot.data[position].row[1]
),
),
);
},
)
: Center(
child:CircularProgressIndicator() ,
);
Actually, the way you wrote it is the standard way of implementation in Flutter. You could call the default ListView constructor instead of ListView.builder one and then call the for loop but that's not the best practice.
List<Widget> _buildListItems(BuildContext context, List<...> list) {
final output = List<Widget>();
for (var item in list) {
output.add(
Card(
child: ListTile(
title: Text(item.row[1]),
),
),
);
}
return output;
}
//... back to your build(context) body
body: FutureBuilder<List>(
future: db.getAllRecords("EMPLOYEE"),
builder: (context, snapshot) {
return snapshot.hasData
? ListView(
children: [
..._buildListItems(context, snapshot.data),
],
)
: Center(
child: CircularProgressIndicator(),
);
}
)

how to convert the data coming from snapshot into List to fit in this column?

my this code is showing me error that querysnapshot is not a subtype of a list. can you edit my code and tell me how to make this error free.
buildProfilePosts() {
if (_isLoading) {
return Center(
child: Text(
"Loading...",
style: TextStyle(fontFamily: "QuickSand"),
),
);
}
return StreamBuilder(
stream: postsRef.document(widget.profileId).collection('userPosts').orderBy('timestamp', descending: true).snapshots(),
builder: (context, snapshot) {
return Column(
children: snapshot.data,
);
}
);
}
children is a property inside the widget Column, it takes a list of widgets. You should do the following:
child: Column(children: <Widget>[
StreamBuilder(
stream: postsRef.document(widget.profileId).collection('userPosts').orderBy('timestamp', descending: true).snapshots(),,
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: EdgeInsets.all(8.0),
title:
Text(snapshot.data.documents[index].data["name"]),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
),
]),
Assuming you have a name field in your document.
Try
Column(
children: <Widget>[
...List.generate(
snapshot.data.length,
(index) {
return Container(
child: Text(snapshot.data[index].yourobject),
);
},
),
],
),

How to add a filter in SliverGrid to show only part of the StreamBuilder result

I have a SliverGrid that populates with the result of a StreamBuilder from Firestore.
Right now I have other screens where I can filter the results by category, but that means a request to Firebase everytime the user pick a category, because I make the filter in the query.
So Im thinking if there is any way I can filter the results "locally" in the app, instead of making another call to the server, since all the info is already loaded.
My question is, if there any way to add a filter in the "SliverGrid" to show only the results that meet the criteria?
This is the part of my code with the Stream and the SliverGrid:
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance.collection('COLLECTION')
.orderBy('updated_at', descending: true)
.where('status', isEqualTo : 'published')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator()
);
}
return CustomScrollView(
slivers: [
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.3,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return InkWell(
child: CustomWidget();
);
},
childCount: snapshot.data.documents.length,
),
),
],
);
}),
);
Ok, the solution was easier than I thought.
I added a DropdownButton that updates the state dropdownValue onChanged.
Also, I replaced the query in the stream with a variable that have a filter depending of the dropdownValue value.
Here is the code of the SliverGrid with the filter:
String dropdownValue = 'all';
#override
Widget build(BuildContext context) {
var menuItems = {
'1': 'option 1',
'2': 'option 2',
'3': 'option 3'
};
var firestoreQuery;
if (dropdownValue == 'all'){
firestoreQuery = (
Firestore.instance.collection('COLLECTION')
.orderBy('updated_at', descending: true)
.where('status', isEqualTo : 'published')
.snapshots()
);
}else{
firestoreQuery = (
Firestore.instance.collection('COLLECTION')
.orderBy('updated_at', descending: true)
.where('fielt_to_filter', isEqualTo : dropdownValue)
.where('status', isEqualTo : 'published')
.snapshots()
);
}
return Scaffold(
body: StreamBuilder(
stream: firestoreQuery,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator()
);
}
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[ DropdownButton(
value: dropdownValue,
items: menuItems.entries
.map<DropdownMenuItem<String>>(
(MapEntry<String, String> e) => DropdownMenuItem<String>(
value: e.key,
child: Text(e.value),
))
.toList(),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
),
]
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.3,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return InkWell(
child: CustomWidget();
);
},
childCount: snapshot.data.documents.length,
),
),
],
);
}),
);
}

Resources