Flutter + Firebase : How to view images depend on id? - firebase

I have an app show data from firebase ,and image in folder called category in firebase storage ,the name of image is same id field of collections.
now I want to view data and view image of same field :
child: ListView.builder(
padding: EdgeInsets.all(10),
itemCount: doctorData.length,
itemBuilder: (context, index) {
return Card(
elevation: 15,
child: ListTile(
leading: Container(
width: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30)),
child: Image(
image: NetworkImage(
'gs://myproject.appspot.com/categories/categories/${doctorData[index]['id']}.png'),
)
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(doctorData[index]),
),
);
},
title: Text('Dr. ${doctorData[index]['name_en']}',
style: TextStyle(fontSize: 22)),
subtitle: Text('د. ${doctorData[index]['name_ar']}',
style: TextStyle(fontSize: 22)),
),
);
}),
),
The image isn't shown , How can I view the image

I had the same issue, but after a while i figured this out. I used Futurebuilder and CachedNetworkImageProvider and they are solved my problem.
If you want to you the CachedNetworkImageProvider you need this in the pubspec.yaml.
dependencies:
cached_network_image: ^2.3.3
FutureBuilder<dynamic>(
future: FirebaseStorage().ref('yourImage.jpg').getDownloadURL(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState != ConnectionState.waiting) {
return Image(
image: CachedNetworkImageProvider(snapshot.data.toString()),
fit: BoxFit.cover,
);
} else {
return Text('Loading image....');
}
},
),

Related

Get URl from cloud firestore and use Gesture Detector to redirect to the link?

In my project I am making an flutter app which fetch images from cloud firestore.
Right now i also want to call URL from cloud firestore so that whenever someone Tap on a particular image they redirect to specific link provided for images.
I have a collection name most and within collection i have 7 documents and within documents i have fields Image and its unique url
And i have this code for fetching images which is working absolutely fine:
FutureBuilder(
future: getMost(),
builder:(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Lottie.asset('animations/loading.json');
} else {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return GestureDetector( onTap: null,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: SizedBox(
height: 150.0,
width: 130.0,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage((snapshot.data[index].data()['image']),),fit: BoxFit.cover),
borderRadius:
BorderRadius.circular(10),
),
)
),
),
);
}
);
}
}
)
Use the flutter package url_launcher if you want to launch any kind of urls.
link : https://pub.dev/packages/url_launcher/
In pubsec.yaml
dependencies:
url_launcher: ^6.0.18
Actual code:
openUrl(url) async {
if (await canLaunch(url)){
await launch(url);
}
else {
// error
}
}
FutureBuilder(
future: getMost(),
builder:(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Lottie.asset('animations/loading.json');
} else {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return GestureDetector( onTap: () => openUrl(snapshot.data[index].data()['url']),
child: Padding(
padding: const EdgeInsets.all(2.0),
child: SizedBox(
height: 150.0,
width: 130.0,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage((snapshot.data[index].data()['image']),),fit: BoxFit.cover),
borderRadius:
BorderRadius.circular(10),
),
)
),
),
);
}
);
}
}
)

How to click on an image to display the details of that image (that data is taken from firebase)

