Flutter Gridview button functionality to new screen with Firebase - firebase

I've made a Gridview using Firebase and Streambuilder and Gridview.builder. This grid displays album titles, the album cover art for each album, and the artists that make each album. I'd like for each grid tile to be able to be pressed and navigate to a separate page with its specific album details. The plan was on press, the app would be able to identify the entire document the grid tile was referring to, move to a new page, and display the document in full to unveil the album details. The thing is, I don't know how to do that. Since snapshot.data.documents[index]['Title'] worked when iterating though all the documents to create the gridview, I thought that typing snapshot.data.documents[index] would work, but it just displays Instance of 'DocumentSnapshot' in the debug console. I'm out of ideas on how to tackle this, so any suggestions are welcome
My code is shown below
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final Services services = Services();
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bgcolour,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: Icon(Icons.menu),
title: Text("Home"),
actions: <Widget>[
Padding(padding: EdgeInsets.all(10), child: Icon(Icons.more_vert))
],
),
body: StreamBuilder(
stream: Firestore.instance.collection('music').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text("Loading...");
return GridView.builder(
itemCount: snapshot.data.documents.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, childAspectRatio: 0.655172413),
//cacheExtent: 1000.0,
itemBuilder: (BuildContext context, int index) {
var url = snapshot.data.documents[index]['Cover Art'];
return GestureDetector(
child: Container(
width: 190.0,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32)),
color: hexToColor(
snapshot.data.documents[index]['Palette'][0]),
elevation: 1,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(height: 12),
ClipRRect(
borderRadius: BorderRadius.circular(21.0),
child: Image.network(url,
height: 180.0, width: 180)),
SizedBox(height: 10),
Text(
snapshot.data.documents[index]['Artist']
.join(', '),
textAlign: TextAlign.center,
style: GoogleFonts.montserrat(
textStyle: TextStyle(color: Colors.white),
fontSize: 14,
fontWeight: FontWeight.w300)),
SizedBox(height: 10),
Text(snapshot.data.documents[index]['Title'],
style: GoogleFonts.montserrat(
textStyle: TextStyle(color: Colors.white),
fontSize: 16,
fontWeight: FontWeight.w600),
textAlign: TextAlign.center),
],
),
),
),
onTap: () {
print("Tapped ${snapshot.data.documents[index]}");
},
);
},
);
}
),
);
}
}

Is there an ID for your snapshot.data.documents[index]? If yes, add it to the end.
onTap: () {
print("Tapped ${snapshot.data.documents[index]['the property you want']}");
},

Related

How to put different images and redirect users to other pages in ListView Builder?

Writing a code in Flutter right now and I can display a database with ListView.
However, I want to put pictures of the destination according to its location so I was wondering how to put different images for each different item? The same goes for the onTap void callback function as well. I want each list item to go to different pages where further details of the destination is given.
Code:
class _DispDestState extends State<DispDest> {
List<AllDestinations> destinationsList = [];
#override
void initState() {
super.initState();
DatabaseReference referenceAllCourses = FirebaseDatabase.instance
.reference()
.child('Database')
.child('Destinations');
referenceAllCourses.once().then(((DataSnapshot dataSnapshot) {
destinationsList.clear();
var keys = dataSnapshot.value.keys;
var values = dataSnapshot.value;
for (var key in keys) {
AllDestinations allDestinations = new AllDestinations(
values[key]['name'],
values[key]['description'],
values[key]['category'],
);
if (allDestinations.category.toString() == 'Destination')
destinationsList.add(allDestinations);
}
setState(() {});
}));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.fromLTRB(20, 5, 20, 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Come and Explore",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 14,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w500,
letterSpacing: 0.5,
),
),
SizedBox(height: 15),
Expanded(
child: SingleChildScrollView(
child: Column(children: <Widget>[
destinationsList.length == 0
? Center(
child: Text(
"Loading...",
style: TextStyle(fontSize: 15),
))
: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: destinationsList.length,
itemBuilder: (_, index) {
return DestinationCard(
title: destinationsList[index].destname,
onTap: () {},
img: 'assets/icons/temp.png');
})
]),
),
),
])));
}
}
class DestinationCard extends StatelessWidget {
final String title, img;
final VoidCallback onTap;
const DestinationCard({
Key? key,
required this.title,
required this.img,
required this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 400,
height: 190,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(15, 155, 0, 0),
width: 350,
height: 190,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
image: AssetImage(img), fit: BoxFit.cover),
),
child: Text(
title,
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
);
}
}
You should add a parameter named imagePath to AllDestinations class. So when you use DestinationCard in ListView.builder, you can add:
return DestinationCard(
title: destinationsList[index].destname,
onTap: () {},
img: destinationsList[index].imagePath,
);

How to display one particular data from Realtime Database?

In a firebase animated list, how do you put in a conditional statement, or anything else, so that only one set of data in Realtime Database will be displayed? I currently can display all of them in a ListTile but I only want to display a destination whose name is 'Spain' and its description instead of all the database that contains Spain, Italy, USA etc.
class _TestDestinationsState extends State<TestDestinations> {
final destdatabaseref = FirebaseDatabase.instance
.reference()
.child('Database')
.child('Destinations');
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF4D71AC),
elevation: 0,
centerTitle: true,
title: Text('Eh',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Colors.white)),
),
body: SafeArea(
child: FirebaseAnimatedList(
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(8),
child: ListTile(
title: Text(snapshot.value['name'],
style: TextStyle(fontSize: 20)),
subtitle: Text(snapshot.value['description'])),
),
],
),
);
},
query: destdatabaseref,
)),
);
}
}
If we need to only display specific data from FirebaseDatabase we can use the following logic:
Visibility(
visible: snapshot.value['name'] == 'Spain',
child: ...
),
The complete snippet can be found below:
class _TestDestinationsState extends State<TestDestinations> {
final destdatabaseref = FirebaseDatabase.instance
.reference()
.child('Database')
.child('Destinations');
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF4D71AC),
elevation: 0,
centerTitle: true,
title: Text('Eh',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Colors.white)),
),
body: SafeArea(
child: FirebaseAnimatedList(
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return Visibility(
visible: snapshot.value['name'] == 'Spain',
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(8),
child: ListTile(
title: Text(snapshot.value['name'],
style: TextStyle(fontSize: 20)),
subtitle: Text(snapshot.value['description'])),
),
],
),
),
);
},
query: destdatabaseref,
)),
);
}
}
However a much better solution, would be to retrieve only specific data based on the filter, which can be done by filtering our query to FirebaseDatabase as follows:
final destdatabaseref = FirebaseDatabase.instance
.reference()
.child('Database')
.child('Destinations')
.orderByChild('name')
.equalTo('Spain');

i want to create a listview with firebase in flutter that will show title subtitle and image and when user click on listview that will open a webview