How can I know which event I clicked on? How to click on an image to display the details of that image (that data is taken from firebase). I can't find a solution to this problem, please help!
Widget _allUsers(BuildContext context) {
return StreamBuilder <List<MatHangSnapshot>>(
stream: getAllMatHangFromFirebase(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator(),);
else {
return GridView.builder(
itemCount: snapshot.data.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2),
itemBuilder: (context, index) {
return Card(
child: GridTile(
child: FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ChiTietNongSan()),
);
},
padding: EdgeInsets.all(0.0),
child: Column(
children: [
Image.network(snapshot.data[index].mh.image, width: 150, height: 150,),
],
),
),
footer: Column(
children: [
Center(
child: Text(snapshot.data[index].mh.tenMH, style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),),
),
Center(
child: Text("Giá: ${snapshot.data[index].mh.gia.toString()}/kg",style: TextStyle(fontSize: 15, color: Colors.red),),
)
],
)
accept the image via the constructor of ChiTietNongSan class then make your onPressed look like this
onPressed: () {
//change this to your actual image
var image = snapshot.data[index]["image"];
Navigator.push(context,
MaterialPageRoute(builder: (context) => ChiTietNongSan(image)),
);
},
You can get the image in the FlatButton's onPressed method, the same way you're displaying it in the Image.network widget by using the code below:
snapshot.data[index].mh.image
And you can use it in your onPressed like this:
FlatButton(
onPressed: () {
print(snapshot.data[index].mh.image);
Navigator.push(context, MaterialPageRoute(builder: (context) => ChiTietNongSan()),);
},
...
)
The important thing with knowing which exact image you clicked on is the index and you can use that to get any information you need from the MatHangSnapshot class.

I need field data to be updated in the UI when there is some update in that field from firestore

I want to update document field value in the UI of flutter whenever there is some change in field value in realtime.
I have tried using StreamBuilder but the only output I am getting is 'Instance QuerySnapshot'
StreamBuilder(
stream: db.collection('users').snapshots(),
initialData: 0,
builder:(BuildContext context, AsyncSnapshot snapshot) {
return new Text(snapshot.data.DocumentSnapshot,
style: TextStyle(
color: Colors.yellow,
fontWeight: FontWeight.bold,
fontSize: 12.0));
},
),`
Expected output is int value of reward field in document uid.
Because of this line stream: db.collection('users').snapshots(),
You are getting the collection, but you expected the document. Refer to the following:
StreamBuilder(
stream: db.collection('users').document(userId).snapshots(), // insert the userId
initialData: 0,
builder:(BuildContext context, DocumentSnapshot snapshot) { // change to DocumentSnapshot instead of AsyncSnapshot
return new Text(snapshot.data.documentID, // you can get the documentID hear
style: TextStyle(
color: Colors.yellow,
fontWeight: FontWeight.bold,
fontSize: 12.0));
},
),`
I have done one of my project with stream builder and it's working fine. I am putting some code snippet from there please check it out this may helps you.
Code of StreamBuilder
StreamBuilder<QuerySnapshot>(
stream: db.collection("students").snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text("There is no expense");
return Expanded(
child: new ListView(
children: generateStudentList(snapshot),
),
);
},
),
code of generateStudentList
generateStudentList(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents
.map<Widget>(
(doc) => new ListTile(
title: new Text(doc["name"]),
subtitle: new Text(
doc["age"].toString(),
),
trailing: Container(
width: 100,
child: Row(
children: <Widget>[
IconButton(
onPressed: () {
setState(() {
_studentNameController.text = doc["name"];
_studentAgeController.text = doc["age"].toString();
docIdToUpdate = doc.documentID;
isUpdate = true;
});
},
icon: Icon(
Icons.edit,
color: Colors.blue,
),
),
IconButton(
onPressed: () {
deleteStudent(doc);
},
icon: Icon(
Icons.delete,
color: Colors.red,
),
)
],
),
),
),
)
.toList();
}
You can change fields according your needs.

How to load image to the Card from data retrieved from async task in flutter?

I'm new to flutter development. I need to load images into a card depending on data loaded via async task.
I have an async task which returns Future> user data quired from the sqlite local database. With retrieved data, I build a ListView to show users using Card. But inside the card, I'm trying to show an image which will be downloaded from Firebase Storage depending on the data retrieved from the local database. But the image URL is null.
Widget build(BuildContext context) {
var allCards = DBProvider.db.getAllCards();
return FutureBuilder<List<User>>(
future: DBProvider.db.getAllCards(),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
User user = snapshot.data[index];
return Card(
elevation: 8.0,
margin:
new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
child: Image(
image: CachedNetworkImageProvider(FirebaseStorage().ref().child('employer_logo').child('00001').child('google-banner.jpg').getDownloadURL().toString()),
fit: BoxFit.cover,
),
),
Positioned(
bottom: 0,
left: 0,
child: Container(
padding: EdgeInsets.all(10),
child: Text(
'Google Incorperation',
style: TextStyle(
fontSize: 20, color: Colors.white),
),
),
)
],
),
Container(
decoration: BoxDecoration(
color: Colors.white10,
),
child: ListTile(
title: Text(user.fname + " " + user.lname,
style: TextStyle(
color: Colors.blue[400], fontSize: 20)),
subtitle: Text(user.designation,
style: TextStyle(
color: Colors.blue[300], fontSize: 16)),
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Profile(
user.fname,
user.lname,
user.uid,
user.designation,
user.mobile,
user.employerId)))
},
),
)
],
),
);
},
);
}
},
);
}
I expect to show images downloaded from firebase storage
This would be my first answer, and there are probably many ways to improve my answer here. But I will give it a go: Actually, you will have to look up a lot on Futuresand Streams, because it is quite a big part in many a app. If your app needs any content on the web, it will need Futures, or it's bigger counterpart Stream. In this case, where you want to set up a Listview with probably multiple images, I would go for a Stream. Also, I would save all my database logic in a seperate file. However, if you don't want to modify your code too much now, I would use a FutureBuilder.
I've seen you already use one of them in your code. But in this case, use:
...
int maxsize = 10e6.round(); // This is needed for getData. 10e^6 is usually big enough.
return new Card (
FutureBuilder<UInt8List> ( // I also think getting Data, instead of a DownloadUrl is more practical here. It keeps the data more secure, instead of generating a DownloadUrl which is accesible for everyone who knows it.
future: FirebaseStorage().ref().child('entire/path/can/go/here')
.getData(maxsize),
builder: (BuildContext context, AsyncSnapshot<UInt8List> snapshot) {
// When this builder is called, the Future is already resolved into snapshot.data
// So snapshot.data contains the not-yet-correctly formatted Image.
return Image.memory(data, fit: BoxFit.Cover);
},
),
Widget build(BuildContext context) {
var allCards = DBProvider.db.getAllCards();
return FutureBuilder<List<User>>(
future: DBProvider.db.getAllCards(),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
User user = snapshot.data[index];
int maxsize = 10e6.round();
return Card(
elevation: 8.0,
margin:
new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
child: FutureBuilder<dynamic>(
future: FirebaseStorage()
.ref()
.child('employer_logo')
.child('00001')
.child('google-banner.jpg')
.getDownloadURL(),
builder: (BuildContext context,
AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState !=
ConnectionState.waiting) {
return Image(
image: CachedNetworkImageProvider(
snapshot.data.toString()),
fit: BoxFit.cover,
);
}
else {
return Text('Loading image....');
}
},
),
),
Positioned(
bottom: 0,
left: 0,
child: Container(
padding: EdgeInsets.all(10),
child: Text(
'Google Incorperation',
style: TextStyle(
fontSize: 20, color: Colors.white),
),
),
)
],
),
Container(
decoration: BoxDecoration(
color: Colors.white10,
),
child: ListTile(
title: Text(user.fname + " " + user.lname,
style: TextStyle(
color: Colors.blue[400], fontSize: 20)),
subtitle: Text(user.designation,
style: TextStyle(
color: Colors.blue[300], fontSize: 16)),
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Profile(
user.fname,
user.lname,
user.uid,
user.designation,
user.mobile,
user.employerId)))
},
),
)
],
),
);
},
);
}
},
);
}

Flutter: Do FutureBuilder Loads everything at the same time?

My app has a book summaries Feature, Now since I don't have money to host an API, I am using Firebase/Firestore database where I add summaries manually and then retrieve data from firebase to App.
I am using FutureBuilder for it.
Now say I have 10 summaries will FutureBuilder first load all 10 of them and then display data on screen(which is a ListView.builder and can show only 2 summaries without scrolling) or it will load only the data which need to be painted on the screen just like simple ListView.builder.
// code to retrieve data:
Future<QuerySnapshot> getFeedsfromFb() async {
var data = await Firestore.instance
.collection('feedItem')
.orderBy('feedId', descending: true).getDocuments();
return data;
}
// building widget:
Widget feed() {
return Container(
width: deviceWidth,
height: deviceHeight / 3,
child: FutureBuilder(
future: getFeedsfromFb(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.documents.length > 10
? 10
: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return Container(
width: deviceWidth / 2.5,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => FeedIntro(
snapshot.data.documents[index]['feedId'])));
},
child: Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
// width: 150,
height: 150,
foregroundDecoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
snapshot.data.documents[index]['feedImage'],
),
fit: BoxFit.fill)),
),
Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(snapshot.data.documents[index]['title']),
)),
],
)),
),
);
},
);
} else if (snapshot.hasError) {
return Center(child: Text('Sorry Something went wrong!'));
} else {
return Center(
child: SizedBox(
child: CircularProgressIndicator(),
width: 50,
height: 50,
),
);
}
}),
);
}
Your FutureBuilder will load all items at the same, but only needed data by ListView.builder will be painted on the screen.

Resources