I sm creating a flutter app where i want to create a listview with firebase in flutter that will show title subtitle and image and when user click on listview that will open a webview but I want the web view URL should come from the firebase title subtitle and the image part already working I stuck in the URL part please help how to do this
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:watched_movie_list/Widget/webviewx.dart';
class ListviewPage extends StatefulWidget {
final firBaseLists;
final String webviewTitle;
final String weburl;
ListviewPage(
{this.firBaseLists, required this.webviewTitle, required this.weburl});
#override
_ListviewPageState createState() => _ListviewPageState();
}
class _ListviewPageState extends State<ListviewPage> {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance.collection('listview').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CupertinoActivityIndicator(
radius: 20,
),
);
}
return Scaffold(
appBar: AppBar(
title: Text(
' नवीनतम सूचनाएं',
style: TextStyle(color: Colors.black),
),
leading: BackButton(color: Colors.black),
backgroundColor: Colors.white,
),
body: Container(
height: 800,
color: Color(0xfff5f5f5),
child: ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InAppWebViewx(
title: widget
.firBaseLists["${data['titletext']}"],
url: widget.firBaseLists("${data['url']}"),
)));
},
child: Container(
height: 150,
decoration: BoxDecoration(
color: Colors.lightGreen,
borderRadius: BorderRadius.circular(18)),
margin:
EdgeInsets.only(top: 8, right: 12, left: 12, bottom: 2),
child: Row(
children: [
Container(
padding: const EdgeInsets.only(top: 15, left: 20),
height: 150,
width: 330,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
"${data['img']}",
height: 40,
width: 40,
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"${data['titletext']}",
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"${data['subtitle']}",
maxLines: 2,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
),
],
),
),
);
}).toList(),
),
),
);
},
);
}
}```
You should use Listview.builder instead of Listview. Inside the Listview.builder you could capture the data with index of the itemBuilder and pass it to the WebView. Here's the link to get started on Listview.builder https://www.geeksforgeeks.org/listview-builder-in-flutter/

Fetch user data from firestore and show them in profile screen using flutter

The issue here is that when I fetch the data, I am suppose to fetch it for the current user but it is rather fetching data for all users within that collection.
I have done reading and watched a number of videos for a possible solution but I can't seem to find how to do this. Your help is needed please. Thanks.
A excerpt of the bode is below.
File image;
TextEditingController loginNameController = TextEditingController();
TextEditingController loginPhoneController = TextEditingController();
TextEditingController loginAddressController = TextEditingController();
clearForm() {
setState(() {
image = null;
loginNameController.clear();
loginPhoneController.clear();
loginAddressController.clear();
});
}
//=====> FOR INSTANCES OF FIREBASE <=====
final auth = FirebaseAuth.instance;
final db = FirebaseFirestore.instance;
User user = FirebaseAuth.instance.currentUser;
body: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: StreamBuilder(
stream: db.collection("collection name").snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if (!snapshot.hasData) {
return Center(
child: spinkit,
);
}
return ListView.builder (
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index){
return Stack(
children: [
Column(
children: [
Stack(
children: [
// ===> RETRIEVING USER DETAILS AND SHOWING IT IN A ROW <===
Container(
padding : EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
backgroundColor: Palette.mainColor,
radius: 50,
child: ClipOval(
child: SizedBox(
height: 150,
width: 150,
child: image == null ? Center(
// child: Image.asset("asset/images/placeholder.png", fit: BoxFit.cover,),
child: Image.network(snapshot.data.documents[index].get("image")),
):
Image.file(image, fit: BoxFit.cover,),
),
),
),
SizedBox(width: 16,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 0),
child: Text(snapshot.data.documents[index].get("Name"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),),
),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Address"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Number"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
],
),
),
Padding(
padding: EdgeInsets.only(left: 0, bottom: 15),
child: IconButton(
icon:Icon(Icons.edit, color: Palette.mainColor, ),
onPressed: () { },
),
),
],
),
),
],
),
],
),
],
);
},
);
},
),
)
The collection name is members
Try like this, stream of your widget should be like this, as said above.
db.collection("Users").document(user.uid).snapshots();
for length in Listview.builder, change it too
snapshot.data.length;
And last, All the data which you fetch data like this should change into
from:
snapshot.data.documents[index].get("image")
To:
snapshot.data["image"]
Note I didn't test it. So, it might or might not work.
First of All use a DocumentSnapshot Shown below:
StreamBuilder<DocumentSnapshot>
Make a collection to get current user Profile data.
db.collection("Users").doc(user.uid).snapshots();
Remove ListView.builder
To get an Email Address use the below Line
Text('${streamSnapshot.data['Email Address']}'),
Here is the complete Article https://medium.com/#kamranktk807/fetch-user-data-from-firestore-and-show-them-in-profile-screen-using-flutter-609d2533e703
By the way I sol this problem with the help of a Professional Flutter Developer SHAKIR ZAHID [shakirzahid191#gmail.com].

firestore map to StreamBuilder => ListView.Builder

i want to show the songs list inside document (singer that user clicked on). Every song should load in list tile but all of them load in one tile.
and it loads the 'songs list' from all documents(all singers).
this is the FireStore DB
this is list of singers to choose from.
this should show only the songs from selected singer each one in a tile but shows all songs from all singers. and every singers song in one tile
class SongsList extends StatefulWidget {
#override
_SongsListState createState() => _SongsListState();
}
class _SongsListState extends State<SongsList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance.collection('singers').snapshots(),
builder: (
context,
snapshot,
) {
if (snapshot.data == null)
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
valueColor: new AlwaysStoppedAnimation<Color>(Colors.teal),
),
);
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/back.png'), fit: BoxFit.contain)),
child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
var result = snapshot.data.documents[index]['songs list'];
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(
left: 10, right: 10, top: 10, bottom: 0),
child: Container(
height: 50,
width: 300,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.white.withOpacity(0.5),
spreadRadius: 1.5,
blurRadius: 1.5,
//offset: Offset(0, 1), // changes position of shadow
),
],
borderRadius: BorderRadius.circular(5),
border: Border.all(
color: Colors.red[200],
width: 0.5,
style: BorderStyle.solid)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (var res in result.entries)
Text(
res.key,
style: TextStyle(
fontSize: 20, color: Colors.red[500]),
),
]),
),
),
);
}),
);
},
),
);
}
}
If you want to get only the songs of one singer, then you need to specify the document id to retrieve one document, change this:
stream: Firestore.instance.collection('singers').snapshots(),
into this:
stream: Firestore.instance.collection('singers').document('aryana sayeed').snapshots(),
List tile has a corresponding index. I think you might have to build a list tile instead of a container. If you need a container, you have to write a code that would specifically get the singers name (documentID) wired on each container

Resources